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
endThere 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
endand 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) == trueMacroTools.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.