I am not very good at macros but I took a stap at doing this. It is very
possible this could be done in a cleaner way.
Code:
macroerror() = throw(ArgumentError("invalid macro expression"))
function extract(ex)
if !(ex.head == :call)
macroerror()
end
f_name = ex.args[1]
vars = Symbol[]
types = Symbol[]
for var_ex in ex.args[2:end]
if isa(var_ex, Expr)
if !(var_ex.head == :(::))
macroerror()
end
sym = var_ex.args[1]::Symbol
typ = var_ex.args[2]::Symbol
elseif isa(var_ex, Symbol)
sym = var_ex
typ = :Any
end
push!(vars, sym)
push!(types, typ)
end
return f_name, vars, types
end
macro deffun(expr)
f, args, types = extract(expr)
ex = Expr(:function)
ex_def = Expr(:(call))
push!(ex_def.args, f)
for (arg, typ) in zip(args, types)
var_ex = Expr(:(::))
push!(var_ex.args, arg)
push!(var_ex.args, typ)
push!(ex_def.args, var_ex)
end
push!(ex.args, ex_def)
# Function body goes here
ex_body = quote
println("hello")
end
push!(ex.args, ex_body)
return esc(ex)
end
Usage:
julia> @deffun foo(a,b::Int)
foo (generic function with 1 method)
julia> foo(5, 3.0)
ERROR: MethodError: `foo` has no method matching foo(::Int64, ::Float64)
Closest candidates are:
foo(::Any, ::Int64)
julia> foo(5, 3)
hello
julia> @deffun bar(a::AbstractString,b::Int)
bar (generic function with 1 method)
julia> bar("hoho", 3)
hello
On Monday, October 19, 2015 at 9:45:14 AM UTC+2, Andrei Zh wrote:
>
> I'm trying to write a macro for generation of new functions given their
> name and arguments, e.g. given macro call:
>
> @deffun foo(a, b)
>
> it should generate function like:
>
> function foo(a, b)
> # do some stuff
>
>
> end
>
> Important part is that both - name of a function and name of arguments -
> should be preserved. My best attempt to do it looks like this:
>
> macro deffun(ex)
> func = ex.args[1]
> args = ex.args[2:end]
> return quote
> function $(esc(func))($(esc(args...)))
> # do some stuff
>
>
> end
> end
> end
>
> `$(esc(func))` works pretty well, but `args` isn't a Symbol and so macro
> compilation fails.
>
> 1. How do I escape list of arguments here?
> 2. How do I make this macro to also support argument types? E.g. given
> macro call:
>
>
> @deffun foo(a::Int, b::Float64)
>
> the following functions should be generated:
>
> function foo(a::Int, b::Float64)
> # do some stuff
>
>
> end
>
>
>
>