【问题标题】:Elixir: Variable undefined during AST expansionElixir:AST扩展期间未定义的变量
【发布时间】:2018-12-03 12:27:28
【问题描述】:

我有一个像这样的模块,ast1ast2 看起来一样,但在第二个模块中出现 rest undefined 错误。谁能解释一下这个问题?

defmodule PacketDef do
  pk_def = {:pk_name, [
    {:unk_int1, :int},
    {:unk_int2, :int},
  ]}

  {pkn, field_defs} = pk_def

  field_decs = Enum.map(field_defs, fn
    ({var_name, var_type}) when var_type in [:int] ->
        rest = Macro.var(:rest, __MODULE__)

        dec_name = String.to_atom("decode_#{var_type}")
        xvar_name = Macro.var(var_name, __MODULE__)
        quote do
            {:ok, unquote(xvar_name), unquote(rest)} = unquote(dec_name)(unquote(rest))
        end
    (_field_def) ->
        nil
  end)

  ast1 = quote do
      def decode(unquote(pkn), rest) do
        {:ok, unk_int1, rest} = decode_int(rest)
        {:ok, unk_int2, rest} = decode_int(rest)
        {:ok, rest}
      end
  end
  ast2 = quote do
      def decode(unquote(pkn), rest) do
        unquote_splicing(field_decs)        
        {:ok, rest}
      end
  end

  IO.puts("ast1")
  IO.inspect(ast1, width: 100)
  IO.puts("ast2")
  IO.inspect(ast2, width: 100)

  def decode(unquote(pkn), rest) do
    {:ok, unk_int1, rest} = decode_int(rest)
    {:ok, unk_int2, rest} = decode_int(rest)
    {:ok, rest}
  end

  # why get error *rest* here
  def decode(unquote(pkn), rest) do
    unquote_splicing(field_decs)        
    {:ok, rest}
  end

  def decode_int(<<b::32-little, rest::binary>>) do
    {:ok, b, rest}
  end
end

更新

  • 我想做的是,给定pk_def 生成的decode 函数类似于ast1,但fields decode 是动态生成的。

【问题讨论】:

    标签: macros elixir abstract-syntax-tree


    【解决方案1】:

    问题在于函数定义而不是标题,特别是行:

    unquote_splicing(field_decs)
    

    如果删除此行,代码将起作用。原因是当field_decs AST 使用unquote_splicing 扩展时,它会进行子调用尝试取消对rest 变量的引用,但失败了。修复评估 AST 的方式也可以解决此问题。


    在我看来,这就像一个 XY Problem。我不确定您在这里要做什么,但是在处理语言扩展和自定义 DSL 时,您应该将其分解为多个较小且可组合的Macros(大部分功能在私有函数中实现)并且应该还要注意宏观卫生。这将大大降低您的代码复杂性,并且通常更容易处理代码扩展,因为您不必直接处理 AST。

    【讨论】:

    • 我实际上想在这里询问 Y 是因为我想了解更多关于宏/AST 扩展的信息,而不是解决可能会发生很大变化的 X .我也知道问题出在unquote_splicing,但不知道这里出了什么问题。 修复你的 AST 的评估方式也可以解决这个问题
    • 您能否更新您的问题以解释(详细)您要做什么?由于我无法弄清楚这一点,因此我无法告诉您要在 AST 中修复什么。
    猜你喜欢
    • 2013-05-22
    • 2018-09-02
    • 1970-01-01
    • 2015-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    • 1970-01-01
    相关资源
    最近更新 更多