在不取消引用的情况下将 AST 插入到引用 do end 块中
Inserting an AST into a quote do end block without unquoting it
使用 quote do end
和 unquote
通常提供了一种将值注入 AST 的超级简单方法,让我避免遍历它。
这是一种情况。
ast = quote do 1 + 1 end
quote do
unquote(ast)
|> manipulate_number
end
但是,如果我想插入的不是引用表达式 1 + 1
的结果,而是 AST {:+, [context: Elixir, import: Kernel], [1, 1]}
,我发现自己将 AST 包装在对 [=12 的另一个调用的 AST 中=],像这样:
ast1 = quote do 1 + 1 end
ast2 = {:quote, [], [[do: ast1]]}
quote do
unquote(ast2)
|> manipulate_number
end
还有其他方法吗?
如果我对你的问题的理解正确,下面应该可以满足你的要求:
defmodule MacroExample do
defmacro example(ast) do
quoted = quote bind_quoted: [ast: ast] do
ast + 3
end
IO.inspect Macro.to_string(quoted)
quoted
end
end
defmodule MacroTest do
require MacroExample
IO.inspect MacroExample.example(1 + 1)
end
而 iex
中的结果:
iex> c "test.ex"
"(\n ast = 1 + 1\n ast + 3\n)"
5
我猜你的具体问题可能比仅仅推迟加法操作更复杂,如果以上不是你正在寻找的,也许你正在尝试完成的更现实的例子可以阐明问题及其解决方案。
如果你想将 AST 按原样注入到另一个引用的表达式中,你需要 Macro.escape/1
。换一种说法,您可以使用 Macro.escape/1
来确保某些引用的表达式在 evaluated/expanded.
时会 return 本身
使用 quote do end
和 unquote
通常提供了一种将值注入 AST 的超级简单方法,让我避免遍历它。
这是一种情况。
ast = quote do 1 + 1 end
quote do
unquote(ast)
|> manipulate_number
end
但是,如果我想插入的不是引用表达式 1 + 1
的结果,而是 AST {:+, [context: Elixir, import: Kernel], [1, 1]}
,我发现自己将 AST 包装在对 [=12 的另一个调用的 AST 中=],像这样:
ast1 = quote do 1 + 1 end
ast2 = {:quote, [], [[do: ast1]]}
quote do
unquote(ast2)
|> manipulate_number
end
还有其他方法吗?
如果我对你的问题的理解正确,下面应该可以满足你的要求:
defmodule MacroExample do
defmacro example(ast) do
quoted = quote bind_quoted: [ast: ast] do
ast + 3
end
IO.inspect Macro.to_string(quoted)
quoted
end
end
defmodule MacroTest do
require MacroExample
IO.inspect MacroExample.example(1 + 1)
end
而 iex
中的结果:
iex> c "test.ex"
"(\n ast = 1 + 1\n ast + 3\n)"
5
我猜你的具体问题可能比仅仅推迟加法操作更复杂,如果以上不是你正在寻找的,也许你正在尝试完成的更现实的例子可以阐明问题及其解决方案。
如果你想将 AST 按原样注入到另一个引用的表达式中,你需要 Macro.escape/1
。换一种说法,您可以使用 Macro.escape/1
来确保某些引用的表达式在 evaluated/expanded.