Skip to content

Instantly share code, notes, and snippets.

@ityonemo
Last active November 6, 2015 03:36
Show Gist options
  • Select an option

  • Save ityonemo/a6fcf08c867391bf22c0 to your computer and use it in GitHub Desktop.

Select an option

Save ityonemo/a6fcf08c867391bf22c0 to your computer and use it in GitHub Desktop.
macros that cleanly Injecting code into a function's AST in julia
#cleaninject.jl
#cleanly injects some code into the AST of a function.
function code_to_inject()
println("this code is injected")
end
function code_to_inject(a,b)
println("injected code handles $a and $b")
end
macro inject_code_prepend(f)
#make sure this macro precedes a function definition.
isa(f, Expr) || error("checkable macro must precede a function definition")
(f.head == :function) || error("checkable macro must precede a function definition")
#be lazy and let the parser do the hard work.
b2 = parse("code_to_inject()")
#inject the generated code into the AST.
unshift!(f.args[2].args, b2)
#return the escaped function to the parser so that it generates the new function.
return Expr(:escape, f)
end
macro inject_code_append(f)
#make sure this macro precedes a function definition.
isa(f, Expr) || error("checkable macro must precede a function definition")
(f.head == :function) || error("checkable macro must precede a function definition")
#be lazy and let the parser do the hard work.
b2 = parse("code_to_inject()")
#inject the generated code into the AST.
push!(f.args[2].args, b2)
#return the escaped function to the parser so that it generates the new function.
return Expr(:escape, f)
end
macro inject_code_with_args(f)
#make sure this macro precedes a function definition.
isa(f, Expr) || error("checkable macro must precede a function definition")
(f.head == :function) || error("checkable macro must precede a function definition")
#be lazy and let the parser do the hard work.
b2 = parse(string("code_to_inject(", join(f.args[1].args[2:end], ","), ")"))
#inject the generated code into the AST.
unshift!(f.args[2].args, b2)
#return the escaped function to the parser so that it generates the new function.
return Expr(:escape, f)
end
################################################################################
# RESULTS
#=
julia> @inject_code_prepend function p()
println("victim function")
end
p (generic function with 1 method)
julia> p()
this code is injected
victim function
julia> @inject_code_append function p()
println("victim function")
end
p (generic function with 1 method)
julia> p()
victim function
this code is injected
julia> @inject_code_with_args function p(a, b)
println("victim called with $a and $b")
end
p (generic function with 2 methods)
julia> p(1, 2)
injected code handles 1 and 2
victim called with 1 and 2
=#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment