натяните к абстрактному дереву синтаксиса

Я хотел бы преобразовать последовательность, содержащую действительное выражение Erlang к его абстрактному представлению дерева синтаксиса без любого успеха до сих пор.

Ниже пример того, что я хотел бы сделать. После компилирования, боли z:z(). производит модуль zed, который, называя zed:zed(). возвращает результат из применения lists:reverse в данном списке.

-module(z).
-export([z/0]).

z() ->
  ModuleAST = erl_syntax:attribute(erl_syntax:atom(module),
                                   [erl_syntax:atom("zed")]),

  ExportAST = erl_syntax:attribute(erl_syntax:atom(export),
                                   [erl_syntax:list(
                                    [erl_syntax:arity_qualifier(
                                     erl_syntax:atom("zed"),
                                     erl_syntax:integer(0))])]),

  %ListAST = ?(String),  % This is where I would put my AST
  ListAST = erl_syntax:list([erl_syntax:integer(1), erl_syntax:integer(2)]),

  FunctionAST = erl_syntax:function(erl_syntax:atom("zed"),
                                    [erl_syntax:clause(
                                     [], none,
                                     [erl_syntax:application(
                                        erl_syntax:atom(lists),
                                        erl_syntax:atom(reverse),
                                        [ListAST]
                    )])]),

  Forms = [erl_syntax:revert(AST) || AST <- [ModuleAST, ExportAST, FunctionAST]],

  case compile:forms(Forms) of
    {ok,ModuleName,Binary}           -> code:load_binary(ModuleName, "z", Binary);
    {ok,ModuleName,Binary,_Warnings} -> code:load_binary(ModuleName, "z", Binary)
  end.

String мог быть "[1,2,3].", или "begin A=4, B=2+3, [A,B] end.", или что-либо одинаково.

(Обратите внимание, что это - просто пример того, что я хотел бы сделать, таким образом оценивая String не возможность для меня.)


Править:

Определение ListAST как ниже производит огромного dict ошибочного монстра диграфа и говорит «внутреннюю ошибку в lint_module».

String = "[1,2,3].",
{ok, Ts, _} = erl_scan:string(String),
{ok, ListAST} = erl_parse:parse_exprs(Ts),

EDIT2:

Это решение работает на простые условия:

{ok, Ts, _} = erl_scan:string(String),
{ok, Term} = erl_parse:parse_term(Ts),
ListAST = erl_syntax:abstract(Term),
10
задан jldupont 29 December 2009 в 16:07
поделиться

3 ответа

В вашем примере EDIT:

String = "[1,2,3].",
{ok, Ts, _} = erl_scan:string(String),
{ok, ListAST} = erl_parse:parse_exprs(Ts),

ListAST на самом деле является списком AST:s (потому что parse_exprs, как указывает имя, разбирает несколько выражений (каждое из которых заканчивается на период). Так как ваша строка содержит одно выражение, вы получаете список из одного элемента. Всё, что вам нужно сделать, это сопоставить:

{ok, [ListAST]} = erl_parse:parse_exprs(Ts),

так что это не имеет никакого отношения к erl_syntax (который принимает все деревья erl_parse); просто у вас была лишняя обёртка списка вокруг ListAST, из-за которой компилятор блеванул.

.
5
ответ дан 4 December 2019 в 01:31
поделиться

Zoltan

Вот как мы получаем AST:

11> String = "fun() -> io:format(\"blah~n\") end.".
"fun() -> io:format(\"blah~n\") end."
12> {ok, Tokens, _} = erl_scan:string(String).     
{ok,[{'fun',1},
     {'(',1},
     {')',1},
     {'->',1},
     {atom,1,io},
     {':',1},
     {atom,1,format},
     {'(',1},
     {string,1,"blah~n"},
     {')',1},
     {'end',1},
     {dot,1}],
    1}
13> {ok, AbsForm} = erl_parse:parse_exprs(Tokens). 
{ok,[{'fun',1,
            {clauses,[{clause,1,[],[],
                              [{call,1,
                                     {remote,1,{atom,1,io},{atom,1,format}},
                                     [{string,1,"blah~n"}]}]}]}}]}
14> 
2
ответ дан 4 December 2019 в 01:31
поделиться

Некоторые комментарии в верхней части моей головы.

На самом деле я не использовал библиотеки erl_syntax, но я думаю, что они затрудняют чтение и "видение" того, что вы пытаетесь собрать. Скорее всего, я бы импортировал функции или определил свое собственное API, чтобы сделать его короче и разборчивее. Но тогда я обычно предпочитаю более короткие имена функций и переменных.

AST, созданный erl_syntax, и "стандартный", созданный erl_parse и используемый в компиляторе, разные и не может быть смешанным. Поэтому нужно выбрать один из них и придерживаться его.

Пример во втором EDIT будет работать для терминов, но не в более общем случае:

{ok, Ts, _} = erl_scan:string(String),
{ok, Term} = erl_parse:parse_term(Ts),
ListAST = erl_syntax:abstract(Term),

Это потому, что erl_parse:parse_term/1 возвращает актуальный термин, представленный маркерами, в то время как другие функции erl_parse parse_form и parse_exprs возвращают AST. Помещение их в erl_syntax:abstract сделает забавные вещи.

В зависимости от того, что вы пытаетесь сделать, может быть на самом деле проще переписать и скомпилировать файл erlang, чем работать непосредственно с абстрактными формами. Это противоречит моим укоренившимся чувствам, но генерирование АСТ-файла erlang не тривиально. Какой тип кода вы собираетесь производить?

Если вы не боитесь списков, вы можете попробовать использовать LFE (erlang со вкусом lisp) для генерации кода, так как для всех lisps не существует специальной абстрактной формы, все это гомоиконично и намного проще в работе.

3
ответ дан 4 December 2019 в 01:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: