Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Support {% for .. in .. reversed %} syntax

  • Loading branch information...
commit 898fbae78cd199795653b0d741073c7aa8d976d9 1 parent 604cdda
@evanmiller evanmiller authored
View
21 src/erlydtl_compiler.erl
@@ -570,12 +570,12 @@ body_ast(DjangoParseTree, Context, TreeWalker) ->
filter_tag_ast(FilterList, Contents, Context, TreeWalkerAcc);
({'firstof', Vars}, TreeWalkerAcc) ->
firstof_ast(Vars, Context, TreeWalkerAcc);
- ({'for', {'in', IteratorList, Variable}, Contents}, TreeWalkerAcc) ->
+ ({'for', {'in', IteratorList, Variable, Reversed}, Contents}, TreeWalkerAcc) ->
{EmptyAstInfo, TreeWalker1} = empty_ast(TreeWalkerAcc),
- for_loop_ast(IteratorList, Variable, Contents, EmptyAstInfo, Context, TreeWalker1);
- ({'for', {'in', IteratorList, Variable}, Contents, EmptyPartContents}, TreeWalkerAcc) ->
+ for_loop_ast(IteratorList, Variable, Reversed, Contents, EmptyAstInfo, Context, TreeWalker1);
+ ({'for', {'in', IteratorList, Variable, Reversed}, Contents, EmptyPartContents}, TreeWalkerAcc) ->
{EmptyAstInfo, TreeWalker1} = body_ast(EmptyPartContents, Context, TreeWalkerAcc),
- for_loop_ast(IteratorList, Variable, Contents, EmptyAstInfo, Context, TreeWalker1);
+ for_loop_ast(IteratorList, Variable, Reversed, Contents, EmptyAstInfo, Context, TreeWalker1);
({'if', Expression, Contents, Elif}, TreeWalkerAcc) ->
{IfAstInfo, TreeWalker1} = body_ast(Contents, Context, TreeWalkerAcc),
{ElifAstInfo, TreeWalker2} = body_ast(Elif, Context, TreeWalker1),
@@ -1114,7 +1114,7 @@ regroup_filter({variable,{identifier,_,Var}},Acc) ->
erl_syntax:list([erl_syntax:atom(Var)|Acc]).
-for_loop_ast(IteratorList, LoopValue, Contents, {EmptyContentsAst, EmptyContentsInfo}, Context, TreeWalker) ->
+for_loop_ast(IteratorList, LoopValue, IsReversed, Contents, {EmptyContentsAst, EmptyContentsInfo}, Context, TreeWalker) ->
Vars = lists:map(fun({identifier, _, Iterator}) ->
erl_syntax:variable(lists:concat(["Var_", Iterator]))
end, IteratorList),
@@ -1129,11 +1129,16 @@ for_loop_ast(IteratorList, LoopValue, Contents, {EmptyContentsAst, EmptyContents
{{LoopValueAst, LoopValueInfo}, TreeWalker2} = value_ast(LoopValue, false, true, Context, TreeWalker1),
+ LoopValueAst0 = case IsReversed of
+ true -> erl_syntax:application(erl_syntax:atom(lists), erl_syntax:atom(reverse), [LoopValueAst]);
+ false -> LoopValueAst
+ end,
+
CounterVars0 = case resolve_scoped_variable_ast('forloop', Context) of
undefined ->
- erl_syntax:application(erl_syntax:atom(erlydtl_runtime), erl_syntax:atom(init_counter_stats), [LoopValueAst]);
+ erl_syntax:application(erl_syntax:atom(erlydtl_runtime), erl_syntax:atom(init_counter_stats), [LoopValueAst0]);
Value ->
- erl_syntax:application(erl_syntax:atom(erlydtl_runtime), erl_syntax:atom(init_counter_stats), [LoopValueAst, Value])
+ erl_syntax:application(erl_syntax:atom(erlydtl_runtime), erl_syntax:atom(init_counter_stats), [LoopValueAst0, Value])
end,
{{erl_syntax:case_expr(
erl_syntax:application(
@@ -1145,7 +1150,7 @@ for_loop_ast(IteratorList, LoopValue, Contents, {EmptyContentsAst, EmptyContents
_ -> [erl_syntax:list(Vars), erl_syntax:variable("Counters")] end, none,
[erl_syntax:tuple([InnerAst, CounterAst])])
]),
- CounterVars0, LoopValueAst]),
+ CounterVars0, LoopValueAst0]),
[erl_syntax:clause(
[erl_syntax:tuple([erl_syntax:underscore(),
erl_syntax:list([erl_syntax:tuple([erl_syntax:atom(counter), erl_syntax:integer(1)])],
View
4 src/erlydtl_parser.yrl
@@ -176,6 +176,7 @@ Terminals
open_var
parsed_keyword
regroup_keyword
+ reversed_keyword
spaceless_keyword
ssi_keyword
string_literal
@@ -295,7 +296,8 @@ ForBlock -> ForBraced Elements EmptyBraced Elements EndForBraced : {for, '$1', '
EmptyBraced -> open_tag empty_keyword close_tag.
ForBraced -> open_tag for_keyword ForExpression close_tag : '$3'.
EndForBraced -> open_tag endfor_keyword close_tag.
-ForExpression -> ForGroup in_keyword Variable : {'in', '$1', '$3'}.
+ForExpression -> ForGroup in_keyword Variable : {'in', '$1', '$3', false}.
+ForExpression -> ForGroup in_keyword Variable reversed_keyword : {'in', '$1', '$3', true}.
ForGroup -> identifier : ['$1'].
ForGroup -> ForGroup ',' identifier : '$1' ++ ['$3'].
View
2  src/erlydtl_scanner.erl
@@ -335,6 +335,8 @@ mark_keywords([{identifier, Pos, "parsed" = String}, {close_tag, _, _} = CloseTa
mark_keywords(T, lists:reverse([{parsed_keyword, Pos, String}, CloseTag], Acc));
mark_keywords([{identifier, Pos, "noop" = String}, {close_tag, _, _} = CloseTag|T], Acc) ->
mark_keywords(T, lists:reverse([{noop_keyword, Pos, String}, CloseTag], Acc));
+mark_keywords([{identifier, Pos, "reversed" = String}, {close_tag, _, _} = CloseTag|T], Acc) ->
+ mark_keywords(T, lists:reverse([{reversed_keyword, Pos, String}, CloseTag], Acc));
mark_keywords([{identifier, Pos, "openblock" = String}, {close_tag, _, _} = CloseTag|T], Acc) ->
mark_keywords(T, lists:reverse([{openblock_keyword, Pos, String}, CloseTag], Acc));
mark_keywords([{identifier, Pos, "closeblock" = String}, {close_tag, _, _} = CloseTag|T], Acc) ->
View
3  tests/src/erlydtl_unittests.erl
@@ -213,6 +213,9 @@ tests() ->
{"Simple loop",
<<"{% for x in list %}{{ x }}{% endfor %}">>, [{'list', ["1", "2", "3"]}],
<<"123">>},
+ {"Reversed loop",
+ <<"{% for x in list reversed %}{{ x }}{% endfor %}">>, [{'list', ["1", "2", "3"]}],
+ <<"321">>},
{"Expand list",
<<"{% for x, y in list %}{{ x }},{{ y }}\n{% endfor %}">>, [{'list', [["X", "1"], ["X", "2"]]}],
<<"X,1\nX,2\n">>},

1 comment on commit 898fbae

@kaos
Owner

Fixes #67.

Please sign in to comment.
Something went wrong with that request. Please try again.