剥离Expr中的LineNumberNode的泛型函数(应该能够处理:macrocalls)?

时间:2018-11-13 04:49:11

标签: julia

是否有内置的Julia函数用于剥离LineNumberNode中的Expr?尤其是对于宏调用:

julia> ex = :(@foo 1)
:(#= REPL[5]:1 =# @foo 1)

julia> dump(ex)
Expr
  head: Symbol macrocall
  args: Array{Any}((3,))
    1: Symbol @foo
    2: LineNumberNode
      line: Int64 1
      file: Symbol REPL[5]
    3: Int64 1

尝试过MacroTools.striplines,但是

julia> ex = :(@foo 1+1)
:(#= REPL[7]:1 =# @foo 1 + 1)

julia> MacroTools.striplines(ex) |> dump
Expr
  head: Symbol macrocall
  args: Array{Any}((3,))
    1: Symbol @foo
    2: LineNumberNode
      line: Int64 1
      file: Symbol REPL[7]
    3: Expr
      head: Symbol call
      args: Array{Any}((3,))
        1: Symbol +
        2: Int64 1
        3: Int64 1

我的用例是比较构造在不同文件中的两个不同的expr(因此,不同的行号信息)。我当前的解决方法是显式编写Expr(:macrocall,Symbol(“ @ foo”),什么都没有,:(1 + 1)),这有点冗长。

4 个答案:

答案 0 :(得分:3)

不是内置的,但是MacroTools.jl具有MacroTools.striplines(ex),可从表达式中删除LineNumberNodes

答案 1 :(得分:3)

内置函数为Base.remove_linenums!

julia> ex = quote begin
   x = 3 
   y = 2
   z = 4
   foo(x) = 3
   end
end
quote
    #= REPL[2]:1 =#
    begin
        #= REPL[2]:2 =#
        x = 3
        #= REPL[2]:3 =#
        y = 2
        #= REPL[2]:4 =#
        z = 4
        #= REPL[2]:5 =#
        foo(x) = begin
                #= REPL[2]:5 =#
                3
        end
    end
end

julia> Base.remove_linenums!(ex)
quote
    begin
        x = 3
        y = 2
        z = 4
        foo(x) = begin
                3
        end
    end
end

亚历克斯·阿尔斯兰(Alex Arslan)提醒我。

答案 2 :(得分:2)

由于您的目标是能够比较Expr,因此可以将LineNumberNode替换为nothing。这样可以进行比较,并且Expr仍然有效。请参见下面的示例:

julia> macro hello(world)
       println("hello ",world)
       end
@hello (macro with 1 method)

julia> m1 = :(@hello "world")
:(#= REPL[99]:1 =# @hello "world")

julia> m2 = :(@hello "world")
:(#= REPL[100]:1 =# @hello "world")

julia> m1 == m2
false

julia> replace!(arg -> typeof(arg) <: LineNumberNode ? nothing : arg, m1.args);

julia> replace!(arg -> typeof(arg) <: LineNumberNode ? nothing : arg, m2.args);

julia> dump(m1)
Expr
  head: Symbol macrocall
  args: Array{Any}((3,))
    1: Symbol @hello
    2: Nothing nothing
    3: String "world"

julia> eval(m1)
hello world

julia> m1 == m2
true

当然,如果您的代码是嵌套的,则必须在整个Expr的AST上递归地替换其元素。

答案 3 :(得分:2)

您可以考虑定义以下函数,以比较两个表达式是否相等而忽略行号节点,从而实现所需的功能:

function cmpexpr(ex1::Expr, ex2::Expr)
    ex1.head === ex2.head || return false
    length(ex1.args) === length(ex2.args) || return false

    for (a1, a2) in zip(ex1.args, ex2.args)
        typeof(a1) === typeof(a2) || return false
        if a1 isa Expr
            cmpexpr(a1, a2) || return false
        elseif !(a1 isa LineNumberNode)
            isequal(a1, a2) || return false
        end
    end
    return true
end