I have a struct to represent symbolic variable:
struct Var name::Symbol value::Any end
Now I want to generate a function expression that takes objects of type
Var and returns an expression made from their
.name fields, e.g. like this:
function +(x::Var, y::Var) return Expr(:call, :+, x.name, y.name) end x = Var(:a, 1) # note: julia variable `x`, but internal name is :a y = Var(:b, 2) x + y # ==> :(a + b)
Code generation will be wrapped into a macro, so I’ll refer to this stage - stage where we generate function like above - as a macroexpand time. On the contrary, the returned expression, e.g.
Expr(:call, :+, x.name, y.name) can only be created in runtime since
y.name aren’t known beforehand.
I have many function like this with different signatures, e.g.:
+(x::Var, y::Var) exp(x::Var) ^(x::Var, n::Int) ...
Obviously, I don’t want to copy-paste function body for of these cases but instead to have something like:
@symbolic +(x::Var, y::Var) @symbolic exp(x::Var) @symbolic ^(x::Var, n::Int) ...
So the list of argument names is always different (we can ignore types for a moment). Now the basic setup of a problem looks like this:
f_vars = [:x, :y] # the list of `Var` names from function signature, known during macroexpand time quote ex_vars = ... # something that returns [:a, :b] in runtime Expr(:call, :op, ex_vars...) end
The missing piece is the code to get
ex_vars, i.e. values of
y.name during runtime. Note, that during macroexpand time we known the names of variables (i.e.
y), but not their values.
First I tried the following:
:(ex_vars = [v.name for v in $f_vars])
f_vars is a list of symbols, not
v.name fails with
type Symbol has no field name.
So I tried to interpolate each
v first, meaning that interpolation should happen in runtime:
:(ex_vars = [$(v).name for v in $f_vars])
Surely, it’s interpolated in macroexpand time instead. I also tried multiple options with
Expr(:$, ...) and
QuoteNode(...), but couldn’t find anything working. One more attempt with
escin hope it passes
$ as is:
:(ex_vars = [esc($(v).name) for v in $f_vars])
But it also tries to interpolate
v right in macroexpand time.
Any other options?