Skip to content

Commit

Permalink
... and more conversions (#123)
Browse files Browse the repository at this point in the history
  • Loading branch information
kaos committed Feb 21, 2014
1 parent 401450d commit 577a665
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 143 deletions.
208 changes: 66 additions & 142 deletions src/erlydtl_compiler.erl
Expand Up @@ -1363,59 +1363,36 @@ resolve_variable_ast(VarTuple, Context, TreeWalker, EmptyIfUndefined)
resolve_variable_ast(VarTuple, Context, TreeWalker, FinderFunction) ->
resolve_variable_ast1(VarTuple, Context, TreeWalker, FinderFunction).

resolve_variable_ast1({attribute, {{AttrKind, Pos, Attr}, Variable}}, Context, TreeWalker, FinderFunction) ->
resolve_variable_ast1({attribute, {{_, Pos, Attr}, Variable}}, Context, TreeWalker, FinderFunction) ->
{{VarAst, VarInfo}, TreeWalker1} = resolve_variable_ast(Variable, Context, TreeWalker, FinderFunction),
FileNameAst = erl_syntax:tuple(
[erl_syntax:atom(filename),
case Context#dtl_context.parse_trail of
[] -> erl_syntax:atom(undefined);
[H|_] -> erl_syntax:string(H)
end]),
AttrAst = erl_syntax:abstract(
case AttrKind of
number_literal -> erlang:list_to_integer(Attr);
_ -> Attr
end),
FileName = case Context#dtl_context.parse_trail of
[] -> undefined;
[H|_] -> H
end,
{Runtime, Finder} = FinderFunction,
{{erl_syntax:application(
erl_syntax:atom(Runtime),
erl_syntax:atom(Finder),
[AttrAst, VarAst,
erl_syntax:list(
[FileNameAst,
erl_syntax:abstract({pos, Pos}),
erl_syntax:tuple([erl_syntax:atom(record_info),
erl_syntax:variable("_RecordInfo")]),
erl_syntax:tuple([erl_syntax:atom(render_options),
erl_syntax:variable("RenderOptions")])
])
]),
{{?Q(["'@Runtime@':'@Finder@'(",
" _@Attr@, _@VarAst,",
" [{filename, _@FileName@},",
" {pos, _@Pos@},",
" {record_info, _RecordInfo},",
" {render_options, RenderOptions}])"]),
VarInfo},

TreeWalker1};

resolve_variable_ast1({variable, {identifier, Pos, VarName}}, Context, TreeWalker, FinderFunction) ->
VarValue = case resolve_scoped_variable_ast(VarName, Context) of
undefined ->
FileNameAst = erl_syntax:tuple(
[erl_syntax:atom(filename),
case Context#dtl_context.parse_trail of
[] -> erl_syntax:atom(undefined);
[H|_] -> erl_syntax:string(H)
end]),
FileName = case Context#dtl_context.parse_trail of
[] -> undefined;
[H|_] -> H
end,
{Runtime, Finder} = FinderFunction,
erl_syntax:application(
erl_syntax:atom(Runtime), erl_syntax:atom(Finder),
[erl_syntax:atom(VarName), erl_syntax:variable("_Variables"),
erl_syntax:list(
[FileNameAst,
erl_syntax:abstract({pos, Pos}),
erl_syntax:tuple([erl_syntax:atom(record_info),
erl_syntax:variable("_RecordInfo")]),
erl_syntax:tuple([erl_syntax:atom(render_options),
erl_syntax:variable("RenderOptions")])
])
]);
?Q(["'@Runtime@':'@Finder@'(",
" _@VarName@, _Variables,",
" [{filename, _@FileName@},",
" {pos, _@Pos@},",
" {record_info, _RecordInfo},",
" {render_options, RenderOptions}])"]);
Val ->
Val
end,
Expand All @@ -1439,14 +1416,13 @@ format(Ast, Context, TreeWalker) ->
auto_escape(format_number_ast(Ast), Context, TreeWalker).

format_number_ast(Ast) ->
erl_syntax:application(erl_syntax:atom(erlydtl_filters), erl_syntax:atom(format_number),
[Ast]).
?Q("erlydtl_filters:format_number(_@Ast)").


auto_escape(Value, _, #treewalker{safe = true}) ->
Value;
auto_escape(Value, #dtl_context{auto_escape = on}, _) ->
erl_syntax:application(erl_syntax:atom(erlydtl_filters), erl_syntax:atom(force_escape), [Value]);
?Q("erlydtl_filters:force_escape(_@Value)");
auto_escape(Value, _, _) ->
Value.

Expand All @@ -1465,12 +1441,12 @@ firstof_ast(Vars, Context, TreeWalker) ->
ifelse_ast(Expression, {IfContentsAst, IfContentsInfo}, {ElseContentsAst, ElseContentsInfo}, Context, TreeWalker) ->
Info = merge_info(IfContentsInfo, ElseContentsInfo),
{{Ast, ExpressionInfo}, TreeWalker1} = value_ast(Expression, false, false, Context, TreeWalker),
{{erl_syntax:case_expr(erl_syntax:application(erl_syntax:atom(erlydtl_runtime), erl_syntax:atom(is_true), [Ast]),
[erl_syntax:clause([erl_syntax:atom(true)], none,
[IfContentsAst]),
erl_syntax:clause([erl_syntax:underscore()], none,
[ElseContentsAst])
]), merge_info(ExpressionInfo, Info)}, TreeWalker1}.
{{?Q(["case erlydtl_runtime:is_true(_@Ast) of",
" true -> _@IfContentsAst;",
" _ -> _@ElseContentsAst",
"end"]),
merge_info(ExpressionInfo, Info)},
TreeWalker1}.

with_ast(ArgList, Contents, Context, TreeWalker) ->
{ArgAstList, {ArgInfo, TreeWalker1}} =
Expand All @@ -1491,41 +1467,35 @@ with_ast(ArgList, Contents, Context, TreeWalker) ->
Context#dtl_context{local_scopes = [NewScope|Context#dtl_context.local_scopes]},
TreeWalker1),

{{erl_syntax:application(
erl_syntax:fun_expr(
[erl_syntax:clause(
lists:map(fun({_, Var}) -> Var end, NewScope),
none,
[InnerAst])]),
ArgAstList),
{{?Q("fun (_@args) -> _@InnerAst end (_@ArgAstList)",
[{args, element(2, lists:unzip(NewScope))}]),
merge_info(ArgInfo, InnerInfo)},
TreeWalker2}.

regroup_ast(ListVariable, GrouperVariable, LocalVarName, Contents, Context, TreeWalker) ->
{{ListAst, ListInfo}, TreeWalker1} = value_ast(ListVariable, false, true, Context, TreeWalker),
NewScope = [{LocalVarName, erl_syntax:variable(lists:concat(["Var_", LocalVarName]))}],
LocalVarAst = erl_syntax:variable(lists:concat(["Var_", LocalVarName])),
NewScope = [{LocalVarName, LocalVarAst}],

{{InnerAst, InnerInfo}, TreeWalker2} = body_ast(Contents,
Context#dtl_context{ local_scopes = [NewScope|Context#dtl_context.local_scopes] }, TreeWalker1),

Ast = {erl_syntax:application(
erl_syntax:fun_expr([
erl_syntax:clause([erl_syntax:variable(lists:concat(["Var_", LocalVarName]))], none,
[InnerAst])]),
[erl_syntax:application(erl_syntax:atom(erlydtl_runtime), erl_syntax:atom(regroup),
[ListAst, regroup_filter(GrouperVariable,[])])]), merge_info(ListInfo, InnerInfo)},
{Ast,TreeWalker2}.
Context#dtl_context{
local_scopes = [NewScope|Context#dtl_context.local_scopes]
},
TreeWalker1),

{{?Q(["fun (_@LocalVarAst) -> _@InnerAst end",
"(erlydtl_runtime:regroup(_@ListAst, _@regroup))"],
[{regroup, regroup_filter(GrouperVariable, [])}]),
merge_info(ListInfo, InnerInfo)},
TreeWalker2}.

regroup_filter({attribute,{{identifier,_,Ident},Next}},Acc) ->
regroup_filter(Next,[erl_syntax:atom(Ident)|Acc]);
regroup_filter({variable,{identifier,_,Var}},Acc) ->
erl_syntax:list([erl_syntax:atom(Var)|Acc]).

to_list_ast(Value, IsReversed) ->
erl_syntax:application(
erl_syntax:atom(erlydtl_runtime),
erl_syntax:atom(to_list),
[Value, IsReversed]).
?Q("erlydtl_runtime:to_list(_@Value, _@IsReversed)").

to_list_ast(Value, IsReversed, Context, TreeWalker) ->
case call_extension(Context, to_list_ast, [Value, IsReversed, Context, TreeWalker]) of
Expand All @@ -1539,8 +1509,8 @@ for_loop_ast(IteratorList, LoopValue, IsReversed, Contents, {EmptyContentsAst, E
{Row, Col} = element(2, hd(IteratorList)),
ForId = lists:concat(["/", Level, "_", Row, ":", Col]),

Counters = lists:concat(["Counters", ForId]),
Vars = lists:concat(["Vars", ForId]),
Counters = merl:var(lists:concat(["Counters", ForId])),
Vars = merl:var(lists:concat(["Vars", ForId])),

%% setup
VarScope = lists:map(
Expand All @@ -1558,83 +1528,37 @@ for_loop_ast(IteratorList, LoopValue, IsReversed, Contents, {EmptyContentsAst, E
Contents,
Context#dtl_context{
local_scopes =
[[{'forloop', erl_syntax:variable(Counters)} | VarScope]
[[{'forloop', Counters} | VarScope]
| Context#dtl_context.local_scopes]
},
TreeWalker),

CounterAst = erl_syntax:application(
erl_syntax:atom(erlydtl_runtime),
erl_syntax:atom(increment_counter_stats),
[erl_syntax:variable(Counters)]),

{{LoopValueAst, LoopValueInfo}, TreeWalker2} = value_ast(LoopValue, false, true, Context, TreeWalker1),

LoopValueAst0 = to_list_ast(LoopValueAst, erl_syntax:atom(IsReversed), Context, TreeWalker2),

ParentLoop = resolve_scoped_variable_ast('forloop', Context, erl_syntax:atom(undefined)),

%% call for loop
{{erl_syntax:case_expr(
erl_syntax:application(
erl_syntax:atom('erlydtl_runtime'), erl_syntax:atom('forloop'),
[erl_syntax:fun_expr(
[erl_syntax:clause(
[erl_syntax:variable(Vars),
erl_syntax:variable(Counters)],
none,
[erl_syntax:match_expr(
erl_syntax:tuple(IteratorVars),
erl_syntax:if_expr(
[erl_syntax:clause(
[], [erl_syntax:application(none, erl_syntax:atom(is_tuple), [erl_syntax:variable(Vars)]),
erl_syntax:infix_expr(
erl_syntax:application(none, erl_syntax:atom(size), [erl_syntax:variable(Vars)]),
erl_syntax:operator('=='),
erl_syntax:integer(IteratorCount))
],
[erl_syntax:variable(Vars)])
| if IteratorCount > 1 ->
[erl_syntax:clause(
[], [erl_syntax:application(none, erl_syntax:atom(is_list), [erl_syntax:variable(Vars)]),
erl_syntax:infix_expr(
erl_syntax:application(none, erl_syntax:atom(length), [erl_syntax:variable(Vars)]),
erl_syntax:operator('=='),
erl_syntax:integer(IteratorCount))
],
[erl_syntax:application(none, erl_syntax:atom(list_to_tuple), [erl_syntax:variable(Vars)])]),
erl_syntax:clause(
[], [erl_syntax:atom(true)],
[erl_syntax:application(
none, erl_syntax:atom(throw),
[erl_syntax:tuple(
[erl_syntax:atom(for_loop),
erl_syntax:abstract(Iterators),
erl_syntax:variable(Vars)])
])
])
];
true ->
[erl_syntax:clause(
[], [erl_syntax:atom(true)],
[erl_syntax:tuple([erl_syntax:variable(Vars)])])
]
end
])),
erl_syntax:tuple([LoopBodyAst, CounterAst])
])
]),
LoopValueAst0, ParentLoop
]),
%% of
[erl_syntax:clause(
[erl_syntax:atom(empty)],
none,
[EmptyContentsAst]),
erl_syntax:clause(
[erl_syntax:tuple([erl_syntax:variable("L"), erl_syntax:underscore()])],
none, [erl_syntax:variable("L")])
]),
{{?Q(["case erlydtl_runtime:forloop(",
" fun (_@Vars, _@Counters) ->",
" {_@IteratorVars} = if is_tuple(_@Vars), size(_@Vars) == _@IteratorCount@ -> _@Vars;",
" _@___ifclauses -> _",
" end,",
" {_@LoopBodyAst, erlydtl_runtime:increment_counter_stats(_@Counters)}",
" end,",
" _@LoopValueAst0, _@ParentLoop)",
"of",
" empty -> _@EmptyContentsAst;",
" {L, _} -> L",
"end"],
[{ifclauses, if IteratorCount > 1 ->
?Q(["() when is_list(_@Vars), length(_@Vars) == _@IteratorCount@ ->",
" list_to_tuple(_@Vars);",
"() when true -> throw({for_loop, _@Iterators@, _@Vars})"]);
true ->
?Q("() when true -> {_@Vars}")
end}]),
merge_info(merge_info(Info, EmptyContentsInfo), LoopValueInfo)},
TreeWalker2}.

Expand Down
2 changes: 1 addition & 1 deletion tests/src/erlydtl_functional_tests.erl
Expand Up @@ -256,7 +256,7 @@ test_compile_render(Name) ->
force_recompile,
return_errors,
return_warnings,
%% debug_compiler,
%% debug_info,
{custom_tags_modules, [erlydtl_custom_tags]}],
io:format("compiling ... "),
case erlydtl:compile(File, Module, Options) of
Expand Down

0 comments on commit 577a665

Please sign in to comment.