Actually, a macro is very close to being an ordinary function, which receives something called an Expr (or Symbol), and returns an Expr, usually made by a quote statement. A macro can call ordinary functions to manipulate the Expr it works on. The returned Expr is then inserted where the macro call is done.
An Expr is a lisp-like data-structure. (It’s said that julia is an abbreviation for Jeff’s Unusual Lisp is Automated). You can create your own Expr with Expr, quote or :( ... ):
julia> dump( :(a + b + c) )
Expr
head: Symbol call
args: Array{Any}((4,))
1: Symbol +
2: Symbol a
3: Symbol b
4: Symbol c
julia> dump(Expr(:call, :+, :a, :b, :c))
Expr
head: Symbol call
args: Array{Any}((4,))
1: Symbol +
2: Symbol a
3: Symbol b
4: Symbol c