I am trying to write a macro which would transform
@enum_and_dict(foo, foodict, "A" => A, "B" => B)
to
@enum foo A B
foodict = Dict("A" => A, "B" => B)
I have tried this:
macro enum_and_dict(enumname, dictvar, pairs...)
function expr_second(expr)
@assert expr.head ≡ :(=>) "$expr is not a Pair."
esc(expr.args[2])
end
quote
@enum($(esc(enumname)), $(map(expr_second, pairs)...))
$(esc(dictvar)) = Dict($(pairs...))
end
end
and the Dict part works fine, but for the first one I get a very complicated expression, and I don’t know why, or how to fix it.
Using the macro above in another module, I found that is missing an esc. A correct MWE is
module Foo # minimal working example
macro enum_and_Dict(enumname, dictvar, pairs...)
function expr_second(expr)
@assert expr.head ≡ :(=>) "$expr is not a Pair."
esc(expr.args[2])
end
quote
@enum($(esc(enumname)), $(map(expr_second, pairs)...))
$(esc(dictvar)) = Dict($(map(esc, pairs)...))
end
end
module Bar # using the macro in a submodule
import ..@enum_and_Dict
@enum_and_Dict(BarEnum, bar_dict, "a"=>a)
end
end
Question: is it possible to simplify this code, or make it more idiomatic? Style hints are welcome, I am still learning Julia macros.
Enumerating values twice is error prone and tedious. I don’t see any resemblance to LISP in the code above, the goal is to eliminate redundancy. Also, I am not sure how you can do this without macros (but I am interested in suggestions — macros are not the end here, just the means).
You don’t need a new macro if you don’t mind starting with symbols (at the risk of annoying akis with somewhat cryptic code):
module M
function enum_and_dict(d::Dict{String,Symbol},ename)
ds=([v for (k,v) in d]...)
@eval @enum $ename $(ds...)
dnew = Dict(k => getfield(M,v) for (k,v) in d)
end
d1 = Dict("A" => :A, "B" => :B)
d2 = enum_and_dict(d1,:MyEnum)
display(MyEnum)
display(d2)
end
Enum M.MyEnum:
B = 0
A = 1
Dict{String,M.MyEnum} with 2 entries:
"B" => B
"A" => A
To my eyes, the resemblance is in the mixed arguments inside long parentheses (I may be biased though).
I don’t mind symbols (they are present eitherway). And not annoyed by @eval (definitely less cryptic than the proposed macro). It should be $(values(d)...) though.