Browse Source

monster commit: integrated Evan's changes (much improved everything)

Roberto Saccon 17 years ago
parent
commit
873b0eff6b

+ 0 - 13
demo/out/test_extends.html

@@ -1,13 +0,0 @@
-preset-base-barstring
-
-base-barstring
-
-base template
-
-replacing the base title
-
-more of base template
-
-replacing the base content - variable: test-barstring after variable 
-
-end of base template

+ 0 - 13
demo/out/test_var_preset.html

@@ -1,13 +0,0 @@
-<!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
-	preset-var1
-	foostring2
-	preset-var2
-  </body>
-</html>

+ 10 - 4
src/demo/erlydtl_demo.erl

@@ -51,7 +51,8 @@ compile_all() ->
         true,
         true,
         fun(Path, _Acc) ->
         fun(Path, _Acc) ->
             Module = filename:rootname(filename:basename(Path)),
             Module = filename:rootname(filename:basename(Path)),
-            case erlydtl_server:compile(Path, DocRoot, Module, {?MODULE, preset}) of
+            % case erlydtl_server:compile(Path, DocRoot, Module, {?MODULE, preset}) of
+            case erlydtl_compiler:compile(Path, DocRoot, Module) of
                 ok ->
                 ok ->
                     io:format("compile success: ~p~n",[Module]);
                     io:format("compile success: ~p~n",[Module]);
                 _ ->
                 _ ->
@@ -111,7 +112,8 @@ compile(Name, Ext) ->
     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]),
     Path = filename:join([DocRoot, Module ++ Ext]),
-    case erlydtl_server:compile(Path, DocRoot, Module, {?MODULE, preset}) of
+    % case erlydtl_server:compile(Path, DocRoot, Module, {?MODULE, preset}) of
+    case erlydtl_compiler:compile(Path, DocRoot, Module) of
         ok ->
         ok ->
             io:format("compile success: ~p~n",[Module]);
             io:format("compile success: ~p~n",[Module]);
         _ ->
         _ ->
@@ -235,7 +237,9 @@ render2(OutDir, Module, Ext, Arg) ->
             io:format("TRACE ~p:~p Errors: ~p~n",[?MODULE, ?LINE, Err]),
             io:format("TRACE ~p:~p Errors: ~p~n",[?MODULE, ?LINE, Err]),
             io:format("TRACE ~p:~p Warnings: ~p~n",[?MODULE, ?LINE, Warnings]);
             io:format("TRACE ~p:~p Warnings: ~p~n",[?MODULE, ?LINE, Warnings]);
         {'EXIT', Reason} -> 
         {'EXIT', Reason} -> 
-            io:format("TRACE ~p:~p ~p: render failure: ~n",[?MODULE, ?LINE, Reason])
+            io:format("TRACE ~p:~p ~p: render failure: ~n",[?MODULE, ?LINE, Reason]);
+        Val -> %% only temporarly
+            write_file(OutDir, Module, Ext, Val, [])
     end.
     end.
     
     
     
     
@@ -247,7 +251,9 @@ render2(OutDir, Module, Ext) ->
             io:format("TRACE ~p:~p Errors: ~p~n",[?MODULE, ?LINE, Err]),
             io:format("TRACE ~p:~p Errors: ~p~n",[?MODULE, ?LINE, Err]),
             io:format("TRACE ~p:~p Warnings: ~p~n",[?MODULE, ?LINE, Warnings]);
             io:format("TRACE ~p:~p Warnings: ~p~n",[?MODULE, ?LINE, Warnings]);
         {'EXIT', Reason} -> 
         {'EXIT', Reason} -> 
-            io:format("TRACE ~p:~p ~p: render failure: ~n",[?MODULE, ?LINE, Reason])
+            io:format("TRACE ~p:~p ~p: render failure: ~n",[?MODULE, ?LINE, Reason]);
+        Val -> %% only temporarly
+            write_file(OutDir, Module, Ext, Val, [])
     end.
     end.
 
 
 
 

+ 0 - 21
src/erlydtl/erlydtl.app.src

@@ -1,21 +0,0 @@
-{application, erlydtl,
- [{description, "ErlyDTL Server"},
-  {vsn, "0.1"},
-  {modules, [
-    erlydtl,
-    erlydtl_server,
-    erlydtl_app,
-    erlydtl_sup,
-    erlydtl_deps,
-    erlydtl_parser,
-    erlydtl_scanner,
-    erlydtl_tools
-  ]},
-  {registered, []},
-  {applications, [
-    kernel,
-    stdlib
-  ]},
-  {included_applications, []},
-  {env, []},
-  {mod, {erlydtl_app, []}}]}.

+ 5 - 3
src/erlydtl/erlydtl.erl

@@ -1,7 +1,8 @@
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 %%% File:      erlydtl.erl
 %%% File:      erlydtl.erl
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
-%%% @copyright 2007 Roberto Saccon
+%%% @author    Evan Miller <emmiller@gmail.com>
+%%% @copyright 2008 Roberto Saccon, Evan Miller
 %%% @doc  
 %%% @doc  
 %%% Helper module to start and stop ErlyDTL application and for 
 %%% Helper module to start and stop ErlyDTL application and for 
 %%% creating yecc-grammar based template parser
 %%% creating yecc-grammar based template parser
@@ -9,7 +10,7 @@
 %%%
 %%%
 %%% The MIT License
 %%% The MIT License
 %%%
 %%%
-%%% Copyright (c) 2007 Roberto Saccon
+%%% Copyright (c) 2008 Roberto Saccon, Evan Miller
 %%%
 %%%
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% of this software and associated documentation files (the "Software"), to deal
 %%% of this software and associated documentation files (the "Software"), to deal
@@ -29,10 +30,11 @@
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% THE SOFTWARE.
 %%% THE SOFTWARE.
 %%%
 %%%
-%%% @since 2007-11-17 by Roberto Saccon
+%%% @since 2007-11-11 by Roberto Saccon, Evan Miller
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 -module(erlydtl).
 -module(erlydtl).
 -author('rsaccon@gmail.com').
 -author('rsaccon@gmail.com').
+-author('emmiller@gmail.com').
 
 
 %% API
 %% API
 -export([start/0, stop/0, create_parser/0, reload/2, write_beam/3]).
 -export([start/0, stop/0, create_parser/0, reload/2, write_beam/3]).

+ 5 - 3
src/erlydtl/erlydtl_app.erl

@@ -1,14 +1,15 @@
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 %%% File:      erlydtl_app.erl
 %%% File:      erlydtl_app.erl
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
-%%% @copyright 2007 Roberto Saccon
+%%% @author    Evan Miller <emmiller@gmail.com>
+%%% @copyright 2008 Roberto Saccon, Evan Miller
 %%% @doc  
 %%% @doc  
 %%%
 %%%
 %%% @end  
 %%% @end  
 %%%
 %%%
 %%% The MIT License
 %%% The MIT License
 %%%
 %%%
-%%% Copyright (c) 2007 Roberto Saccon
+%%% Copyright (c) 2007 Roberto Saccon, Evan Miller
 %%%
 %%%
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% of this software and associated documentation files (the "Software"), to deal
 %%% of this software and associated documentation files (the "Software"), to deal
@@ -28,10 +29,11 @@
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% THE SOFTWARE.
 %%% THE SOFTWARE.
 %%%
 %%%
-%%% @since 2007-12-15 by Roberto Saccon
+%%% @since 2007-12-15 by Roberto Saccon, Evan Miller
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 -module(erlydtl_app).
 -module(erlydtl_app).
 -author('rsaccon@gmail.com').
 -author('rsaccon@gmail.com').
+-author('emmiller@gmail.com').
 
 
 -behaviour(application).
 -behaviour(application).
 
 

+ 5 - 3
src/erlydtl/erlydtl_base.erl

@@ -1,14 +1,15 @@
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 %%% File:      erlydtl_base.erl
 %%% File:      erlydtl_base.erl
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
-%%% @copyright 2007 Roberto Saccon
+%%% @author    Evan Miller <emmiller@gmail.com>
+%%% @copyright 2008 Roberto Saccon, Evan Miller
 %%% @doc  
 %%% @doc  
 %%% ErlyDTL AST tools (tree builder and parse transformations)
 %%% ErlyDTL AST tools (tree builder and parse transformations)
 %%% @end  
 %%% @end  
 %%%
 %%%
 %%% The MIT License
 %%% The MIT License
 %%%
 %%%
-%%% Copyright (c) 2007 Roberto Saccon
+%%% Copyright (c) 2007 Roberto Saccon, Evan Miller
 %%%
 %%%
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% of this software and associated documentation files (the "Software"), to deal
 %%% of this software and associated documentation files (the "Software"), to deal
@@ -28,10 +29,11 @@
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% THE SOFTWARE.
 %%% THE SOFTWARE.
 %%%
 %%%
-%%% @since 2007-11-17 by Roberto Saccon
+%%% @since 2007-11-17 by Roberto Saccon, Evan Miller
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 -module(erlydtl_base).
 -module(erlydtl_base).
 -author('rsaccon@gmail.com').
 -author('rsaccon@gmail.com').
+-author('emmiller@gmail.com').
 
 
 -record(dtl, {
 -record(dtl, {
     buffer = [], 
     buffer = [], 

+ 325 - 0
src/erlydtl/erlydtl_compiler.erl

@@ -0,0 +1,325 @@
+%%%-------------------------------------------------------------------
+%%% File:      erlydtl_compiler.erl
+%%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
+%%% @author    Evan Miller <emmiller@gmail.com>
+%%% @copyright 2008 Roberto Saccon, Evan Miller
+%%% @doc  
+%%% ErlyDTL template compiler
+%%% @end  
+%%%
+%%% The MIT License
+%%%
+%%% Copyright (c) 2007 Roberto Saccon, Evan Miller
+%%%
+%%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%%% of this software and associated documentation files (the "Software"), to deal
+%%% in the Software without restriction, including without limitation the rights
+%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%%% copies of the Software, and to permit persons to whom the Software is
+%%% furnished to do so, subject to the following conditions:
+%%%
+%%% The above copyright notice and this permission notice shall be included in
+%%% all copies or substantial portions of the Software.
+%%%
+%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%%% THE SOFTWARE.
+%%%
+%%% @since 2007-12-16 by Roberto Saccon, Evan Miller
+%%%-------------------------------------------------------------------
+-module(erlydtl_compiler).
+-author('emmiller@gmail.com').
+-author('emmiller@gmail.com').
+
+-export([compile/3, compile/2, compile/4, parse/1, scan/1]).
+
+-record(dtl_context, {
+	local_scopes = [], 
+	block_dict = dict:new(), 
+	auto_escape = off, 
+	doc_root = "", 
+	parse_trail = []}).
+
+compile(File, Module) ->
+    compile(File, "", Module).
+
+compile(File, DocRoot, Module) ->
+    compile(File, DocRoot, Module, "render").
+
+compile(File, DocRoot, Module, Function) ->
+    case parse(File) of
+        {ok, DjangoAst} ->
+	    RenderFunctionAst = erl_syntax:function(
+		    erl_syntax:atom(Function), 
+		    [erl_syntax:clause([erl_syntax:variable("Variables")], none, 
+			[body_ast(DjangoAst, #dtl_context{doc_root = DocRoot, parse_trail = [File]})])]),
+	    ExtensionFunctionAst = erl_syntax:function(
+		    erl_syntax:atom(file_extension),
+		    [erl_syntax:clause([], none, [erl_syntax:string(file_extension(File))])]),
+	    ModuleAst  = erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
+	    CompileAst = erl_syntax:attribute(erl_syntax:atom(compile), [erl_syntax:atom("export_all")]),
+
+	    Forms = [erl_syntax:revert(X) || X <- [ModuleAst, CompileAst, ExtensionFunctionAst, RenderFunctionAst]],
+
+	    case compile:forms(Forms) of
+	        {ok, Module1, Bin} ->
+		    case file:write_file(atom_to_list(Module1) ++ ".beam", Bin) of
+		        ok ->
+			    code:purge(Module1),
+			    case code:load_binary(Module1, atom_to_list(Module1) ++ ".erl", Bin) of
+			        {module, _} -> ok;
+				_ -> {error, "code reload failed"}
+			    end;
+			_ ->
+			    {error, "beam generation failed"}
+		    end;
+		_ ->
+		    {error, "compilation failed"}
+	    end;
+	Error ->
+	    Error
+    end.
+	    
+scan(File) ->
+    case file:read_file(File) of
+        {ok, B} ->
+	    erlydtl_scanner:scan(binary_to_list(B));
+    _ ->
+    	{error, "reading " ++ File ++ " failed "}
+    end.
+
+parse(File) ->
+    case scan(File) of
+	{ok, Tokens} ->
+	    erlydtl_parser:parse(Tokens);
+	Err ->
+	    Err
+    end.
+
+full_path(File, DocRoot) ->
+    filename:join([DocRoot, File]).
+
+file_extension(File) ->
+    lists:last(string:tokens(lists:flatten(File), ".")).
+
+% child templates should only consist of blocks at the top level
+body_ast([{extends, {string_literal, _Pos, String}} | ThisAst], Context) ->
+    File = full_path(unescape_string_literal(String), Context#dtl_context.doc_root),
+    case lists:member(File, Context#dtl_context.parse_trail) of
+        true ->
+	    {error, "Circular file inclusion!"};
+        _ ->
+	    {ok, ParentAst} = parse(File),
+	    BlockDict = lists:foldl(
+		    fun
+		    ({block, {identifier, _, Name}, Contents}, Dict) ->
+			dict:store(Name, Contents, Dict);
+		    (_, Dict) ->
+			Dict
+		    end, dict:new(), ThisAst),
+	    body_ast(ParentAst, Context#dtl_context{
+		    block_dict = 
+			dict:merge(fun(_Key, _ParentVal, ChildVal) -> ChildVal end,
+			    BlockDict, Context#dtl_context.block_dict),
+		    parse_trail = [File | Context#dtl_context.parse_trail]
+		    })
+    end;
+
+body_ast(DjangoAst, Context) ->
+    erl_syntax:list(
+    lists:map(fun
+        ({'block', {identifier, _, Name}, Contents}) ->
+	    Block = case dict:find(Name, Context#dtl_context.block_dict) of
+			{ok, ChildBlock} ->
+			    ChildBlock;
+			_ ->
+			    Contents
+		    end,
+	    body_ast(Block, Context);
+        ({'comment', _Contents}) ->
+	    erl_syntax:list([]);
+	({'autoescape', {identifier, _, OnOrOff}, Contents}) ->
+	    body_ast(Contents, Context#dtl_context{auto_escape = list_to_atom(OnOrOff)});
+	({'text', _Pos, String}) -> 
+	    erl_syntax:string(String);
+	({'string_literal', _Pos, String}) ->
+	    erl_syntax:string(unescape_string_literal(String));
+	({'number_literal', _Pos, Number}) ->
+	    erl_syntax:string(Number);
+	({'variable', Variable}) ->
+	    resolve_variable_ast(Variable, Context);
+        ({'tag', {identifier, _, Name}, Args}) ->
+	    tag_ast(Name, Args, Context);
+	({'include', {string_literal, _, File}}) ->
+	    FilePath = full_path(unescape_string_literal(File), Context#dtl_context.doc_root),
+	    {ok, IncludeAst} = parse(FilePath),
+	    body_ast(IncludeAst, 
+		    Context#dtl_context{parse_trail = 
+			[FilePath | Context#dtl_context.parse_trail]});
+	({'if', {variable, Variable}, Contents}) ->
+	    ifelse_ast(Variable, body_ast(Contents, Context),
+		erl_syntax:list([]), Context);
+	({'if', {'not', {variable, Variable}}, Contents}) ->
+	    ifelse_ast(Variable, erl_syntax:list([]),
+		    body_ast(Contents, Context), Context);
+	({'ifelse', {variable, Variable}, IfContents, ElseContents}) ->
+	    ifelse_ast(Variable, body_ast(IfContents, Context),
+		    body_ast(ElseContents, Context), Context);
+	({'ifelse', {'not', {variable, Variable}}, IfContents, ElseContents}) ->
+	    ifelse_ast(Variable, body_ast(ElseContents, Context), 
+		    body_ast(IfContents, Context), Context);
+        ({'apply_filter', Variable, Filter}) ->
+	    filter_ast(Variable, Filter, Context);
+	({'for', {'in', {identifier, _, Iterator}, {identifier, _, List}}, Contents}) ->
+	    for_loop_ast(Iterator, List, Contents, Context);
+	({'for', {'in', IteratorList, {identifier, _, List}}, Contents}) when is_list(IteratorList) ->
+	    for_list_loop_ast(IteratorList, List, Contents, Context)
+	end, DjangoAst)
+    ).
+
+filter_ast(Variable, Filter, Context) ->
+% the escape filter is special; it is always applied last, so we have to go digging for it
+
+% AutoEscape = 'did' means we (will have) decided whether to escape the current variable,
+% so don't do any more escaping
+    case search_for_escape_filter(Variable, Filter, Context) of
+        on ->
+	    erl_syntax:application(erl_syntax:atom(erlydtl_filters), erl_syntax:atom(force_escape),
+		    [filter_ast_noescape(Variable, Filter, Context#dtl_context{auto_escape = did})]);
+	_ ->
+	    filter_ast_noescape(Variable, Filter, Context#dtl_context{auto_escape = did})
+    end.
+
+filter_ast_noescape(Variable, [{identifier, _, "escape"}], Context) ->
+    body_ast([Variable], Context);
+filter_ast_noescape(Variable, [{identifier, _, Name} | Arg], Context) ->
+    erl_syntax:application(erl_syntax:atom(erlydtl_filters), erl_syntax:atom(Name), 
+	    [body_ast([Variable], Context) | case Arg of 
+		[{string_literal, _, ArgName}] ->
+		    [erl_syntax:string(unescape_string_literal(ArgName))];
+		[{number_literal, _, ArgName}] ->
+		    [erl_syntax:integer(list_to_integer(ArgName))];
+		_ ->
+		    []
+		end]).
+
+search_for_escape_filter(_, _, #dtl_context{auto_escape = on}) ->
+    on;
+search_for_escape_filter(_, _, #dtl_context{auto_escape = did}) ->
+    off;
+search_for_escape_filter(Variable, Filter, _) ->
+    search_for_escape_filter(Variable, Filter).
+
+search_for_escape_filter(_, [{identifier, _, "escape"}]) ->
+    on;
+search_for_escape_filter({apply_filter, Variable, Filter}, _) ->
+    search_for_escape_filter(Variable, Filter);
+search_for_escape_filter(_Variable, _Filter) ->
+    off.
+
+resolve_variable_ast({{identifier, _, VarName}}, Context) ->
+    resolve_variable_name_ast(VarName, Context);
+
+resolve_variable_ast({{identifier, _, VarName}, {identifier, _, AttrName}}, Context) ->
+    erl_syntax:application(erl_syntax:atom(proplists), erl_syntax:atom(get_value),
+	   [erl_syntax:atom(AttrName), resolve_variable_name_ast(VarName, Context)]).
+
+resolve_variable_name_ast(VarName, Context) ->
+    VarValue = lists:foldl(fun(Scope, Value) ->
+		case Value of
+		    undefined ->
+			proplists:get_value(list_to_atom(VarName), Scope);
+		    _ ->
+			Value
+		end
+	    end, undefined, Context#dtl_context.local_scopes),
+    VarValue1 = case VarValue of
+	undefined ->
+	    erl_syntax:application(erl_syntax:atom(proplists), erl_syntax:atom(get_value),
+		    [erl_syntax:atom(VarName), erl_syntax:variable("Variables")]);
+	_ ->
+	    VarValue
+	end,
+    case Context#dtl_context.auto_escape of
+        on ->
+	    erl_syntax:application(erl_syntax:atom(emiller_filters), erl_syntax:atom(force_escape),
+		    [VarValue1]);
+ 	_ ->
+	    VarValue1
+    end.
+
+ifelse_ast(Variable, IfContentsAst, ElseContentsAst, Context) ->
+    erl_syntax:case_expr(resolve_variable_ast(Variable, Context),
+	    [erl_syntax:clause([erl_syntax:string("")], none, 
+		[ElseContentsAst]),
+	    erl_syntax:clause([erl_syntax:atom(undefined)], none,
+		[ElseContentsAst]),
+	    erl_syntax:clause([erl_syntax:integer(0)], none,
+		[ElseContentsAst]),
+	    erl_syntax:clause([erl_syntax:underscore()], none,
+		[IfContentsAst])
+	    ]).
+
+for_loop_ast(Iterator, List, Contents, Context) ->
+    erl_syntax:application(erl_syntax:atom(lists), erl_syntax:atom(map),
+	[erl_syntax:fun_expr([
+	    erl_syntax:clause([erl_syntax:variable("Var_" ++ Iterator)], 
+	    none, [body_ast(Contents, 
+		Context#dtl_context{local_scopes = 
+		    [[{list_to_atom(Iterator), erl_syntax:variable("Var_" ++ Iterator)}] 
+			| Context#dtl_context.local_scopes]
+		})]
+	    )]),
+	resolve_variable_name_ast(list_to_atom(List), Context)]).
+
+for_list_loop_ast(IteratorList, List, Contents, Context) ->
+    erl_syntax:application(erl_syntax:atom(lists), erl_syntax:atom(map),
+	[erl_syntax:fun_expr([
+	    erl_syntax:clause([erl_syntax:list(
+		lists:map(fun({identifier, _, Iterator}) -> 
+			erl_syntax:variable("Var_" ++ Iterator) 
+		    end, IteratorList))], 
+		none, [body_ast(Contents,
+		    Context#dtl_context{local_scopes = [lists:map(fun({identifier, _, Iterator}) ->
+			{list_to_atom(Iterator), erl_syntax:variable("Var_" ++ Iterator)} 
+			end, IteratorList)
+		    | Context#dtl_context.local_scopes]})]
+		)]),
+        resolve_variable_name_ast(list_to_atom(List), Context)]).
+
+tag_ast(Name, Args, Context) ->
+    InterpretedArgs = lists:map(fun
+	    ({{identifier, _, Key}, {string_literal, _, Value}}) ->
+	        {list_to_atom(Key), erl_syntax:string(unescape_string_literal(Value))};
+	    ({{identifier, _, Key}, {variable, Value}}) ->
+	        {list_to_atom(Key), resolve_variable_ast(Value, Context)}
+	    end, Args),
+    case parse(filename:join([erlydtl_deps:get_base_dir(), "priv", "tags", Name])) of
+        {ok, TagAst} ->
+	    body_ast(TagAst, Context#dtl_context{
+		    local_scopes = [ InterpretedArgs | Context#dtl_context.local_scopes ]});
+	_ ->
+	    {error, Name, "Loading tag source failed"}
+    end.
+
+unescape_string_literal(String) ->
+    unescape_string_literal(string:strip(String, both, 34), [], noslash).
+
+unescape_string_literal([], Acc, noslash) ->
+    lists:reverse(Acc);
+unescape_string_literal([$\\ | Rest], Acc, noslash) ->
+    unescape_string_literal(Rest, Acc, slash);
+unescape_string_literal([C | Rest], Acc, noslash) ->
+    unescape_string_literal(Rest, [C | Acc], noslash);
+unescape_string_literal("n" ++ Rest, Acc, slash) ->
+    unescape_string_literal(Rest, ["\n" | Acc], noslash);
+unescape_string_literal("r" ++ Rest, Acc, slash) ->
+    unescape_string_literal(Rest, ["\r" | Acc], noslash);
+unescape_string_literal("t" ++ Rest, Acc, slash) ->
+    unescape_string_literal(Rest, ["\t" | Acc], noslash);
+unescape_string_literal([C | Rest], Acc, slash) ->
+    unescape_string_literal(Rest, [C | Acc], noslash).

+ 5 - 3
src/erlydtl/erlydtl_deps.erl

@@ -1,14 +1,15 @@
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 %%% File:      erlydtl_deps.erl
 %%% File:      erlydtl_deps.erl
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
-%%% @copyright 2007 Roberto Saccon
+%%% @author    Evan Miller <emmiller@gmail.com>
+%%% @copyright 2008 Roberto Saccon, Evan Miller
 %%% @doc  
 %%% @doc  
 %%% ErlyDTL helper module
 %%% ErlyDTL helper module
 %%% @end  
 %%% @end  
 %%%
 %%%
 %%% The MIT License
 %%% The MIT License
 %%%
 %%%
-%%% Copyright (c) 2007 Roberto Saccon
+%%% Copyright (c) 2007 Roberto Saccon, Evan Miller
 %%%
 %%%
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% of this software and associated documentation files (the "Software"), to deal
 %%% of this software and associated documentation files (the "Software"), to deal
@@ -28,10 +29,11 @@
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% THE SOFTWARE.
 %%% THE SOFTWARE.
 %%%
 %%%
-%%% @since 2007-12-16 by Roberto Saccon
+%%% @since 2007-12-16 by Roberto Saccon, Evan Miller
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 -module(erlydtl_deps).
 -module(erlydtl_deps).
 -author('rsaccon@gmail.com').
 -author('rsaccon@gmail.com').
+-author('emmiller@gmail.com').
 
 
 %% API
 %% API
 -export([get_base_dir/0, get_base_dir/1]).
 -export([get_base_dir/0, get_base_dir/1]).

+ 102 - 0
src/erlydtl/erlydtl_filters.erl

@@ -0,0 +1,102 @@
+%%%-------------------------------------------------------------------
+%%% File:      erlydtl_filters.erl
+%%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
+%%% @author    Evan Miller <emmiller@gmail.com>
+%%% @copyright 2008 Roberto Saccon, Evan Miller
+%%% @doc 
+%%% Template filters
+%%% @end  
+%%%
+%%% The MIT License
+%%%
+%%% Copyright (c) 2007 Roberto Saccon, Evan Miller
+%%%
+%%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%%% of this software and associated documentation files (the "Software"), to deal
+%%% in the Software without restriction, including without limitation the rights
+%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%%% copies of the Software, and to permit persons to whom the Software is
+%%% furnished to do so, subject to the following conditions:
+%%%
+%%% The above copyright notice and this permission notice shall be included in
+%%% all copies or substantial portions of the Software.
+%%%
+%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%%% THE SOFTWARE.
+%%%
+%%% @since 2007-11-11 by Roberto Saccon, Evan Miller
+%%%-------------------------------------------------------------------
+-module(erlydtl_filters).
+-author('rsaccon@gmail.com').
+-author('emmiller@gmail.com').
+
+-compile(export_all).
+
+capfirst(Input) ->
+    [H|T] = lists:flatten(Input),
+    [string:to_upper(H)] ++ T.
+
+center(Input, Number) ->
+    string:centre(lists:flatten(Input), Number).
+
+first([[First|_Rest]]) ->
+    [First].
+
+fix_ampersands(Input) ->
+    fix_ampersands(lists:flatten(Input), []).
+
+force_escape(Input) ->
+    escape(lists:flatten(Input), []).
+
+join([Input], Separator) ->
+    string:join(Input, Separator).
+
+last([Input]) ->
+    [lists:last(Input)].
+
+length([Input]) ->
+    integer_to_list(erlang:length(Input)).
+
+length_is([Input], Number) ->
+    lists:concat([erlang:length(Input) =:= Number]).
+
+ljust(Input, Number) ->
+    string:left(lists:flatten(Input), Number).
+
+lower(Input) ->
+    string:to_lower(lists:flatten(Input)).
+
+rjust(Input, Number) ->
+    string:right(lists:flatten(Input), Number).
+
+upper(Input) ->
+    string:to_upper(lists:flatten(Input)).
+
+% internal
+escape([], Acc) ->
+    lists:reverse(Acc);
+escape("<" ++ Rest, Acc) ->
+    escape(Rest, lists:reverse("&lt;", Acc));
+escape(">" ++ Rest, Acc) ->
+    escape(Rest, lists:reverse("&gt;", Acc));
+escape("&" ++ Rest, Acc) ->
+    escape(Rest, lists:reverse("&amp;", Acc));
+escape("\"" ++ Rest, Acc) ->
+    escape(Rest, lists:reverse("&quot;", Acc));
+escape("'" ++ Rest, Acc) ->
+    escape(Rest, lists:reverse("&#039;", Acc));
+escape([C | Rest], Acc) ->
+    escape(Rest, [C | Acc]).
+
+fix_ampersands([], Acc) ->
+    lists:reverse(Acc);
+fix_ampersands("&" ++ Rest, Acc) ->
+    fix_ampersands(Rest, lists:reverse("&amp;", Acc));
+fix_ampersands([C | Rest], Acc) ->
+    fix_ampersands(Rest, [C | Acc]).
+

+ 1064 - 138
src/erlydtl/erlydtl_parser.erl

@@ -1,52 +1,6 @@
 -module(erlydtl_parser).
 -module(erlydtl_parser).
 -export([parse/1, parse_and_scan/1, format_error/1]).
 -export([parse/1, parse_and_scan/1, format_error/1]).
--file("src/erlydtl/erlydtl_parser.yrl", 68).
-
-string({_, String}) ->
-    erl_syntax:binary([erl_syntax:binary_field(erl_syntax:integer(X)) || X <- String]).
-    %erl_syntax:string(String).  %% less verbose for debugging 
-    
-
-var({_, Line, Var}) ->
-    case string:tokens(Var, ".") of
-        [Namespace, Var1] ->
-            {var, Line, list_to_atom("A" ++ Namespace), list_to_atom(Var1)};
-        _ ->
-            {var, Line, list_to_atom("A" ++ Var)}
-    end.
-
-
-extends({_, Line, [Name]}) ->
-    %% TODO: check if string (enclosed with  "") or variable. 
-    %% for now we handle it (even not enclosed with "") as string
-    {extends, Line, string:strip(Name, both, $")}.
-
-
-block({_, Line, [Name]}, Content) ->
-    {block, Line, list_to_atom(Name), Content}.
-
-
-tag({_, Line, [TagName | Args]}) ->
-    %% TODO: check if string (enclosed with  "") or variable. 
-    %% for now we handle it (even not enclosed with "") as string
-	Args2 = lists:foldl(fun(X, Acc) ->
-	        case string:chr(X, $=) of
-				0 ->
-				    Acc;
-				Pos ->
-			        Var = list_to_atom(string:sub_string(X, 1, Pos-1)),
-			        Val = string:sub_string(X, Pos+1),
-			        Val2 = string:strip(Val, both, $"),
-					[{Var, Val2}| Acc]
-			end
-		end,
-    	[],
-    	Args),
-    {tag, Line, TagName, Args2}.
-
 
 
-for({_, Line, [Iterator, _, Var]}, Content) ->
-    {for, Line, list_to_atom("A" ++ Iterator), list_to_atom("A" ++ Var), Content}.
 -file("/Users/rsaccon/R11B/erlang/lib/parsetools-1.4.1.1/include/yeccpre.hrl", 0).
 -file("/Users/rsaccon/R11B/erlang/lib/parsetools-1.4.1.1/include/yeccpre.hrl", 0).
 %% ``The contents of this file are subject to the Erlang Public License,
 %% ``The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -140,25 +94,19 @@ yecctoken2string(Other) ->
 
 
 
 
 
 
--file("src/erlydtl/erlydtl_parser.erl", 143).
+-file("src/erlydtl/erlydtl_parser.erl", 97).
 
 
 yeccpars2(0, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
 yeccpars2(0, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
  __NewStack = yeccpars2_0_(__Stack),
  __NewStack = yeccpars2_0_(__Stack),
  yeccpars2(1, __Cat, [0 | __Ss], __NewStack, __T, __Ts, __Tzr);
  yeccpars2(1, __Cat, [0 | __Ss], __NewStack, __T, __Ts, __Tzr);
 yeccpars2(1, '$end', _, __Stack, _, _, _) ->
 yeccpars2(1, '$end', _, __Stack, _, _, _) ->
  {ok, hd(__Stack)};
  {ok, hd(__Stack)};
-yeccpars2(1, block, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 3, [1 | __Ss], [__T | __Stack]);
-yeccpars2(1, extends, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 4, [1 | __Ss], [__T | __Stack]);
-yeccpars2(1, for, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 5, [1 | __Ss], [__T | __Stack]);
-yeccpars2(1, string, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 6, [1 | __Ss], [__T | __Stack]);
-yeccpars2(1, tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 7, [1 | __Ss], [__T | __Stack]);
-yeccpars2(1, var, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 8, [1 | __Ss], [__T | __Stack]);
+yeccpars2(1, open_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 16, [1 | __Ss], [__T | __Stack]);
+yeccpars2(1, open_var, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 17, [1 | __Ss], [__T | __Stack]);
+yeccpars2(1, text, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 18, [1 | __Ss], [__T | __Stack]);
 yeccpars2(1, _, _, _, __T, _, _) ->
 yeccpars2(1, _, _, _, __T, _, _) ->
  yeccerror(__T);
  yeccerror(__T);
 yeccpars2(2, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
 yeccpars2(2, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
@@ -167,149 +115,1127 @@ yeccpars2(2, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
  yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
  yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
 yeccpars2(3, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
 yeccpars2(3, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
  __NewStack = yeccpars2_3_(__Stack),
  __NewStack = yeccpars2_3_(__Stack),
- yeccpars2(11, __Cat, [3 | __Ss], __NewStack, __T, __Ts, __Tzr);
+ __Nss = lists:nthtail(1, __Ss),
+ yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
 yeccpars2(4, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
 yeccpars2(4, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
  __NewStack = yeccpars2_4_(__Stack),
  __NewStack = yeccpars2_4_(__Stack),
- yeccpars2(yeccgoto('Element', hd(__Ss)), __Cat, __Ss, __NewStack, __T, __Ts, __Tzr);
+ yeccpars2(88, __Cat, [4 | __Ss], __NewStack, __T, __Ts, __Tzr);
 yeccpars2(5, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
 yeccpars2(5, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
  __NewStack = yeccpars2_5_(__Stack),
  __NewStack = yeccpars2_5_(__Stack),
- yeccpars2(9, __Cat, [5 | __Ss], __NewStack, __T, __Ts, __Tzr);
+ __Nss = lists:nthtail(1, __Ss),
+ yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
 yeccpars2(6, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
 yeccpars2(6, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
  __NewStack = yeccpars2_6_(__Stack),
  __NewStack = yeccpars2_6_(__Stack),
- yeccpars2(yeccgoto('Element', hd(__Ss)), __Cat, __Ss, __NewStack, __T, __Ts, __Tzr);
+ yeccpars2(83, __Cat, [6 | __Ss], __NewStack, __T, __Ts, __Tzr);
 yeccpars2(7, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
 yeccpars2(7, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
  __NewStack = yeccpars2_7_(__Stack),
  __NewStack = yeccpars2_7_(__Stack),
- yeccpars2(yeccgoto('Element', hd(__Ss)), __Cat, __Ss, __NewStack, __T, __Ts, __Tzr);
+ __Nss = lists:nthtail(1, __Ss),
+ yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
 yeccpars2(8, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
 yeccpars2(8, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
  __NewStack = yeccpars2_8_(__Stack),
  __NewStack = yeccpars2_8_(__Stack),
- yeccpars2(yeccgoto('Element', hd(__Ss)), __Cat, __Ss, __NewStack, __T, __Ts, __Tzr);
-yeccpars2(9, block, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 3, [9 | __Ss], [__T | __Stack]);
-yeccpars2(9, endfor, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 10, [9 | __Ss], [__T | __Stack]);
-yeccpars2(9, extends, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 4, [9 | __Ss], [__T | __Stack]);
-yeccpars2(9, for, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 5, [9 | __Ss], [__T | __Stack]);
-yeccpars2(9, string, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 6, [9 | __Ss], [__T | __Stack]);
-yeccpars2(9, tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 7, [9 | __Ss], [__T | __Stack]);
-yeccpars2(9, var, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 8, [9 | __Ss], [__T | __Stack]);
-yeccpars2(9, _, _, _, __T, _, _) ->
- yeccerror(__T);
+ __Nss = lists:nthtail(1, __Ss),
+ yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(9, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_9_(__Stack),
+ __Nss = lists:nthtail(1, __Ss),
+ yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
 yeccpars2(10, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
 yeccpars2(10, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
  __NewStack = yeccpars2_10_(__Stack),
  __NewStack = yeccpars2_10_(__Stack),
- __Nss = lists:nthtail(2, __Ss),
- yeccpars2(yeccgoto('Element', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
-yeccpars2(11, block, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 3, [11 | __Ss], [__T | __Stack]);
-yeccpars2(11, endblock, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 12, [11 | __Ss], [__T | __Stack]);
-yeccpars2(11, extends, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 4, [11 | __Ss], [__T | __Stack]);
-yeccpars2(11, for, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 5, [11 | __Ss], [__T | __Stack]);
-yeccpars2(11, string, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 6, [11 | __Ss], [__T | __Stack]);
-yeccpars2(11, tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 7, [11 | __Ss], [__T | __Stack]);
-yeccpars2(11, var, __Ss, __Stack, __T, __Ts, __Tzr) ->
- yeccpars1(__Ts, __Tzr, 8, [11 | __Ss], [__T | __Stack]);
-yeccpars2(11, _, _, _, __T, _, _) ->
- yeccerror(__T);
+ yeccpars2(78, __Cat, [10 | __Ss], __NewStack, __T, __Ts, __Tzr);
+yeccpars2(11, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_11_(__Stack),
+ __Nss = lists:nthtail(1, __Ss),
+ yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
 yeccpars2(12, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
 yeccpars2(12, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
  __NewStack = yeccpars2_12_(__Stack),
  __NewStack = yeccpars2_12_(__Stack),
+ yeccpars2(73, __Cat, [12 | __Ss], __NewStack, __T, __Ts, __Tzr);
+yeccpars2(13, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_13_(__Stack),
+ __Nss = lists:nthtail(1, __Ss),
+ yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(14, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_14_(__Stack),
+ yeccpars2(68, __Cat, [14 | __Ss], __NewStack, __T, __Ts, __Tzr);
+yeccpars2(15, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_15_(__Stack),
+ __Nss = lists:nthtail(1, __Ss),
+ yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(16, autoescape_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 33, [16 | __Ss], [__T | __Stack]);
+yeccpars2(16, block_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 34, [16 | __Ss], [__T | __Stack]);
+yeccpars2(16, comment_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 35, [16 | __Ss], [__T | __Stack]);
+yeccpars2(16, extends_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 36, [16 | __Ss], [__T | __Stack]);
+yeccpars2(16, for_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 37, [16 | __Ss], [__T | __Stack]);
+yeccpars2(16, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 38, [16 | __Ss], [__T | __Stack]);
+yeccpars2(16, if_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 39, [16 | __Ss], [__T | __Stack]);
+yeccpars2(16, include_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 40, [16 | __Ss], [__T | __Stack]);
+yeccpars2(16, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(17, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 20, [17 | __Ss], [__T | __Stack]);
+yeccpars2(17, number_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 21, [17 | __Ss], [__T | __Stack]);
+yeccpars2(17, string_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 22, [17 | __Ss], [__T | __Stack]);
+yeccpars2(17, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(18, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_18_(__Stack),
+ __Nss = lists:nthtail(1, __Ss),
+ yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(19, close_var, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 25, [19 | __Ss], [__T | __Stack]);
+yeccpars2(19, pipe, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 26, [19 | __Ss], [__T | __Stack]);
+yeccpars2(19, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(20, dot, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 23, [20 | __Ss], [__T | __Stack]);
+yeccpars2(20, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_20_(__Stack),
+ yeccpars2(yeccgoto('Variable', hd(__Ss)), __Cat, __Ss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(21, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars2(yeccgoto('Variable', hd(__Ss)), __Cat, __Ss, __Stack, __T, __Ts, __Tzr);
+yeccpars2(22, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars2(yeccgoto('Variable', hd(__Ss)), __Cat, __Ss, __Stack, __T, __Ts, __Tzr);
+yeccpars2(23, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 24, [23 | __Ss], [__T | __Stack]);
+yeccpars2(23, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(24, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_24_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('Variable', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(25, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_25_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('VariableBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(26, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 28, [26 | __Ss], [__T | __Stack]);
+yeccpars2(26, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(27, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_27_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('Variable', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(28, colon, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 29, [28 | __Ss], [__T | __Stack]);
+yeccpars2(28, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_28_(__Stack),
+ yeccpars2(yeccgoto('Filter', hd(__Ss)), __Cat, __Ss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(29, number_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 31, [29 | __Ss], [__T | __Stack]);
+yeccpars2(29, string_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 32, [29 | __Ss], [__T | __Stack]);
+yeccpars2(29, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(30, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_30_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('Filter', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(31, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars2(yeccgoto('Literal', hd(__Ss)), __Cat, __Ss, __Stack, __T, __Ts, __Tzr);
+yeccpars2(32, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars2(yeccgoto('Literal', hd(__Ss)), __Cat, __Ss, __Stack, __T, __Ts, __Tzr);
+yeccpars2(33, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 66, [33 | __Ss], [__T | __Stack]);
+yeccpars2(33, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(34, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 64, [34 | __Ss], [__T | __Stack]);
+yeccpars2(34, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(35, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 63, [35 | __Ss], [__T | __Stack]);
+yeccpars2(35, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(36, string_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 61, [36 | __Ss], [__T | __Stack]);
+yeccpars2(36, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(37, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 55, [37 | __Ss], [__T | __Stack]);
+yeccpars2(37, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(38, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_38_(__Stack),
+ yeccpars2(48, __Cat, [38 | __Ss], __NewStack, __T, __Ts, __Tzr);
+yeccpars2(39, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 20, [39 | __Ss], [__T | __Stack]);
+yeccpars2(39, not_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 45, [39 | __Ss], [__T | __Stack]);
+yeccpars2(39, number_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 21, [39 | __Ss], [__T | __Stack]);
+yeccpars2(39, string_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 22, [39 | __Ss], [__T | __Stack]);
+yeccpars2(39, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(40, string_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 41, [40 | __Ss], [__T | __Stack]);
+yeccpars2(40, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(41, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 42, [41 | __Ss], [__T | __Stack]);
+yeccpars2(41, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(42, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_42_(__Stack),
+ __Nss = lists:nthtail(3, __Ss),
+ yeccpars2(yeccgoto('IncludeTag', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(43, pipe, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 26, [43 | __Ss], [__T | __Stack]);
+yeccpars2(43, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars2(yeccgoto('IfExpression', hd(__Ss)), __Cat, __Ss, __Stack, __T, __Ts, __Tzr);
+yeccpars2(44, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 47, [44 | __Ss], [__T | __Stack]);
+yeccpars2(44, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(45, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 20, [45 | __Ss], [__T | __Stack]);
+yeccpars2(45, not_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 45, [45 | __Ss], [__T | __Stack]);
+yeccpars2(45, number_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 21, [45 | __Ss], [__T | __Stack]);
+yeccpars2(45, string_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 22, [45 | __Ss], [__T | __Stack]);
+yeccpars2(45, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(46, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_46_(__Stack),
+ __Nss = lists:nthtail(1, __Ss),
+ yeccpars2(yeccgoto('IfExpression', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(47, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_47_(__Stack),
+ __Nss = lists:nthtail(3, __Ss),
+ yeccpars2(yeccgoto('IfBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(48, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 49, [48 | __Ss], [__T | __Stack]);
+yeccpars2(48, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 50, [48 | __Ss], [__T | __Stack]);
+yeccpars2(48, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(49, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_49_(__Stack),
+ __Nss = lists:nthtail(3, __Ss),
+ yeccpars2(yeccgoto('CustomTag', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(50, equal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 51, [50 | __Ss], [__T | __Stack]);
+yeccpars2(50, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(51, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 20, [51 | __Ss], [__T | __Stack]);
+yeccpars2(51, number_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 21, [51 | __Ss], [__T | __Stack]);
+yeccpars2(51, string_literal, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 22, [51 | __Ss], [__T | __Stack]);
+yeccpars2(51, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(52, pipe, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 26, [52 | __Ss], [__T | __Stack]);
+yeccpars2(52, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_52_(__Stack),
+ __Nss = lists:nthtail(3, __Ss),
+ yeccpars2(yeccgoto('Args', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(53, comma, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 57, [53 | __Ss], [__T | __Stack]);
+yeccpars2(53, in_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 58, [53 | __Ss], [__T | __Stack]);
+yeccpars2(53, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(54, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 56, [54 | __Ss], [__T | __Stack]);
+yeccpars2(54, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(55, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars2(yeccgoto('ForExpression', hd(__Ss)), close_tag, __Ss, __Stack, __T, __Ts, __Tzr);
+yeccpars2(55, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars2(yeccgoto('ForGroup', hd(__Ss)), __Cat, __Ss, __Stack, __T, __Ts, __Tzr);
+yeccpars2(56, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_56_(__Stack),
+ __Nss = lists:nthtail(3, __Ss),
+ yeccpars2(yeccgoto('ForBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(57, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 60, [57 | __Ss], [__T | __Stack]);
+yeccpars2(57, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(58, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 59, [58 | __Ss], [__T | __Stack]);
+yeccpars2(58, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(59, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_59_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('ForExpression', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(60, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_60_(__Stack),
  __Nss = lists:nthtail(2, __Ss),
  __Nss = lists:nthtail(2, __Ss),
- yeccpars2(yeccgoto('Element', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+ yeccpars2(yeccgoto('ForGroup', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(61, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 62, [61 | __Ss], [__T | __Stack]);
+yeccpars2(61, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(62, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_62_(__Stack),
+ __Nss = lists:nthtail(3, __Ss),
+ yeccpars2(yeccgoto('ExtendsTag', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(63, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_63_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('CommentBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(64, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 65, [64 | __Ss], [__T | __Stack]);
+yeccpars2(64, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(65, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_65_(__Stack),
+ __Nss = lists:nthtail(3, __Ss),
+ yeccpars2(yeccgoto('BlockBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(66, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 67, [66 | __Ss], [__T | __Stack]);
+yeccpars2(66, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(67, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_67_(__Stack),
+ __Nss = lists:nthtail(3, __Ss),
+ yeccpars2(yeccgoto('AutoEscapeBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(68, open_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 70, [68 | __Ss], [__T | __Stack]);
+yeccpars2(68, open_var, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 17, [68 | __Ss], [__T | __Stack]);
+yeccpars2(68, text, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 18, [68 | __Ss], [__T | __Stack]);
+yeccpars2(68, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(69, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_69_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('AutoEscapeBlock', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(70, autoescape_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 33, [70 | __Ss], [__T | __Stack]);
+yeccpars2(70, block_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 34, [70 | __Ss], [__T | __Stack]);
+yeccpars2(70, comment_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 35, [70 | __Ss], [__T | __Stack]);
+yeccpars2(70, endautoescape_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 71, [70 | __Ss], [__T | __Stack]);
+yeccpars2(70, extends_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 36, [70 | __Ss], [__T | __Stack]);
+yeccpars2(70, for_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 37, [70 | __Ss], [__T | __Stack]);
+yeccpars2(70, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 38, [70 | __Ss], [__T | __Stack]);
+yeccpars2(70, if_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 39, [70 | __Ss], [__T | __Stack]);
+yeccpars2(70, include_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 40, [70 | __Ss], [__T | __Stack]);
+yeccpars2(70, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(71, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 72, [71 | __Ss], [__T | __Stack]);
+yeccpars2(71, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(72, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_72_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('EndAutoEscapeBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(73, open_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 75, [73 | __Ss], [__T | __Stack]);
+yeccpars2(73, open_var, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 17, [73 | __Ss], [__T | __Stack]);
+yeccpars2(73, text, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 18, [73 | __Ss], [__T | __Stack]);
+yeccpars2(73, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(74, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_74_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('BlockBlock', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(75, autoescape_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 33, [75 | __Ss], [__T | __Stack]);
+yeccpars2(75, block_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 34, [75 | __Ss], [__T | __Stack]);
+yeccpars2(75, comment_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 35, [75 | __Ss], [__T | __Stack]);
+yeccpars2(75, endblock_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 76, [75 | __Ss], [__T | __Stack]);
+yeccpars2(75, extends_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 36, [75 | __Ss], [__T | __Stack]);
+yeccpars2(75, for_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 37, [75 | __Ss], [__T | __Stack]);
+yeccpars2(75, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 38, [75 | __Ss], [__T | __Stack]);
+yeccpars2(75, if_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 39, [75 | __Ss], [__T | __Stack]);
+yeccpars2(75, include_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 40, [75 | __Ss], [__T | __Stack]);
+yeccpars2(75, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(76, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 77, [76 | __Ss], [__T | __Stack]);
+yeccpars2(76, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(77, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_77_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('EndBlockBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(78, open_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 80, [78 | __Ss], [__T | __Stack]);
+yeccpars2(78, open_var, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 17, [78 | __Ss], [__T | __Stack]);
+yeccpars2(78, text, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 18, [78 | __Ss], [__T | __Stack]);
+yeccpars2(78, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(79, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_79_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('CommentBlock', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(80, autoescape_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 33, [80 | __Ss], [__T | __Stack]);
+yeccpars2(80, block_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 34, [80 | __Ss], [__T | __Stack]);
+yeccpars2(80, comment_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 35, [80 | __Ss], [__T | __Stack]);
+yeccpars2(80, endcomment_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 81, [80 | __Ss], [__T | __Stack]);
+yeccpars2(80, extends_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 36, [80 | __Ss], [__T | __Stack]);
+yeccpars2(80, for_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 37, [80 | __Ss], [__T | __Stack]);
+yeccpars2(80, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 38, [80 | __Ss], [__T | __Stack]);
+yeccpars2(80, if_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 39, [80 | __Ss], [__T | __Stack]);
+yeccpars2(80, include_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 40, [80 | __Ss], [__T | __Stack]);
+yeccpars2(80, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(81, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 82, [81 | __Ss], [__T | __Stack]);
+yeccpars2(81, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(82, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_82_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('EndCommentBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(83, open_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 85, [83 | __Ss], [__T | __Stack]);
+yeccpars2(83, open_var, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 17, [83 | __Ss], [__T | __Stack]);
+yeccpars2(83, text, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 18, [83 | __Ss], [__T | __Stack]);
+yeccpars2(83, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(84, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_84_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('ForBlock', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(85, autoescape_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 33, [85 | __Ss], [__T | __Stack]);
+yeccpars2(85, block_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 34, [85 | __Ss], [__T | __Stack]);
+yeccpars2(85, comment_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 35, [85 | __Ss], [__T | __Stack]);
+yeccpars2(85, endfor_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 86, [85 | __Ss], [__T | __Stack]);
+yeccpars2(85, extends_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 36, [85 | __Ss], [__T | __Stack]);
+yeccpars2(85, for_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 37, [85 | __Ss], [__T | __Stack]);
+yeccpars2(85, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 38, [85 | __Ss], [__T | __Stack]);
+yeccpars2(85, if_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 39, [85 | __Ss], [__T | __Stack]);
+yeccpars2(85, include_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 40, [85 | __Ss], [__T | __Stack]);
+yeccpars2(85, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(86, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 87, [86 | __Ss], [__T | __Stack]);
+yeccpars2(86, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(87, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_87_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('EndForBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(88, open_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 91, [88 | __Ss], [__T | __Stack]);
+yeccpars2(88, open_var, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 17, [88 | __Ss], [__T | __Stack]);
+yeccpars2(88, text, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 18, [88 | __Ss], [__T | __Stack]);
+yeccpars2(88, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(89, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_89_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('IfBlock', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(90, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_90_(__Stack),
+ yeccpars2(96, __Cat, [90 | __Ss], __NewStack, __T, __Ts, __Tzr);
+yeccpars2(91, autoescape_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 33, [91 | __Ss], [__T | __Stack]);
+yeccpars2(91, block_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 34, [91 | __Ss], [__T | __Stack]);
+yeccpars2(91, comment_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 35, [91 | __Ss], [__T | __Stack]);
+yeccpars2(91, else_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 92, [91 | __Ss], [__T | __Stack]);
+yeccpars2(91, endif_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 93, [91 | __Ss], [__T | __Stack]);
+yeccpars2(91, extends_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 36, [91 | __Ss], [__T | __Stack]);
+yeccpars2(91, for_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 37, [91 | __Ss], [__T | __Stack]);
+yeccpars2(91, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 38, [91 | __Ss], [__T | __Stack]);
+yeccpars2(91, if_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 39, [91 | __Ss], [__T | __Stack]);
+yeccpars2(91, include_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 40, [91 | __Ss], [__T | __Stack]);
+yeccpars2(91, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(92, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 95, [92 | __Ss], [__T | __Stack]);
+yeccpars2(92, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(93, close_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 94, [93 | __Ss], [__T | __Stack]);
+yeccpars2(93, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(94, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_94_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('EndIfBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(95, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_95_(__Stack),
+ __Nss = lists:nthtail(2, __Ss),
+ yeccpars2(yeccgoto('ElseBraced', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(96, open_tag, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 98, [96 | __Ss], [__T | __Stack]);
+yeccpars2(96, open_var, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 17, [96 | __Ss], [__T | __Stack]);
+yeccpars2(96, text, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 18, [96 | __Ss], [__T | __Stack]);
+yeccpars2(96, _, _, _, __T, _, _) ->
+ yeccerror(__T);
+yeccpars2(97, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ __NewStack = yeccpars2_97_(__Stack),
+ __Nss = lists:nthtail(4, __Ss),
+ yeccpars2(yeccgoto('IfBlock', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr);
+yeccpars2(98, autoescape_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 33, [98 | __Ss], [__T | __Stack]);
+yeccpars2(98, block_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 34, [98 | __Ss], [__T | __Stack]);
+yeccpars2(98, comment_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 35, [98 | __Ss], [__T | __Stack]);
+yeccpars2(98, endif_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 93, [98 | __Ss], [__T | __Stack]);
+yeccpars2(98, extends_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 36, [98 | __Ss], [__T | __Stack]);
+yeccpars2(98, for_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 37, [98 | __Ss], [__T | __Stack]);
+yeccpars2(98, identifier, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 38, [98 | __Ss], [__T | __Stack]);
+yeccpars2(98, if_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 39, [98 | __Ss], [__T | __Stack]);
+yeccpars2(98, include_keyword, __Ss, __Stack, __T, __Ts, __Tzr) ->
+ yeccpars1(__Ts, __Tzr, 40, [98 | __Ss], [__T | __Stack]);
+yeccpars2(98, _, _, _, __T, _, _) ->
+ yeccerror(__T);
 yeccpars2(__Other, _, _, _, _, _, _) ->
 yeccpars2(__Other, _, _, _, _, _, _) ->
  erlang:error({yecc_bug,"1.1",{missing_state_in_action_table, __Other}}).
  erlang:error({yecc_bug,"1.1",{missing_state_in_action_table, __Other}}).
 
 
-yeccgoto('Element', 1) ->
+yeccgoto('Args', 38) ->
+ 48;
+yeccgoto('AutoEscapeBlock', 1) ->
+ 15;
+yeccgoto('AutoEscapeBlock', 68) ->
+ 15;
+yeccgoto('AutoEscapeBlock', 73) ->
+ 15;
+yeccgoto('AutoEscapeBlock', 78) ->
+ 15;
+yeccgoto('AutoEscapeBlock', 83) ->
+ 15;
+yeccgoto('AutoEscapeBlock', 88) ->
+ 15;
+yeccgoto('AutoEscapeBlock', 96) ->
+ 15;
+yeccgoto('AutoEscapeBraced', 1) ->
+ 14;
+yeccgoto('AutoEscapeBraced', 68) ->
+ 14;
+yeccgoto('AutoEscapeBraced', 73) ->
+ 14;
+yeccgoto('AutoEscapeBraced', 78) ->
+ 14;
+yeccgoto('AutoEscapeBraced', 83) ->
+ 14;
+yeccgoto('AutoEscapeBraced', 88) ->
+ 14;
+yeccgoto('AutoEscapeBraced', 96) ->
+ 14;
+yeccgoto('BlockBlock', 1) ->
+ 13;
+yeccgoto('BlockBlock', 68) ->
+ 13;
+yeccgoto('BlockBlock', 73) ->
+ 13;
+yeccgoto('BlockBlock', 78) ->
+ 13;
+yeccgoto('BlockBlock', 83) ->
+ 13;
+yeccgoto('BlockBlock', 88) ->
+ 13;
+yeccgoto('BlockBlock', 96) ->
+ 13;
+yeccgoto('BlockBraced', 1) ->
+ 12;
+yeccgoto('BlockBraced', 68) ->
+ 12;
+yeccgoto('BlockBraced', 73) ->
+ 12;
+yeccgoto('BlockBraced', 78) ->
+ 12;
+yeccgoto('BlockBraced', 83) ->
+ 12;
+yeccgoto('BlockBraced', 88) ->
+ 12;
+yeccgoto('BlockBraced', 96) ->
+ 12;
+yeccgoto('CommentBlock', 1) ->
+ 11;
+yeccgoto('CommentBlock', 68) ->
+ 11;
+yeccgoto('CommentBlock', 73) ->
+ 11;
+yeccgoto('CommentBlock', 78) ->
+ 11;
+yeccgoto('CommentBlock', 83) ->
+ 11;
+yeccgoto('CommentBlock', 88) ->
+ 11;
+yeccgoto('CommentBlock', 96) ->
+ 11;
+yeccgoto('CommentBraced', 1) ->
+ 10;
+yeccgoto('CommentBraced', 68) ->
+ 10;
+yeccgoto('CommentBraced', 73) ->
+ 10;
+yeccgoto('CommentBraced', 78) ->
+ 10;
+yeccgoto('CommentBraced', 83) ->
+ 10;
+yeccgoto('CommentBraced', 88) ->
+ 10;
+yeccgoto('CommentBraced', 96) ->
+ 10;
+yeccgoto('CustomTag', 1) ->
+ 9;
+yeccgoto('CustomTag', 68) ->
+ 9;
+yeccgoto('CustomTag', 73) ->
+ 9;
+yeccgoto('CustomTag', 78) ->
+ 9;
+yeccgoto('CustomTag', 83) ->
+ 9;
+yeccgoto('CustomTag', 88) ->
+ 9;
+yeccgoto('CustomTag', 96) ->
+ 9;
+yeccgoto('Elements', 0) ->
+ 1;
+yeccgoto('Elements', 4) ->
+ 88;
+yeccgoto('Elements', 6) ->
+ 83;
+yeccgoto('Elements', 10) ->
+ 78;
+yeccgoto('Elements', 12) ->
+ 73;
+yeccgoto('Elements', 14) ->
+ 68;
+yeccgoto('Elements', 90) ->
+ 96;
+yeccgoto('ElseBraced', 88) ->
+ 90;
+yeccgoto('EndAutoEscapeBraced', 68) ->
+ 69;
+yeccgoto('EndBlockBraced', 73) ->
+ 74;
+yeccgoto('EndCommentBraced', 78) ->
+ 79;
+yeccgoto('EndForBraced', 83) ->
+ 84;
+yeccgoto('EndIfBraced', 88) ->
+ 89;
+yeccgoto('EndIfBraced', 96) ->
+ 97;
+yeccgoto('ExtendsTag', 1) ->
+ 8;
+yeccgoto('ExtendsTag', 68) ->
+ 8;
+yeccgoto('ExtendsTag', 73) ->
+ 8;
+yeccgoto('ExtendsTag', 78) ->
+ 8;
+yeccgoto('ExtendsTag', 83) ->
+ 8;
+yeccgoto('ExtendsTag', 88) ->
+ 8;
+yeccgoto('ExtendsTag', 96) ->
+ 8;
+yeccgoto('Filter', 26) ->
+ 27;
+yeccgoto('ForBlock', 1) ->
+ 7;
+yeccgoto('ForBlock', 68) ->
+ 7;
+yeccgoto('ForBlock', 73) ->
+ 7;
+yeccgoto('ForBlock', 78) ->
+ 7;
+yeccgoto('ForBlock', 83) ->
+ 7;
+yeccgoto('ForBlock', 88) ->
+ 7;
+yeccgoto('ForBlock', 96) ->
+ 7;
+yeccgoto('ForBraced', 1) ->
+ 6;
+yeccgoto('ForBraced', 68) ->
+ 6;
+yeccgoto('ForBraced', 73) ->
+ 6;
+yeccgoto('ForBraced', 78) ->
+ 6;
+yeccgoto('ForBraced', 83) ->
+ 6;
+yeccgoto('ForBraced', 88) ->
+ 6;
+yeccgoto('ForBraced', 96) ->
+ 6;
+yeccgoto('ForExpression', 37) ->
+ 54;
+yeccgoto('ForGroup', 37) ->
+ 53;
+yeccgoto('IfBlock', 1) ->
+ 5;
+yeccgoto('IfBlock', 68) ->
+ 5;
+yeccgoto('IfBlock', 73) ->
+ 5;
+yeccgoto('IfBlock', 78) ->
+ 5;
+yeccgoto('IfBlock', 83) ->
+ 5;
+yeccgoto('IfBlock', 88) ->
+ 5;
+yeccgoto('IfBlock', 96) ->
+ 5;
+yeccgoto('IfBraced', 1) ->
+ 4;
+yeccgoto('IfBraced', 68) ->
+ 4;
+yeccgoto('IfBraced', 73) ->
+ 4;
+yeccgoto('IfBraced', 78) ->
+ 4;
+yeccgoto('IfBraced', 83) ->
+ 4;
+yeccgoto('IfBraced', 88) ->
+ 4;
+yeccgoto('IfBraced', 96) ->
+ 4;
+yeccgoto('IfExpression', 39) ->
+ 44;
+yeccgoto('IfExpression', 45) ->
+ 46;
+yeccgoto('IncludeTag', 1) ->
+ 3;
+yeccgoto('IncludeTag', 68) ->
+ 3;
+yeccgoto('IncludeTag', 73) ->
+ 3;
+yeccgoto('IncludeTag', 78) ->
+ 3;
+yeccgoto('IncludeTag', 83) ->
+ 3;
+yeccgoto('IncludeTag', 88) ->
+ 3;
+yeccgoto('IncludeTag', 96) ->
+ 3;
+yeccgoto('Literal', 29) ->
+ 30;
+yeccgoto('Variable', 17) ->
+ 19;
+yeccgoto('Variable', 39) ->
+ 43;
+yeccgoto('Variable', 45) ->
+ 43;
+yeccgoto('Variable', 51) ->
+ 52;
+yeccgoto('VariableBraced', 1) ->
  2;
  2;
-yeccgoto('Element', 9) ->
+yeccgoto('VariableBraced', 68) ->
  2;
  2;
-yeccgoto('Element', 11) ->
+yeccgoto('VariableBraced', 73) ->
+ 2;
+yeccgoto('VariableBraced', 78) ->
+ 2;
+yeccgoto('VariableBraced', 83) ->
+ 2;
+yeccgoto('VariableBraced', 88) ->
+ 2;
+yeccgoto('VariableBraced', 96) ->
  2;
  2;
-yeccgoto('Elements', 0) ->
- 1;
-yeccgoto('Elements', 3) ->
- 11;
-yeccgoto('Elements', 5) ->
- 9;
 yeccgoto(__Symbol, __State) ->
 yeccgoto(__Symbol, __State) ->
  erlang:error({yecc_bug,"1.1",{__Symbol, __State, missing_in_goto_table}}).
  erlang:error({yecc_bug,"1.1",{__Symbol, __State, missing_in_goto_table}}).
 
 
 -compile({inline,{yeccpars2_0_,1}}).
 -compile({inline,{yeccpars2_0_,1}}).
--file("src/erlydtl/erlydtl_parser.yrl", 54).
+-file("src/erlydtl/erlydtl_parser.yrl", 104).
 yeccpars2_0_(__Stack) ->
 yeccpars2_0_(__Stack) ->
  [begin
  [begin
-   nil
+   [ ]
   end | __Stack].
   end | __Stack].
 
 
 -compile({inline,{yeccpars2_2_,1}}).
 -compile({inline,{yeccpars2_2_,1}}).
--file("src/erlydtl/erlydtl_parser.yrl", 55).
+-file("src/erlydtl/erlydtl_parser.yrl", 106).
 yeccpars2_2_([__2,__1 | __Stack]) ->
 yeccpars2_2_([__2,__1 | __Stack]) ->
  [begin
  [begin
-   [ __1 , __2 ]
+   __1 ++ [ __2 ]
   end | __Stack].
   end | __Stack].
 
 
 -compile({inline,{yeccpars2_3_,1}}).
 -compile({inline,{yeccpars2_3_,1}}).
--file("src/erlydtl/erlydtl_parser.yrl", 54).
-yeccpars2_3_(__Stack) ->
+-file("src/erlydtl/erlydtl_parser.yrl", 108).
+yeccpars2_3_([__2,__1 | __Stack]) ->
  [begin
  [begin
-   nil
+   __1 ++ [ __2 ]
   end | __Stack].
   end | __Stack].
 
 
 -compile({inline,{yeccpars2_4_,1}}).
 -compile({inline,{yeccpars2_4_,1}}).
--file("src/erlydtl/erlydtl_parser.yrl", 59).
-yeccpars2_4_([__1 | __Stack]) ->
+-file("src/erlydtl/erlydtl_parser.yrl", 104).
+yeccpars2_4_(__Stack) ->
  [begin
  [begin
-   extends ( __1 )
+   [ ]
   end | __Stack].
   end | __Stack].
 
 
 -compile({inline,{yeccpars2_5_,1}}).
 -compile({inline,{yeccpars2_5_,1}}).
--file("src/erlydtl/erlydtl_parser.yrl", 54).
-yeccpars2_5_(__Stack) ->
+-file("src/erlydtl/erlydtl_parser.yrl", 112).
+yeccpars2_5_([__2,__1 | __Stack]) ->
  [begin
  [begin
-   nil
+   __1 ++ [ __2 ]
   end | __Stack].
   end | __Stack].
 
 
 -compile({inline,{yeccpars2_6_,1}}).
 -compile({inline,{yeccpars2_6_,1}}).
--file("src/erlydtl/erlydtl_parser.yrl", 57).
-yeccpars2_6_([__1 | __Stack]) ->
+-file("src/erlydtl/erlydtl_parser.yrl", 104).
+yeccpars2_6_(__Stack) ->
  [begin
  [begin
-   string ( __1 )
+   [ ]
   end | __Stack].
   end | __Stack].
 
 
 -compile({inline,{yeccpars2_7_,1}}).
 -compile({inline,{yeccpars2_7_,1}}).
--file("src/erlydtl/erlydtl_parser.yrl", 61).
-yeccpars2_7_([__1 | __Stack]) ->
+-file("src/erlydtl/erlydtl_parser.yrl", 111).
+yeccpars2_7_([__2,__1 | __Stack]) ->
  [begin
  [begin
-   tag ( __1 )
+   __1 ++ [ __2 ]
   end | __Stack].
   end | __Stack].
 
 
 -compile({inline,{yeccpars2_8_,1}}).
 -compile({inline,{yeccpars2_8_,1}}).
--file("src/erlydtl/erlydtl_parser.yrl", 58).
-yeccpars2_8_([__1 | __Stack]) ->
+-file("src/erlydtl/erlydtl_parser.yrl", 107).
+yeccpars2_8_([__2,__1 | __Stack]) ->
  [begin
  [begin
-   var ( __1 )
+   __1 ++ [ __2 ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_9_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 109).
+yeccpars2_9_([__2,__1 | __Stack]) ->
+ [begin
+   __1 ++ [ __2 ]
   end | __Stack].
   end | __Stack].
 
 
 -compile({inline,{yeccpars2_10_,1}}).
 -compile({inline,{yeccpars2_10_,1}}).
--file("src/erlydtl/erlydtl_parser.yrl", 62).
-yeccpars2_10_([__3,__2,__1 | __Stack]) ->
+-file("src/erlydtl/erlydtl_parser.yrl", 104).
+yeccpars2_10_(__Stack) ->
+ [begin
+   [ ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_11_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 114).
+yeccpars2_11_([__2,__1 | __Stack]) ->
  [begin
  [begin
-   for ( __1 , __2 )
+   __1 ++ [ __2 ]
   end | __Stack].
   end | __Stack].
 
 
 -compile({inline,{yeccpars2_12_,1}}).
 -compile({inline,{yeccpars2_12_,1}}).
--file("src/erlydtl/erlydtl_parser.yrl", 60).
-yeccpars2_12_([__3,__2,__1 | __Stack]) ->
+-file("src/erlydtl/erlydtl_parser.yrl", 104).
+yeccpars2_12_(__Stack) ->
  [begin
  [begin
-   block ( __1 , __2 )
+   [ ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_13_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 110).
+yeccpars2_13_([__2,__1 | __Stack]) ->
+ [begin
+   __1 ++ [ __2 ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_14_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 104).
+yeccpars2_14_(__Stack) ->
+ [begin
+   [ ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_15_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 113).
+yeccpars2_15_([__2,__1 | __Stack]) ->
+ [begin
+   __1 ++ [ __2 ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_18_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 105).
+yeccpars2_18_([__2,__1 | __Stack]) ->
+ [begin
+   __1 ++ [ __2 ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_20_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 119).
+yeccpars2_20_([__1 | __Stack]) ->
+ [begin
+   { variable , { __1 } }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_24_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 120).
+yeccpars2_24_([__3,__2,__1 | __Stack]) ->
+ [begin
+   { variable , { __1 , __3 } }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_25_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 116).
+yeccpars2_25_([__3,__2,__1 | __Stack]) ->
+ [begin
+   __2
+  end | __Stack].
+
+-compile({inline,{yeccpars2_27_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 118).
+yeccpars2_27_([__3,__2,__1 | __Stack]) ->
+ [begin
+   { apply_filter , __1 , __3 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_28_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 161).
+yeccpars2_28_([__1 | __Stack]) ->
+ [begin
+   [ __1 ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_30_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 162).
+yeccpars2_30_([__3,__2,__1 | __Stack]) ->
+ [begin
+   [ __1 , __3 ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_38_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 129).
+yeccpars2_38_(__Stack) ->
+ [begin
+   [ ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_42_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 125).
+yeccpars2_42_([__4,__3,__2,__1 | __Stack]) ->
+ [begin
+   { include , __3 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_46_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 151).
+yeccpars2_46_([__2,__1 | __Stack]) ->
+ [begin
+   { 'not' , __2 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_47_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 150).
+yeccpars2_47_([__4,__3,__2,__1 | __Stack]) ->
+ [begin
+   __3
+  end | __Stack].
+
+-compile({inline,{yeccpars2_49_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 127).
+yeccpars2_49_([__4,__3,__2,__1 | __Stack]) ->
+ [begin
+   { tag , __2 , __3 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_52_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 130).
+yeccpars2_52_([__4,__3,__2,__1 | __Stack]) ->
+ [begin
+   __1 ++ [ { __2 , __4 } ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_56_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 141).
+yeccpars2_56_([__4,__3,__2,__1 | __Stack]) ->
+ [begin
+   __3
+  end | __Stack].
+
+-compile({inline,{yeccpars2_59_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 144).
+yeccpars2_59_([__3,__2,__1 | __Stack]) ->
+ [begin
+   { in , __1 , __3 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_60_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 146).
+yeccpars2_60_([__3,__2,__1 | __Stack]) ->
+ [begin
+   [ __1 , __3 ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_62_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 124).
+yeccpars2_62_([__4,__3,__2,__1 | __Stack]) ->
+ [begin
+   { extends , __3 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_63_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 0).
+yeccpars2_63_([__3,__2,__1 | __Stack]) ->
+ [begin
+   '$undefined'
+  end | __Stack].
+
+-compile({inline,{yeccpars2_65_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 133).
+yeccpars2_65_([__4,__3,__2,__1 | __Stack]) ->
+ [begin
+   __3
+  end | __Stack].
+
+-compile({inline,{yeccpars2_67_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 158).
+yeccpars2_67_([__4,__3,__2,__1 | __Stack]) ->
+ [begin
+   __3
+  end | __Stack].
+
+-compile({inline,{yeccpars2_69_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 157).
+yeccpars2_69_([__3,__2,__1 | __Stack]) ->
+ [begin
+   { autoescape , __1 , __2 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_72_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 0).
+yeccpars2_72_([__3,__2,__1 | __Stack]) ->
+ [begin
+   '$undefined'
+  end | __Stack].
+
+-compile({inline,{yeccpars2_74_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 132).
+yeccpars2_74_([__3,__2,__1 | __Stack]) ->
+ [begin
+   { block , __1 , __2 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_77_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 0).
+yeccpars2_77_([__3,__2,__1 | __Stack]) ->
+ [begin
+   '$undefined'
+  end | __Stack].
+
+-compile({inline,{yeccpars2_79_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 136).
+yeccpars2_79_([__3,__2,__1 | __Stack]) ->
+ [begin
+   { comment , __2 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_82_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 0).
+yeccpars2_82_([__3,__2,__1 | __Stack]) ->
+ [begin
+   '$undefined'
+  end | __Stack].
+
+-compile({inline,{yeccpars2_84_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 140).
+yeccpars2_84_([__3,__2,__1 | __Stack]) ->
+ [begin
+   { for , __1 , __2 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_87_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 0).
+yeccpars2_87_([__3,__2,__1 | __Stack]) ->
+ [begin
+   '$undefined'
+  end | __Stack].
+
+-compile({inline,{yeccpars2_89_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 149).
+yeccpars2_89_([__3,__2,__1 | __Stack]) ->
+ [begin
+   { 'if' , __1 , __2 }
+  end | __Stack].
+
+-compile({inline,{yeccpars2_90_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 104).
+yeccpars2_90_(__Stack) ->
+ [begin
+   [ ]
+  end | __Stack].
+
+-compile({inline,{yeccpars2_94_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 0).
+yeccpars2_94_([__3,__2,__1 | __Stack]) ->
+ [begin
+   '$undefined'
+  end | __Stack].
+
+-compile({inline,{yeccpars2_95_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 0).
+yeccpars2_95_([__3,__2,__1 | __Stack]) ->
+ [begin
+   '$undefined'
+  end | __Stack].
+
+-compile({inline,{yeccpars2_97_,1}}).
+-file("src/erlydtl/erlydtl_parser.yrl", 148).
+yeccpars2_97_([__5,__4,__3,__2,__1 | __Stack]) ->
+ [begin
+   { ifelse , __1 , __2 , __4 }
   end | __Stack].
   end | __Stack].
 
 
 
 
--file("src/erlydtl/erlydtl_parser.yrl", 114).

+ 223 - 83
src/erlydtl/erlydtl_parser.yrl

@@ -1,14 +1,15 @@
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 %%% File:      erlydtl_parser.erl
 %%% File:      erlydtl_parser.erl
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
-%%% @copyright 2007 Roberto Saccon, Tait Larson
+%%% @author    Evan Miller <emmiller@gmail.com>
+%%% @copyright 2008 Roberto Saccon, Evan Miller
 %%% @doc Template language grammar
 %%% @doc Template language grammar
 %%% @reference  See <a href="http://erlydtl.googlecode.com" target="_top">http://erlydtl.googlecode.com</a> for more information
 %%% @reference  See <a href="http://erlydtl.googlecode.com" target="_top">http://erlydtl.googlecode.com</a> for more information
 %%% @end  
 %%% @end  
 %%%
 %%%
 %%% The MIT License
 %%% The MIT License
 %%%
 %%%
-%%% Copyright (c) 2007 Roberto Saccon
+%%% Copyright (c) 2007 Roberto Saccon, Evan Miller
 %%%
 %%%
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% of this software and associated documentation files (the "Software"), to deal
 %%% of this software and associated documentation files (the "Software"), to deal
@@ -28,87 +29,226 @@
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% THE SOFTWARE.
 %%% THE SOFTWARE.
 %%%
 %%%
-%%% @since 2007-11-11 by Roberto Saccon
+%%% @since 2007-11-11 by Roberto Saccon, Evan Miller
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 
 
-
-Nonterminals 
+Nonterminals
     Elements
     Elements
-    Element.
-
-Terminals 
-    string
-    var
-    extends
-    block
-    endblock
-    tag
-    for
-    endfor.
-
-Rootsymbol    
-    Elements. 
-
-
-%% -------------------------------------------------------------------
-%% Rules
-%% -------------------------------------------------------------------
-
-Elements -> '$empty' : nil.
-Elements -> Elements Element : ['$1', '$2'].
-
-Element -> string : string('$1').
-Element -> var : var('$1').
-Element -> extends : extends('$1').
-Element -> block Elements endblock : block('$1', '$2').
-Element -> tag : tag('$1').
-Element -> for Elements endfor : for('$1', '$2').
-
-
-Erlang code.
-
-string({_, String}) ->
-    erl_syntax:binary([erl_syntax:binary_field(erl_syntax:integer(X)) || X <- String]).
-    %erl_syntax:string(String).  %% less verbose for debugging 
-    
-
-var({_, Line, Var}) ->
-    case string:tokens(Var, ".") of
-        [Namespace, Var1] ->
-            {var, Line, list_to_atom("A" ++ Namespace), list_to_atom(Var1)};
-        _ ->
-            {var, Line, list_to_atom("A" ++ Var)}
-    end.
-
-
-extends({_, Line, [Name]}) ->
-    %% TODO: check if string (enclosed with  "") or variable. 
-    %% for now we handle it (even not enclosed with "") as string
-    {extends, Line, string:strip(Name, both, $")}.
-
-
-block({_, Line, [Name]}, Content) ->
-    {block, Line, list_to_atom(Name), Content}.
-
-
-tag({_, Line, [TagName | Args]}) ->
-    %% TODO: check if string (enclosed with  "") or variable. 
-    %% for now we handle it (even not enclosed with "") as string
-	Args2 = lists:foldl(fun(X, Acc) ->
-	        case string:chr(X, $=) of
-				0 ->
-				    Acc;
-				Pos ->
-			        Var = list_to_atom(string:sub_string(X, 1, Pos-1)),
-			        Val = string:sub_string(X, Pos+1),
-			        Val2 = string:strip(Val, both, $"),
-					[{Var, Val2}| Acc]
-			end
-		end,
-    	[],
-    	Args),
-    {tag, Line, TagName, Args2}.
-
-
-for({_, Line, [Iterator, _, Var]}, Content) ->
-    {for, Line, list_to_atom("A" ++ Iterator), list_to_atom("A" ++ Var), Content}.
+    Literal
+
+    VariableBraced
+
+    ExtendsTag
+    IncludeTag
+
+    CustomTag
+    Args
+
+    BlockBlock
+    BlockBraced
+    EndBlockBraced
+
+    CommentBlock
+    CommentBraced
+    EndCommentBraced
+
+    ForBlock
+    ForBraced
+    EndForBraced
+    ForExpression
+    ForGroup
+
+    IfBlock
+    IfBraced
+    IfExpression
+    ElseBraced
+    EndIfBraced
+
+    AutoEscapeBlock
+    AutoEscapeBraced
+    EndAutoEscapeBraced
+
+    Variable
+    Filter.
+
+Terminals
+    autoescape_keyword
+    block_keyword
+    close_tag
+    close_var
+    comment_keyword
+    colon
+    comma
+    dot
+    else_keyword
+    endautoescape_keyword
+    endblock_keyword
+    endcomment_keyword
+    endfor_keyword
+    endif_keyword
+    equal
+    extends_keyword
+    for_keyword
+    identifier
+    if_keyword
+    in_keyword
+    include_keyword
+    not_keyword
+    number_literal
+    open_tag
+    open_var
+    pipe
+    string_literal
+    text.
+
+Rootsymbol
+    Elements.
+
+Elements -> '$empty' : [].
+Elements -> Elements text : '$1' ++ ['$2'].
+Elements -> Elements VariableBraced : '$1' ++ ['$2'].
+Elements -> Elements ExtendsTag : '$1' ++ ['$2'].
+Elements -> Elements IncludeTag : '$1' ++ ['$2'].
+Elements -> Elements CustomTag : '$1' ++ ['$2'].
+Elements -> Elements BlockBlock : '$1' ++ ['$2'].
+Elements -> Elements ForBlock : '$1' ++ ['$2'].
+Elements -> Elements IfBlock : '$1' ++ ['$2'].
+Elements -> Elements AutoEscapeBlock : '$1' ++ ['$2'].
+Elements -> Elements CommentBlock : '$1' ++ ['$2'].
+
+VariableBraced -> open_var Variable close_var : '$2'.
+
+Variable -> Variable pipe Filter : {apply_filter, '$1', '$3'}.
+Variable -> identifier : {variable, {'$1'}}.
+Variable -> identifier dot identifier : {variable, {'$1', '$3'}}.
+Variable -> string_literal : '$1'.
+Variable -> number_literal : '$1'.
+
+ExtendsTag -> open_tag extends_keyword string_literal close_tag : {extends, '$3'}.
+IncludeTag -> open_tag include_keyword string_literal close_tag : {include, '$3'}.
+
+CustomTag -> open_tag identifier Args close_tag : {tag, '$2', '$3'}.
+
+Args -> '$empty' : [].
+Args -> Args identifier equal Variable : '$1' ++ [{'$2', '$4'}].
+
+BlockBlock -> BlockBraced Elements EndBlockBraced : {block, '$1', '$2'}.
+BlockBraced -> open_tag block_keyword identifier close_tag : '$3'.
+EndBlockBraced -> open_tag endblock_keyword close_tag.
+
+CommentBlock -> CommentBraced Elements EndCommentBraced : {comment, '$2'}.
+CommentBraced -> open_tag comment_keyword close_tag.
+EndCommentBraced -> open_tag endcomment_keyword close_tag.
+
+ForBlock -> ForBraced Elements EndForBraced : {for, '$1', '$2'}.
+ForBraced -> open_tag for_keyword ForExpression close_tag : '$3'.
+EndForBraced -> open_tag endfor_keyword close_tag.
+ForExpression -> identifier : '$1'.
+ForExpression -> ForGroup in_keyword identifier : {'in', '$1', '$3'}.
+ForGroup -> identifier : '$1'.
+ForGroup -> ForGroup comma identifier : ['$1', '$3'].
+
+IfBlock -> IfBraced Elements ElseBraced Elements EndIfBraced : {ifelse, '$1', '$2', '$4'}.
+IfBlock -> IfBraced Elements EndIfBraced : {'if', '$1', '$2'}.
+IfBraced -> open_tag if_keyword IfExpression close_tag : '$3'.
+IfExpression -> not_keyword IfExpression : {'not', '$2'}.
+IfExpression -> Variable : '$1'.
+
+ElseBraced -> open_tag else_keyword close_tag.
+EndIfBraced -> open_tag endif_keyword close_tag.
+
+AutoEscapeBlock -> AutoEscapeBraced Elements EndAutoEscapeBraced : {autoescape, '$1', '$2'}.
+AutoEscapeBraced -> open_tag autoescape_keyword identifier close_tag : '$3'.
+EndAutoEscapeBraced -> open_tag endautoescape_keyword close_tag.
+
+Filter -> identifier : ['$1'].
+Filter -> identifier colon Literal : ['$1', '$3'].
+
+Literal -> string_literal : '$1'.
+Literal -> number_literal : '$1'.
+
+
+
+
+%% initial, now deprecated version by below:
+
+%% Nonterminals 
+%%     Elements
+%%     Element.
+%% 
+%% Terminals 
+%%     string
+%%     var
+%%     extends
+%%     block
+%%     endblock
+%%     tag
+%%     for
+%%     endfor.
+%% 
+%% Rootsymbol    
+%%     Elements. 
+%% 
+%% 
+%% %% -------------------------------------------------------------------
+%% %% Rules
+%% %% -------------------------------------------------------------------
+%% 
+%% Elements -> '$empty' : nil.
+%% Elements -> Elements Element : ['$1', '$2'].
+%% 
+%% Element -> string : string('$1').
+%% Element -> var : var('$1').
+%% Element -> extends : extends('$1').
+%% Element -> block Elements endblock : block('$1', '$2').
+%% Element -> tag : tag('$1').
+%% Element -> for Elements endfor : for('$1', '$2').
+%% 
+%% 
+%% Erlang code.
+%% 
+%% string({_, String}) ->
+%%     erl_syntax:binary([erl_syntax:binary_field(erl_syntax:integer(X)) || X <- String]).
+%%     %erl_syntax:string(String).  %% less verbose for debugging 
+%%     
+%% 
+%% var({_, Line, Var}) ->
+%%     case string:tokens(Var, ".") of
+%%         [Namespace, Var1] ->
+%%             {var, Line, list_to_atom("A" ++ Namespace), list_to_atom(Var1)};
+%%         _ ->
+%%             {var, Line, list_to_atom("A" ++ Var)}
+%%     end.
+%% 
+%% 
+%% extends({_, Line, [Name]}) ->
+%%     %% TODO: check if string (enclosed with  "") or variable. 
+%%     %% for now we handle it (even not enclosed with "") as string
+%%     {extends, Line, string:strip(Name, both, $")}.
+%% 
+%% 
+%% block({_, Line, [Name]}, Content) ->
+%%     {block, Line, list_to_atom(Name), Content}.
+%% 
+%% 
+%% tag({_, Line, [TagName | Args]}) ->
+%%     %% TODO: check if string (enclosed with  "") or variable. 
+%%     %% for now we handle it (even not enclosed with "") as string
+%%  Args2 = lists:foldl(fun(X, Acc) ->
+%%          case string:chr(X, $=) of
+%%              0 ->
+%%                  Acc;
+%%              Pos ->
+%%                  Var = list_to_atom(string:sub_string(X, 1, Pos-1)),
+%%                  Val = string:sub_string(X, Pos+1),
+%%                  Val2 = string:strip(Val, both, $"),
+%%                  [{Var, Val2}| Acc]
+%%          end
+%%      end,
+%%      [],
+%%      Args),
+%%     {tag, Line, TagName, Args2}.
+%% 
+%% 
+%% for({_, Line, [Iterator, _, Var]}, Content) ->
+%%     {for, Line, list_to_atom("A" ++ Iterator), list_to_atom("A" ++ Var), Content}.

+ 363 - 166
src/erlydtl/erlydtl_scanner.erl

@@ -1,14 +1,15 @@
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 %%% File:      erlydtl_scanner.erl
 %%% File:      erlydtl_scanner.erl
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
-%%% @copyright 2007 Roberto Saccon
-%%% @doc Template language scanner
-%%% @reference  See <a href="http://erlydtl.googlecode.com" target="_top">http://erlydtl.googlecode.com</a> for more information
+%%% @author    Evan Miller <emmiller@gmail.com>
+%%% @copyright 2008 Roberto Saccon, Evan Miller
+%%% @doc 
+%%%Template language scanner
 %%% @end  
 %%% @end  
 %%%
 %%%
 %%% The MIT License
 %%% The MIT License
 %%%
 %%%
-%%% Copyright (c) 2007 Roberto Saccon
+%%% Copyright (c) 2007 Roberto Saccon, Evan Miller
 %%%
 %%%
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% of this software and associated documentation files (the "Software"), to deal
 %%% of this software and associated documentation files (the "Software"), to deal
@@ -28,13 +29,14 @@
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% THE SOFTWARE.
 %%% THE SOFTWARE.
 %%%
 %%%
-%%% @since 2007-11-11 by Roberto Saccon
+%%% @since 2007-11-11 by Roberto Saccon, Evan Miller
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 -module(erlydtl_scanner).
 -module(erlydtl_scanner).
 -author('rsaccon@gmail.com').
 -author('rsaccon@gmail.com').
+-author('emmiller@gmail.com').
+
+-export([scan/1]). 
 
 
-%% API
--export([scan/1]).  
 
 
 %%====================================================================
 %%====================================================================
 %% API
 %% API
@@ -47,182 +49,377 @@
 %% an error.
 %% an error.
 %% @end
 %% @end
 %%--------------------------------------------------------------------
 %%--------------------------------------------------------------------
-
 scan(Template) ->
 scan(Template) ->
-    scan(Template, [], 1).
-
-scan([], Scanned, _Line) ->
-    Tokens = fold_strings(lists:reverse(Scanned), [], []),
-    {ok, Tokens};
-
-scan([$<, $\!, $-, $-, ${, ${ | T], Scanned, Line) ->
-  Rules = [until(fun is_var_end/1), 
-           until(fun is_html_comment_end/1)],
-  Scan = scan2(Rules),
-  case Scan(T) of
-      {ok, Token, LinesScanned, Rest} ->
-          scan(Rest, [{var, Line, Token} | Scanned], Line + LinesScanned);
-      {error, Reason} -> 
-          {error, {var, Line, Reason}}
-  end;             
-
-scan([${, ${ | T], Scanned, Line) ->
-  Rules = [until(fun is_var_end/1)],
-  Scan = scan2(Rules),
-  case Scan(T) of
-      {ok, Token, LinesScanned, Rest} ->
-          scan(Rest, [{var, Line, Token} | Scanned], Line + LinesScanned);
-      {error, Reason} -> 
-          {error, {var, Line, Reason}}
-  end;
-
-scan([$<, $\!, $-, $-, ${, $\% | T], Scanned, Line) ->
-  Rules = [until(fun is_tag_end/1), 
-           until(fun is_html_comment_end/1)],
-  Scan = scan2(Rules),
-  case Scan(T) of
-      {ok, Token, LinesScanned, Rest} ->
-          scan(Rest, [{tag, Line, Token} | Scanned], Line + LinesScanned);
-      {error, Reason} -> 
-          {error, {tag, Line, Reason}}
-  end;
-
-scan([${, $\% | T], Scanned, Line) ->
-  Rules = [until(fun is_tag_end/1)],
-  Scan = scan2(Rules),
-  case Scan(T) of
-      {ok, Token, LinesScanned, Rest} ->
-          scan(Rest, [{tag, Line, Token} | Scanned], Line + LinesScanned);
-      {error, Reason} -> 
-          {error, {tag, Line, Reason}}
-  end;
-
-scan([${, $# | T], Scanned, Line) ->
-  Rules = [until(fun is_comment_end/1)],
-  Scan = scan2(Rules), 
-  case Scan(T) of
-      {ok, _Token, LinesScanned, Rest} ->
-          scan(Rest, Scanned, Line + LinesScanned);
-      {error, Reason} -> 
-          {error, {var, Line, Reason}}
-  end;
-
-scan([H | T], Scanned, Line) when [H] == "\r" andalso hd(T) == "\n" ->
-    scan(tl(T), ["\r\n" | Scanned], Line+1);
-
-scan([H | T], Scanned, Line) when [H] == "\r" orelse [H] == "\n" ->
-    scan(T, [H | Scanned], Line+1);
-
-scan([H | T], Scanned, Line) ->
-    scan(T, [H | Scanned], Line).
-
-
-%%--------------------------------------------------------------------
-%% Internal Functions
-%%--------------------------------------------------------------------   
-
-scan2(Rules) ->
-    fun(Tmpl) ->
-	    scan2(Rules, Tmpl, [], 0)
-    end.
-
-
-scan2([], Tmpl, SoFar, Line) ->
-    {ok, lists:reverse(SoFar), Line, Tmpl};
+    scan(Template, [], {1, 1}, in_text).
 
 
-scan2([Rule | T], Tmpl, SoFar, Line) ->
-    case Rule(Tmpl) of
-	{error, Reason} ->
-	    {error, Reason};
-	{ok, Rest, LinesScanned} ->
-	    scan2(T, Rest, SoFar, Line + LinesScanned);
-	{ok, Tok, LinesScanned, Rest} ->
-	    scan2(T, Rest, [Tok | SoFar], Line + LinesScanned)
-    end.
-
-fold_strings([], Folded, []) ->
-    lists:reverse(Folded);
-
-fold_strings([], Folded, Acc) ->
-    S = {string, lists:reverse(Acc)},
-    lists:reverse([S | Folded]);
+scan([], Scanned, _, in_text) ->
+    {ok, lists:reverse(lists:map(
+		fun
+		({identifier, Pos, String}) ->
+		    RevString = lists:reverse(String),
+		    Keywords = ["for", "endfor", "in", "include", "block", "endblock",
+		    	"extends", "autoescape", "endautoescape", "if", "else", "endif",
+			"not", "or", "and", "comment", "endcomment", "cycle", "firstof",
+			"ifchanged", "ifequal", "endifequal", "ifnotequal", "endifnotequal",
+			"now", "regroup", "spaceless", "endspaceless", "ssi", "templatetag"], 
+		    Type = case lists:member(RevString, Keywords) of
+		        true ->
+			    list_to_atom(RevString ++ "_keyword");
+			_ ->
+			    identifier
+		    end,
+		    {Type, Pos, RevString};
+		({Type, Pos, String}) ->
+		    {Type, Pos, lists:reverse(String)} 
+		end, Scanned))};
 
 
-fold_strings([H | T], Folded, []) when is_tuple(H) ->
-    fold_strings(T, [translate_token(H) | Folded], []);
+scan([], _Scanned, _, {in_comment, _}) ->
+    {error, "Reached end of file inside a comment."};
 
 
-fold_strings([H | T], Folded, Acc) when is_tuple(H) ->
-    S = {string, lists:reverse(Acc)},
-    fold_strings(T, [translate_token(H), S | Folded], []);
+scan([], _Scanned, _, _) ->
+    {error, "Reached end of file inside a code block."};
 
 
-fold_strings([H | T], Folded, Acc) ->
-    fold_strings(T, Folded, [H | Acc]).
+scan("<!--{{" ++ T, Scanned, {Row, Column}, in_text) ->
+    scan(T, [{open_var, {Row, Column}, "<!--{{"} | Scanned], {Row, Column + length("<!--{{")}, {in_code, "}}-->"});
 
 
+scan("{{" ++ T, Scanned, {Row, Column}, in_text) ->
+    scan(T, [{open_var, {Row, Column}, "{{"} | Scanned], {Row, Column + 2}, {in_code, "}}"});
 
 
-translate_token({var, Line, [[S] | _]}) ->
-    {var, Line, S};
+scan("<!--{#" ++ T, Scanned, {Row, Column}, in_text) ->
+    scan(T, Scanned, {Row, Column + length("<!--{#")}, {in_comment, "#}-->"});
 
 
-translate_token({tag, Line, [[H | T] | _]}) ->
-    translate_tag(H, T, Line) ;
+scan("{#" ++ T, Scanned, {Row, Column}, in_text) ->
+    scan(T, Scanned, {Row, Column + 2}, {in_comment, "#}"});
+
+scan("#}-->" ++ T, Scanned, {Row, Column}, {in_comment, "#}-->"}) ->
+    scan(T, Scanned, {Row, Column + length("#}-->")}, in_text);
+
+scan("#}" ++ T, Scanned, {Row, Column}, {in_comment, "#}"}) ->
+    scan(T, Scanned, {Row, Column + 2}, in_text);
+
+scan("<!--{%" ++ T, Scanned, {Row, Column}, in_text) ->
+    scan(T, [{open_tag, {Row, Column}, lists:reverse("<!--{%")} | Scanned], 
+	    {Row, Column + length("<!--{%")}, {in_code, "%}-->"});
+
+scan("{%" ++ T, Scanned, {Row, Column}, in_text) ->
+    scan(T, [{open_tag, {Row, Column}, lists:reverse("{%")} | Scanned], 
+	    {Row, Column + 2}, {in_code, "%}"});
+
+scan([_ | T], Scanned, {Row, Column}, {in_comment, Closer}) ->
+    scan(T, Scanned, {Row, Column + 1}, {in_comment, Closer});
+
+scan("\n" ++ T, Scanned, {Row, Column}, in_text) ->
+    scan(T, append_text_char(Scanned, {Row, Column}, $\n), {Row + 1, 1}, in_text);
+
+scan([H | T], Scanned, {Row, Column}, in_text) ->
+    scan(T, append_text_char(Scanned, {Row, Column}, H), {Row, Column + 1}, in_text);
+
+scan("\"" ++ T, Scanned, {Row, Column}, {in_code, Closer}) ->
+    scan(T, [{string_literal, {Row, Column}, "\""} | Scanned], {Row, Column + 1}, {in_double_quote, Closer});
+
+scan("\"" ++ T, Scanned, {Row, Column}, {in_identifier, Closer}) ->
+    scan(T, [{string_literal, {Row, Column}, "\""} | Scanned], {Row, Column + 1}, {in_double_quote, Closer});
+
+scan([$\\ | T], Scanned, {Row, Column}, {in_double_quote, Closer}) ->
+    scan(T, append_char(Scanned, $\\), {Row, Column + 1}, {in_double_quote_slash, Closer});
+
+scan([H | T], Scanned, {Row, Column}, {in_double_quote_slash, Closer}) ->
+    scan(T, append_char(Scanned, H), {Row, Column + 1}, {in_double_quote, Closer});
+
+% end quote
+scan("\"" ++ T, Scanned, {Row, Column}, {in_double_quote, Closer}) ->
+    scan(T, append_char(Scanned, 34), {Row, Column + 1}, {in_code, Closer});
+
+scan([H | T], Scanned, {Row, Column}, {in_double_quote, Closer}) ->
+    scan(T, append_char(Scanned, H), {Row, Column + 1}, {in_double_quote, Closer});
+
+
+scan("," ++ T, Scanned, {Row, Column}, {_, Closer}) ->
+    scan(T, [{comma, {Row, Column}, ","} | Scanned], {Row, Column + 1}, {in_code, Closer});
+
+scan("|" ++ T, Scanned, {Row, Column}, {_, Closer}) ->
+    scan(T, [{pipe, {Row, Column}, "|"} | Scanned], {Row, Column + 1}, {in_code, Closer});
+
+scan("=" ++ T, Scanned, {Row, Column}, {_, Closer}) ->
+    scan(T, [{equal, {Row, Column}, "="} | Scanned], {Row, Column + 1}, {in_code, Closer});
+
+scan(":" ++ T, Scanned, {Row, Column}, {_, Closer}) ->
+    scan(T, [{colon, {Row, Column}, ":"} | Scanned], {Row, Column + 1}, {in_code, Closer});
+
+scan("." ++ T, Scanned, {Row, Column}, {_, Closer}) ->
+    scan(T, [{dot, {Row, Column}, "."} | Scanned], {Row, Column + 1}, {in_code, Closer});
+
+scan(" " ++ T, Scanned, {Row, Column}, {_, Closer}) ->
+    scan(T, Scanned, {Row, Column + 1}, {in_code, Closer});
+
+scan("}}-->" ++ T, Scanned, {Row, Column}, {in_code, "}}-->"}) ->
+    scan(T, [{close_var, {Row, Column}, lists:reverse("}}-->")} | Scanned], 
+	    {Row, Column + 2}, in_text);
+
+scan("}}" ++ T, Scanned, {Row, Column}, {in_code, "}}"}) ->
+    scan(T, [{close_var, {Row, Column}, "}}"} | Scanned], {Row, Column + 2}, in_text);
 
 
-translate_token(Token) ->
-    io:format("TRACE ~p:~p unrecognized token: ~p~n",[?MODULE, ?LINE, Token]),
-    Token.
+scan("%}-->" ++ T, Scanned, {Row, Column}, {in_code, "%}-->"}) ->
+    scan(T, [{close_tag, {Row, Column}, lists:reverse("%}-->")} | Scanned], 
+	    {Row, Column + 2}, in_text);
 
 
-translate_tag("extends" = H, T, Line) ->
-    {list_to_atom(H), Line, T};
-    
-translate_tag("block" = H, T, Line) ->
-    {list_to_atom(H), Line, T};   
-    
-translate_tag("endblock" = H, T, Line) ->
-    {list_to_atom(H), Line, T};    
-    
-translate_tag("for" = H, T, Line) ->
-    {list_to_atom(H), Line, T};   
+scan("%}" ++ T, Scanned, {Row, Column}, {in_code, "%}"}) ->
+    scan(T, [{close_tag, {Row, Column}, lists:reverse("%}")} | Scanned], 
+	    {Row, Column + 2}, in_text);
 
 
-translate_tag("endfor" = H, T, Line) ->
-    {list_to_atom(H), Line, T};    
-         
-translate_tag(H, T, Line) ->
-    {tag, Line, [list_to_atom(H) | T]}.
+scan([H | T], Scanned, {Row, Column}, {in_code, Closer}) ->
+    case char_type(H) of
+        letter_underscore ->
+	    scan(T, [{identifier, {Row, Column}, [H]} | Scanned], {Row, Column + 1}, {in_identifier, Closer});
+        digit ->
+	    scan(T, [{number_literal, {Row, Column}, [H]} | Scanned], {Row, Column + 1}, {in_number, Closer});
+        _ ->
+	    {error, io:format("Illegal character line ~p column ~p", [Row, Column])}
+    end;
 
 
+scan([H | T], Scanned, {Row, Column}, {in_number, Closer}) ->
+    case char_type(H) of
+        digit ->
+	    scan(T, append_char(Scanned, H), {Row, Column + 1}, {in_number, Closer});
+        _ ->
+	    {error, io:format("Illegal character line ~p column ~p", [Row, Column])}
+    end;
 
 
-until(P) ->
-    fun (Tmpl) -> 
-            until(P, Tmpl, 0, []) 
+scan([H | T], Scanned, {Row, Column}, {in_identifier, Closer}) ->
+    case char_type(H) of
+        letter_underscore ->
+	    scan(T, append_char(Scanned, H), {Row, Column + 1}, {in_identifier, Closer});
+	digit ->
+	    scan(T, append_char(Scanned, H), {Row, Column + 1}, {in_identifier, Closer});
+        _ ->
+	    {error, io:format("Illegal character line ~p column ~p", [Row, Column])}
     end.
     end.
 
 
-until(_P, [], _Line, _Scanned) ->    
-    {error, end_not_found};
-
-until(P, [H|T], Line, Scanned) when [H]=="\r" andalso hd(T)=="\n" ->
-    until(P, tl(T), Line+1, Scanned);
-
-until(P, [H|T], Line, Scanned) when [H]=="\n" orelse [H]== "\r" ->
-    until(P, T, Line+1, Scanned);
-
-until(P, [H|T]=Tmpl, Line, Scanned) ->
-    case P(Tmpl) of
-	{true, R} ->
-            Scanned1 = string:strip(lists:reverse(Scanned)),
-            Scanned2 = string:tokens(Scanned1, " "),
-	    {ok, Scanned2, Line, R};
-	_ ->
-	    until(P, T, Line, [H | Scanned])
+% internal functions
+
+append_char(Scanned, Char) ->
+    [String | Scanned1] = Scanned,
+    [{element(1, String), element(2, String), [Char | element(3, String)]} | Scanned1].
+
+append_text_char(Scanned, {Row, Column}, Char) ->
+    case length(Scanned) of
+        0 ->
+	    [{text, {Row, Column}, [Char]}];
+        _ ->
+	    [Token | Scanned1] = Scanned,
+	    case element(1, Token) of
+	        text ->
+		    [{text, element(2, Token), [Char | element(3, Token)]} | Scanned1];
+    		_ ->
+		    [{text, element(2, Token), [Char]} | Scanned]
+ 	    end
     end.
     end.
 
 
+char_type(Char) ->
+    case Char of 
+        C when ((C >= $a) and (C =< $z)) or ((C >= $A) and (C =< $Z)) or (C == $_) ->
+	    letter_underscore;
+	C when ((C >= $0) and (C =< $9)) ->
+    	    digit;
+ 	_ ->
+	    undefined
+    end.
 
 
-is_var_end([$}, $} | T]) -> {true, T};
-is_var_end(_) -> false.
-   
-
-is_tag_end([$\%, $} | T]) -> {true, T};
-is_tag_end(_) -> false.
-
-
-is_comment_end([$#, $} | T]) -> {true, T};
-is_comment_end(_) -> false.
 
 
 
 
-is_html_comment_end([$-, $-, $> | T]) -> {true, T};
-is_html_comment_end(_) -> false.
+%% -module(erlydtl_scanner).
+%% -author('rsaccon@gmail.com').
+%% 
+%% %% API
+%% -export([scan/1]).  
+%% 
+%% %%====================================================================
+%% %% API
+%% %%====================================================================
+%% %%--------------------------------------------------------------------
+%% %% @spec scan(T::template()) -> {ok, S::tokens()} | {error, Reason}
+%% %% @type template() = string() | binary(). Template to parse
+%% %% @type tokens() = [tuple()].
+%% %% @doc Scan the template string T and return the a token list or
+%% %% an error.
+%% %% @end
+%% %%--------------------------------------------------------------------
+%% 
+%% scan(Template) ->
+%%     scan(Template, [], 1).
+%% 
+%% scan([], Scanned, _Line) ->
+%%     Tokens = fold_strings(lists:reverse(Scanned), [], []),
+%%     {ok, Tokens};
+%% 
+%% scan([$<, $\!, $-, $-, ${, ${ | T], Scanned, Line) ->
+%%   Rules = [until(fun is_var_end/1), 
+%%            until(fun is_html_comment_end/1)],
+%%   Scan = scan2(Rules),
+%%   case Scan(T) of
+%%       {ok, Token, LinesScanned, Rest} ->
+%%           scan(Rest, [{var, Line, Token} | Scanned], Line + LinesScanned);
+%%       {error, Reason} -> 
+%%           {error, {var, Line, Reason}}
+%%   end;             
+%% 
+%% scan([${, ${ | T], Scanned, Line) ->
+%%   Rules = [until(fun is_var_end/1)],
+%%   Scan = scan2(Rules),
+%%   case Scan(T) of
+%%       {ok, Token, LinesScanned, Rest} ->
+%%           scan(Rest, [{var, Line, Token} | Scanned], Line + LinesScanned);
+%%       {error, Reason} -> 
+%%           {error, {var, Line, Reason}}
+%%   end;
+%% 
+%% scan([$<, $\!, $-, $-, ${, $\% | T], Scanned, Line) ->
+%%   Rules = [until(fun is_tag_end/1), 
+%%            until(fun is_html_comment_end/1)],
+%%   Scan = scan2(Rules),
+%%   case Scan(T) of
+%%       {ok, Token, LinesScanned, Rest} ->
+%%           scan(Rest, [{tag, Line, Token} | Scanned], Line + LinesScanned);
+%%       {error, Reason} -> 
+%%           {error, {tag, Line, Reason}}
+%%   end;
+%% 
+%% scan([${, $\% | T], Scanned, Line) ->
+%%   Rules = [until(fun is_tag_end/1)],
+%%   Scan = scan2(Rules),
+%%   case Scan(T) of
+%%       {ok, Token, LinesScanned, Rest} ->
+%%           scan(Rest, [{tag, Line, Token} | Scanned], Line + LinesScanned);
+%%       {error, Reason} -> 
+%%           {error, {tag, Line, Reason}}
+%%   end;
+%% 
+%% scan([${, $# | T], Scanned, Line) ->
+%%   Rules = [until(fun is_comment_end/1)],
+%%   Scan = scan2(Rules), 
+%%   case Scan(T) of
+%%       {ok, _Token, LinesScanned, Rest} ->
+%%           scan(Rest, Scanned, Line + LinesScanned);
+%%       {error, Reason} -> 
+%%           {error, {var, Line, Reason}}
+%%   end;
+%% 
+%% scan([H | T], Scanned, Line) when [H] == "\r" andalso hd(T) == "\n" ->
+%%     scan(tl(T), ["\r\n" | Scanned], Line+1);
+%% 
+%% scan([H | T], Scanned, Line) when [H] == "\r" orelse [H] == "\n" ->
+%%     scan(T, [H | Scanned], Line+1);
+%% 
+%% scan([H | T], Scanned, Line) ->
+%%     scan(T, [H | Scanned], Line).
+%% 
+%% 
+%% %%--------------------------------------------------------------------
+%% %% Internal Functions
+%% %%--------------------------------------------------------------------   
+%% 
+%% scan2(Rules) ->
+%%     fun(Tmpl) ->
+%%      scan2(Rules, Tmpl, [], 0)
+%%     end.
+%% 
+%% 
+%% scan2([], Tmpl, SoFar, Line) ->
+%%     {ok, lists:reverse(SoFar), Line, Tmpl};
+%% 
+%% scan2([Rule | T], Tmpl, SoFar, Line) ->
+%%     case Rule(Tmpl) of
+%%  {error, Reason} ->
+%%      {error, Reason};
+%%  {ok, Rest, LinesScanned} ->
+%%      scan2(T, Rest, SoFar, Line + LinesScanned);
+%%  {ok, Tok, LinesScanned, Rest} ->
+%%      scan2(T, Rest, [Tok | SoFar], Line + LinesScanned)
+%%     end.
+%% 
+%% fold_strings([], Folded, []) ->
+%%     lists:reverse(Folded);
+%% 
+%% fold_strings([], Folded, Acc) ->
+%%     S = {string, lists:reverse(Acc)},
+%%     lists:reverse([S | Folded]);
+%% 
+%% fold_strings([H | T], Folded, []) when is_tuple(H) ->
+%%     fold_strings(T, [translate_token(H) | Folded], []);
+%% 
+%% fold_strings([H | T], Folded, Acc) when is_tuple(H) ->
+%%     S = {string, lists:reverse(Acc)},
+%%     fold_strings(T, [translate_token(H), S | Folded], []);
+%% 
+%% fold_strings([H | T], Folded, Acc) ->
+%%     fold_strings(T, Folded, [H | Acc]).
+%% 
+%% 
+%% translate_token({var, Line, [[S] | _]}) ->
+%%     {var, Line, S};
+%% 
+%% translate_token({tag, Line, [[H | T] | _]}) ->
+%%     translate_tag(H, T, Line) ;
+%% 
+%% translate_token(Token) ->
+%%     io:format("TRACE ~p:~p unrecognized token: ~p~n",[?MODULE, ?LINE, Token]),
+%%     Token.
+%% 
+%% translate_tag("extends" = H, T, Line) ->
+%%     {list_to_atom(H), Line, T};
+%%     
+%% translate_tag("block" = H, T, Line) ->
+%%     {list_to_atom(H), Line, T};   
+%%     
+%% translate_tag("endblock" = H, T, Line) ->
+%%     {list_to_atom(H), Line, T};    
+%%     
+%% translate_tag("for" = H, T, Line) ->
+%%     {list_to_atom(H), Line, T};   
+%% 
+%% translate_tag("endfor" = H, T, Line) ->
+%%     {list_to_atom(H), Line, T};    
+%%          
+%% translate_tag(H, T, Line) ->
+%%     {tag, Line, [list_to_atom(H) | T]}.
+%% 
+%% 
+%% until(P) ->
+%%     fun (Tmpl) -> 
+%%             until(P, Tmpl, 0, []) 
+%%     end.
+%% 
+%% until(_P, [], _Line, _Scanned) ->    
+%%     {error, end_not_found};
+%% 
+%% until(P, [H|T], Line, Scanned) when [H]=="\r" andalso hd(T)=="\n" ->
+%%     until(P, tl(T), Line+1, Scanned);
+%% 
+%% until(P, [H|T], Line, Scanned) when [H]=="\n" orelse [H]== "\r" ->
+%%     until(P, T, Line+1, Scanned);
+%% 
+%% until(P, [H|T]=Tmpl, Line, Scanned) ->
+%%     case P(Tmpl) of
+%%  {true, R} ->
+%%             Scanned1 = string:strip(lists:reverse(Scanned)),
+%%             Scanned2 = string:tokens(Scanned1, " "),
+%%      {ok, Scanned2, Line, R};
+%%  _ ->
+%%      until(P, T, Line, [H | Scanned])
+%%     end.
+%% 
+%% 
+%% is_var_end([$}, $} | T]) -> {true, T};
+%% is_var_end(_) -> false.
+%%    
+%% 
+%% is_tag_end([$\%, $} | T]) -> {true, T};
+%% is_tag_end(_) -> false.
+%% 
+%% 
+%% is_comment_end([$#, $} | T]) -> {true, T};
+%% is_comment_end(_) -> false.
+%% 
+%% 
+%% is_html_comment_end([$-, $-, $> | T]) -> {true, T};
+%% is_html_comment_end(_) -> false.

+ 5 - 3
src/erlydtl/erlydtl_server.erl

@@ -1,14 +1,15 @@
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 %%% File:      erlydtl_server.erl
 %%% File:      erlydtl_server.erl
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
-%%% @copyright 2007 Roberto Saccon
+%%% @author    Evan Miller <emmiller@gmail.com>
+%%% @copyright 2008 Roberto Saccon, Evan Miller
 %%% @doc  
 %%% @doc  
 %%% Server for compiling ErlyDTL templeates
 %%% Server for compiling ErlyDTL templeates
 %%% @end  
 %%% @end  
 %%%
 %%%
 %%% The MIT License
 %%% The MIT License
 %%%
 %%%
-%%% Copyright (c) 2007 Roberto Saccon
+%%% Copyright (c) 2007 Roberto Saccon, Evan Miller
 %%%
 %%%
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% of this software and associated documentation files (the "Software"), to deal
 %%% of this software and associated documentation files (the "Software"), to deal
@@ -28,10 +29,11 @@
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% THE SOFTWARE.
 %%% THE SOFTWARE.
 %%%
 %%%
-%%% @since 2007-11-17 by Roberto Saccon
+%%% @since 2007-11-17 by Roberto Saccon, Evan Miller
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 -module(erlydtl_server).
 -module(erlydtl_server).
 -author('rsaccon@gmail.com').
 -author('rsaccon@gmail.com').
+-author('emmiller@gmail.com').
 
 
 -behaviour(gen_server).
 -behaviour(gen_server).
 	
 	

+ 6 - 4
src/erlydtl/erlydtl_sup.erl

@@ -1,14 +1,15 @@
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 %%% File:      erlydtl_sup.erl
 %%% File:      erlydtl_sup.erl
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
 %%% @author    Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
-%%% @copyright 2007 Roberto Saccon
+%%% @author    Evan Miller <emmiller@gmail.com>
+%%% @copyright 2008 Roberto Saccon, Evan Miller
 %%% @doc  
 %%% @doc  
-%%%
+%%% ErlyDtl supervisor
 %%% @end  
 %%% @end  
 %%%
 %%%
 %%% The MIT License
 %%% The MIT License
 %%%
 %%%
-%%% Copyright (c) 2007 Roberto Saccon
+%%% Copyright (c) 2007 Roberto Saccon, Evan Miller
 %%%
 %%%
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% Permission is hereby granted, free of charge, to any person obtaining a copy
 %%% of this software and associated documentation files (the "Software"), to deal
 %%% of this software and associated documentation files (the "Software"), to deal
@@ -28,10 +29,11 @@
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %%% THE SOFTWARE.
 %%% THE SOFTWARE.
 %%%
 %%%
-%%% @since 2007-12-15 by Roberto Saccon
+%%% @since 2007-12-15 by Roberto Saccon, Evan Miller
 %%%-------------------------------------------------------------------
 %%%-------------------------------------------------------------------
 -module(erlydtl_sup).
 -module(erlydtl_sup).
 -author('rsaccon@gmail.com').
 -author('rsaccon@gmail.com').
+-author('emmiller@gmail.com').
 
 
 -behaviour(supervisor).
 -behaviour(supervisor).