Юлия: передать строку в макрос - PullRequest
0 голосов
/ 18 сентября 2018

предположим, что у меня есть макрос, который определен как:

macro foomacro(ex::Expr)
    dump(ex)
    ex
end

В настоящее время я хотел бы передать свое выражение в виде разобранной строки, чтобы я мог передать довольно сложное и зависящее от регистра выражение, которое былополучается путем конкатенации строк.

Однако попытка:

@foomacro 1+2+3

дает ожидаемый результат 6, тогда как

@foomacro parse("1+2+3")

возвращает проанализированное выражение: (1 + 2 + 3) вместо фактического анализа ...

Насколько я понимаю, оба макроса должны получать одно и то же выражение, но это явно не тот случай.

Как мне получить этот MWE дляработа?

ps: я понял это исправление, но мне кажется, что оно очень грязное и «неправильное»

macro foomacro(ex::Expr)
    if ex.head == :call
        #in this case the user is calling the macro via a parsed string
        dump(ex)
        return ex
    end
    dump(ex)
    ex
end

ps: если это имеет какое-либо значение, в настоящее время код выполняетсяна 0.6.4 и, если возможно, я бы предпочел не обновляться до 1.0, так как это отложило бы мой фактический проект на много ...

1 Ответ

0 голосов
/ 18 сентября 2018

Вы путаете уровни.Давайте введем промежуточную функцию для ясности:

function foomacro_impl(expr)
    dump(expr)
    expr
end

macro foomacro(expr)
    foomacro_impl(expr)
end

При запуске выражение @foomacro <someexpr> будет проанализировано, часть <someexpr> передана в foomacro_impl, а результат обработан как выражение и вставлен вместооригинального выражения.Это означает, что написание @foomacro 1+2+3 эквивалентно написанию

let expr = :(1+2+3)
    dump(expr)
    expr
end

, которое возвращает

Expr
  head: Symbol call
  args: Array{Any}((4,))
    1: Symbol +
    2: Int64 1
    3: Int64 2
    4: Int64 3
:(1 + 2 + 3)

Expr, что оценивается в 6.

С другой стороныhand, в @foomacro Meta.parse("1+2+3"), аргумент целом , parse("1+2+3"), используется как expr:

julia> let expr = :(Meta.parse("1+2+3"))
           dump(expr)
           expr
       end
Expr
  head: Symbol call
  args: Array{Any}((2,))
    1: Expr
      head: Symbol .
      args: Array{Any}((2,))
        1: Symbol Meta
        2: QuoteNode
          value: Symbol parse
    2: String "1+2+3"
:(Meta.parse("1+2+3"))

Таким образом, результатом вызова макроса является выражение Meta.parse("1+2+3"), который оценивает другое выражение :(1 + 2 + 3), так как это вызов parse.Таким образом, две формы не получают одно и то же выражение!

Но есть способы вручную проанализировать выражение и передать его макросу:

  1. Вы можетеделай как я, и используй отдельную "функцию реализации макроса".Тогда выражение, возвращаемое @foomacro bla, эквивалентно foomacro_impl(Meta.parse(bla)).(Этот подход, кстати, очень полезен для тестирования, и я рекомендую его большую часть времени.)
  2. Вы можете использовать макрос @eval, чтобы создать выражение, объединить его и оценитьэто сразу:

    julia> @eval @foomacro $(Meta.parse("1+2+3"))
    Expr
      head: Symbol call
      args: Array{Any}((4,))
    1: Symbol +
        2: Int64 1
        3: Int64 2
        4: Int64 3
    6
    

    (или аналогично, используйте eval и вручную построенные Expr значения.)

...