Вы путаете уровни.Давайте введем промежуточную функцию для ясности:
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
.Таким образом, две формы не получают одно и то же выражение!
Но есть способы вручную проанализировать выражение и передать его макросу:
- Вы можетеделай как я, и используй отдельную "функцию реализации макроса".Тогда выражение, возвращаемое
@foomacro bla
, эквивалентно foomacro_impl(Meta.parse(bla))
.(Этот подход, кстати, очень полезен для тестирования, и я рекомендую его большую часть времени.) Вы можете использовать макрос @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
значения.)