Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Erlydtl compiler #44

Merged
merged 2 commits into from

2 participants

@saleyn

Three bug fixes described in individual commits

@saleyn

Also I removed the commit that exported render_tag/3.

@saleyn saleyn Property handle compiler return code
* Bug fix: When compiler_option includes 'return', properly handle Error
and Warnings returned by the Erlang compiler, so that the user still gets
'ok' instead of {ok, Module, Bin, {Errors, Warnings}}, which rebar doesn't
property handle.

* Add `verbose` compiler option.
f74b94f
@saleyn

Please see the changes in both commits that address your concerns. Promoted verbose to be 1st class ErlyDTL option, fixed the compiler to save custom tags argument key as atom as opposed to be a string.

@evanmiller
Owner

Hmm. Don't you just want

erl_syntax:string(atom_to_list(Key)) ?

So the semantics of the BEAM are unchanged.

@saleyn

I was unsure as to what you had in mind when you wrote in the implementation erl_syntax:string(Atom). Was it that you wanted the result to be represented as an atom or a string? With that the beam compiled fine, and I am unsure what the impact of that implementation would be at run-time. But an attempt to decompile the beam into the source code failed miserably, so I wanted to fix that. Just let me know if you want the named arguments to be stored as atoms or strings, and I'll patch it accordingly. For my own purpose it doesn't make a difference, so the decision is yours.

@evanmiller
Owner

Please store them as strings as they are stored now.

@saleyn saleyn Bug fix in saving template containing custom_tags_modules feature
* Bug fix: when compiling templates with custom tags with a given
custom_tags_modules option, the arguments are saved as atoms in the
AST as opposed to strings. This causes a failure when decompiling
the beam and printing its source by erl_prettypr.

In order to illustrate the issue compile the template test.dtl containing:

    {% tr xxx="ABC" %}

with options:

    [
        , {doc_root, "src"}
        , {out_dir,   "ebin"}
        , {compiler_options, [verbose, debug_info, report, return]}
        , {custom_tags_modules, [custom_tags]}
        , {force_recompile, true}
    ].

where custom_tags module is:

    -module(custom_tags).

    -export([tr/2]).

    tr(Vars, Context) ->
        io:format("Vars: ~p\n  Context: ~p\n", [Vars, Context]),
        [].

Observe the return code of erlydtl_compiler:compile/3, and also try to
decompile the emitted beam with:
[http://erlang.org/pipermail/erlang-questions/2006-January/018813.html]
15a46cd
@saleyn

Ok, this last commit does it the way you recommended.

@evanmiller
Owner

Thanks!

@evanmiller evanmiller merged commit 2ef2f7d into from
@saleyn

Great! Thanks for merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 26, 2012
  1. @saleyn

    Property handle compiler return code

    saleyn authored
    * Bug fix: When compiler_option includes 'return', properly handle Error
    and Warnings returned by the Erlang compiler, so that the user still gets
    'ok' instead of {ok, Module, Bin, {Errors, Warnings}}, which rebar doesn't
    property handle.
    
    * Add `verbose` compiler option.
  2. @saleyn

    Bug fix in saving template containing custom_tags_modules feature

    saleyn authored
    * Bug fix: when compiling templates with custom tags with a given
    custom_tags_modules option, the arguments are saved as atoms in the
    AST as opposed to strings. This causes a failure when decompiling
    the beam and printing its source by erl_prettypr.
    
    In order to illustrate the issue compile the template test.dtl containing:
    
        {% tr xxx="ABC" %}
    
    with options:
    
        [
            , {doc_root, "src"}
            , {out_dir,   "ebin"}
            , {compiler_options, [verbose, debug_info, report, return]}
            , {custom_tags_modules, [custom_tags]}
            , {force_recompile, true}
        ].
    
    where custom_tags module is:
    
        -module(custom_tags).
    
        -export([tr/2]).
    
        tr(Vars, Context) ->
            io:format("Vars: ~p\n  Context: ~p\n", [Vars, Context]),
            [].
    
    Observe the return code of erlydtl_compiler:compile/3, and also try to
    decompile the emitted beam with:
    [http://erlang.org/pipermail/erlang-questions/2006-January/018813.html]
This page is out of date. Refresh to see the latest.
Showing with 40 additions and 15 deletions.
  1. +1 −0  README.markdown
  2. +39 −15 src/erlydtl_compiler.erl
View
1  README.markdown
@@ -102,6 +102,7 @@ Defaults to [].
* `binary_strings` - Whether to compile strings as binary terms (rather than
lists). Defaults to `true`.
+* `verbose` - Enable verbose printing of compilation results.
Helper compilation
------------------
View
54 src/erlydtl_compiler.erl
@@ -86,7 +86,7 @@ compile(Binary, Module, Options) when is_binary(Binary) ->
{ok, DjangoParseTree} ->
case compile_to_binary(File, DjangoParseTree,
init_dtl_context(File, Module, Options), CheckSum) of
- {ok, Module1, _} ->
+ {ok, Module1, _, _} ->
{ok, Module1};
Err ->
Err
@@ -102,8 +102,8 @@ compile(File, Module, Options) ->
ok;
{ok, DjangoParseTree, CheckSum} ->
case compile_to_binary(File, DjangoParseTree, Context, CheckSum) of
- {ok, Module1, Bin} ->
- write_binary(Module1, Bin, Options);
+ {ok, Module1, Bin, Warnings} ->
+ write_binary(Module1, Bin, Options, Warnings);
Err ->
Err
end;
@@ -143,8 +143,8 @@ compile_dir(Dir, Module, Options) ->
case ParserErrors of
[] ->
case compile_multiple_to_binary(Dir, ParserResults, Context) of
- {ok, Module1, Bin} ->
- write_binary(Module1, Bin, Options);
+ {ok, Module1, Bin, Warnings} ->
+ write_binary(Module1, Bin, Options, Warnings);
Err ->
Err
end;
@@ -156,17 +156,31 @@ compile_dir(Dir, Module, Options) ->
%% Internal functions
%%====================================================================
-write_binary(Module1, Bin, Options) ->
+write_binary(Module1, Bin, Options, Warnings) ->
+ Verbose = proplists:get_value(verbose, Options, false),
case proplists:get_value(out_dir, Options) of
undefined ->
+ Verbose =:= true andalso
+ io:format("Template module: ~w not saved (no out_dir option)\n", [Module1]),
ok;
OutDir ->
BeamFile = filename:join([OutDir, atom_to_list(Module1) ++ ".beam"]),
+
+ Verbose =:= true andalso
+ io:format("Template module: ~w -> ~s~s\n",
+ [Module1, BeamFile,
+ case Warnings of
+ [] -> "";
+ _ -> io_lib:format("\n Warnings: ~p", [Warnings])
+ end]),
+
case file:write_file(BeamFile, Bin) of
ok ->
ok;
{error, Reason} ->
- {error, lists:concat(["beam generation failed (", Reason, "): ", BeamFile])}
+ {error, lists:flatten(
+ io_lib:format("Beam generation of '~s' failed: ~p",
+ [BeamFile, file:format_error(Reason)]))}
end
end.
@@ -205,17 +219,22 @@ compile_to_binary(File, DjangoParseTree, Context, CheckSum) ->
compile_forms_and_reload(File, Forms, CompilerOptions) ->
case compile:forms(Forms, CompilerOptions) of
{ok, Module1, Bin} ->
- code:purge(Module1),
- case code:load_binary(Module1, atom_to_list(Module1) ++ ".erl", Bin) of
- {module, _} -> {ok, Module1, Bin};
- _ -> {error, lists:concat(["code reload failed: ", Module1])}
- end;
+ load_code(Module1, Bin, []);
+ {ok, Module1, Bin, Warnings} ->
+ load_code(Module1, Bin, Warnings);
error ->
{error, lists:concat(["compilation failed: ", File])};
OtherError ->
OtherError
end.
+load_code(Module, Bin, Warnings) ->
+ code:purge(Module),
+ case code:load_binary(Module, atom_to_list(Module) ++ ".erl", Bin) of
+ {module, _} -> {ok, Module, Bin, Warnings};
+ _ -> {error, lists:concat(["code reload failed: ", Module])}
+ end.
+
init_dtl_context(File, Module, Options) when is_list(Module) ->
init_dtl_context(File, list_to_atom(Module), Options);
init_dtl_context(File, Module, Options) ->
@@ -1218,17 +1237,22 @@ full_path(File, DocRoot) ->
%% Custom tags
%%-------------------------------------------------------------------
+key_to_string(Key) when is_atom(Key) ->
+ erl_syntax:string(atom_to_list(Key));
+key_to_string(Key) when is_list(Key) ->
+ erl_syntax:string(Key).
+
tag_ast(Name, Args, Context, TreeWalker) ->
{InterpretedArgs, AstInfo} = lists:mapfoldl(fun
({{identifier, _, Key}, {string_literal, _, Value}}, AstInfoAcc) ->
{{StringAst, StringAstInfo}, _} = string_ast(unescape_string_literal(Value), Context, TreeWalker),
- {erl_syntax:tuple([erl_syntax:string(Key), StringAst]), merge_info(StringAstInfo, AstInfoAcc)};
+ {erl_syntax:tuple([key_to_string(Key), StringAst]), merge_info(StringAstInfo, AstInfoAcc)};
({{identifier, _, Key}, {trans, StringLiteral}}, AstInfoAcc) ->
{{TransAst, TransAstInfo}, _} = translated_ast(StringLiteral, Context, TreeWalker),
- {erl_syntax:tuple([erl_syntax:string(Key), TransAst]), merge_info(TransAstInfo, AstInfoAcc)};
+ {erl_syntax:tuple([key_to_string(Key), TransAst]), merge_info(TransAstInfo, AstInfoAcc)};
({{identifier, _, Key}, Value}, AstInfoAcc) ->
{AST, VarName} = resolve_variable_ast(Value, Context),
- {erl_syntax:tuple([erl_syntax:string(Key), format(AST,Context, TreeWalker)]), merge_info(#ast_info{var_names=[VarName]}, AstInfoAcc)}
+ {erl_syntax:tuple([key_to_string(Key), format(AST,Context, TreeWalker)]), merge_info(#ast_info{var_names=[VarName]}, AstInfoAcc)}
end, #ast_info{}, Args),
{RenderAst, RenderInfo} = custom_tags_modules_ast(Name, InterpretedArgs, Context),
Something went wrong with that request. Please try again.