Browse Source

added optional "OutDir" argument to compile command

Roberto Saccon 17 years ago
parent
commit
27cac56db6
2 changed files with 173 additions and 169 deletions
  1. 1 2
      Makefile
  2. 172 167
      src/erlydtl/erlydtl_compiler.erl

+ 1 - 2
Makefile

@@ -5,8 +5,7 @@ APP_NAME=erlydtl
 
 
 
 
 all:
 all:
-	( $(ERL) -make && \
-	if [ ! -e ebin/$(APP_NAME).app ]; then cp -f src/$(APP_NAME)/$(APP_NAME).app.src ebin/$(APP_NAME).app; fi )	
+	$(ERL) -make 
 
 
 run:
 run:
 	$(ERL) -pa `pwd`/ebin -s $(APP_NAME)
 	$(ERL) -pa `pwd`/ebin -s $(APP_NAME)

+ 172 - 167
src/erlydtl/erlydtl_compiler.erl

@@ -35,69 +35,74 @@
 -author('emmiller@gmail.com').
 -author('emmiller@gmail.com').
 -author('emmiller@gmail.com').
 -author('emmiller@gmail.com').
 
 
--export([compile/3, compile/2, compile/4, parse/1, scan/1]).
+-export([compile/2, compile/3, compile/4, compile/5, parse/1, scan/1]).
 
 
 -record(dtl_context, {
 -record(dtl_context, {
-	local_scopes = [], 
-	block_dict = dict:new(), 
-	auto_escape = off, 
-	doc_root = "", 
-	parse_trail = []}).
+    local_scopes = [], 
+    block_dict = dict:new(), 
+    auto_escape = off, 
+    doc_root = "", 
+    parse_trail = []}).
 
 
 compile(File, Module) ->
 compile(File, Module) ->
     compile(File, "", Module).
     compile(File, "", Module).
 
 
 compile(File, DocRoot, Module) ->
 compile(File, DocRoot, Module) ->
     compile(File, DocRoot, Module, "render").
     compile(File, DocRoot, Module, "render").
-
+    
 compile(File, DocRoot, Module, Function) ->
 compile(File, DocRoot, Module, Function) ->
+    compile(File, DocRoot, Module, Function, "ebin").
+    
+compile(File, DocRoot, Module, Function, OutDir) ->
     case parse(File) of
     case parse(File) of
         {ok, DjangoAst} ->
         {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")]),
+        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]],
+        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
+        case compile:forms(Forms) of
+            {ok, Module1, Bin} ->       
+            Path = filename:join([OutDir, atom_to_list(Module1) ++ ".beam"]),
+            case file:write_file(Path, 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.
     end.
-	    
+
+        
 scan(File) ->
 scan(File) ->
     case file:read_file(File) of
     case file:read_file(File) of
         {ok, B} ->
         {ok, B} ->
-	    erlydtl_scanner:scan(binary_to_list(B));
+        erlydtl_scanner:scan(binary_to_list(B));
     _ ->
     _ ->
-    	{error, "reading " ++ File ++ " failed "}
+        {error, "reading " ++ File ++ " failed "}
     end.
     end.
 
 
 parse(File) ->
 parse(File) ->
     case scan(File) of
     case scan(File) of
-	{ok, Tokens} ->
-	    erlydtl_parser:parse(Tokens);
-	Err ->
-	    Err
+    {ok, Tokens} ->
+        erlydtl_parser:parse(Tokens);
+    Err ->
+        Err
     end.
     end.
 
 
 full_path(File, DocRoot) ->
 full_path(File, DocRoot) ->
@@ -111,74 +116,74 @@ body_ast([{extends, {string_literal, _Pos, String}} | ThisAst], Context) ->
     File = full_path(unescape_string_literal(String), Context#dtl_context.doc_root),
     File = full_path(unescape_string_literal(String), Context#dtl_context.doc_root),
     case lists:member(File, Context#dtl_context.parse_trail) of
     case lists:member(File, Context#dtl_context.parse_trail) of
         true ->
         true ->
-	    {error, "Circular file inclusion!"};
+        {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]
-		    })
+        {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;
     end;
 
 
 body_ast(DjangoAst, Context) ->
 body_ast(DjangoAst, Context) ->
     erl_syntax:list(
     erl_syntax:list(
     lists:map(fun
     lists:map(fun
         ({'block', {identifier, _, Name}, Contents}) ->
         ({'block', {identifier, _, Name}, Contents}) ->
-	    Block = case dict:find(Name, Context#dtl_context.block_dict) of
-			{ok, ChildBlock} ->
-			    ChildBlock;
-			_ ->
-			    Contents
-		    end,
-	    body_ast(Block, Context);
+        Block = case dict:find(Name, Context#dtl_context.block_dict) of
+            {ok, ChildBlock} ->
+                ChildBlock;
+            _ ->
+                Contents
+            end,
+        body_ast(Block, Context);
         ({'comment', _Contents}) ->
         ({'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);
+        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', {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);
+        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}) ->
         ({'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);
+    ({'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) ->
 filter_ast(Variable, Filter, Context) ->
@@ -188,24 +193,24 @@ filter_ast(Variable, Filter, Context) ->
 % so don't do any more escaping
 % so don't do any more escaping
     case search_for_escape_filter(Variable, Filter, Context) of
     case search_for_escape_filter(Variable, Filter, Context) of
         on ->
         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})
+        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.
     end.
 
 
 filter_ast_noescape(Variable, [{identifier, _, "escape"}], Context) ->
 filter_ast_noescape(Variable, [{identifier, _, "escape"}], Context) ->
     body_ast([Variable], Context);
     body_ast([Variable], Context);
 filter_ast_noescape(Variable, [{identifier, _, Name} | Arg], Context) ->
 filter_ast_noescape(Variable, [{identifier, _, Name} | Arg], Context) ->
     erl_syntax:application(erl_syntax:atom(erlydtl_filters), erl_syntax:atom(Name), 
     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]).
+        [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}) ->
 search_for_escape_filter(_, _, #dtl_context{auto_escape = on}) ->
     on;
     on;
@@ -226,84 +231,84 @@ resolve_variable_ast({{identifier, _, VarName}}, Context) ->
 
 
 resolve_variable_ast({{identifier, _, VarName}, {identifier, _, AttrName}}, Context) ->
 resolve_variable_ast({{identifier, _, VarName}, {identifier, _, AttrName}}, Context) ->
     erl_syntax:application(erl_syntax:atom(proplists), erl_syntax:atom(get_value),
     erl_syntax:application(erl_syntax:atom(proplists), erl_syntax:atom(get_value),
-	   [erl_syntax:atom(AttrName), resolve_variable_name_ast(VarName, Context)]).
+       [erl_syntax:atom(AttrName), resolve_variable_name_ast(VarName, Context)]).
 
 
 resolve_variable_name_ast(VarName, Context) ->
 resolve_variable_name_ast(VarName, Context) ->
     VarValue = lists:foldl(fun(Scope, Value) ->
     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),
+        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
     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,
+    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
     case Context#dtl_context.auto_escape of
         on ->
         on ->
-	    erl_syntax:application(erl_syntax:atom(emiller_filters), erl_syntax:atom(force_escape),
-		    [VarValue1]);
- 	_ ->
-	    VarValue1
+        erl_syntax:application(erl_syntax:atom(emiller_filters), erl_syntax:atom(force_escape),
+            [VarValue1]);
+    _ ->
+        VarValue1
     end.
     end.
 
 
 ifelse_ast(Variable, IfContentsAst, ElseContentsAst, Context) ->
 ifelse_ast(Variable, IfContentsAst, ElseContentsAst, Context) ->
     erl_syntax:case_expr(resolve_variable_ast(Variable, 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])
-	    ]).
+        [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) ->
 for_loop_ast(Iterator, List, Contents, Context) ->
     erl_syntax:application(erl_syntax:atom(lists), erl_syntax:atom(map),
     erl_syntax:application(erl_syntax:atom(lists), erl_syntax:atom(map),
-	[erl_syntax:fun_expr([
-	    erl_syntax:clause([erl_syntax: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)]).
+    [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) ->
 for_list_loop_ast(IteratorList, List, Contents, Context) ->
     erl_syntax:application(erl_syntax:atom(lists), erl_syntax:atom(map),
     erl_syntax:application(erl_syntax:atom(lists), erl_syntax:atom(map),
-	[erl_syntax:fun_expr([
-	    erl_syntax:clause([erl_syntax: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]})]
-		)]),
+    [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)]).
         resolve_variable_name_ast(list_to_atom(List), Context)]).
 
 
 tag_ast(Name, Args, Context) ->
 tag_ast(Name, Args, Context) ->
     InterpretedArgs = lists:map(fun
     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),
+        ({{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
     case parse(filename:join([erlydtl_deps:get_base_dir(), "priv", "tags", Name])) of
         {ok, TagAst} ->
         {ok, TagAst} ->
-	    body_ast(TagAst, Context#dtl_context{
-		    local_scopes = [ InterpretedArgs | Context#dtl_context.local_scopes ]});
-	_ ->
-	    {error, Name, "Loading tag source failed"}
+        body_ast(TagAst, Context#dtl_context{
+            local_scopes = [ InterpretedArgs | Context#dtl_context.local_scopes ]});
+    _ ->
+        {error, Name, "Loading tag source failed"}
     end.
     end.
 
 
 unescape_string_literal(String) ->
 unescape_string_literal(String) ->