erlang 如何从本地函数获取Elixir AST

shstlldc  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(192)

我想从作为参数传递的本地函数(如doSomething(fn a -> a * 10 end))获取AST
所以我试着

def test do
    inspectAST(fn a,b -> a + b + 42 end)
    inspectAST(quote do: fn a,b -> a + b + 42 end)
    inspectFunctionInfo(fn a,b -> a + b + 42 end)
    :ok
  end

  def inspectAST(this_is_AST) do
    IO.inspect(this_is_AST)
    IO.inspect("--------------------------------")
  end

  def inspectFunctionInfo(fun) do
    IO.inspect(Function.info(fun))
    IO.inspect("--------------------------------")
  end

结果:

iex(3)> Utils.test
#Function<0.30424669/2 in Utils.test/0>
"--------------------------------"
{:fn, [],
 [
   {:->, [],
    [
      [{:a, [], Utils}, {:b, [], Utils}],
      {:+, [context: Utils, import: Kernel],
       [
         {:+, [context: Utils, import: Kernel],
          [{:a, [], Utils}, {:b, [], Utils}]},
         42
       ]}
    ]}
 ]}
"--------------------------------"
[
  pid: #PID<0.485.0>,
  module: Utils,
  new_index: 1,
  new_uniq: <<58, 7, 203, 172, 99, 108, 54, 80, 24, 151, 75, 56, 73, 174, 138,
    177>>,
  index: 1,
  uniq: 30424669,
  name: :"-test/0-fun-1-",
  arity: 2,
  env: [],
  type: :local
]
"--------------------------------"

我想要的是inspectAST(quote do: fn a,b -> a + b + 42 end)(AST)的结果,但我想发送类似inspectAST(fn a,b -> a + b + 42 end)的函数,而不发送quote do:
如果有人对此有一些想法,你的帮助将非常感激:)

hgb9j2n6

hgb9j2n61#

If you want a "function" to be called on the AST, not values, it should be a macro, not a function.
The following should be a good base for what you want to achieve:

defmacro inspectAST(ast) do
    quote do
      IO.inspect(unquote(Macro.escape(ast)))
      :ok
    end
  end

  def test do
    inspectAST(fn a,b -> a + b + 42 end)
  end
  • you need to use defmacro to treat your parameter as AST, not a regular value
  • we want IO.inspect to happen at runtime, not compile time, so we need to return the AST for it using quote
  • what we want to inspect is the content of the ast variable, so we are using unquote
  • but unquote will unescape ast as well, so we need to escape it once more using Macro.escape/2

Please note that the macro should be defined before calling it, so defmacro has to be before test , not after.
For more advanced explanations about macros, you should check this serie of articles which is very detailed.

相关问题