2
votes

I'm writing a Julia macro that takes an expression and serializes it, so that I can run it somewhere else. The macro therefore takes the expression and replaces all symbols with variables. The expression is then serialized and evaluated somewhere else.

My problem is related to evaluating variables that are not in the global scope. I.e. the following works fine, as a is defined in the global scope:

macro myprintf(ex)
    print(eval(ex))
end

# works 
a = 2
@myprintf a

This throws an error as the macro doesn't see a, which is defined in the local scope of the loop (run in a new session):

macro myprintf(ex)
    print(eval(ex))
end

# UndefVarError: a not defined
for j=1:3
    a = 2
    @myprintf a
end

Is there any way I can access a inside the macro if it is defined in a local scope such as a loop? I'm aware that I'm not necessarily using macros as intended as I am calling eval on the expression inside the macro definition. The overall idea is that I want to serialize the expression that's passed to the macro and evaluate it somewhere else later (e.g. in a different Julia session).

1

1 Answers

1
votes

eval only works in global scope. But then I don't see how much use there is in replacing the variables by evaluated literals, resulting in an expression of literals.

Anyway, a different approach to the original problem could be mimick what R does: constructing thunks out of an expression plus its environment at the place where it was called. To recreate that in Julia, you'd have to

  1. Figure out the free variables in the expression
  2. Create an environment data structure of their values
  3. Wrap the original expression in a closure such that it takes the local variables from the environment
  4. Put everything into a new object

Example:

for j=1:3
    a = 2
    @saveexpr a + 2
end

should expand to something like

for j=1:3
    a = 2
    SerializedExpr(
      (; a),
      function (env)
          let (a,) = env
              a + 2
          end
      end,
      :(a + 2))
end

If saving the closure is not feasible in your use case, I guess you have to either implement your own evaluator, or use something like JuliaInterpreter.jl.