Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access the AST for generic functions in Julia

Tags:

julia

How can I access the abstract syntax tree for a generic function in Julia?

like image 716
Simon Byrne Avatar asked Feb 18 '23 23:02

Simon Byrne


2 Answers

To recap: It looks like Simon was looking for the AST for a specific method associated with a generic function. We can get a LambdaStaticData object, which contains the AST, for a specific method as follows:

julia> f(x,y)=x+y

julia> f0 = methods(f, (Any, Any))[1]
((Any,Any),(),AST(:($(expr(:lambda, {x, y}, {{}, {{x, Any, 0}, {y, Any, 0}}, {}}, quote  # none, line 1:
        return +(x,y)
    end)))),())

julia> f0[3]
AST(:($(expr(:lambda, {x, y}, {{}, {{x, Any, 0}, {y, Any, 0}}, {}}, quote  # none, line 1:
        return +(x,y)
    end))))

julia> typeof(ans)
LambdaStaticData

Apparently this AST can either be an Expr object or a compressed AST object, represented as a sequence of bytes:

julia> typeof(f0[3].ast)
Array{Uint8,1}

The show() method for LambdaStaticData from base/show.jl illustrates how to decompress this, when encountered:

julia> ccall(:jl_uncompress_ast, Any, (Any, Any), f0[3], f0[3].ast)
:($(expr(:lambda, {x, y}, {{}, {{x, Any, 0}, {y, Any, 0}}, {}}, quote  # none, line 1:
        return +(x,y)
    end)))

julia> typeof(ans)
Expr
like image 81
Jon Riehl Avatar answered May 20 '23 01:05

Jon Riehl


Julia has four functions and four macros analog to those functions, used to inspect a lot about generic function's methods:

julia> f(x, y) = x + y                                                                                                    
f (generic function with 1 method)

julia> methods(f)                                                                                                         
# 1 method for generic function "f":                                                                                      
f(x,y) at none:1 

Lowered code:

julia> code_lowered(f, (Int, Int))                                                                                        
1-element Array{Any,1}:
 :($(Expr(:lambda, {:x,:y}, {{},{{:x,:Any,0},{:y,:Any,0}},{}}, :(begin  # none, line 1:
        return x + y
    end))))

julia> @code_lowered f(1, 1)    # Both `Int`s 
...same output.

Typed code:

julia> code_typed(f, (Int, Int))    

1-element Array{Any,1}:
 :($(Expr(:lambda, {:x,:y}, {{},{{:x,Int64,0},{:y,Int64,0}},{}}, :(begin  # none, line 1:                                 
        return (top(box))(Int64,(top(add_int))(x::Int64,y::Int64))::Int64                                                 
    end::Int64))))      

julia> @code_lowered f(1, 1)    # Both `Int`s  
...same output.

LLVM code:

julia> code_llvm(f, (Int, Int))                                                                                           

define i64 @julia_f_24771(i64, i64) {                                                                                     
top:                                                                                                                      
  %2 = add i64 %1, %0, !dbg !1014                                                                                         
  ret i64 %2, !dbg !1014                                                                                                  
}                           

julia> @code_llvm f(1, 1)    # Both `Int`s   
...same output.

Native code:

julia> code_native(f, (Int, Int))  

      .text                                                                                                               
Filename: none                                                                                                            
Source line: 1                                                                                                            
        push    RBP                                                                                                       
        mov     RBP, RSP                                                                                                  
Source line: 1                                                                                                            
        add     RDI, RSI                                                                                                  
        mov     RAX, RDI                                                                                                  
        pop     RBP                                                                                                       
        ret    

julia> @code_llvm f(1, 1)    # Both `Int`s
...same output.

Type instability warnings (v0.4+):

julia> @code_warntype f(1, 1)
Variables:
  x::Int64
  y::Int64

Body:
  begin  # In[17], line 1:
      return (top(box))(Int64,(top(add_int))(x::Int64,y::Int64))
  end::Int64

Reflection and introspection

like image 45
HarmonicaMuse Avatar answered May 20 '23 02:05

HarmonicaMuse