@Kristoffer, as you said, there may be cleaner (more declarative) way to do 
it, but beyond that your definition works perfectly, thanks! 

On Monday, October 19, 2015 at 2:21:45 PM UTC+3, Kristoffer Carlsson wrote:
>
> 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