Browse Source

Fix issue #183.

Added optional list of filters to apply when looking up scoped
variables.

The `block.super` variable has the `safe` filter applied to it, to
avoid further escaping.
Andreas Stenius 11 years ago
parent
commit
33b1fa2932
2 changed files with 41 additions and 16 deletions
  1. 28 6
      src/erlydtl_beam_compiler.erl
  2. 13 10
      src/erlydtl_compiler_utils.erl

+ 28 - 6
src/erlydtl_beam_compiler.erl

@@ -582,7 +582,7 @@ body_ast(DjangoParseTree, BodyScope, TreeWalker) ->
                             {{ContentsAst, _ContentsInfo}, _ContentsTW} = body_ast(Contents, TW),
                             {ChildBlock,
                              create_scope(
-                               [{block, ?Q("[{super, _@ContentsAst}]")}],
+                               [{block, ?Q("[{super, _@ContentsAst}]"), safe}],
                                Pos, TW)
                             };
                         _ ->
@@ -1179,7 +1179,8 @@ resolve_variable_ast1({attribute, {{_, Pos, Attr}, Variable}}, {Runtime, Finder}
      TreeWalker1};
 
 resolve_variable_ast1({variable, {identifier, Pos, VarName}}, {Runtime, Finder}, TreeWalker) ->
-    Ast = case resolve_variable(VarName, TreeWalker) of
+    {Source, Value, Filters} = resolve_variable(VarName, TreeWalker),
+    Ast = case {Source, Value} of
               {_, undefined} ->
                   FileName = get_current_file(TreeWalker),
                   {?Q(["'@Runtime@':'@Finder@'(",
@@ -1208,14 +1209,30 @@ resolve_variable_ast1({variable, {identifier, Pos, VarName}}, {Runtime, Finder},
               {scope, Val} ->
                   {Val, #ast_info{}}
           end,
-    {Ast, TreeWalker}.
+    lists:foldr(
+      fun ({escape, []}, {{AccAst, AccInfo}, TW}) ->
+              {{?Q("erlydtl_filters:force_escape(_@AccAst)"), AccInfo}, TW#treewalker{ safe = true }};
+          ({Safe, []}, {Acc, TW}) when Safe == safe; Safe == safeseq ->
+              {Acc, TW#treewalker{ safe = true }};
+          ({Filter, Args}, {{AccAst, AccInfo}, TW})
+            when is_atom(Filter), is_list(Args) ->
+              case filter_ast2(Filter, [AccAst|Args], TW#treewalker.context) of
+                  {ok, FilteredAst} ->
+                      {{FilteredAst, AccInfo}, TW};
+                  Error ->
+                      empty_ast(?WARN({Pos, Error}, TW))
+              end
+      end,
+      {Ast, TreeWalker},
+      Filters
+     ).
 
 resolve_reserved_variable(ReservedName, TreeWalker) ->
     resolve_reserved_variable(ReservedName, merl:term(undefined), TreeWalker).
 
 resolve_reserved_variable(ReservedName, Default, TreeWalker) ->
     case resolve_variable(ReservedName, Default, TreeWalker) of
-        {Src, Value} when Src =:= scope; Value =:= Default ->
+        {Src, Value, []} when Src =:= scope; Value =:= Default ->
             {Value, TreeWalker};
         _ ->
             {Default, ?ERR({reserved_variable, ReservedName}, TreeWalker)}
@@ -1532,9 +1549,14 @@ call_ast(Module, Variable, AstInfo, TreeWalker) ->
 create_scope(Vars, VarScope) ->
     {Scope, Values} =
         lists:foldl(
-          fun ({Name, Value}, {VarAcc, ValueAcc}) ->
+          fun (Var, {VarAcc, ValueAcc}) ->
+                  {Name, Value, Filters} =
+                      case Var of
+                          {N, V} -> {N, V, []};
+                          {_, _, _} -> Var
+                      end,
                   NameAst = varname_ast(lists:concat(["_", Name, VarScope])),
-                  {[{Name, NameAst}|VarAcc],
+                  {[{Name, NameAst, Filters}|VarAcc],
                    [?Q("_@NameAst = _@Value")|ValueAcc]
                   }
           end,

+ 13 - 10
src/erlydtl_compiler_utils.erl

@@ -202,12 +202,12 @@ resolve_variable(VarName, Default, #treewalker{ context=Context }) ->
             case proplists:get_value(VarName, Context#dtl_context.const) of
                 undefined ->
                     case proplists:get_value(VarName, Context#dtl_context.vars) of
-                        undefined -> {default, Default};
-                        Value -> {default_vars, Value}
+                        undefined -> {default, Default, []};
+                        Value -> {default_vars, Value, []}
                     end;
-                Value -> {constant, Value}
+                Value -> {constant, Value, []}
             end;
-        Value -> {scope, Value}
+        {Value, Filters} -> {scope, Value, Filters}
     end.
 
 push_scope(Scope, #treewalker{ context=Context }=TreeWalker) ->
@@ -413,12 +413,18 @@ pos_info({Line, Col}) when is_integer(Line), is_integer(Col) ->
 
 resolve_variable1([], _VarName) -> undefined;
 resolve_variable1([Scope|Scopes], VarName) ->
-    case proplists:get_value(VarName, get_scope(Scope)) of
-        undefined ->
+    case lists:keyfind(VarName, 1, get_scope(Scope)) of
+        false ->
             resolve_variable1(Scopes, VarName);
-        Value -> Value
+        {_, Value} -> {Value, []};
+        {_, Value, Filters} when is_list(Filters) -> {Value, Filters};
+        {_, Value, Filter} when is_atom(Filter) -> {Value, [{Filter, []}]};
+        {_, Value, Filter} -> {Value, [Filter]}
     end.
 
+get_scope({_Id, Scope, _Values}) -> Scope;
+get_scope(Scope) -> Scope.
+
 merge_info1(1, _, _, Info) -> Info;
 merge_info1(FieldIdx, Info1, Info2, Info) ->
     Value = lists:umerge(
@@ -426,9 +432,6 @@ merge_info1(FieldIdx, Info1, Info2, Info) ->
               lists:usort(element(FieldIdx, Info2))),
     merge_info1(FieldIdx - 1, Info1, Info2, setelement(FieldIdx, Info, Value)).
 
-get_scope({_Id, Scope, _Values}) -> Scope;
-get_scope(Scope) -> Scope.
-
 close_scope(Fun, Id, AstList, TreeWalker) ->
     case merge_scopes(Id, TreeWalker) of
         {[], TreeWalker1} -> {AstList, TreeWalker1};