Эликсир: переменная не определена во время расширения AST - PullRequest
0 голосов
/ 30 ноября 2018

У меня есть такой модуль, ast1 и ast2 выглядят одинаково, но я получаю ошибку с 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

update

  • Что я хочу сделать, учитывая, что pk_def генерируется decode функция, как в ast1, но с fields decode генерируется динамически.

1 Ответ

0 голосов
/ 30 ноября 2018

Проблема заключается в определении функции, а не в заголовке, а именно в строке:

unquote_splicing(field_decs)

Если вы удалите эту строку, код будет работать.Причина в том, что когда field_decs AST раскрывается с использованием unquote_splicing, он выполняет дополнительный вызов, пытаясь снять кавычку с переменной rest, что не удается.Исправление оценки вашего AST также исправит это.


Для меня это выглядит как XY Проблема .Я не совсем уверен, что вы пытаетесь сделать здесь, но когда речь идет о расширении языка и пользовательских DSL, вы должны разбить его на несколько меньших и компонуемых макросов (с большинством функций, реализованных в приватной среде).функции), а также должны хорошо заботиться о макро гигиены.Это существенно снизит сложность вашего кода и облегчит работу с раскрытием кода в целом, поскольку вам не придется иметь дело с AST напрямую.

...