Julia code is represented by objects that can be created and manipulated from within the language.
Macro is used to generate code.
Expr
Julia code will be parsed into Expr,
eg:
julia> dump(r)
Expr
head: Symbol =
args: Array(Any,(2,))
1: Symbol a
2: Int64 1
typ: Any
The expr works like other code.
Fields
head: identifying the kind of expression. eg: :call, :+, :block
args, an array of subexpressions.
typ, field is used by type inference to store type annotations,
isn't used for most time
Usage
Quoting
ex = :(a+b*c+1)
ex2 = quote x=1
y=2
x+y
end
ex2.head
# block
#+END_SRC
Use Expr
a, b, c = 1, 2, 3
ex1 = Expr(:call)
ex1.args = [:*, :b, :c]
ex = Expr(:call)
ex.args = [:+, :a, ex1]
eval(ex)
7
Meta.show_sexpr(ex)
Macro
How it works
Julia macro
A macro is a way of generating a new output expression, given an unevaluated input expression.
When your Julia program runs, it first parses and evaluates the macro,
and the processed code produced by the macro is eventually evaluated like an ordinary expression.
macro foo()
println("macro foo is evalued")
:("foo")
end
function f()
println("f is execulated")
@foo()
end
# got 'macro foo is evalued' in REPL,
# so this means, f is compiled and the macro generate the code.
'f.env.defs.func.code '
will got
AST(:($(Expr(:lambda, Any[], Any[Any[],Any[],Any[]], :(begin # none, line 2:
println("f is execulated") # line 3:
return "foo"
end)))))
f()
# f is execulated
# "foo"
Why we need macro?
Allow the programmer to generate and include fragments of customized code before the full program is run
Methods: eval, $, :, esc
1. eval
eval expression in top level
2. $
will eval in a quote
3. :
quote
4. esc
escape
Do not let Julia generates new symbol for a variable.
The Clojure works in the opposite way, Clojure use variable# to generate symbol.
'$' vs 'eval'
| | $ | eval |
|-------+---------------+----------|
| usage | :($a) | eval(:a) |
| scope | current place | global |
More useful methods
dump: dump expression
Meta.show_sexpr: print an AST as an S-expression
parse: parse string to expresion
macroexpand: macroexpand(:(@macro(a)))
Tricks
Macro syntax sugar for string
macro p_str(s)
println(s)
end
p"abc"
macro with multiple lines
@my_macro begin
...
...
end
How to create a macro for creating a symbol in Julia
macro s_str(p)
:(symbol($p))
end
r = s"c"
# another way
macro s(p)
QuoteNode(p)
end
r = @s(a)