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
>
>
>
>

Reply via email to