Files
n8n-openai-adapter/lib/elixir/src/elixir_parser.yrl
T
José Valim 89cbe93bba The AST now allows metadata to be attached to each node
This means the second item in the AST is no longer an integer
(representing the line), but a keywords list. Code that relies
on the line information from AST or that manually generate AST
nodes need to be properly updated.
2013-01-21 15:42:03 -07:00

581 lines
20 KiB
Erlang

Nonterminals
grammar expr_list
expr paren_expr block_expr fn_expr bracket_expr call_expr bracket_at_expr max_expr
base_expr matched_expr matched_op_expr unmatched_expr op_expr
add_op mult_op unary_op two_op pipeline_op bin_concat_op
match_op send_op default_op when_op pipe_op in_op inc_op stab_op range_op
andand_op oror_op and_op or_op comp_expr_op colon_colon_op three_op at_op
open_paren close_paren empty_paren
open_bracket close_bracket
open_curly close_curly
open_bit close_bit
base_comma_expr comma_expr optional_comma_expr matched_comma_expr
call_args call_args_parens call_args_parens_not_one call_args_no_parens parens_call
stab_expr stab_expr_list
kw_eol kw_expr kw_comma kw_base
matched_kw_expr matched_kw_comma matched_kw_base
dot_op dot_ref dot_identifier dot_op_identifier dot_do_identifier
dot_paren_identifier dot_punctuated_identifier dot_bracket_identifier
var list bracket_access bit_string tuple
do_block fn_eol do_eol end_eol block_eol block_item block_list
.
Terminals
identifier kw_identifier punctuated_identifier
bracket_identifier paren_identifier do_identifier block_identifier
fn 'end' aliases
number signed_number atom bin_string list_string sigil
dot_call_op comp_op op_identifier
'not' 'and' 'or' 'xor' 'when' 'in' 'inlist' 'inbits' 'do'
'true' 'false' 'nil'
'=' '+' '-' '*' '/' '++' '--' '**' '//'
'(' ')' '[' ']' '{' '}' '<<' '>>' '::'
eol ',' '&' '|' '.' '^' '@' '<-' '<>' '->' '|>' '/>' '=~'
'&&' '||' '!' '...' '..'
'<<<' '>>>' '&&&' '|||' '^^^' '~~~'
.
Rootsymbol grammar.
Left 5 do.
Right 10 '->'.
Left 20 ','. % Solve nested call_args conflicts
Right 30 colon_colon_op.
Right 40 when_op.
Right 50 default_op.
Left 60 pipe_op.
Left 70 inc_op.
Right 80 match_op.
Right 110 send_op.
Left 120 oror_op.
Left 130 andand_op.
Left 140 or_op.
Left 150 and_op.
Left 160 comp_expr_op.
Left 170 in_op.
Left 180 range_op.
Left 190 three_op.
Left 200 add_op.
Left 210 mult_op.
Right 220 bin_concat_op.
Right 230 two_op.
Right 290 pipeline_op.
Nonassoc 300 unary_op.
Left 310 dot_call_op.
Left 310 dot_op.
Nonassoc 320 at_op.
Nonassoc 330 var.
%%% MAIN FLOW OF EXPRESSIONS
grammar -> eol : [nil].
grammar -> expr_list : lists:reverse('$1').
grammar -> eol expr_list : lists:reverse('$2').
grammar -> expr_list eol : lists:reverse('$1').
grammar -> eol expr_list eol : lists:reverse('$2').
grammar -> '$empty' : [nil].
% Note expressions are on reverse order
expr_list -> expr : ['$1'].
expr_list -> empty_paren : [nil].
expr_list -> expr_list eol expr : ['$3'|'$1'].
paren_expr -> empty_paren : nil.
paren_expr -> expr : '$1'.
expr -> matched_expr : '$1'.
expr -> unmatched_expr : '$1'.
matched_expr -> matched_expr matched_op_expr : build_op(element(1, '$2'), '$1', element(2, '$2')).
matched_expr -> unary_op matched_expr : build_unary_op('$1', '$2').
matched_expr -> at_op matched_expr : build_unary_op('$1', '$2').
matched_expr -> bracket_at_expr : '$1'.
matched_expr -> fn_expr : '$1'.
unmatched_expr -> matched_expr op_expr : build_op(element(1, '$2'), '$1', element(2, '$2')).
unmatched_expr -> unmatched_expr op_expr : build_op(element(1, '$2'), '$1', element(2, '$2')).
unmatched_expr -> unary_op expr : build_unary_op('$1', '$2').
unmatched_expr -> at_op expr : build_unary_op('$1', '$2').
unmatched_expr -> block_expr : '$1'.
op_expr -> match_op expr : { '$1', '$2' }.
op_expr -> add_op expr : { '$1', '$2' }.
op_expr -> mult_op expr : { '$1', '$2' }.
op_expr -> two_op expr : { '$1', '$2' }.
op_expr -> pipeline_op expr : { '$1', '$2' }.
op_expr -> andand_op expr : { '$1', '$2' }.
op_expr -> three_op expr : { '$1', '$2' }.
op_expr -> oror_op expr : { '$1', '$2' }.
op_expr -> and_op expr : { '$1', '$2' }.
op_expr -> or_op expr : { '$1', '$2' }.
op_expr -> pipe_op expr : { '$1', '$2' }.
op_expr -> bin_concat_op expr : { '$1', '$2' }.
op_expr -> in_op expr : { '$1', '$2' }.
op_expr -> inc_op expr : { '$1', '$2' }.
op_expr -> when_op expr : { '$1', '$2' }.
op_expr -> send_op expr : { '$1', '$2' }.
op_expr -> range_op expr : { '$1', '$2' }.
op_expr -> default_op expr : { '$1', '$2' }.
op_expr -> colon_colon_op expr : { '$1', '$2' }.
op_expr -> comp_expr_op expr : { '$1', '$2' }.
matched_op_expr -> match_op matched_expr : { '$1', '$2' }.
matched_op_expr -> add_op matched_expr : { '$1', '$2' }.
matched_op_expr -> mult_op matched_expr : { '$1', '$2' }.
matched_op_expr -> two_op matched_expr : { '$1', '$2' }.
matched_op_expr -> pipeline_op matched_expr : { '$1', '$2' }.
matched_op_expr -> andand_op matched_expr : { '$1', '$2' }.
matched_op_expr -> three_op matched_expr : { '$1', '$2' }.
matched_op_expr -> oror_op matched_expr : { '$1', '$2' }.
matched_op_expr -> and_op matched_expr : { '$1', '$2' }.
matched_op_expr -> or_op matched_expr : { '$1', '$2' }.
matched_op_expr -> pipe_op matched_expr : { '$1', '$2' }.
matched_op_expr -> bin_concat_op matched_expr : { '$1', '$2' }.
matched_op_expr -> in_op matched_expr : { '$1', '$2' }.
matched_op_expr -> inc_op matched_expr : { '$1', '$2' }.
matched_op_expr -> when_op matched_expr : { '$1', '$2' }.
matched_op_expr -> send_op matched_expr : { '$1', '$2' }.
matched_op_expr -> range_op matched_expr : { '$1', '$2' }.
matched_op_expr -> default_op matched_expr : { '$1', '$2' }.
matched_op_expr -> colon_colon_op matched_expr : { '$1', '$2' }.
matched_op_expr -> comp_expr_op matched_expr : { '$1', '$2' }.
block_expr -> parens_call call_args_parens do_block : build_identifier('$1', '$2' ++ '$3').
block_expr -> parens_call call_args_parens call_args_parens do_block : build_nested_parens('$1', '$2', '$3' ++ '$4').
block_expr -> dot_punctuated_identifier call_args_no_parens do_block : build_identifier('$1', '$2' ++ '$3').
block_expr -> dot_do_identifier do_block : build_identifier('$1', '$2').
block_expr -> dot_identifier call_args_no_parens do_block : build_identifier('$1', '$2' ++ '$3').
fn_expr -> fn_eol stab_expr_list end_eol : build_fn('$1', build_stab(lists:reverse('$2'))).
fn_expr -> fn_eol '->' grammar 'end' : build_fn('$1', { '->', [{line,?line('$2')}], [{ [], build_block('$3') }] }).
fn_expr -> call_expr : '$1'.
call_expr -> dot_punctuated_identifier call_args_no_parens : build_identifier('$1', '$2').
call_expr -> dot_op_identifier call_args_no_parens : build_identifier('$1', '$2').
call_expr -> dot_identifier call_args_no_parens : build_identifier('$1', '$2').
call_expr -> dot_punctuated_identifier : build_identifier('$1', []).
call_expr -> dot_do_identifier : build_identifier('$1', nil).
call_expr -> var : build_identifier('$1', nil).
call_expr -> max_expr : '$1'.
max_expr -> bracket_expr : '$1'.
max_expr -> parens_call call_args_parens : build_identifier('$1', '$2').
max_expr -> parens_call call_args_parens call_args_parens : build_nested_parens('$1', '$2', '$3').
max_expr -> dot_ref : '$1'.
max_expr -> base_expr : '$1'.
max_expr -> open_paren stab_expr_list close_paren : build_stab(lists:reverse('$2')).
bracket_expr -> dot_bracket_identifier bracket_access : build_access(build_identifier('$1', nil), '$2').
bracket_expr -> max_expr bracket_access : build_access('$1', '$2').
bracket_at_expr -> at_op dot_bracket_identifier bracket_access : build_access(build_unary_op('$1', build_identifier('$2', nil)), '$3').
bracket_at_expr -> at_op max_expr bracket_access : build_access(build_unary_op('$1', '$2'), '$3').
bracket_at_expr -> bracket_at_expr bracket_access : build_access('$1', '$2').
base_expr -> number : ?exprs('$1').
base_expr -> signed_number : { element(4, '$1'), [{line,?line('$1')}], ?exprs('$1') }.
base_expr -> atom : build_atom('$1').
base_expr -> list : '$1'.
base_expr -> tuple : '$1'.
base_expr -> 'true' : ?op('$1').
base_expr -> 'false' : ?op('$1').
base_expr -> 'nil' : ?op('$1').
base_expr -> aliases : { '__aliases__', [{line,?line('$1')}], ?exprs('$1') }.
base_expr -> bin_string : build_bin_string('$1').
base_expr -> list_string : build_list_string('$1').
base_expr -> bit_string : '$1'.
base_expr -> '&' : { '&', [{line,?line('$1')}], ?exprs('$1') }.
base_expr -> '...' : { ?op('$1'), [{line,?line('$1')}], [] }.
base_expr -> sigil : build_sigil('$1').
%% Blocks
do_block -> do_eol 'end' : [[{do,nil}]].
do_block -> do_eol stab_expr_list end_eol : [[{ do, build_stab(lists:reverse('$2')) }]].
do_block -> do_eol block_list 'end' : [[{ do, nil }|'$2']].
do_block -> do_eol stab_expr_list eol block_list 'end' : [[{ do, build_stab(lists:reverse('$2')) }|'$4']].
fn_eol -> 'fn' : '$1'.
fn_eol -> 'fn' eol : '$1'.
do_eol -> 'do' : '$1'.
do_eol -> 'do' eol : '$1'.
end_eol -> 'end' : '$1'.
end_eol -> eol 'end' : '$2'.
block_eol -> block_identifier : '$1'.
block_eol -> block_identifier eol : '$1'.
stab_expr_list -> stab_expr : ['$1'].
stab_expr_list -> stab_expr_list eol stab_expr : ['$3'|'$1'].
stab_expr -> expr : '$1'.
stab_expr -> call_args_no_parens stab_op expr : build_op('$2', '$1', '$3').
stab_expr -> call_args_parens_not_one stab_op expr : build_op('$2', '$1', '$3').
block_item -> block_eol stab_expr_list eol : { ?exprs('$1'), build_stab(lists:reverse('$2')) }.
block_item -> block_eol : { ?exprs('$1'), nil }.
block_list -> block_item : ['$1'].
block_list -> block_item block_list : ['$1'|'$2'].
%% Helpers
var -> dot_identifier : '$1'.
open_paren -> '(' : '$1'.
open_paren -> '(' eol : '$1'.
close_paren -> ')' : '$1'.
close_paren -> eol ')' : '$2'.
empty_paren -> open_paren ')' : nil.
open_bracket -> '[' : '$1'.
open_bracket -> '[' eol : '$1'.
close_bracket -> ']' : '$1'.
close_bracket -> eol ']' : '$2'.
open_bit -> '<<' : '$1'.
open_bit -> '<<' eol : '$1'.
close_bit -> '>>' : '$1'.
close_bit -> eol '>>' : '$2'.
open_curly -> '{' : '$1'.
open_curly -> '{' eol : '$1'.
close_curly -> '}' : '$1'.
close_curly -> eol '}' : '$2'.
% Operators
add_op -> '+' : '$1'.
add_op -> '-' : '$1'.
add_op -> '+' eol : '$1'.
add_op -> '-' eol : '$1'.
mult_op -> '*' : '$1'.
mult_op -> '/' : '$1'.
mult_op -> '*' eol : '$1'.
mult_op -> '/' eol : '$1'.
two_op -> '++' : '$1'.
two_op -> '--' : '$1'.
two_op -> '++' eol : '$1'.
two_op -> '--' eol : '$1'.
two_op -> '**' : '$1'.
two_op -> '**' eol : '$1'.
pipeline_op -> '=~' : '$1'.
pipeline_op -> '=~' eol : '$1'.
pipeline_op -> '|>' : '$1'.
pipeline_op -> '|>' eol : '$1'.
pipeline_op -> '/>' : '$1'.
pipeline_op -> '/>' eol : '$1'.
three_op -> '&&&' : '$1'.
three_op -> '&&&' eol : '$1'.
three_op -> '|||' : '$1'.
three_op -> '|||' eol : '$1'.
three_op -> '<<<' : '$1'.
three_op -> '<<<' eol : '$1'.
three_op -> '>>>' : '$1'.
three_op -> '>>>' eol : '$1'.
three_op -> '^^^' : '$1'.
three_op -> '^^^' eol : '$1'.
default_op -> '//' : '$1'.
default_op -> '//' eol : '$1'.
colon_colon_op -> '::' : '$1'.
colon_colon_op -> '::' eol : '$1'.
unary_op -> '+' : '$1'.
unary_op -> '+' eol : '$1'.
unary_op -> '-' : '$1'.
unary_op -> '-' eol : '$1'.
unary_op -> '!' : '$1'.
unary_op -> '!' eol : '$1'.
unary_op -> '^' : '$1'.
unary_op -> '^' eol : '$1'.
unary_op -> 'not' : '$1'.
unary_op -> 'not' eol : '$1'.
unary_op -> '~~~' : '$1'.
unary_op -> '~~~' eol : '$1'.
at_op -> '@' : '$1'.
at_op -> '@' eol : '$1'.
match_op -> '=' : '$1'.
match_op -> '=' eol : '$1'.
andand_op -> '&&' : '$1'.
andand_op -> '&&' eol : '$1'.
oror_op -> '||' : '$1'.
oror_op -> '||' eol : '$1'.
and_op -> 'and' : '$1'.
and_op -> 'and' eol : '$1'.
or_op -> 'or' : '$1'.
or_op -> 'or' eol : '$1'.
or_op -> 'xor' : '$1'.
or_op -> 'xor' eol : '$1'.
pipe_op -> '|' : '$1'.
pipe_op -> '|' eol : '$1'.
bin_concat_op -> '<>' : '$1'.
bin_concat_op -> '<>' eol : '$1'.
in_op -> 'in' : '$1'.
in_op -> 'in' eol : '$1'.
inc_op -> 'inlist' : '$1'.
inc_op -> 'inlist' eol : '$1'.
inc_op -> 'inbits' : '$1'.
inc_op -> 'inbits' eol : '$1'.
when_op -> 'when' : '$1'.
when_op -> 'when' eol : '$1'.
stab_op -> '->' : '$1'.
stab_op -> '->' eol : '$1'.
send_op -> '<-' : '$1'.
send_op -> '<-' eol : '$1'.
range_op -> '..' : '$1'.
range_op -> '..' eol : '$1'.
comp_expr_op -> comp_op : '$1'.
comp_expr_op -> comp_op eol : '$1'.
% Dot operator
dot_op -> '.' : '$1'.
dot_op -> '.' eol : '$1'.
dot_identifier -> identifier : '$1'.
dot_identifier -> matched_expr dot_op identifier : build_dot('$2', '$1', '$3').
dot_ref -> matched_expr dot_op aliases : build_dot_ref('$2', '$1', '$3').
dot_op_identifier -> op_identifier : '$1'.
dot_op_identifier -> matched_expr dot_op op_identifier : build_dot('$2', '$1', '$3').
dot_do_identifier -> do_identifier : '$1'.
dot_do_identifier -> matched_expr dot_op do_identifier : build_dot('$2', '$1', '$3').
dot_bracket_identifier -> bracket_identifier : '$1'.
dot_bracket_identifier -> matched_expr dot_op bracket_identifier : build_dot('$2', '$1', '$3').
dot_paren_identifier -> paren_identifier : '$1'.
dot_paren_identifier -> matched_expr dot_op paren_identifier : build_dot('$2', '$1', '$3').
dot_punctuated_identifier -> punctuated_identifier : '$1'.
dot_punctuated_identifier -> matched_expr dot_op punctuated_identifier : build_dot('$2', '$1', '$3').
parens_call -> dot_paren_identifier : '$1'.
parens_call -> matched_expr dot_call_op : { '.', [{line,?line('$2')}], ['$1'] }. % Fun/local calls
% Function calls
matched_comma_expr -> matched_expr : ['$1'].
matched_comma_expr -> matched_comma_expr ',' matched_expr : ['$3'|'$1'].
call_args_no_parens -> matched_comma_expr : lists:reverse('$1').
call_args_no_parens -> matched_kw_base : ['$1'].
call_args_no_parens -> matched_comma_expr ',' matched_kw_base : lists:reverse(['$3'|'$1']).
call_args_parens_not_one -> open_paren ')' : [].
call_args_parens_not_one -> open_paren matched_kw_base close_paren : ['$2'].
call_args_parens_not_one -> open_paren matched_expr ',' call_args_no_parens close_paren : ['$2'|'$4'].
base_comma_expr -> paren_expr ',' : ['$1'].
base_comma_expr -> base_comma_expr paren_expr ',' : ['$2'|'$1'].
comma_expr -> paren_expr : ['$1'].
comma_expr -> kw_base : ['$1'].
comma_expr -> base_comma_expr : '$1'.
comma_expr -> base_comma_expr paren_expr : ['$2'|'$1'].
comma_expr -> base_comma_expr kw_base : ['$2'|'$1'].
optional_comma_expr -> paren_expr : '$1'.
optional_comma_expr -> paren_expr ',' : '$1'.
call_args -> comma_expr : lists:reverse('$1').
call_args_parens -> open_paren ')' : [].
call_args_parens -> open_paren call_args close_paren : '$2'.
% KV
kw_eol -> kw_identifier : '$1'.
kw_eol -> kw_identifier eol : '$1'.
kw_expr -> kw_eol paren_expr : { ?exprs('$1'),'$2' }.
kw_comma -> kw_expr ',' : ['$1'].
kw_comma -> kw_comma kw_expr ',' : ['$2'|'$1'].
kw_base -> kw_expr : ['$1'].
kw_base -> kw_comma : lists:reverse('$1').
kw_base -> kw_comma kw_expr : lists:reverse(['$2'|'$1']).
matched_kw_expr -> kw_eol matched_expr : {?exprs('$1'),'$2'}.
matched_kw_expr -> kw_eol empty_paren : {?exprs('$1'),nil}.
matched_kw_comma -> matched_kw_expr : ['$1'].
matched_kw_comma -> matched_kw_expr ',' matched_kw_comma : ['$1'|'$3'].
matched_kw_base -> matched_kw_comma : '$1'.
% Lists
bracket_access -> open_bracket ']' : { [], ?line('$1') }.
bracket_access -> open_bracket optional_comma_expr close_bracket : { '$2', ?line('$1') }.
bracket_access -> open_bracket kw_base close_bracket : { '$2', ?line('$1') }.
list -> open_bracket ']' : [].
list -> open_bracket kw_base close_bracket : '$2'.
list -> open_bracket optional_comma_expr close_bracket : ['$2'].
list -> open_bracket paren_expr ',' call_args close_bracket : ['$2'|'$4'].
% Tuple
tuple -> open_curly '}' : build_tuple('$1', []).
tuple -> open_curly optional_comma_expr close_curly : build_tuple('$1', ['$2']).
tuple -> open_curly paren_expr ',' call_args close_curly : build_tuple('$1', ['$2'|'$4']).
% Bitstrings
bit_string -> open_bit '>>' : { '<<>>', [{line,?line('$1')}], [] }.
bit_string -> open_bit call_args close_bit : { '<<>>', [{line,?line('$1')}], '$2' }.
Erlang code.
-define(op(Node), element(1, Node)).
-define(line(Node), element(2, Node)).
-define(exprs(Node), element(3, Node)).
-define(rearrange_uop(Op), Op == 'not' orelse Op == '!').
-define(rearrange_bop(Op), Op == 'in' orelse Op == 'inlist' orelse Op == 'inbits').
%% The following directive is needed for (significantly) faster
%% compilation of the generated .erl file by the HiPE compiler
-compile([{hipe,[{regalloc,linear_scan}]}]).
%% Operators
build_op({ _, _, _ } = Op, Left, Right) ->
{ ?exprs(Op), [{line,?line(Op)}], [Left, Right] };
build_op({ BOp, Line }, { UOp, _, [Left] }, Right) when ?rearrange_bop(BOp), ?rearrange_uop(UOp) ->
{ UOp, [{line,Line}], [{ BOp, [{line,Line}], [Left, Right] }] };
build_op(Op, Left, Right) ->
{ ?op(Op), [{line,?line(Op)}], [Left, Right] }.
build_unary_op(Op, Expr) ->
{ ?op(Op), [{line,?line(Op)}], [Expr] }.
build_tuple(_Marker, [Left, Right]) ->
{ Left, Right };
build_tuple(Marker, Args) ->
{ '{}', [{line,?line(Marker)}], Args }.
%% Blocks
build_block([nil]) -> { '__block__', [], [nil] };
build_block([{Op,_,[_]}]=Exprs) when ?rearrange_uop(Op) -> { '__block__', [], Exprs };
build_block([Expr]) when not is_list(Expr) -> Expr;
build_block(Exprs) -> { '__block__', [], Exprs }.
%% Dots
build_dot_ref(Dot, { '__aliases__', _, Left }, { 'aliases', _, Right }) ->
{ '__aliases__', [{line,?line(Dot)}], Left ++ Right };
build_dot_ref(Dot, Other, { 'aliases', _, Right }) ->
{ '__aliases__', [{line,?line(Dot)}], [Other|Right] }.
build_dot(Dot, Left, Right) ->
{ '.', [{line,?line(Dot)}], [Left, extract_identifier(Right)] }.
%% Identifiers
build_nested_parens(Dot, Args1, Args2) ->
Identifier = build_identifier(Dot, Args1),
{ Identifier, ?line(Identifier), Args2 }.
build_identifier({ '.', Meta, _ } = Dot, Args) ->
FArgs = case Args of
nil -> [];
_ -> Args
end,
{ Dot, Meta, FArgs };
build_identifier({ Keyword, Line }, Args) when Keyword == fn ->
{ fn, [{line,Line}], Args };
build_identifier({ op_identifier, Line, Identifier }, Args) ->
{ '__ambiguousop__', [{line,Line}], [{ Identifier, [{line,Line}], nil }|Args] };
build_identifier({ _, Line, Identifier }, Args) ->
{ Identifier, [{line,Line}], Args }.
extract_identifier({ Kind, _, Identifier }) when
Kind == identifier; Kind == punctuated_identifier; Kind == bracket_identifier;
Kind == paren_identifier; Kind == do_identifier; Kind == op_identifier ->
Identifier;
extract_identifier(Other) -> Other.
%% Fn
build_fn(Op, Stab) ->
{ fn, [{line,?line(Op)}], [[{ do, Stab }]] }.
%% Access
build_access(Expr, Access) ->
Meta = [{line,?line(Access)}],
{ { '.', Meta, ['Elixir-Kernel', access] }, Meta, [ Expr, ?op(Access) ] }.
%% Interpolation aware
build_sigil({ sigil, Line, Sigil, Parts, Modifiers }) ->
Meta = [{line,Line}],
{ list_to_atom([$_,$_,Sigil,$_,$_]), Meta, [ { '<<>>', Meta, Parts }, Modifiers ] }.
build_bin_string({ bin_string, _Line, [H] }) when is_binary(H) -> H;
build_bin_string({ bin_string, Line, Args }) -> { '<<>>', [{line,Line}], Args }.
build_list_string({ list_string, _Line, [H] }) when is_binary(H) -> binary_to_list(H);
build_list_string({ list_string, Line, Args }) ->
Meta = [{line,Line}],
{ { '.', Meta, [erlang, binary_to_list] }, Meta, [{ '<<>>', Meta, Args}] }.
build_atom({ atom, _Line, Atom }) when is_atom(Atom) -> Atom;
build_atom({ atom, Line, Args }) ->
Meta = [{line,Line}],
{ { '.', Meta, [erlang, binary_to_atom] }, Meta, [{ '<<>>', Meta, Args }, utf8] }.
%% Keywords
build_stab([{ '->', Meta, [Left, Right] }|T]) ->
{ '->', Meta, build_stab(T, Left, [Right], []) };
build_stab(Else) ->
build_block(Else).
build_stab([{ '->', _, [Left, Right] }|T], Marker, Temp, Acc) ->
H = { Marker, build_block(lists:reverse(Temp)) },
build_stab(T, Left, [Right], [H|Acc]);
build_stab([H|T], Marker, Temp, Acc) ->
build_stab(T, Marker, [H|Temp], Acc);
build_stab([], Marker, Temp, Acc) ->
H = { Marker, build_block(lists:reverse(Temp)) },
lists:reverse([H|Acc]).