在不取消引用的情况下将 AST 插入到引用 do end 块中

Inserting an AST into a quote do end block without unquoting it

使用 quote do endunquote 通常提供了一种将值注入 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 本身