Browse Source

added variable presetting, more tests and fixed if tag

Roberto Saccon 17 years ago
parent
commit
e21125a525

+ 7 - 0
demo/out/test_for_list_preset.html

@@ -0,0 +1,7 @@
+
+More than one apple is called "apples".
+
+More than one banana is called "bananas".
+
+More than one coconut is called "coconuts".
+

+ 4 - 0
demo/out/test_if_preset.html

@@ -0,0 +1,4 @@
+One but not two:  one 
+Two but not one:  two 
+One:  one 
+None: 

+ 5 - 11
demo/out/test_var.html

@@ -1,11 +1,5 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-    <title>Test variable</title>								 
-  </head>
-  <body>
-	foostring1
-	foostring2
-  </body>
-</html>
+before varriable1
+foostring1
+after variable1
+foostring2
+after variable2 (HTML-comment-wrapped)

+ 9 - 0
demo/out/test_var_preset.html

@@ -0,0 +1,9 @@
+one
+foostring1
+two
+preset-var1
+three
+foostring2
+four
+preset-var2
+five

+ 3 - 0
demo/templates/test_for_list_preset.html

@@ -0,0 +1,3 @@
+{% for singular, plural in fruit_list %}
+More than one {{ singular }} is called "{{ plural }}".
+{% endfor %}

+ 4 - 0
demo/templates/test_if_preset.html

@@ -0,0 +1,4 @@
+One but not two: {% if var1 %} one {% else %} two {% endif %}
+Two but not one: {% if not var1 %} one {% else %} two {% endif %}
+One: {% if var1 %} one {% endif %}
+None: {% if var2 %} one {% endif %}

+ 5 - 11
demo/templates/test_var.html

@@ -1,11 +1,5 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-    <title>Test variable</title>								 
-  </head>
-  <body>
-	{{ var1 }}
-	<!--{{ var2 }}-->
-  </body>
-</html>
+before varriable1
+{{ var1 }}
+after variable1
+<!--{{ var2 }}-->
+after variable2 (HTML-comment-wrapped)

+ 9 - 13
demo/templates/test_var_preset.html

@@ -1,13 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-    <title>Test variable</title>								 
-  </head>
-  <body>
-	{{ var1 }}
-	{{ preset_var1 }}
-	<!--{{ var2 }}-->
-	{{ preset_var2 }}
-  </body>
-</html>
+one
+{{ var1 }}
+two
+{{ preset_var1 }}
+three
+<!--{{ var2 }}-->
+four
+{{ preset_var2 }}
+five

+ 69 - 76
src/demo/erlydtl_demo.erl

@@ -34,7 +34,7 @@
 -author('rsaccon@gmail.com').
 -author('rsaccon@gmail.com').
 
 
 %% API
 %% API
--export([compile_all/0, compile/1, compile/2, render_all/0, render/1, render/2, preset/1]).
+-export([compile_all/0, compile/1, compile/3, render_all/0, render/1, render/2]).
 
 
 %%====================================================================
 %%====================================================================
 %% API
 %% API
@@ -50,10 +50,9 @@ compile_all() ->
     filelib:fold_files(DocRoot,
     filelib:fold_files(DocRoot,
         "\.html$|\.css$",
         "\.html$|\.css$",
         true,
         true,
-        fun(Path, _Acc) ->
-            Module = filename:rootname(filename:basename(Path)),
-            % case erlydtl_server:compile(Path, DocRoot, Module, {?MODULE, preset}) of
-            case erlydtl_compiler:compile(Path, DocRoot, Module) of
+        fun(File, _Acc) ->
+            Module = filename:rootname(filename:basename(File)),
+            case erlydtl_compiler:compile(File, Module, DocRoot) of
                 ok ->
                 ok ->
                     io:format("compile success: ~p~n",[Module]);
                     io:format("compile success: ~p~n",[Module]);
                 _ ->
                 _ ->
@@ -70,49 +69,61 @@ compile_all() ->
 %% @end 
 %% @end 
 %%--------------------------------------------------------------------        
 %%--------------------------------------------------------------------        
 compile("var" = Name) ->
 compile("var" = Name) ->
-    compile(Name, ".html");
+    compile(Name, ".html", []);
+    
+compile("var_preset" = Name) ->
+    Vars = [{preset_var1, "preset-var1"}, {preset_var2, "preset-var2"}],
+    compile(Name, ".html", Vars);
 
 
 compile("extends" = Name) ->
 compile("extends" = Name) ->
-    compile(Name, ".html"); 
+    compile(Name, ".html", []);
 
 
 compile("include" = Name) ->
 compile("include" = Name) ->
-    compile(Name, ".html"); 
+    compile(Name, ".html", []);
 
 
 compile("autoescape" = Name) ->
 compile("autoescape" = Name) ->
-    compile(Name, ".html"); 
+    compile(Name, ".html", []);
 
 
 compile("if" = Name) ->
 compile("if" = Name) ->
-    compile(Name, ".html"); 
+    compile(Name, ".html", []);
+    
+compile("if_preset" = Name) ->
+    Vars = [{var1, "something"}],
+    compile(Name, ".html", Vars);    
           
           
 compile("filters" = Name) ->
 compile("filters" = Name) ->
-    compile(Name, ".html"); 
+    compile(Name, ".html", []);
 
 
 compile("comment" = Name) ->
 compile("comment" = Name) ->
-    compile(Name, ".html");
+    compile(Name, ".html", []);
                
                
 compile("for" = Name) ->
 compile("for" = Name) ->
-    compile(Name, ".html");
+    compile(Name, ".html", []);
  
  
 compile("for_records" = Name) ->
 compile("for_records" = Name) ->
-    compile(Name, ".html");
+    compile(Name, ".html", []);
     
     
 compile("for_list" = Name) ->
 compile("for_list" = Name) ->
-    compile(Name, ".html");
-                                
+    compile(Name, ".html", []);
+ 
+compile("for_list_preset" = Name) ->
+    Vars = [{fruit_list, [["apple", "apples"], ["banana", "bananas"], ["coconut", "coconuts"]]}],
+    compile(Name, ".html", Vars);
+                                      
 compile("htmltags" = Name) ->
 compile("htmltags" = Name) ->
-    compile(Name, ".html");
-                    
-compile("csstags" = Name) ->
-    compile(Name, ".css");
+    compile(Name, ".html", []);
 
 
-compile("var_preset" = Name) ->
-    compile(Name, ".html");
      
      
 compile("for_preset" = Name) ->
 compile("for_preset" = Name) ->
-    compile(Name, ".html");     
+    Vars = [{fruit_list, ["preset-apple", "preset-banana", "preset-coconut"]}],
+    compile(Name, ".html", Vars);     
 
 
 compile("for_records_preset" = Name) ->
 compile("for_records_preset" = Name) ->
-    compile(Name, ".html");
+    Link1 = [{name, "Amazon (preset)"}, {url, "http://amazon.com"}],
+    Link2 = [{name, "Google (preset)"}, {url, "http://google.com"}],
+    Link3 = [{name, "Microsoft (preset)"}, {url, "http://microsoft.com"}],
+    Var = [{software_links, [Link1, Link2, Link3]}],
+    compile(Name, ".html", Var);
           
           
 compile(Name) ->
 compile(Name) ->
     io:format("No such template: ~p~n",[Name]).
     io:format("No such template: ~p~n",[Name]).
@@ -124,12 +135,11 @@ compile(Name) ->
 %% compiles the template to beam files
 %% compiles the template to beam files
 %% @end 
 %% @end 
 %%--------------------------------------------------------------------       
 %%--------------------------------------------------------------------       
-compile(Name, Ext) ->
+compile(Name, Ext, Vars) ->
     DocRoot = filename:join([filename:dirname(code:which(?MODULE)),"..", "demo", "templates"]),
     DocRoot = filename:join([filename:dirname(code:which(?MODULE)),"..", "demo", "templates"]),
     Module = "test_" ++ Name,
     Module = "test_" ++ Name,
-    Path = filename:join([DocRoot, Module ++ Ext]),
-    % case erlydtl_server:compile(Path, DocRoot, Module, {?MODULE, preset}) of
-    case erlydtl_compiler:compile(Path, DocRoot, Module) of
+    File = filename:join([DocRoot, Module ++ Ext]),
+    case erlydtl_compiler:compile(File, Module, DocRoot, Vars) of
         ok ->
         ok ->
             io:format("compile success: ~p~n",[Module]);
             io:format("compile success: ~p~n",[Module]);
         _ ->
         _ ->
@@ -145,19 +155,20 @@ compile(Name, Ext) ->
 render_all() ->
 render_all() ->
     render("autoescape"),
     render("autoescape"),
     render("comment"),
     render("comment"),
-    render("csstags"),
     render("extends"),
     render("extends"),
     render("filters"),
     render("filters"),
     render("for"),
     render("for"),
+    render("for_preset"),    
     render("for_list"),
     render("for_list"),
-    %render("for_preset"),
+    render("for_list_preset"),
     render("for_records"),
     render("for_records"),
-    %render("for_records_preset"),
+    render("for_records_preset"),
     render("htmltags"),
     render("htmltags"),
     render("if"),
     render("if"),
+    render("if_preset"),        
     render("include"),
     render("include"),
-    render("var").
-    %render("var_preset")
+    render("var"),
+    render("var_preset").
         
         
 
 
 %%--------------------------------------------------------------------
 %%--------------------------------------------------------------------
@@ -165,33 +176,39 @@ render_all() ->
 %% @doc renders template to a file
 %% @doc renders template to a file
 %% @end 
 %% @end 
 %%--------------------------------------------------------------------
 %%--------------------------------------------------------------------
-render("var" = Name) ->
-    render(Name, [{var1, "foostring1"}, {var2, "foostring2"}, {var_not_used, "foostring3"}]);
- 
+render("autoescape" = Name) ->
+    render(Name, [{var1, "<b>bold</b>"}]);
+  
+render("comment" = Name) ->
+    render(Name, []);
+          
+render("extends" = Name) ->
+    render(Name, [{base_var, "base-barstring"}, {test_var, "test-barstring"}]);
+    
 render("filters" = Name) ->
 render("filters" = Name) ->
     render(Name, [{'list', ["eins", "zwei", "drei"]}]);
     render(Name, [{'list', ["eins", "zwei", "drei"]}]);
 
 
 render("include" = Name) ->
 render("include" = Name) ->
     render(Name, [{var1, "foostring1"}, {var2, "foostring2"}]);
     render(Name, [{var1, "foostring1"}, {var2, "foostring2"}]);
  
  
-render("autoescape" = Name) ->
-    render(Name, [{var1, "<b>bold</b>"}]);
-
 render("if" = Name) ->
 render("if" = Name) ->
     render(Name, [{var1, "something"}]);
     render(Name, [{var1, "something"}]);
-
-render("extends" = Name) ->
-    render(Name, [{base_var, "base-barstring"}, {test_var, "test-barstring"}]);
-        
-render("comment" = Name) ->
+    
+render("if_preset" = Name) ->
     render(Name, []);
     render(Name, []);
 
 
 render("for" = Name) ->
 render("for" = Name) ->
     render(Name, [{fruit_list, ["apple", "banana", "coconut"]}]);
     render(Name, [{fruit_list, ["apple", "banana", "coconut"]}]);
+    
+render("for_preset" = Name) ->
+    render(Name, []);
             
             
 render("for_list" = Name) ->
 render("for_list" = Name) ->
     render(Name, [{fruit_list, [["apple", "apples"], ["banana", "bananas"], ["coconut", "coconuts"]]}]);
     render(Name, [{fruit_list, [["apple", "apples"], ["banana", "bananas"], ["coconut", "coconuts"]]}]);
 
 
+render("for_list_preset" = Name) ->
+    render(Name, []);
+        
 render("for_records" = Name) ->
 render("for_records" = Name) ->
     Link1 = [{name, "Amazon"}, {url, "http://amazon.com"}],
     Link1 = [{name, "Amazon"}, {url, "http://amazon.com"}],
     Link2 = [{name, "Google"}, {url, "http://google.com"}],
     Link2 = [{name, "Google"}, {url, "http://google.com"}],
@@ -200,21 +217,18 @@ render("for_records" = Name) ->
                 
                 
 render("htmltags" = Name) ->
 render("htmltags" = Name) ->
     render(Name, []);
     render(Name, []);
-    
-render("csstags" = Name) ->
-    render(Name, []);
-  
-render("var_preset" = Name) ->
-    render(Name, [{var1, "foostring1"}, {var2, "foostring2"}]);
- 
-render("for_preset" = Name) ->
-    render(Name, []);
-            
+             
 render("for_records_preset" = Name) ->
 render("for_records_preset" = Name) ->
     Link1 = [{name, "Canon"}, {url, "http://canon.com"}],
     Link1 = [{name, "Canon"}, {url, "http://canon.com"}],
     Link2 = [{name, "Leica"}, {url, "http://leica.com"}],
     Link2 = [{name, "Leica"}, {url, "http://leica.com"}],
     Link3 = [{name, "Nikon"}, {url, "http://nikon.com"}],
     Link3 = [{name, "Nikon"}, {url, "http://nikon.com"}],
     render(Name, [{photo_links, [Link1, Link2, Link3]}]);
     render(Name, [{photo_links, [Link1, Link2, Link3]}]);
+
+render("var" = Name) ->
+    render(Name, [{var1, "foostring1"}, {var2, "foostring2"}, {var_not_used, "foostring3"}]);
+
+render("var_preset" = Name) ->
+    render(Name, [{var1, "foostring1"}, {var2, "foostring2"}]);
         
         
 render(Name) ->
 render(Name) ->
     io:format("No such template: ~p~n",[Name]).  
     io:format("No such template: ~p~n",[Name]).  
@@ -242,28 +256,7 @@ render(Name, Args) ->
             io:format("render failure: ~p ~p~n",[Module, Err])
             io:format("render failure: ~p ~p~n",[Module, Err])
     end.    
     end.    
             
             
-
-%%--------------------------------------------------------------------
-%% @spec (atom()) -> proplist()
-%% @doc returns template preset variables
-%% @end 
-%%--------------------------------------------------------------------
-preset(test_extends) ->
-    [{preset_base_var, "preset-base-barstring"}];
-
-preset(test_var_preset) ->
-    [{preset_var1, "preset-var1"}, {preset_var2, "preset-var2"}];
-    
-preset(test_for_preset) ->
-    [{fruit_list, ["preset-apple", "preset-banana", "preset-coconut"]}];
-           
-preset(test_for_records_preset) ->
-    Link1 = [{name, "Amazon (preset)"}, {url, "http://amazon.com"}],
-    Link2 = [{name, "Google (preset)"}, {url, "http://google.com"}],
-    Link3 = [{name, "Microsoft (preset)"}, {url, "http://microsoft.com"}],
-    [{software_links, [Link1, Link2, Link3]}].
-
-              
+          
 %%====================================================================
 %%====================================================================
 %% Internal functions
 %% Internal functions
 %%====================================================================
 %%====================================================================

+ 111 - 43
src/erlydtl/erlydtl_compiler.erl

@@ -35,66 +35,81 @@
 -author('rsaccon@gmail.com').
 -author('rsaccon@gmail.com').
 -author('emmiller@gmail.com').
 -author('emmiller@gmail.com').
 
 
--export([compile/2, compile/3, compile/4, compile/5, parse/1, scan/1]).
+-export([compile/2, compile/3, compile/4, compile/5, compile/6, parse/1, scan/1]).
 
 
 -record(dtl_context, {
 -record(dtl_context, {
         local_scopes = [], 
         local_scopes = [], 
         block_dict = dict:new(), 
         block_dict = dict:new(), 
         auto_escape = off, 
         auto_escape = off, 
         doc_root = "", 
         doc_root = "", 
-        parse_trail = []}).
+        parse_trail = [],
+        preset_vars = []}).
 
 
 -record(ast_info, {
 -record(ast_info, {
-        dependencies = []
+        dependencies = [],
+        template_vars = [],
+        pre_render_asts = []
     }).
     }).
 
 
 compile(File, Module) ->
 compile(File, Module) ->
-    compile(File, "", Module).
+    compile(File, Module, "").
 
 
-compile(File, DocRoot, Module) ->
-    compile(File, DocRoot, Module, "render").
+compile(File, Module, DocRoot) ->
+    compile(File, Module, DocRoot, []).
 
 
-compile(File, DocRoot, Module, Function) ->
-    compile(File, DocRoot, Module, Function, "ebin").
+compile(File, Module, DocRoot, Vars) ->
+    compile(File, Module, DocRoot, Vars, "render").
+    
+compile(File, Module, DocRoot, Vars, Function) ->
+    compile(File, Module, DocRoot, Vars, Function, "ebin").
 
 
-compile(File, DocRoot, Module, Function, OutDir) ->
+compile(File, Module, DocRoot, Vars, Function, OutDir) ->   
     case parse(File) of
     case parse(File) of
         {ok, DjangoParseTree} ->
         {ok, DjangoParseTree} ->
+            OldProcessDictVal = put(erlydtl_counter, 0),
+            
             {BodyAst, BodyInfo} = body_ast(DjangoParseTree,
             {BodyAst, BodyInfo} = body_ast(DjangoParseTree,
-                #dtl_context{doc_root = DocRoot, parse_trail = [File]}),
+                #dtl_context{doc_root = DocRoot, parse_trail = [File], preset_vars = Vars}), 
+
+            Render0FunctionAst = erl_syntax:function(erl_syntax:atom(Function),
+                [erl_syntax:clause([], none, [erl_syntax:application(none, 
+                    erl_syntax:atom(Function), [erl_syntax:list([])])])]),
+
             Function2 = erl_syntax:application(none, erl_syntax:atom(Function ++ "2"),
             Function2 = erl_syntax:application(none, erl_syntax:atom(Function ++ "2"),
                 [erl_syntax:variable("Variables")]),
                 [erl_syntax:variable("Variables")]),
             ClauseOk = erl_syntax:clause([erl_syntax:variable("Val")], none,
             ClauseOk = erl_syntax:clause([erl_syntax:variable("Val")], none,
                 [erl_syntax:tuple([erl_syntax:atom(ok), erl_syntax:variable("Val")])]),     
                 [erl_syntax:tuple([erl_syntax:atom(ok), erl_syntax:variable("Val")])]),     
             ClauseCatch = erl_syntax:clause([erl_syntax:variable("Err")], none,
             ClauseCatch = erl_syntax:clause([erl_syntax:variable("Err")], none,
-                    [erl_syntax:tuple([erl_syntax:atom(error), erl_syntax:variable("Err")])]),                                            
-            Render0FunctionAst = erl_syntax:function(erl_syntax:atom(Function),
-                [erl_syntax:clause([], none, [erl_syntax:application(none, 
-                    erl_syntax:atom(Function), [erl_syntax:list([])])])]),
+                [erl_syntax:tuple([erl_syntax:atom(error), erl_syntax:variable("Err")])]),            
             Render1FunctionAst = erl_syntax:function(erl_syntax:atom(Function),
             Render1FunctionAst = erl_syntax:function(erl_syntax:atom(Function),
                 [erl_syntax:clause([erl_syntax:variable("Variables")], none, 
                 [erl_syntax:clause([erl_syntax:variable("Variables")], none, 
-                    [erl_syntax:try_expr([Function2], [ClauseOk], [ClauseCatch])])]),        
+                    [erl_syntax:try_expr([Function2], [ClauseOk], [ClauseCatch])])]),  
+                          
             SourceFunctionAst = erl_syntax:function(
             SourceFunctionAst = erl_syntax:function(
                 erl_syntax:atom(source),
                 erl_syntax:atom(source),
                     [erl_syntax:clause([], none, [erl_syntax:string(File)])]),
                     [erl_syntax:clause([], none, [erl_syntax:string(File)])]),
+                    
             DependenciesFunctionAst = erl_syntax:function(
             DependenciesFunctionAst = erl_syntax:function(
                 erl_syntax:atom(dependencies), [erl_syntax:clause([], none, 
                 erl_syntax:atom(dependencies), [erl_syntax:clause([], none, 
                     [erl_syntax:list(lists:map(fun(Dep) -> erl_syntax:string(Dep) end, 
                     [erl_syntax:list(lists:map(fun(Dep) -> erl_syntax:string(Dep) end, 
-                        BodyInfo#ast_info.dependencies))])]),                                
+                        BodyInfo#ast_info.dependencies))])]),     
+                                                   
             RenderInternalFunctionAst = erl_syntax:function(
             RenderInternalFunctionAst = erl_syntax:function(
                 erl_syntax:atom(Function ++ "2"), 
                 erl_syntax:atom(Function ++ "2"), 
                     [erl_syntax:clause([erl_syntax:variable("Variables")], none, 
                     [erl_syntax:clause([erl_syntax:variable("Variables")], none, 
-                        [BodyAst])]),           
+                        [BodyAst])]),   
+                                 
             ProplistsClauseErr = erl_syntax:clause([erl_syntax:atom(undefined)], none, 
             ProplistsClauseErr = erl_syntax:clause([erl_syntax:atom(undefined)], none, 
                 [erl_syntax:application(none, erl_syntax:atom(throw),
                 [erl_syntax:application(none, erl_syntax:atom(throw),
                     [erl_syntax:tuple([erl_syntax:atom(undefined_variable), erl_syntax:variable("Key")])])]),  
                     [erl_syntax:tuple([erl_syntax:atom(undefined_variable), erl_syntax:variable("Key")])])]),  
             ProplistsClauseOk = erl_syntax:clause([erl_syntax:variable("Val")], none, 
             ProplistsClauseOk = erl_syntax:clause([erl_syntax:variable("Val")], none, 
                 [erl_syntax:variable("Val")]),       
                 [erl_syntax:variable("Val")]),       
-            ProplistsFunctionAst = erl_syntax:function(erl_syntax:atom(proplists_get_value), 
+            ProplistsFunctionAst = erl_syntax:function(erl_syntax:atom(get_value), 
                 [erl_syntax:clause([erl_syntax:variable("Key"), erl_syntax:variable("L")], none, 
                 [erl_syntax:clause([erl_syntax:variable("Key"), erl_syntax:variable("L")], none, 
                     [erl_syntax:case_expr(erl_syntax:application(erl_syntax:atom(proplists), 
                     [erl_syntax:case_expr(erl_syntax:application(erl_syntax:atom(proplists), 
                         erl_syntax:atom(get_value), [erl_syntax:variable("Key"), erl_syntax:variable("L")]), 
                         erl_syntax:atom(get_value), [erl_syntax:variable("Key"), erl_syntax:variable("L")]), 
                             [ProplistsClauseErr, ProplistsClauseOk])])]),
                             [ProplistsClauseErr, ProplistsClauseOk])])]),
+
             ModuleAst  = erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
             ModuleAst  = erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
             ExportAst = erl_syntax:attribute(erl_syntax:atom(export),
             ExportAst = erl_syntax:attribute(erl_syntax:atom(export),
                 [erl_syntax:list([erl_syntax:arity_qualifier(erl_syntax:atom(Function), erl_syntax:integer(0)),
                 [erl_syntax:list([erl_syntax:arity_qualifier(erl_syntax:atom(Function), erl_syntax:integer(0)),
@@ -102,10 +117,15 @@ compile(File, DocRoot, Module, Function, OutDir) ->
                         erl_syntax:arity_qualifier(erl_syntax:atom(source), erl_syntax:integer(0)),
                         erl_syntax:arity_qualifier(erl_syntax:atom(source), erl_syntax:integer(0)),
                             erl_syntax:arity_qualifier(erl_syntax:atom(dependencies), erl_syntax:integer(0))])]),
                             erl_syntax:arity_qualifier(erl_syntax:atom(dependencies), erl_syntax:integer(0))])]),
             
             
-            Forms = [erl_syntax:revert(X) || X <- [ModuleAst, ExportAst, Render0FunctionAst, Render1FunctionAst,
-                  SourceFunctionAst, DependenciesFunctionAst, RenderInternalFunctionAst, ProplistsFunctionAst]],
-
-            case compile:forms(Forms, []) of  %% use: compile:forms(Forms) for more debug info
+            Forms = [erl_syntax:revert(X) || X <- [ModuleAst, ExportAst, Render0FunctionAst,
+                Render1FunctionAst, SourceFunctionAst, DependenciesFunctionAst, RenderInternalFunctionAst, 
+                    ProplistsFunctionAst | BodyInfo#ast_info.pre_render_asts]],
+                    
+            case OldProcessDictVal of
+                undefined -> erase(erlydtl_counter);
+                _ -> put(erlydtl_counter, OldProcessDictVal)
+            end,
+            case compile:forms(Forms, []) of
                 {ok, Module1, Bin} ->       
                 {ok, Module1, Bin} ->       
                     Path = filename:join([OutDir, atom_to_list(Module1) ++ ".beam"]),
                     Path = filename:join([OutDir, atom_to_list(Module1) ++ ".beam"]),
                     case file:write_file(Path, Bin) of
                     case file:write_file(Path, Bin) of
@@ -145,6 +165,7 @@ parse(File) ->
 full_path(File, DocRoot) ->
 full_path(File, DocRoot) ->
     filename:join([DocRoot, File]).
     filename:join([DocRoot, File]).
 
 
+        
 % child templates should only consist of blocks at the top level
 % child templates should only consist of blocks at the top level
 body_ast([{extends, {string_literal, _Pos, String}} | ThisParseTree], Context) ->
 body_ast([{extends, {string_literal, _Pos, String}} | ThisParseTree], Context) ->
     File = full_path(unescape_string_literal(String), Context#dtl_context.doc_root),
     File = full_path(unescape_string_literal(String), Context#dtl_context.doc_root),
@@ -165,7 +186,7 @@ body_ast([{extends, {string_literal, _Pos, String}} | ThisParseTree], Context) -
                         BlockDict, Context#dtl_context.block_dict),
                         BlockDict, Context#dtl_context.block_dict),
                     parse_trail = [File | Context#dtl_context.parse_trail]}))
                     parse_trail = [File | Context#dtl_context.parse_trail]}))
     end;
     end;
-
+    
 body_ast(DjangoParseTree, Context) ->
 body_ast(DjangoParseTree, Context) ->
     AstInfoList = lists:map(
     AstInfoList = lists:map(
         fun
         fun
@@ -188,7 +209,8 @@ body_ast(DjangoParseTree, Context) ->
             ({'number_literal', _Pos, Number}) ->
             ({'number_literal', _Pos, Number}) ->
                 string_ast(Number);
                 string_ast(Number);
             ({'variable', Variable}) ->
             ({'variable', Variable}) ->
-                {resolve_variable_ast(Variable, Context), #ast_info{}};
+                {Ast, Var} = resolve_variable_ast(Variable, Context),
+                {Ast, #ast_info{template_vars = [Var]}};
             ({'tag', {identifier, _, Name}, Args}) ->
             ({'tag', {identifier, _, Name}, Args}) ->
                 tag_ast(Name, Args, Context);
                 tag_ast(Name, Args, Context);
             ({'include', {string_literal, _, File}}) ->
             ({'include', {string_literal, _, File}}) ->
@@ -199,10 +221,10 @@ body_ast(DjangoParseTree, Context) ->
                 ifelse_ast(Variable, empty_ast(), body_ast(Contents, Context), Context);
                 ifelse_ast(Variable, empty_ast(), body_ast(Contents, Context), Context);
             ({'ifelse', {variable, Variable}, IfContents, ElseContents}) ->
             ({'ifelse', {variable, Variable}, IfContents, ElseContents}) ->
                 ifelse_ast(Variable, body_ast(IfContents, Context), 
                 ifelse_ast(Variable, body_ast(IfContents, Context), 
-                        body_ast(ElseContents, Context), Context);
+                    body_ast(ElseContents, Context), Context);
             ({'ifelse', {'not', {variable, Variable}}, IfContents, ElseContents}) ->
             ({'ifelse', {'not', {variable, Variable}}, IfContents, ElseContents}) ->
                 ifelse_ast(Variable, body_ast(ElseContents, Context), 
                 ifelse_ast(Variable, body_ast(ElseContents, Context), 
-                        body_ast(IfContents, Context), Context);
+                    body_ast(IfContents, Context), Context);
             ({'apply_filter', Variable, Filter}) ->
             ({'apply_filter', Variable, Filter}) ->
                 filter_ast(Variable, Filter, Context);
                 filter_ast(Variable, Filter, Context);
             ({'for', {'in', {identifier, _, Iterator}, {identifier, _, List}}, Contents}) ->
             ({'for', {'in', {identifier, _, Iterator}, {identifier, _, List}}, Contents}) ->
@@ -212,7 +234,30 @@ body_ast(DjangoParseTree, Context) ->
         end, DjangoParseTree),
         end, DjangoParseTree),
     {AstList, Info} = lists:mapfoldl(
     {AstList, Info} = lists:mapfoldl(
         fun({Ast, Info}, InfoAcc) -> 
         fun({Ast, Info}, InfoAcc) -> 
-                {Ast, merge_info(Info, InfoAcc)}
+                PresetVars = lists:foldl(fun
+                        (X, Acc) ->
+                            case proplists:lookup(list_to_atom(X), Context#dtl_context.preset_vars) of
+                                none ->
+                                    Acc;
+                                Val ->
+                                    [erl_syntax:abstract(Val) | Acc]
+                            end
+                    end, [], Info#ast_info.template_vars),
+                case PresetVars of
+                    [] ->
+                        {Ast, merge_info(Info, InfoAcc)};
+                    _ ->
+                        Id = get(erlydtl_counter),
+                        put(erlydtl_counter, Id + 1),
+                        Name = lists:concat([pre_render, Id]),
+                        Ast1 = erl_syntax:application(none, erl_syntax:atom(Name),
+                            [erl_syntax:list(PresetVars)]),
+                        PreRenderAst = erl_syntax:function(erl_syntax:atom(Name),
+                            [erl_syntax:clause([erl_syntax:variable("Variables")], none, [Ast])]),
+                        PreRenderAsts = Info#ast_info.pre_render_asts,
+                        Info1 = Info#ast_info{pre_render_asts = [PreRenderAst | PreRenderAsts]},     
+                        {Ast1, merge_info(Info1, InfoAcc)}
+                end
         end, #ast_info{}, AstInfoList),
         end, #ast_info{}, AstInfoList),
     {erl_syntax:list(AstList), Info}.
     {erl_syntax:list(AstList), Info}.
 
 
@@ -220,7 +265,15 @@ merge_info(Info1, Info2) ->
     #ast_info{dependencies = 
     #ast_info{dependencies = 
         lists:merge(
         lists:merge(
             lists:sort(Info1#ast_info.dependencies), 
             lists:sort(Info1#ast_info.dependencies), 
-            lists:sort(Info2#ast_info.dependencies))}.
+            lists:sort(Info2#ast_info.dependencies)),
+        template_vars = 
+            lists:merge(
+                lists:sort(Info1#ast_info.template_vars), 
+                lists:sort(Info2#ast_info.template_vars)),
+        pre_render_asts = 
+            lists:merge(
+                Info1#ast_info.pre_render_asts,
+                Info2#ast_info.pre_render_asts)}.
 
 
 with_dependency(FilePath, {Ast, Info}) ->
 with_dependency(FilePath, {Ast, Info}) ->
     {Ast, Info#ast_info{dependencies = [FilePath | Info#ast_info.dependencies]}}.
     {Ast, Info#ast_info{dependencies = [FilePath | Info#ast_info.dependencies]}}.
@@ -229,7 +282,8 @@ empty_ast() ->
     {erl_syntax:list([]), #ast_info{}}.
     {erl_syntax:list([]), #ast_info{}}.
 
 
 string_ast(String) ->
 string_ast(String) ->
-    {erl_syntax:string(String), #ast_info{}}.
+    {erl_syntax:string(String), #ast_info{}}. %% less verbose AST, good for debugging
+    % {erl_syntax:binary([erl_syntax:binary_field(erl_syntax:integer(X)) || X <- String]), #ast_info{}}.       
 
 
 include_ast(File, Context) ->
 include_ast(File, Context) ->
     FilePath = full_path(File, Context#dtl_context.doc_root),
     FilePath = full_path(File, Context#dtl_context.doc_root),
@@ -283,16 +337,25 @@ search_for_escape_filter({apply_filter, Variable, Filter}, _) ->
 search_for_escape_filter(_Variable, _Filter) ->
 search_for_escape_filter(_Variable, _Filter) ->
     off.
     off.
 
 
-resolve_variable_ast({{identifier, _, VarName}}, Context) ->
-    auto_escape(resolve_variable_name_ast(VarName, Context), Context);
-
-resolve_variable_ast({{identifier, _, VarName}, {identifier, _, AttrName}}, Context) ->
-    auto_escape(erl_syntax:application(
-            none, erl_syntax:atom(proplists_get_value),
+resolve_variable_ast(VarTuple, Context) ->
+    resolve_variable_ast(VarTuple, Context, none).
+ 
+resolve_ifvariable_ast(VarTuple, Context) ->
+    resolve_variable_ast(VarTuple, Context, erl_syntax:atom(proplists)).
+           
+resolve_variable_ast({{identifier, _, VarName}}, Context, ModuleAst) ->
+    {auto_escape(resolve_variable_name_ast(VarName, Context, ModuleAst), Context), VarName};
+
+resolve_variable_ast({{identifier, _, VarName}, {identifier, _, AttrName}}, Context, ModuleAst) ->
+    {auto_escape(erl_syntax:application(
+            ModuleAst, erl_syntax:atom(get_value),
         [erl_syntax:atom(AttrName), resolve_variable_name_ast(VarName, Context)]), 
         [erl_syntax:atom(AttrName), resolve_variable_name_ast(VarName, Context)]), 
-        Context).
-
+        Context), []}.
+                
 resolve_variable_name_ast(VarName, Context) ->
 resolve_variable_name_ast(VarName, Context) ->
+    resolve_variable_name_ast(VarName, Context, none).
+    
+resolve_variable_name_ast(VarName, Context, ModuleAst) ->
     VarValue = lists:foldl(fun(Scope, Value) ->
     VarValue = lists:foldl(fun(Scope, Value) ->
                 case Value of
                 case Value of
                     undefined ->
                     undefined ->
@@ -303,11 +366,11 @@ resolve_variable_name_ast(VarName, Context) ->
         end, undefined, Context#dtl_context.local_scopes),
         end, undefined, Context#dtl_context.local_scopes),
     case VarValue of
     case VarValue of
         undefined ->
         undefined ->
-            erl_syntax:application(none, erl_syntax:atom(proplists_get_value),
+            erl_syntax:application(ModuleAst, erl_syntax:atom(get_value),
                 [erl_syntax:atom(VarName), erl_syntax:variable("Variables")]);
                 [erl_syntax:atom(VarName), erl_syntax:variable("Variables")]);
         _ ->
         _ ->
             VarValue
             VarValue
-    end.
+    end.    
 
 
 auto_escape(Value, Context) ->
 auto_escape(Value, Context) ->
     case Context#dtl_context.auto_escape of
     case Context#dtl_context.auto_escape of
@@ -319,7 +382,10 @@ auto_escape(Value, Context) ->
     end.
     end.
 
 
 ifelse_ast(Variable, {IfContentsAst, IfContentsInfo}, {ElseContentsAst, ElseContentsInfo}, Context) ->
 ifelse_ast(Variable, {IfContentsAst, IfContentsInfo}, {ElseContentsAst, ElseContentsInfo}, Context) ->
-    {erl_syntax:case_expr(resolve_variable_ast(Variable, Context),
+    Info2 = merge_info(IfContentsInfo, ElseContentsInfo),
+    TemplateVars = Info2#ast_info.template_vars,
+    {Ast, Var} = resolve_ifvariable_ast(Variable, Context),
+    {erl_syntax:case_expr(Ast,
         [erl_syntax:clause([erl_syntax:string("")], none, 
         [erl_syntax:clause([erl_syntax:string("")], none, 
                 [ElseContentsAst]),
                 [ElseContentsAst]),
             erl_syntax:clause([erl_syntax:atom(undefined)], none,
             erl_syntax:clause([erl_syntax:atom(undefined)], none,
@@ -328,7 +394,7 @@ ifelse_ast(Variable, {IfContentsAst, IfContentsInfo}, {ElseContentsAst, ElseCont
                 [ElseContentsAst]),
                 [ElseContentsAst]),
             erl_syntax:clause([erl_syntax:underscore()], none,
             erl_syntax:clause([erl_syntax:underscore()], none,
                 [IfContentsAst])
                 [IfContentsAst])
-        ]), merge_info(IfContentsInfo, ElseContentsInfo)}.
+        ]), Info2#ast_info{template_vars = [Var | TemplateVars]}}.
 
 
 for_loop_ast(Iterator, List, Contents, Context) ->
 for_loop_ast(Iterator, List, Contents, Context) ->
     {InnerAst, Info} = body_ast(Contents, 
     {InnerAst, Info} = body_ast(Contents, 
@@ -339,7 +405,7 @@ for_loop_ast(Iterator, List, Contents, Context) ->
         [erl_syntax:fun_expr([
         [erl_syntax:fun_expr([
                     erl_syntax:clause([erl_syntax:variable("Var_" ++ Iterator)], 
                     erl_syntax:clause([erl_syntax:variable("Var_" ++ Iterator)], 
                         none, [InnerAst])]),
                         none, [InnerAst])]),
-            resolve_variable_name_ast(list_to_atom(List), Context)]), Info}.
+            resolve_variable_name_ast(list_to_atom(List), Context)]), Info#ast_info{template_vars = [List]}}.
 
 
 for_list_loop_ast(IteratorList, List, Contents, Context) ->
 for_list_loop_ast(IteratorList, List, Contents, Context) ->
     Vars = erl_syntax:list(lists:map(
     Vars = erl_syntax:list(lists:map(
@@ -354,8 +420,9 @@ for_list_loop_ast(IteratorList, List, Contents, Context) ->
     {erl_syntax:application(erl_syntax:atom(lists), erl_syntax:atom(map),
     {erl_syntax:application(erl_syntax:atom(lists), erl_syntax:atom(map),
         [erl_syntax:fun_expr([erl_syntax:clause(
         [erl_syntax:fun_expr([erl_syntax:clause(
                         [Vars], none, [InnerAst])]),
                         [Vars], none, [InnerAst])]),
-            resolve_variable_name_ast(list_to_atom(List), Context)]), Info}.
+            resolve_variable_name_ast(list_to_atom(List), Context)]), Info#ast_info{template_vars = [List]}}.
 
 
+%% TODO: implement "laod" tag to make custom tags work like in original django
 tag_ast(Name, Args, Context) ->
 tag_ast(Name, Args, Context) ->
     InterpretedArgs = lists:map(fun
     InterpretedArgs = lists:map(fun
             ({{identifier, _, Key}, {string_literal, _, Value}}) ->
             ({{identifier, _, Key}, {string_literal, _, Value}}) ->
@@ -390,3 +457,4 @@ unescape_string_literal("t" ++ Rest, Acc, slash) ->
     unescape_string_literal(Rest, ["\t" | Acc], noslash);
     unescape_string_literal(Rest, ["\t" | Acc], noslash);
 unescape_string_literal([C | Rest], Acc, slash) ->
 unescape_string_literal([C | Rest], Acc, slash) ->
     unescape_string_literal(Rest, [C | Acc], noslash).
     unescape_string_literal(Rest, [C | Acc], noslash).
+