【问题标题】:Access the AST for generic functions in Julia在 Julia 中访问通用函数的 AST
【发布时间】:2015-07-03 19:40:30
【问题描述】:

如何访问 Julia 中泛型函数的抽象语法树?

【问题讨论】:

    标签: julia


    【解决方案1】:

    回顾一下:看起来 Simon 正在寻找与泛型函数关联的特定方法的 AST。我们可以得到一个LambdaStaticData对象,其中包含AST,具体方法如下:

    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
    

    显然这个 AST 可以是一个 Expr 对象,也可以是一个压缩的 AST 对象,表示为一个字节序列:

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

    来自base/show.jlLambdaStaticDatashow() 方法说明了遇到此问题时如何解压缩:

    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
    

    【讨论】:

      【解决方案2】:

      Julia 有四个函数和四个与这些函数类似的宏,用于检查很多关于泛型函数的方法:

      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 
      

      降低代码:

      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.
      

      输入代码:

      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 代码:

      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.
      

      本机代码:

      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.
      

      类型不稳定警告(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

      【讨论】:

        【解决方案3】:

        由于多次分派,我不确定是否存在与通用函数关联的 AST。如果您正在编写函数定义fbody,您应该能够通过执行dump(quote(fbody)) 来获取AST。

        【讨论】:

        • 我后来才知道你可以通过methods(f,signature)找到具体的方法。然而,其中的 AST 是 Uint8 Array,而不是 Expr 对象。关于如何转换它的任何想法?
        • @DiegoJavierZea 你知道如何从dump(quote f end) 得到结果吗?它返回 Nothing 但会打印出我感兴趣的 AST。
        • quote f end 已经是 AST。 dump 只是漂亮地打印出来。
        猜你喜欢
        • 1970-01-01
        • 2018-07-21
        • 1970-01-01
        • 2016-10-21
        • 2020-09-09
        • 2014-01-30
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        相关资源
        最近更新 更多