假设我有一个定义为的宏:
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,因为这会将我的实际项目推迟很多...
答案 0 :(得分:4)
您正在混合级别。为了清楚起见,我们来介绍一个中间函数:
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。
另一方面,在@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
。因此,这两种形式 not 不能接收相同的表达式!
但是有一些方法可以手动解析表达式并将其传递给宏:
@foomacro bla
返回的表达式等于foomacro_impl(Meta.parse(bla))
。 (BTW这种方法对于测试非常有用,我大多数时候都建议这样做。)您可以使用宏@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
值。)