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