Browse Source

Handle loops within {%block%} and {%extend%}

When base and parent templates within {%block%} tags contain for loops,
there is an 'unsafe L' error due to matched variables automatically
being bound in case expressions.  This wraps the case statement in a
function call, containing the 'L' variable, and preventing a crash.

This also adds the relavent test.
Jesse Gumm 11 years ago
parent
commit
fc7b5ac270

+ 15 - 13
src/erlydtl_beam_compiler.erl

@@ -1336,19 +1336,21 @@ for_loop_ast(IteratorList, LoopValue, IsReversed, Contents,
 
 
     {ParentLoop, TreeWalker3} = resolve_reserved_variable('forloop', TreeWalker2),
     {ParentLoop, TreeWalker3} = resolve_reserved_variable('forloop', TreeWalker2),
 
 
-    %% call for loop
-    {{?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"],
+    %% call for loop (wrapped in a fun to contain the variable L)
+    {{?Q(["fun() ->",
+          "  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",
+          "end()"],
          [{ifclauses, if IteratorCount > 1 ->
          [{ifclauses, if IteratorCount > 1 ->
                               ?Q(["() when is_list(_@Vars), length(_@Vars) == _@IteratorCount@ ->",
                               ?Q(["() when is_list(_@Vars), length(_@Vars) == _@IteratorCount@ ->",
                                   "  list_to_tuple(_@Vars);",
                                   "  list_to_tuple(_@Vars);",

+ 4 - 1
test/erlydtl_test_defs.erl

@@ -1656,7 +1656,7 @@ all_test_defs() ->
                 "var", "var_preset", "cycle", "custom_tag", "custom_tag1",
                 "var", "var_preset", "cycle", "custom_tag", "custom_tag1",
                 "custom_tag2", "custom_tag3", "custom_tag4", "custom_call",
                 "custom_tag2", "custom_tag3", "custom_tag4", "custom_call",
                 "include_template", "include_path", "ssi", "extends_path",
                 "include_template", "include_path", "ssi", "extends_path",
-                "extends_path2", "trans", "extends2", "extends3",
+                "extends_path2", "trans", "extends_for", "extends2", "extends3",
                 "recursive_block", "extend_recursive_block", "missing",
                 "recursive_block", "extend_recursive_block", "missing",
                 "block_super"]
                 "block_super"]
       ]},
       ]},
@@ -1801,6 +1801,9 @@ setup_compile("ifnotequal_preset") ->
 setup_compile("var_preset") ->
 setup_compile("var_preset") ->
     CompileVars = [{preset_var1, "preset-var1"}, {preset_var2, "preset-var2"}],
     CompileVars = [{preset_var1, "preset-var1"}, {preset_var2, "preset-var2"}],
     {ok, [CompileVars]};
     {ok, [CompileVars]};
+setup_compile("extends_for") ->
+	CompileVars = [{veggie_list, ["broccoli", "beans", "peas", "carrots"]}],
+	{ok, [CompileVars]};
 setup_compile("extends2") ->
 setup_compile("extends2") ->
     File = template_file(input, "extends2"),
     File = template_file(input, "extends2"),
     Error = {none, erlydtl_beam_compiler, unexpected_extends_tag},
     Error = {none, erlydtl_beam_compiler, unexpected_extends_tag},

+ 17 - 0
test/files/expect/extends_for

@@ -0,0 +1,17 @@
+before
+
+
+<ul>
+
+<li>broccoli</li>
+
+<li>beans</li>
+
+<li>peas</li>
+
+<li>carrots</li>
+
+</ul>
+
+
+after

+ 11 - 0
test/files/input/base_for

@@ -0,0 +1,11 @@
+before
+
+{% block forloop %}
+<ul>
+{% for iterator in fruit_list %}
+<li>{{ forloop.counter }}. {{ iterator }}</li>
+{% endfor %}
+</ul>
+{% endblock %}
+
+after

+ 8 - 0
test/files/input/extends_for

@@ -0,0 +1,8 @@
+{% extends "base_for" %}
+{% block forloop %}
+<ul>
+{% for iterator in veggie_list %}
+<li>{{ iterator }}</li>
+{% endfor %}
+</ul>
+{% endblock %}