reflectionjuliametaprogramming

Getting the Expression Tree of the Body of a Function in Julia


Is there a function or macro in Julia (or in package) that given a function returns the expression object (Expr) representing its body; or, in other words, returns the expression used in its definition?

For example, suppose a function foo is defined somewhere as

function foo(x, y)
    z = 2 * x
    return z + y
end

Then, supposing said function is called definition, calling definition(foo) should return the expression

quote
    z = 2 * x
    z + y
end

This should also in principle work for anonymous functions. The return value of definition(x -> 2 + x) should be the expression

:(2 + x)

I have been only able to find macros such as @code_lowered and @code_typed that get the code at LLVM Internal Representation, or native machine code level, but none at the expression level.


Solution

  • You could try code_lowered, code_typed (without @) or Base.uncompressed_ast(methods(foo).ms[1]).code.

    function foo(x, y)
        z = 2 * x
        return z + y
    end
    
    code_lowered(foo)
    #1-element Vector{Core.CodeInfo}:
    # CodeInfo(
    #1 ─      z = 2 * x
    #│   %2 = z + y
    #└──      return %2
    #)
    
    code_typed(foo)
    #1-element Vector{Any}:
    # CodeInfo(
    #1 ─ %1 = (2 * x)::Any
    #│   %2 = (%1 + y)::Any
    #└──      return %2
    #) => Any
    
    Base.uncompressed_ast(methods(foo).ms[1]).code
    #3-element Vector{Any}:
    # :(_4 = 2 * _2)
    # :(_4 + _3)
    # :(return %2)
    
    code_lowered(x -> 2 + x)
    #1-element Vector{Core.CodeInfo}:
    # CodeInfo(
    #1 ─ %1 = 2 + x
    #└──      return %1
    #)
    
    code_typed(x -> 2 + x)
    #1-element Vector{Any}:
    # CodeInfo(
    #1 ─ %1 = (2 + x)::Any
    #└──      return %1
    #) => Any
    
    Base.uncompressed_ast(methods(x -> 2 + x).ms[1]).code
    #2-element Vector{Any}:
    # :(2 + _2)
    # :(return %1)