Utilities
Function definitions
Function definitions pose a problem to pattern matching, since there are a lot of different ways to define a function. For example, a pattern that captures f(x) = 2x
will not match
function f(x)
return 2x
end
There are a couple of ways to handle this. One way is to use longdef
or shortdef
to normalise function definitions to short form, before matching it.
julia> ex = :(function f(x) 2x end)
:(function f(x)
#= none:1 =#
2x
end)
julia> MacroTools.shortdef(ex)
:(f(x) = begin
#= none:1 =#
2x
end)
More generally it's also possible to use splitdef
and combinedef
to handle the full range of function syntax.
splitdef(def)
matches a function definition of the form
function name(args; kwargs)::rtype where {whereparams}
body
end
and returns Dict(:name=>..., :args=>..., etc.)
. The definition can be rebuilt by calling MacroTools.combinedef(dict)
, or explicitly with
rtype = get(dict, :rtype, :Any)
:(function $(dict[:name])($(dict[:args]...);
$(dict[:kwargs]...))::$rtype where {$(dict[:whereparams]...)}
$(dict[:body].args...)
end)
splitarg(arg)
matches function arguments (whether from a definition or a function call) such as x::Int=2
and returns (arg_name, arg_type, slurp, default)
. default
is nothing
when there is none. For example:
> map(splitarg, (:(f(y, a=2, x::Int=nothing, args...))).args[2:end])
4-element Array{Tuple{Symbol,Symbol,Bool,Any},1}:
(:y, :Any, false, nothing)
(:a, :Any, false, 2)
(:x, :Int, false, :nothing)
(:args, :Any, true, nothing)
Other Utilities
MacroTools.isexpr
— Function.isexpr(x, ts...)
Convenient way to test the type of a Julia expression. Expression heads and types are supported, so for example you can call
isexpr(expr, String, :string)
to pick up on all string-like expressions.
MacroTools.rmlines
— Function.rmlines(x)
Remove the line nodes from a block or array of expressions.
Compare quote end
vs rmlines(quote end)
Examples
To work with nested blocks:
prewalk(rmlines, ex)
MacroTools.unblock
— Function.unblock(expr)
Remove outer begin
blocks from an expression, if the block is redundant (i.e. contains only a single expression).
MacroTools.namify
— Function.An easy way to get the (function/type) name out of expressions like foo{T}
or Bar{T} <: Vector{T}
.
MacroTools.inexpr
— Function.inexpr(expr, x)
Simple expression match; will return true
if the expression x
can be found inside expr
.
inexpr(:(2+2), 2) == true
MacroTools.gensym_ids
— Function.gensym_ids(expr)
Replaces gensyms with unique ids (deterministically).
julia> x, y = gensym("x"), gensym("y")
(Symbol("##x#363"), Symbol("##y#364"))
julia> MacroTools.gensym_ids(:($x+$y))
:(x_1 + y_2)
MacroTools.alias_gensyms
— Function.alias_gensyms(expr)
Replaces gensyms with animal names. This makes gensym'd code far easier to follow.
julia> x, y = gensym("x"), gensym("y")
(Symbol("##x#363"), Symbol("##y#364"))
julia> MacroTools.alias_gensyms(:($x+$y))
:(porcupine + gull)
MacroTools.@expand
— Macro.More convenient macro expansion, e.g.
@expand @time foo()
MacroTools.isdef
— Function.Test for function definition expressions.
MacroTools.flatten
— Function.flatten(ex)
Flatten any redundant blocks into a single block, over the whole expression.
MacroTools.prettify
— Function.prettify(ex)
Makes generated code generaly nicer to look at.