IIUC, the following yields the desired behavior:
macro deffun(ex)
func = ex.args[1]
args = ex.args[2:end]
decl = Expr(:call, func, args...)
body = quote
# do some stuff
end
res = Expr(:function, esc(decl), body)
end
gives
julia> macroexpand(:( @deffun f(x::Int, y::Int) ))
:(function f(x::Int,y::Int)
end)
On Monday, October 19, 2015 at 3:11:11 PM UTC-7, Andrei Zh wrote:
>
> @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
>>>
>>>
>>>
>>>