Общая функция для удаления `LineNumberNode` в` Expr` (должна быть в состоянии справиться с: macrocalls)? - PullRequest
0 голосов
/ 13 ноября 2018

Есть ли встроенная функция Джулии для удаления 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 (: macrocall, Symbol ("@ foo"), none,: (1 + 1)), что немного многословно.

Ответы [ 4 ]

0 голосов
/ 17 ноября 2018

Встроенная функция 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

Благодарю Алекса Арслана за напоминание об этом.

0 голосов
/ 13 ноября 2018

Поскольку ваша цель состоит в том, чтобы иметь возможность сравнивать Expr s, возможно, замените LineNumberNode s на nothing. Это позволяет проводить сравнения, и Expr s все еще работают. Смотрите пример ниже:

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

Конечно, если ваш код является вложенным, вам придется делать замену его элементов рекурсивно по всему AST Expr.

0 голосов
/ 15 ноября 2018

Вы можете определить следующую функцию для достижения желаемого, сравнив два выражения для равенства, игнорируя узлы с номерами строк:

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
0 голосов
/ 13 ноября 2018

Не встроено, но в MacroTools.jl есть MacroTools.striplines(ex), который удаляет LineNumberNodes из выражения.

...