codegen:gen_module/3 support

This commit is contained in:
Ulf Wiger 2012-12-19 17:30:23 +01:00
parent c55c8861cd
commit f83f77c2cc
3 changed files with 86 additions and 6 deletions

View File

@ -64,10 +64,10 @@ Forms = [{attribute,1,file,{"./ex1.erl",1}},
<table width="100%" border="0" summary="list of modules">
<tr><td><a href="http://github.com/esl/parse_trans/blob/master/doc/ct_expand.md" class="module">ct_expand</a></td></tr>
<tr><td><a href="http://github.com/esl/parse_trans/blob/master/doc/exprecs.md" class="module">exprecs</a></td></tr>
<tr><td><a href="http://github.com/esl/parse_trans/blob/master/doc/parse_trans.md" class="module">parse_trans</a></td></tr>
<tr><td><a href="http://github.com/esl/parse_trans/blob/master/doc/parse_trans_codegen.md" class="module">parse_trans_codegen</a></td></tr>
<tr><td><a href="http://github.com/esl/parse_trans/blob/master/doc/parse_trans_mod.md" class="module">parse_trans_mod</a></td></tr>
<tr><td><a href="http://github.com/esl/parse_trans/blob/master/doc/parse_trans_pp.md" class="module">parse_trans_pp</a></td></tr></table>
<tr><td><a href="http://github.com/esl/parse_trans/blob/2.5.4/doc/ct_expand.md" class="module">ct_expand</a></td></tr>
<tr><td><a href="http://github.com/esl/parse_trans/blob/2.5.4/doc/exprecs.md" class="module">exprecs</a></td></tr>
<tr><td><a href="http://github.com/esl/parse_trans/blob/2.5.4/doc/parse_trans.md" class="module">parse_trans</a></td></tr>
<tr><td><a href="http://github.com/esl/parse_trans/blob/2.5.4/doc/parse_trans_codegen.md" class="module">parse_trans_codegen</a></td></tr>
<tr><td><a href="http://github.com/esl/parse_trans/blob/2.5.4/doc/parse_trans_mod.md" class="module">parse_trans_mod</a></td></tr>
<tr><td><a href="http://github.com/esl/parse_trans/blob/2.5.4/doc/parse_trans_pp.md" class="module">parse_trans_pp</a></td></tr></table>

View File

@ -117,6 +117,20 @@ a data type representing the abstract form of the list of expressions in
the body. The arguments of the function clause are ignored, but can be
used to ensure that all necessary variables are known to the compiler.
##gen_module/3##
Generates abstract forms for a complete module definition.
Usage: `codegen:gen_module(ModuleName, Exports, Functions)`
`ModuleName` is either an atom or a `{'$var', V}` reference.
`Exports` is a list of `{Function, Arity}` tuples.
`Functions` is a list of `{Name, Fun}` tuples analogous to that for
`gen_functions/1`.
##Variable substitution##

View File

@ -95,6 +95,19 @@
%% the body. The arguments of the function clause are ignored, but can be
%% used to ensure that all necessary variables are known to the compiler.
%%
%% <h2>gen_module/3</h2>
%%
%% Generates abstract forms for a complete module definition.
%%
%% Usage: `codegen:gen_module(ModuleName, Exports, Functions)'
%%
%% `ModuleName' is either an atom or a <code>{'$var', V}</code> reference.
%%
%% `Exports' is a list of `{Function, Arity}' tuples.
%%
%% `Functions' is a list of `{Name, Fun}' tuples analogous to that for
%% `gen_functions/1'.
%%
%% <h2>Variable substitution</h2>
%%
%% It is possible to do some limited expansion (importing a value
@ -145,6 +158,11 @@ xform_fun(application, Form, _Ctxt, Acc) ->
MFA = erl_syntax_lib:analyze_application(Form),
L = erl_syntax:get_pos(Form),
case MFA of
{codegen, {gen_module, 3}} ->
[NameF, ExportsF, FunsF] =
erl_syntax:application_arguments(Form),
NewForms = gen_module(NameF, ExportsF, FunsF, L, Acc),
{NewForms, Acc};
{codegen, {gen_function, 2}} ->
[NameF, FunF] =
erl_syntax:application_arguments(Form),
@ -177,6 +195,54 @@ xform_fun(application, Form, _Ctxt, Acc) ->
xform_fun(_, Form, _Ctxt, Acc) ->
{Form, Acc}.
gen_module(NameF, ExportsF, FunsF, L, Acc) ->
try gen_module_(NameF, ExportsF, FunsF, L, Acc)
catch
error:E ->
ErrStr = parse_trans:format_exception(error, E),
{error, {L, ?MODULE, ErrStr}}
end.
gen_module_(NameF, ExportsF, FunsF, L0, Acc) ->
P = erl_syntax:get_pos(NameF),
ModF = case parse_trans:revert_form(NameF) of
{atom,_,_} = Am -> Am;
{tuple,_,[{atom,_,'$var'},
{var,_,V}]} ->
{var,P,V}
end,
cons(
{cons,P,
{tuple,P,
[{atom,P,attribute},
{integer,P,1},
{atom,P,module},
ModF]},
substitute(
abstract(
[{attribute,P,export,
lists:map(
fun(TupleF) ->
[F,A] = erl_syntax:tuple_elements(TupleF),
{erl_syntax:atom_value(F), erl_syntax:integer_value(A)}
end, erl_syntax:list_elements(ExportsF))}]))},
lists:map(
fun(FTupleF) ->
Pos = erl_syntax:get_pos(FTupleF),
[FName, FFunF] = erl_syntax:tuple_elements(FTupleF),
gen_function(FName, FFunF, L0, Pos, Acc)
end, erl_syntax:list_elements(FunsF))).
cons({cons,L,H,T}, L2) ->
{cons,L,H,cons(T, L2)};
cons({nil,L}, [H|T]) ->
Pos = erl_syntax:get_pos(H),
{cons,L,H,cons({nil,Pos}, T)};
cons({nil,L}, []) ->
{nil,L}.
gen_function(NameF, FunF, L0, L, Acc) ->
try gen_function_(NameF, FunF, L, Acc)
catch