mirror of
https://github.com/valitydev/parse_trans.git
synced 2024-11-06 00:25:16 +00:00
codegen:gen_function_alt/3
This commit is contained in:
parent
f889dea6ee
commit
663ddebb6e
@ -1,73 +0,0 @@
|
||||
|
||||
|
||||
#The parse_trans application#
|
||||
|
||||
|
||||
__Authors:__ Ulf Wiger ([`ulf@feuerlabs.com`](mailto:ulf@feuerlabs.com)).
|
||||
|
||||
A generic parse transform library
|
||||
This library is intended to simplify the task of writing parse transform
|
||||
modules for Erlang.
|
||||
|
||||
#Introduction to parse transforms#
|
||||
|
||||
|
||||
##The simplest transform##
|
||||
|
||||
|
||||
The very simplest transform we can make is one that doesn't
|
||||
change a thing. For convenience, we will at least print the forms.
|
||||
This will enlighten us as to what the forms actually look like.<pre>
|
||||
-module(test_pt).
|
||||
|
||||
-export([parse_transform/2]).
|
||||
|
||||
parse_transform(Forms, _Options) ->
|
||||
io:fwrite("Forms = ~p~n", [Forms]),
|
||||
Forms.
|
||||
</pre>
|
||||
|
||||
Trying this with a very simple module:<pre>
|
||||
-module(ex1).
|
||||
-export([add/2]).
|
||||
|
||||
add(X,Y) ->
|
||||
X + Y.
|
||||
</pre><pre>
|
||||
1> c(ex1, [{parse_transform,test_pt}]).
|
||||
Forms = [{attribute,1,file,{"./ex1.erl",1}},
|
||||
{attribute,1,module,ex1},
|
||||
{attribute,2,export,[{add,2}]},
|
||||
{function,4,add,2,
|
||||
[{clause,4,
|
||||
[{var,4,'X'},{var,4,'Y'}],
|
||||
[],
|
||||
[{op,5,'+',{var,5,'X'},{var,5,'Y'}}]}]},
|
||||
{eof,6}]
|
||||
{ok,ex1}
|
||||
</pre>
|
||||
|
||||
##`transform/4`##
|
||||
|
||||
|
||||
|
||||
...
|
||||
|
||||
#Current limitations#
|
||||
|
||||
|
||||
|
||||
...
|
||||
|
||||
|
||||
##Modules##
|
||||
|
||||
|
||||
<table width="100%" border="0" summary="list of modules">
|
||||
<tr><td><a href="ct_expand.md" class="module">ct_expand</a></td></tr>
|
||||
<tr><td><a href="exprecs.md" class="module">exprecs</a></td></tr>
|
||||
<tr><td><a href="parse_trans.md" class="module">parse_trans</a></td></tr>
|
||||
<tr><td><a href="parse_trans_codegen.md" class="module">parse_trans_codegen</a></td></tr>
|
||||
<tr><td><a href="parse_trans_mod.md" class="module">parse_trans_mod</a></td></tr>
|
||||
<tr><td><a href="parse_trans_pp.md" class="module">parse_trans_pp</a></td></tr></table>
|
||||
|
@ -1,98 +0,0 @@
|
||||
|
||||
|
||||
#Module ct_expand#
|
||||
* [Description](#description)
|
||||
* [Data Types](#types)
|
||||
* [Function Index](#index)
|
||||
* [Function Details](#functions)
|
||||
|
||||
|
||||
Compile-time expansion utility.
|
||||
|
||||
__Authors:__ : Ulf Wiger ([`ulf@feuerlabs.com`](mailto:ulf@feuerlabs.com)).<a name="description"></a>
|
||||
|
||||
##Description##
|
||||
|
||||
|
||||
|
||||
|
||||
This module serves as an example of parse_trans-based transforms,
|
||||
but might also be a useful utility in its own right.
|
||||
The transform searches for calls to the pseudo-function
|
||||
`ct_expand:term(Expr)`, and then replaces the call site with the
|
||||
result of evaluating `Expr` at compile-time.
|
||||
|
||||
|
||||
|
||||
For example, the line
|
||||
|
||||
|
||||
|
||||
`ct_expand:term(lists:sort([3,5,2,1,4]))`
|
||||
|
||||
|
||||
|
||||
would be expanded at compile-time to `[1,2,3,4,5]`.
|
||||
|
||||
|
||||
|
||||
ct_expand has now been extended to also evaluate calls to local functions.
|
||||
See examples/ct_expand_test.erl for some examples.
|
||||
|
||||
|
||||
|
||||
A debugging facility exists: passing the option {ct_expand_trace, Flags} as an option,
|
||||
or adding a compiler attribute -ct_expand_trace(Flags) will enable a form of call trace.
|
||||
|
||||
`Flags` can be `[]` (no trace) or `[F]`, where `F` is `c` (call trace),
|
||||
`r` (return trace), or `x` (exception trace)'.
|
||||
|
||||
<a name="types"></a>
|
||||
|
||||
##Data Types##
|
||||
|
||||
|
||||
|
||||
|
||||
###<a name="type-form">form()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>form() = any()</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-forms">forms()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>forms() = [<a href="#type-form">form()</a>]</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-options">options()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>options() = [{atom(), any()}]</pre>
|
||||
<a name="index"></a>
|
||||
|
||||
##Function Index##
|
||||
|
||||
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#parse_transform-2">parse_transform/2</a></td><td></td></tr></table>
|
||||
|
||||
|
||||
<a name="functions"></a>
|
||||
|
||||
##Function Details##
|
||||
|
||||
<a name="parse_transform-2"></a>
|
||||
|
||||
###parse_transform/2##
|
||||
|
||||
|
||||
<pre>parse_transform(Forms::<a href="#type-forms">forms()</a>, Options::<a href="#type-options">options()</a>) -> <a href="#type-forms">forms()</a></pre>
|
||||
<br></br>
|
||||
|
||||
|
514
doc/exprecs.md
514
doc/exprecs.md
@ -1,514 +0,0 @@
|
||||
|
||||
|
||||
#Module exprecs#
|
||||
* [Description](#description)
|
||||
* [Data Types](#types)
|
||||
* [Function Index](#index)
|
||||
* [Function Details](#functions)
|
||||
|
||||
|
||||
Parse transform for generating record access functions.
|
||||
|
||||
__Authors:__ : Ulf Wiger ([`ulf.wiger@ericsson.com`](mailto:ulf.wiger@ericsson.com)).<a name="description"></a>
|
||||
|
||||
##Description##
|
||||
|
||||
|
||||
This parse transform can be used to reduce compile-time
|
||||
dependencies in large systems.
|
||||
|
||||
|
||||
In the old days, before records, Erlang programmers often wrote
|
||||
access functions for tuple data. This was tedious and error-prone.
|
||||
The record syntax made this easier, but since records were implemented
|
||||
fully in the pre-processor, a nasty compile-time dependency was
|
||||
introduced.
|
||||
|
||||
|
||||
This module automates the generation of access functions for
|
||||
records. While this method cannot fully replace the utility of
|
||||
pattern matching, it does allow a fair bit of functionality on
|
||||
records without the need for compile-time dependencies.
|
||||
|
||||
|
||||
Whenever record definitions need to be exported from a module,
|
||||
inserting a compiler attribute,
|
||||
`export_records([RecName|...])` causes this transform
|
||||
to lay out access functions for the exported records:
|
||||
|
||||
As an example, consider the following module:
|
||||
<pre>
|
||||
-module(test_exprecs).
|
||||
-export([f/0]).
|
||||
-compile({parse_transform, exprecs}).
|
||||
-record(r, {a = 0 :: integer(),
|
||||
b = 0 :: integer(),
|
||||
c = 0 :: integer()}).
|
||||
-record(s,{a}).
|
||||
-export_records([r,s]).
|
||||
f() ->
|
||||
{new,'#new-r'([])}.</pre>
|
||||
|
||||
|
||||
|
||||
Compiling this (assuming exprecs is in the path) will produce the
|
||||
following code.
|
||||
|
||||
<pre>
|
||||
-module(test_exprecs).
|
||||
-compile({pt_pp_src,true}).
|
||||
-export([f/0]).
|
||||
-record(r,{a = 0 :: integer(),b = 0 :: integer(),c = 0 :: integer()}).
|
||||
-record(s,{a}).
|
||||
-export_records([r,s]).
|
||||
-export(['#exported_records-'/0,
|
||||
'#new-'/1,
|
||||
'#info-'/1,
|
||||
'#info-'/2,
|
||||
'#pos-'/2,
|
||||
'#is_record-'/1,
|
||||
'#is_record-'/2,
|
||||
'#get-'/2,
|
||||
'#set-'/2,
|
||||
'#fromlist-'/2,
|
||||
'#lens-'/2,
|
||||
'#new-r'/0,
|
||||
'#new-r'/1,
|
||||
'#get-r'/2,
|
||||
'#set-r'/2,
|
||||
'#pos-r'/1,
|
||||
'#fromlist-r'/1,
|
||||
'#fromlist-r'/2,
|
||||
'#info-r'/1,
|
||||
'#lens-r'/1,
|
||||
'#new-s'/0,
|
||||
'#new-s'/1,
|
||||
'#get-s'/2,
|
||||
'#set-s'/2,
|
||||
'#pos-s'/1,
|
||||
'#fromlist-s'/1,
|
||||
'#fromlist-s'/2,
|
||||
'#info-s'/1,
|
||||
'#lens-s'/1]).
|
||||
-type '#prop-r'() :: {a, integer()} | {b, integer()} | {c, integer()}.
|
||||
-type '#attr-r'() :: a | b | c.
|
||||
-type '#prop-s'() :: {a, any()}.
|
||||
-type '#attr-s'() :: a.
|
||||
-spec '#exported_records-'() -> [r | s].
|
||||
'#exported_records-'() ->
|
||||
[r,s].
|
||||
-spec '#new-'(r) -> #r{};
|
||||
(s) -> #s{}.
|
||||
'#new-'(r) ->
|
||||
'#new-r'();
|
||||
'#new-'(s) ->
|
||||
'#new-s'().
|
||||
-spec '#info-'(r) -> [a | b | c];
|
||||
(s) -> [a].
|
||||
'#info-'(RecName) ->
|
||||
'#info-'(RecName, fields).
|
||||
-spec '#info-'(r, size) -> 4;
|
||||
(r, fields) -> [a | b | c];
|
||||
(s, size) -> 2;
|
||||
(s, fields) -> [a].
|
||||
'#info-'(r, Info) ->
|
||||
'#info-r'(Info);
|
||||
'#info-'(s, Info) ->
|
||||
'#info-s'(Info).
|
||||
-spec '#pos-'(r, a) -> 1;
|
||||
(r, b) -> 2;
|
||||
(r, c) -> 3;
|
||||
(s, a) -> 1.
|
||||
'#pos-'(r, Attr) ->
|
||||
'#pos-r'(Attr);
|
||||
'#pos-'(s, Attr) ->
|
||||
'#pos-s'(Attr).
|
||||
-spec '#is_record-'(#r{}) -> true;
|
||||
(#s{}) -> true;
|
||||
(any()) -> false.
|
||||
'#is_record-'(X) ->
|
||||
if
|
||||
is_record(X, r) ->
|
||||
true;
|
||||
is_record(X, s) ->
|
||||
true;
|
||||
true ->
|
||||
false
|
||||
end.
|
||||
-spec '#is_record-'(r, #r{}) -> true;
|
||||
(s, #s{}) -> true;
|
||||
(any(), any()) -> false.
|
||||
'#is_record-'(s, Rec) when tuple_size(Rec) == 2, element(1, Rec) == s ->
|
||||
true;
|
||||
'#is_record-'(r, Rec) when tuple_size(Rec) == 4, element(1, Rec) == r ->
|
||||
true;
|
||||
'#is_record-'(_, _) ->
|
||||
false.
|
||||
-spec '#get-'(a, #r{}) -> integer();
|
||||
(b, #r{}) -> integer();
|
||||
(c, #r{}) -> integer();
|
||||
(a, #s{}) -> any();
|
||||
(['#attr-r'()], #r{}) -> [integer()];
|
||||
(['#attr-s'()], #s{}) -> [any()].
|
||||
'#get-'(Attrs, Rec) when is_record(Rec, r) ->
|
||||
'#get-r'(Attrs, Rec);
|
||||
'#get-'(Attrs, Rec) when is_record(Rec, s) ->
|
||||
'#get-s'(Attrs, Rec).
|
||||
-spec '#set-'(['#prop-r'()], #r{}) -> #r{};
|
||||
(['#prop-s'()], #s{}) -> #s{}.
|
||||
'#set-'(Vals, Rec) when is_record(Rec, r) ->
|
||||
'#set-r'(Vals, Rec);
|
||||
'#set-'(Vals, Rec) when is_record(Rec, s) ->
|
||||
'#set-s'(Vals, Rec).
|
||||
-spec '#fromlist-'(['#prop-r'()], #r{}) -> #r{};
|
||||
(['#prop-s'()], #s{}) -> #s{}.
|
||||
'#fromlist-'(Vals, Rec) when is_record(Rec, r) ->
|
||||
'#fromlist-r'(Vals, Rec);
|
||||
'#fromlist-'(Vals, Rec) when is_record(Rec, s) ->
|
||||
'#fromlist-s'(Vals, Rec).
|
||||
-spec '#lens-'('#prop-r'(), r) ->
|
||||
{fun((#r{}) -> any()), fun((any(), #r{}) -> #r{})};
|
||||
('#prop-s'(), s) ->
|
||||
{fun((#s{}) -> any()), fun((any(), #s{}) -> #s{})}.
|
||||
'#lens-'(Attr, r) ->
|
||||
'#lens-r'(Attr);
|
||||
'#lens-'(Attr, s) ->
|
||||
'#lens-s'(Attr).
|
||||
-spec '#new-r'() -> #r{}.
|
||||
'#new-r'() ->
|
||||
#r{}.
|
||||
-spec '#new-r'(['#prop-r'()]) -> #r{}.
|
||||
'#new-r'(Vals) ->
|
||||
'#set-r'(Vals, #r{}).
|
||||
-spec '#get-r'(a, #r{}) -> integer();
|
||||
(b, #r{}) -> integer();
|
||||
(c, #r{}) -> integer();
|
||||
(['#attr-r'()], #r{}) -> [integer()].
|
||||
'#get-r'(Attrs, R) when is_list(Attrs) ->
|
||||
[
|
||||
'#get-r'(A, R) ||
|
||||
A <- Attrs
|
||||
];
|
||||
'#get-r'(a, R) ->
|
||||
R#r.a;
|
||||
'#get-r'(b, R) ->
|
||||
R#r.b;
|
||||
'#get-r'(c, R) ->
|
||||
R#r.c;
|
||||
'#get-r'(Attr, R) ->
|
||||
error(bad_record_op, ['#get-r',Attr,R]).
|
||||
-spec '#set-r'(['#prop-r'()], #r{}) -> #r{}.
|
||||
'#set-r'(Vals, Rec) ->
|
||||
F = fun([], R, _F1) ->
|
||||
R;
|
||||
([{a,V}|T], R, F1) when is_list(T) ->
|
||||
F1(T, R#r{a = V}, F1);
|
||||
([{b,V}|T], R, F1) when is_list(T) ->
|
||||
F1(T, R#r{b = V}, F1);
|
||||
([{c,V}|T], R, F1) when is_list(T) ->
|
||||
F1(T, R#r{c = V}, F1);
|
||||
(Vs, R, _) ->
|
||||
error(bad_record_op, ['#set-r',Vs,R])
|
||||
end,
|
||||
F(Vals, Rec, F).
|
||||
-spec '#fromlist-r'(['#prop-r'()]) -> #r{}.
|
||||
'#fromlist-r'(Vals) when is_list(Vals) ->
|
||||
'#fromlist-r'(Vals, '#new-r'()).
|
||||
-spec '#fromlist-r'(['#prop-r'()], #r{}) -> #r{}.
|
||||
'#fromlist-r'(Vals, Rec) ->
|
||||
AttrNames = [{a,2},{b,3},{c,4}],
|
||||
F = fun([], R, _F1) ->
|
||||
R;
|
||||
([{H,Pos}|T], R, F1) when is_list(T) ->
|
||||
case lists:keyfind(H, 1, Vals) of
|
||||
false ->
|
||||
F1(T, R, F1);
|
||||
{_,Val} ->
|
||||
F1(T, setelement(Pos, R, Val), F1)
|
||||
end
|
||||
end,
|
||||
F(AttrNames, Rec, F).
|
||||
-spec '#pos-r'('#attr-r'() | atom()) -> integer().
|
||||
'#pos-r'(a) ->
|
||||
2;
|
||||
'#pos-r'(b) ->
|
||||
3;
|
||||
'#pos-r'(c) ->
|
||||
4;
|
||||
'#pos-r'(A) when is_atom(A) ->
|
||||
0.
|
||||
-spec '#info-r'(fields) -> [a | b | c];
|
||||
(size) -> 3.
|
||||
'#info-r'(fields) ->
|
||||
record_info(fields, r);
|
||||
'#info-r'(size) ->
|
||||
record_info(size, r).
|
||||
-spec '#lens-r'('#prop-r'()) ->
|
||||
{fun((#r{}) -> any()), fun((any(), #r{}) -> #r{})}.
|
||||
'#lens-r'(a) ->
|
||||
{fun(R) ->
|
||||
'#get-r'(a, R)
|
||||
end,
|
||||
fun(X, R) ->
|
||||
'#set-r'([{a,X}], R)
|
||||
end};
|
||||
'#lens-r'(b) ->
|
||||
{fun(R) ->
|
||||
'#get-r'(b, R)
|
||||
end,
|
||||
fun(X, R) ->
|
||||
'#set-r'([{b,X}], R)
|
||||
end};
|
||||
'#lens-r'(c) ->
|
||||
{fun(R) ->
|
||||
'#get-r'(c, R)
|
||||
end,
|
||||
fun(X, R) ->
|
||||
'#set-r'([{c,X}], R)
|
||||
end}.
|
||||
-spec '#new-s'() -> #s{}.
|
||||
'#new-s'() ->
|
||||
#s{}.
|
||||
-spec '#new-s'(['#prop-s'()]) -> #s{}.
|
||||
'#new-s'(Vals) ->
|
||||
'#set-s'(Vals, #s{}).
|
||||
-spec '#get-s'(a, #s{}) -> any();
|
||||
(['#attr-s'()], #s{}) -> [any()].
|
||||
'#get-s'(Attrs, R) when is_list(Attrs) ->
|
||||
[
|
||||
'#get-s'(A, R) ||
|
||||
A <- Attrs
|
||||
];
|
||||
'#get-s'(a, R) ->
|
||||
R#s.a;
|
||||
'#get-s'(Attr, R) ->
|
||||
error(bad_record_op, ['#get-s',Attr,R]).
|
||||
-spec '#set-s'(['#prop-s'()], #s{}) -> #s{}.
|
||||
'#set-s'(Vals, Rec) ->
|
||||
F = fun([], R, _F1) ->
|
||||
R;
|
||||
([{a,V}|T], R, F1) when is_list(T) ->
|
||||
F1(T, R#s{a = V}, F1);
|
||||
(Vs, R, _) ->
|
||||
error(bad_record_op, ['#set-s',Vs,R])
|
||||
end,
|
||||
F(Vals, Rec, F).
|
||||
-spec '#fromlist-s'(['#prop-s'()]) -> #s{}.
|
||||
'#fromlist-s'(Vals) when is_list(Vals) ->
|
||||
'#fromlist-s'(Vals, '#new-s'()).
|
||||
-spec '#fromlist-s'(['#prop-s'()], #s{}) -> #s{}.
|
||||
'#fromlist-s'(Vals, Rec) ->
|
||||
AttrNames = [{a,2}],
|
||||
F = fun([], R, _F1) ->
|
||||
R;
|
||||
([{H,Pos}|T], R, F1) when is_list(T) ->
|
||||
case lists:keyfind(H, 1, Vals) of
|
||||
false ->
|
||||
F1(T, R, F1);
|
||||
{_,Val} ->
|
||||
F1(T, setelement(Pos, R, Val), F1)
|
||||
end
|
||||
end,
|
||||
F(AttrNames, Rec, F).
|
||||
-spec '#pos-s'('#attr-s'() | atom()) -> integer().
|
||||
'#pos-s'(a) ->
|
||||
2;
|
||||
'#pos-s'(A) when is_atom(A) ->
|
||||
0.
|
||||
-spec '#info-s'(fields) -> [a];
|
||||
(size) -> 1.
|
||||
'#info-s'(fields) ->
|
||||
record_info(fields, s);
|
||||
'#info-s'(size) ->
|
||||
record_info(size, s).
|
||||
-spec '#lens-s'('#prop-s'()) ->
|
||||
{fun((#s{}) -> any()), fun((any(), #s{}) -> #s{})}.
|
||||
'#lens-s'(a) ->
|
||||
{fun(R) ->
|
||||
'#get-s'(a, R)
|
||||
end,
|
||||
fun(X, R) ->
|
||||
'#set-s'([{a,X}], R)
|
||||
end}.
|
||||
f() ->
|
||||
{new,'#new-r'([])}.</pre>
|
||||
|
||||
|
||||
|
||||
It is possible to modify the naming rules of exprecs, through the use
|
||||
of the following attributes (example reflecting the current rules):
|
||||
|
||||
<pre>
|
||||
-exprecs_prefix(["#", operation, "-"]).
|
||||
-exprecs_fname([prefix, record]).
|
||||
-exprecs_vfname([fname, "__", version]).</pre>
|
||||
|
||||
The lists must contain strings or any of the following control atoms:
|
||||
|
||||
* in `exprecs_prefix`: `operation`
|
||||
|
||||
* in `exprecs_fname`: `operation`, `record`, `prefix`
|
||||
|
||||
* in `exprecs_vfname`: `operation`, `record`, `prefix`, `fname`, `version`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Exprecs will substitute the control atoms with the string values of the
|
||||
corresponding items. The result will then be flattened and converted to an
|
||||
atom (a valid function or type name).
|
||||
|
||||
`operation` is one of:
|
||||
|
||||
|
||||
|
||||
<dt><code>new</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Creates a new record</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><code>get</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Retrieves given attribute values from a record</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><code>set</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Sets given attribute values in a record</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><code>fromlist</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Creates a record from a key-value list</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><code>info</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Equivalent to record_info/2</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><code>pos</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Returns the position of a given attribute</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><code>is_record</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Tests if a value is a specific record</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><code>convert</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Converts an old record to the current version</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><code>prop</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Used only in type specs</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><code>attr</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Used only in type specs</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><code>lens</code></dt>
|
||||
|
||||
|
||||
|
||||
<dd>Returns a 'lens' (an accessor pair) as described in
|
||||
<a href="http://github.com/jlouis/erl-lenses" target="_top"><tt>http://github.com/jlouis/erl-lenses</tt></a></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="types"></a>
|
||||
|
||||
##Data Types##
|
||||
|
||||
|
||||
|
||||
|
||||
###<a name="type-form">form()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>form() = any()</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-forms">forms()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>forms() = [<a href="#type-form">form()</a>]</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-options">options()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>options() = [{atom(), any()}]</pre>
|
||||
<a name="index"></a>
|
||||
|
||||
##Function Index##
|
||||
|
||||
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#parse_transform-2">parse_transform/2</a></td><td></td></tr></table>
|
||||
|
||||
|
||||
<a name="functions"></a>
|
||||
|
||||
##Function Details##
|
||||
|
||||
<a name="parse_transform-2"></a>
|
||||
|
||||
###parse_transform/2##
|
||||
|
||||
|
||||
<pre>parse_transform(Forms::<a href="#type-forms">forms()</a>, Options::<a href="#type-options">options()</a>) -> <a href="#type-forms">forms()</a></pre>
|
||||
<br></br>
|
||||
|
||||
|
@ -1,484 +0,0 @@
|
||||
|
||||
|
||||
#Module parse_trans#
|
||||
* [Description](#description)
|
||||
* [Data Types](#types)
|
||||
* [Function Index](#index)
|
||||
* [Function Details](#functions)
|
||||
|
||||
|
||||
Generic parse transform library for Erlang.
|
||||
|
||||
__Authors:__ : Ulf Wiger ([`ulf.wiger@feuerlabs.com`](mailto:ulf.wiger@feuerlabs.com)).<a name="description"></a>
|
||||
|
||||
##Description##
|
||||
|
||||
|
||||
|
||||
|
||||
...
|
||||
|
||||
<a name="types"></a>
|
||||
|
||||
##Data Types##
|
||||
|
||||
|
||||
|
||||
|
||||
###<a name="type-form">form()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>form() = any()</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-forms">forms()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>forms() = [<a href="#type-form">form()</a>]</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-insp_f">insp_f()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>insp_f() = fun((<a href="#type-type">type()</a>, <a href="#type-form">form()</a>, #context{}, A) -> {boolean(), A})</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-options">options()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>options() = [{atom(), any()}]</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-type">type()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>type() = atom()</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-xform_f_df">xform_f_df()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>xform_f_df() = fun((<a href="#type-type">type()</a>, <a href="#type-form">form()</a>, #context{}, Acc) -> {<a href="#type-form">form()</a>, Acc} | {<a href="#type-forms">forms()</a>, <a href="#type-form">form()</a>, <a href="#type-forms">forms()</a>, Acc})</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-xform_f_rec">xform_f_rec()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>xform_f_rec() = fun((<a href="#type-type">type()</a>, <a href="#type-form">form()</a>, #context{}, Acc) -> {<a href="#type-form">form()</a>, boolean(), Acc} | {<a href="#type-forms">forms()</a>, <a href="#type-form">form()</a>, <a href="#type-forms">forms()</a>, boolean(), Acc})</pre>
|
||||
<a name="index"></a>
|
||||
|
||||
##Function Index##
|
||||
|
||||
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#context-2">context/2</a></td><td>
|
||||
Accessor function for the Context record.</td></tr><tr><td valign="top"><a href="#depth_first-4">depth_first/4</a></td><td></td></tr><tr><td valign="top"><a href="#do_depth_first-4">do_depth_first/4</a></td><td></td></tr><tr><td valign="top"><a href="#do_insert_forms-4">do_insert_forms/4</a></td><td></td></tr><tr><td valign="top"><a href="#do_inspect-4">do_inspect/4</a></td><td></td></tr><tr><td valign="top"><a href="#do_transform-4">do_transform/4</a></td><td></td></tr><tr><td valign="top"><a href="#error-3">error/3</a></td><td>.</td></tr><tr><td valign="top"><a href="#export_function-3">export_function/3</a></td><td></td></tr><tr><td valign="top"><a href="#format_error-1">format_error/1</a></td><td></td></tr><tr><td valign="top"><a href="#format_exception-2">format_exception/2</a></td><td>Equivalent to <a href="#format_exception-3"><tt>format_exception(Class, Reason, 4)</tt></a>.</td></tr><tr><td valign="top"><a href="#format_exception-3">format_exception/3</a></td><td>Produces a few lines of user-friendly formatting of exception info.</td></tr><tr><td valign="top"><a href="#function_exists-3">function_exists/3</a></td><td>
|
||||
Checks whether the given function is defined in Forms.</td></tr><tr><td valign="top"><a href="#get_attribute-2">get_attribute/2</a></td><td>
|
||||
Returns the value of the first occurence of attribute A.</td></tr><tr><td valign="top"><a href="#get_attribute-3">get_attribute/3</a></td><td></td></tr><tr><td valign="top"><a href="#get_file-1">get_file/1</a></td><td>
|
||||
Returns the name of the file being compiled.</td></tr><tr><td valign="top"><a href="#get_module-1">get_module/1</a></td><td>
|
||||
Returns the name of the module being compiled.</td></tr><tr><td valign="top"><a href="#get_orig_syntax_tree-1">get_orig_syntax_tree/1</a></td><td>.</td></tr><tr><td valign="top"><a href="#get_pos-1">get_pos/1</a></td><td>
|
||||
Tries to retrieve the line number from an erl_syntax form.</td></tr><tr><td valign="top"><a href="#initial_context-2">initial_context/2</a></td><td>
|
||||
Initializes a context record.</td></tr><tr><td valign="top"><a href="#inspect-4">inspect/4</a></td><td>
|
||||
Equvalent to do_inspect(Fun,Acc,Forms,initial_context(Forms,Options)).</td></tr><tr><td valign="top"><a href="#optionally_pretty_print-3">optionally_pretty_print/3</a></td><td></td></tr><tr><td valign="top"><a href="#plain_transform-2">plain_transform/2</a></td><td>
|
||||
Performs a transform of <code>Forms</code> using the fun <code>Fun(Form)</code>.</td></tr><tr><td valign="top"><a href="#pp_beam-1">pp_beam/1</a></td><td>
|
||||
Reads debug_info from the beam file Beam and returns a string containing
|
||||
the pretty-printed corresponding erlang source code.</td></tr><tr><td valign="top"><a href="#pp_beam-2">pp_beam/2</a></td><td>
|
||||
Reads debug_info from the beam file Beam and pretty-prints it as
|
||||
Erlang source code, storing it in the file Out.</td></tr><tr><td valign="top"><a href="#pp_src-2">pp_src/2</a></td><td>Pretty-prints the erlang source code corresponding to Forms into Out.</td></tr><tr><td valign="top"><a href="#replace_function-4">replace_function/4</a></td><td></td></tr><tr><td valign="top"><a href="#return-2">return/2</a></td><td>Checks the transformed result for errors and warnings.</td></tr><tr><td valign="top"><a href="#revert-1">revert/1</a></td><td>Reverts back from Syntax Tools format to Erlang forms.</td></tr><tr><td valign="top"><a href="#revert_form-1">revert_form/1</a></td><td>Reverts a single form back from Syntax Tools format to Erlang forms.</td></tr><tr><td valign="top"><a href="#top-3">top/3</a></td><td></td></tr><tr><td valign="top"><a href="#transform-4">transform/4</a></td><td>
|
||||
Makes one pass.</td></tr></table>
|
||||
|
||||
|
||||
<a name="functions"></a>
|
||||
|
||||
##Function Details##
|
||||
|
||||
<a name="context-2"></a>
|
||||
|
||||
###context/2##
|
||||
|
||||
|
||||
<pre>context(X1::Attr, Context) -> any()</pre>
|
||||
<ul class="definitions"><li><pre>Attr = module | function | arity | options</pre></li></ul>
|
||||
|
||||
|
||||
Accessor function for the Context record.<a name="depth_first-4"></a>
|
||||
|
||||
###depth_first/4##
|
||||
|
||||
|
||||
<pre>depth_first(Fun::<a href="#type-xform_f_df">xform_f_df()</a>, Acc, Forms::<a href="#type-forms">forms()</a>, Options::<a href="#type-options">options()</a>) -> {<a href="#type-forms">forms()</a>, Acc} | {error, list()}</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="do_depth_first-4"></a>
|
||||
|
||||
###do_depth_first/4##
|
||||
|
||||
|
||||
<pre>do_depth_first(F::<a href="#type-xform_f_df">xform_f_df()</a>, Acc::term(), Forms::<a href="#type-forms">forms()</a>, Context::#context{}) -> {<a href="#type-forms">forms()</a>, term()}</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="do_insert_forms-4"></a>
|
||||
|
||||
###do_insert_forms/4##
|
||||
|
||||
|
||||
<pre>do_insert_forms(X1::above | below, Insert::<a href="#type-forms">forms()</a>, Forms::<a href="#type-forms">forms()</a>, Context::#context{}) -> <a href="#type-forms">forms()</a></pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="do_inspect-4"></a>
|
||||
|
||||
###do_inspect/4##
|
||||
|
||||
|
||||
<pre>do_inspect(F::<a href="#type-insp_f">insp_f()</a>, Acc::term(), Forms::<a href="#type-forms">forms()</a>, Context::#context{}) -> term()</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="do_transform-4"></a>
|
||||
|
||||
###do_transform/4##
|
||||
|
||||
|
||||
<pre>do_transform(F::<a href="#type-xform_f_rec">xform_f_rec()</a>, Acc::term(), Forms::<a href="#type-forms">forms()</a>, Context::#context{}) -> {<a href="#type-forms">forms()</a>, term()}</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="error-3"></a>
|
||||
|
||||
###error/3##
|
||||
|
||||
|
||||
<pre>error(R::Reason, F::Form, I::Info) -> <a href="#type-throw">throw()</a></pre>
|
||||
<ul class="definitions"><li><pre>Info = [{Key, Value}]</pre></li></ul>
|
||||
|
||||
|
||||
|
||||
|
||||
Used to report errors detected during the parse transform.<a name="export_function-3"></a>
|
||||
|
||||
###export_function/3##
|
||||
|
||||
|
||||
`export_function(F, Arity, Forms) -> any()`
|
||||
|
||||
<a name="format_error-1"></a>
|
||||
|
||||
###format_error/1##
|
||||
|
||||
|
||||
<pre>format_error(Error::{atom(), term()}) -> iolist()</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="format_exception-2"></a>
|
||||
|
||||
###format_exception/2##
|
||||
|
||||
|
||||
<pre>format_exception(Class, Reason) -> String</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
Equivalent to [`format_exception(Class, Reason, 4)`](#format_exception-3).<a name="format_exception-3"></a>
|
||||
|
||||
###format_exception/3##
|
||||
|
||||
|
||||
<pre>format_exception(Class, Reason, Lines) -> String</pre>
|
||||
<ul class="definitions"><li><pre>Class = error | throw | exit</pre></li><li><pre>Reason = term()</pre></li><li><pre>Lines = integer() | infinity</pre></li></ul>
|
||||
|
||||
|
||||
|
||||
Produces a few lines of user-friendly formatting of exception info
|
||||
|
||||
|
||||
|
||||
This function is very similar to the exception pretty-printing in the shell,
|
||||
but returns a string that can be used as error info e.g. by error forms
|
||||
handled by [`return/2`](#return-2). By default, the first 4 lines of the
|
||||
pretty-printed exception info are returned, but this can be controlled
|
||||
with the `Lines` parameter.
|
||||
|
||||
Note that a stacktrace is generated inside this function.<a name="function_exists-3"></a>
|
||||
|
||||
###function_exists/3##
|
||||
|
||||
|
||||
<pre>function_exists(Fname::atom(), Arity::integer(), Forms) -> boolean()</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
Checks whether the given function is defined in Forms.<a name="get_attribute-2"></a>
|
||||
|
||||
###get_attribute/2##
|
||||
|
||||
|
||||
<pre>get_attribute(A, Forms) -> any()</pre>
|
||||
<ul class="definitions"><li><pre>A = atom()</pre></li></ul>
|
||||
|
||||
|
||||
Returns the value of the first occurence of attribute A.<a name="get_attribute-3"></a>
|
||||
|
||||
###get_attribute/3##
|
||||
|
||||
|
||||
`get_attribute(A, Forms, Undef) -> any()`
|
||||
|
||||
<a name="get_file-1"></a>
|
||||
|
||||
###get_file/1##
|
||||
|
||||
|
||||
<pre>get_file(Forms) -> string()</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
Returns the name of the file being compiled.<a name="get_module-1"></a>
|
||||
|
||||
###get_module/1##
|
||||
|
||||
|
||||
<pre>get_module(Forms) -> atom()</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
Returns the name of the module being compiled.<a name="get_orig_syntax_tree-1"></a>
|
||||
|
||||
###get_orig_syntax_tree/1##
|
||||
|
||||
|
||||
<pre>get_orig_syntax_tree(File) -> Forms</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Fetches a Syntax Tree representing the code before pre-processing,
|
||||
that is, including record and macro definitions. Note that macro
|
||||
definitions must be syntactically complete forms (this function
|
||||
uses epp_dodger).<a name="get_pos-1"></a>
|
||||
|
||||
###get_pos/1##
|
||||
|
||||
|
||||
<pre>get_pos(I::list()) -> integer()</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
Tries to retrieve the line number from an erl_syntax form. Returns a
|
||||
(very high) dummy number if not successful.<a name="initial_context-2"></a>
|
||||
|
||||
###initial_context/2##
|
||||
|
||||
|
||||
<pre>initial_context(Forms, Options) -> #context{}</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
Initializes a context record. When traversing through the form
|
||||
list, the context is updated to reflect the current function and
|
||||
arity. Static elements in the context are the file name, the module
|
||||
name and the options passed to the transform function.<a name="inspect-4"></a>
|
||||
|
||||
###inspect/4##
|
||||
|
||||
|
||||
<pre>inspect(F::Fun, Acc::Forms, Forms::Acc, Options) -> NewAcc</pre>
|
||||
<ul class="definitions"><li><pre>Fun = function()</pre></li></ul>
|
||||
|
||||
|
||||
Equvalent to do_inspect(Fun,Acc,Forms,initial_context(Forms,Options)).<a name="optionally_pretty_print-3"></a>
|
||||
|
||||
###optionally_pretty_print/3##
|
||||
|
||||
|
||||
<pre>optionally_pretty_print(Result::<a href="#type-forms">forms()</a>, Options::<a href="#type-options">options()</a>, Context::#context{}) -> ok</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="plain_transform-2"></a>
|
||||
|
||||
###plain_transform/2##
|
||||
|
||||
|
||||
<pre>plain_transform(Fun, Forms) -> <a href="#type-forms">forms()</a></pre>
|
||||
<ul class="definitions"><li><pre>Fun = function()</pre></li><li><pre>Forms = <a href="#type-forms">forms()</a></pre></li></ul>
|
||||
|
||||
|
||||
|
||||
|
||||
Performs a transform of `Forms` using the fun `Fun(Form)`. `Form` is always
|
||||
an Erlang abstract form, i.e. it is not converted to syntax_tools
|
||||
representation. The intention of this transform is for the fun to have a
|
||||
catch-all clause returning `continue`. This will ensure that it stays robust
|
||||
against additions to the language.
|
||||
|
||||
|
||||
|
||||
`Fun(Form)` must return either of the following:
|
||||
|
||||
|
||||
|
||||
* `NewForm` - any valid form
|
||||
* `continue` - dig into the sub-expressions of the form
|
||||
* `{done, NewForm}` - Replace `Form` with `NewForm`; return all following
|
||||
forms unchanged
|
||||
* `{error, Reason}` - Abort transformation with an error message.
|
||||
|
||||
Example - This transform fun would convert all instances of `P ! Msg` to
|
||||
`gproc:send(P, Msg)`:
|
||||
<pre>
|
||||
parse_transform(Forms, _Options) ->
|
||||
parse_trans:plain_transform(fun do_transform/1, Forms).
|
||||
do_transform({'op', L, '!', Lhs, Rhs}) ->
|
||||
[NewLhs] = parse_trans:plain_transform(fun do_transform/1, [Lhs]),
|
||||
[NewRhs] = parse_trans:plain_transform(fun do_transform/1, [Rhs]),
|
||||
{call, L, {remote, L, {atom, L, gproc}, {atom, L, send}},
|
||||
[NewLhs, NewRhs]};
|
||||
do_transform(_) ->
|
||||
continue.</pre><a name="pp_beam-1"></a>
|
||||
|
||||
###pp_beam/1##
|
||||
|
||||
|
||||
<pre>pp_beam(Beam::<a href="file.md#type-filename">file:filename()</a>) -> string() | {error, Reason}</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
Reads debug_info from the beam file Beam and returns a string containing
|
||||
the pretty-printed corresponding erlang source code.<a name="pp_beam-2"></a>
|
||||
|
||||
###pp_beam/2##
|
||||
|
||||
|
||||
<pre>pp_beam(Beam::<a href="#type-filename">filename()</a>, Out::<a href="#type-filename">filename()</a>) -> ok | {error, Reason}</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
Reads debug_info from the beam file Beam and pretty-prints it as
|
||||
Erlang source code, storing it in the file Out.<a name="pp_src-2"></a>
|
||||
|
||||
###pp_src/2##
|
||||
|
||||
|
||||
<pre>pp_src(Res::Forms, Out::<a href="#type-filename">filename()</a>) -> ok</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
Pretty-prints the erlang source code corresponding to Forms into Out
|
||||
<a name="replace_function-4"></a>
|
||||
|
||||
###replace_function/4##
|
||||
|
||||
|
||||
`replace_function(F, Arity, NewForm, Forms) -> any()`
|
||||
|
||||
<a name="return-2"></a>
|
||||
|
||||
###return/2##
|
||||
|
||||
|
||||
<pre>return(Forms, Context) -> Forms | {error, Es, Ws} | {warnings, Forms, Ws}</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
Checks the transformed result for errors and warnings
|
||||
|
||||
|
||||
Errors and warnings can be produced from inside a parse transform, with
|
||||
a bit of care. The easiest way is to simply produce an `{error, Err}` or
|
||||
`{warning, Warn}` form in place. This function finds such forms, and
|
||||
removes them from the form list (otherwise, the linter will crash), and
|
||||
produces a return value that the compiler can work with.
|
||||
|
||||
The format of the `error` and `warning` "forms" must be
|
||||
`{Tag, {Pos, Module, Info}}`, where:
|
||||
|
||||
* `Tag :: error | warning`
|
||||
|
||||
* `Pos :: LineNumber | {LineNumber, ColumnNumber}`
|
||||
|
||||
* `Module` is a module that exports a corresponding
|
||||
`Module:format_error(Info)`
|
||||
|
||||
* `Info :: term()`
|
||||
|
||||
|
||||
|
||||
|
||||
If the error is in the form of a caught exception, `Info` may be produced
|
||||
using the function [`format_exception/2`](#format_exception-2).<a name="revert-1"></a>
|
||||
|
||||
###revert/1##
|
||||
|
||||
|
||||
<pre>revert(Tree) -> Forms</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
Reverts back from Syntax Tools format to Erlang forms.
|
||||
|
||||
|
||||
Note that the Erlang forms are a subset of the Syntax Tools
|
||||
syntax tree, so this function is safe to call even on a list of
|
||||
regular Erlang forms.<a name="revert_form-1"></a>
|
||||
|
||||
###revert_form/1##
|
||||
|
||||
|
||||
<pre>revert_form(F::Tree) -> Form</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
Reverts a single form back from Syntax Tools format to Erlang forms.
|
||||
|
||||
|
||||
`erl_syntax:revert/1` has had a long-standing bug where it doesn't
|
||||
completely revert attribute forms. This function deals properly with those
|
||||
cases.
|
||||
|
||||
|
||||
Note that the Erlang forms are a subset of the Syntax Tools
|
||||
syntax tree, so this function is safe to call even on a regular Erlang
|
||||
form.<a name="top-3"></a>
|
||||
|
||||
###top/3##
|
||||
|
||||
|
||||
<pre>top(F::function(), Forms::<a href="#type-forms">forms()</a>, Options::list()) -> <a href="#type-forms">forms()</a> | {error, term()}</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="transform-4"></a>
|
||||
|
||||
###transform/4##
|
||||
|
||||
|
||||
<pre>transform(Fun, Acc, Forms, Options) -> {TransformedForms, NewAcc}</pre>
|
||||
<ul class="definitions"><li><pre>Fun = function()</pre></li><li><pre>Options = [{Key, Value}]</pre></li></ul>
|
||||
|
||||
|
||||
Makes one pass
|
@ -1,204 +0,0 @@
|
||||
|
||||
|
||||
#Module parse_trans_codegen#
|
||||
* [Description](#description)
|
||||
* [Function Index](#index)
|
||||
* [Function Details](#functions)
|
||||
|
||||
|
||||
Parse transform for code generation pseduo functions.
|
||||
|
||||
__Authors:__ : Ulf Wiger ([`ulf@feuerlabs.com`](mailto:ulf@feuerlabs.com)).<a name="description"></a>
|
||||
|
||||
##Description##
|
||||
|
||||
|
||||
|
||||
|
||||
...
|
||||
<a name="index"></a>
|
||||
|
||||
##Function Index##
|
||||
|
||||
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#format_error-1">format_error/1</a></td><td></td></tr><tr><td valign="top"><a href="#parse_transform-2">parse_transform/2</a></td><td>
|
||||
Searches for calls to pseudo functions in the module <code>codegen</code>,
|
||||
and converts the corresponding erlang code to a data structure
|
||||
representing the abstract form of that code.</td></tr></table>
|
||||
|
||||
|
||||
<a name="functions"></a>
|
||||
|
||||
##Function Details##
|
||||
|
||||
<a name="format_error-1"></a>
|
||||
|
||||
###format_error/1##
|
||||
|
||||
|
||||
`format_error(E) -> any()`
|
||||
|
||||
<a name="parse_transform-2"></a>
|
||||
|
||||
###parse_transform/2##
|
||||
|
||||
|
||||
<pre>parse_transform(Forms, Options) -> NewForms</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Searches for calls to pseudo functions in the module `codegen`,
|
||||
and converts the corresponding erlang code to a data structure
|
||||
representing the abstract form of that code.
|
||||
|
||||
|
||||
|
||||
The purpose of these functions is to let the programmer write
|
||||
the actual code that is to be generated, rather than manually
|
||||
writing abstract forms, which is more error prone and cannot be
|
||||
checked by the compiler until the generated module is compiled.
|
||||
|
||||
|
||||
|
||||
Supported functions:
|
||||
|
||||
|
||||
|
||||
##gen_function/2##
|
||||
|
||||
|
||||
|
||||
|
||||
Usage: `codegen:gen_function(Name, Fun)`
|
||||
|
||||
|
||||
|
||||
Substitutes the abstract code for a function with name `Name`
|
||||
and the same behaviour as `Fun`.
|
||||
|
||||
`Fun` can either be a anonymous `fun`, which is then converted to
|
||||
a named function, or it can be an `implicit fun`, e.g.
|
||||
`fun is_member/2`. In the latter case, the referenced function is fetched
|
||||
and converted to an abstract form representation. It is also renamed
|
||||
so that the generated function has the name `Name`.
|
||||
|
||||
|
||||
|
||||
Another alternative is to wrap a fun inside a list comprehension, e.g.
|
||||
<pre>
|
||||
f(Name, L) ->
|
||||
codegen:gen_function(
|
||||
Name,
|
||||
[ fun({'$var',X}) ->
|
||||
{'$var', Y}
|
||||
end || {X, Y} <- L ]).</pre>
|
||||
|
||||
|
||||
|
||||
Calling the above with `f(foo, [{1,a},{2,b},{3,c}])` will result in
|
||||
generated code corresponding to:
|
||||
<pre>
|
||||
foo(1) -> a;
|
||||
foo(2) -> b;
|
||||
foo(3) -> c.</pre>
|
||||
|
||||
|
||||
|
||||
##gen_functions/1##
|
||||
|
||||
|
||||
|
||||
|
||||
Takes a list of `{Name, Fun}` tuples and produces a list of abstract
|
||||
data objects, just as if one had written
|
||||
`[codegen:gen_function(N1,F1),codegen:gen_function(N2,F2),...]`.
|
||||
|
||||
|
||||
|
||||
##exprs/1##
|
||||
|
||||
|
||||
|
||||
|
||||
Usage: `codegen:exprs(Fun)`
|
||||
|
||||
|
||||
|
||||
`Fun` is either an anonymous function, or an implicit fun with only one
|
||||
function clause. This "function" takes the body of the fun and produces
|
||||
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##
|
||||
|
||||
|
||||
|
||||
|
||||
It is possible to do some limited expansion (importing a value
|
||||
bound at compile-time), using the construct `{'$var', V}`, where
|
||||
`V` is a bound variable in the scope of the call to `gen_function/2`.
|
||||
|
||||
Example:
|
||||
<pre>
|
||||
gen(Name, X) ->
|
||||
codegen:gen_function(Name, fun(L) -> lists:member({'$var',X}, L) end).</pre>
|
||||
|
||||
After transformation, calling `gen(contains_17, 17)` will yield the
|
||||
abstract form corresponding to:
|
||||
<pre>
|
||||
contains_17(L) ->
|
||||
lists:member(17, L).</pre>
|
||||
|
||||
|
||||
|
||||
##Form substitution##
|
||||
|
||||
|
||||
|
||||
|
||||
It is possible to inject abstract forms, using the construct
|
||||
`{'$form', F}`, where `F` is bound to a parsed form in
|
||||
the scope of the call to `gen_function/2`.
|
||||
|
||||
Example:
|
||||
<pre>
|
||||
gen(Name, F) ->
|
||||
codegen:gen_function(Name, fun(X) -> X =:= {'$form',F} end).</pre>
|
||||
|
||||
After transformation, calling `gen(is_foo, {atom,0,foo})` will yield the
|
||||
abstract form corresponding to:
|
||||
<pre>
|
||||
is_foo(X) ->
|
||||
X =:= foo.</pre>
|
@ -1,102 +0,0 @@
|
||||
|
||||
|
||||
#Module parse_trans_mod#
|
||||
* [Data Types](#types)
|
||||
* [Function Index](#index)
|
||||
* [Function Details](#functions)
|
||||
|
||||
|
||||
|
||||
<a name="types"></a>
|
||||
|
||||
##Data Types##
|
||||
|
||||
|
||||
|
||||
|
||||
###<a name="type-compile_options">compile_options()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>compile_options() = [term()]</pre>
|
||||
|
||||
|
||||
|
||||
###<a name="type-erlang_form">erlang_form()</a>##
|
||||
|
||||
|
||||
|
||||
<pre>erlang_form() = term()</pre>
|
||||
<a name="index"></a>
|
||||
|
||||
##Function Index##
|
||||
|
||||
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#abstract_code-1">abstract_code/1</a></td><td></td></tr><tr><td valign="top"><a href="#beam_file-1">beam_file/1</a></td><td></td></tr><tr><td valign="top"><a href="#compile_and_load_forms-1">compile_and_load_forms/1</a></td><td></td></tr><tr><td valign="top"><a href="#compile_and_load_forms-2">compile_and_load_forms/2</a></td><td></td></tr><tr><td valign="top"><a href="#compile_options-1">compile_options/1</a></td><td></td></tr><tr><td valign="top"><a href="#rename_module-2">rename_module/2</a></td><td></td></tr><tr><td valign="top"><a href="#transform_module-3">transform_module/3</a></td><td></td></tr></table>
|
||||
|
||||
|
||||
<a name="functions"></a>
|
||||
|
||||
##Function Details##
|
||||
|
||||
<a name="abstract_code-1"></a>
|
||||
|
||||
###abstract_code/1##
|
||||
|
||||
|
||||
<pre>abstract_code(BeamFile::binary()) -> <a href="#type-erlang_form">erlang_form()</a></pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="beam_file-1"></a>
|
||||
|
||||
###beam_file/1##
|
||||
|
||||
|
||||
<pre>beam_file(Module::module()) -> binary()</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="compile_and_load_forms-1"></a>
|
||||
|
||||
###compile_and_load_forms/1##
|
||||
|
||||
|
||||
<pre>compile_and_load_forms(AbsCode::<a href="#type-erlang_form">erlang_form()</a>) -> ok</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="compile_and_load_forms-2"></a>
|
||||
|
||||
###compile_and_load_forms/2##
|
||||
|
||||
|
||||
<pre>compile_and_load_forms(AbsCode::<a href="#type-erlang_form">erlang_form()</a>, Opts::<a href="#type-compile_options">compile_options()</a>) -> ok</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="compile_options-1"></a>
|
||||
|
||||
###compile_options/1##
|
||||
|
||||
|
||||
<pre>compile_options(BeamFile::binary() | module()) -> <a href="#type-compile_options">compile_options()</a></pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="rename_module-2"></a>
|
||||
|
||||
###rename_module/2##
|
||||
|
||||
|
||||
<pre>rename_module(T::<a href="#type-erlang_form">erlang_form()</a>, NewName::module()) -> <a href="#type-erlang_form">erlang_form()</a></pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="transform_module-3"></a>
|
||||
|
||||
###transform_module/3##
|
||||
|
||||
|
||||
`transform_module(Mod, PT, Options) -> any()`
|
||||
|
@ -1,86 +0,0 @@
|
||||
|
||||
|
||||
#Module parse_trans_pp#
|
||||
* [Description](#description)
|
||||
* [Function Index](#index)
|
||||
* [Function Details](#functions)
|
||||
|
||||
|
||||
Generic parse transform library for Erlang.
|
||||
|
||||
__Authors:__ : Ulf Wiger ([`ulf@feuerlabs.com`](mailto:ulf@feuerlabs.com)).<a name="description"></a>
|
||||
|
||||
##Description##
|
||||
|
||||
|
||||
|
||||
|
||||
This module contains some useful utility functions for inspecting
|
||||
the results of parse transforms or code generation.
|
||||
The function `main/1` is called from escript, and can be used to
|
||||
pretty-print debug info in a .beam file from a Linux shell.
|
||||
|
||||
Using e.g. the following bash alias:
|
||||
<pre>
|
||||
alias pp='escript $PARSE_TRANS_ROOT/ebin/parse_trans_pp.beam'</pre>
|
||||
|
||||
|
||||
a file could be pretty-printed using the following command:
|
||||
|
||||
`$ pp ex_codegen.beam | less`<a name="index"></a>
|
||||
|
||||
##Function Index##
|
||||
|
||||
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#main-1">main/1</a></td><td></td></tr><tr><td valign="top"><a href="#pp_beam-1">pp_beam/1</a></td><td>
|
||||
Reads debug_info from the beam file Beam and returns a string containing
|
||||
the pretty-printed corresponding erlang source code.</td></tr><tr><td valign="top"><a href="#pp_beam-2">pp_beam/2</a></td><td>
|
||||
Reads debug_info from the beam file Beam and pretty-prints it as
|
||||
Erlang source code, storing it in the file Out.</td></tr><tr><td valign="top"><a href="#pp_src-2">pp_src/2</a></td><td>Pretty-prints the erlang source code corresponding to Forms into Out.</td></tr></table>
|
||||
|
||||
|
||||
<a name="functions"></a>
|
||||
|
||||
##Function Details##
|
||||
|
||||
<a name="main-1"></a>
|
||||
|
||||
###main/1##
|
||||
|
||||
|
||||
<pre>main(X1::[string()]) -> any()</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
<a name="pp_beam-1"></a>
|
||||
|
||||
###pp_beam/1##
|
||||
|
||||
|
||||
<pre>pp_beam(Beam::<a href="#type-filename">filename()</a>) -> string() | {error, Reason}</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
Reads debug_info from the beam file Beam and returns a string containing
|
||||
the pretty-printed corresponding erlang source code.<a name="pp_beam-2"></a>
|
||||
|
||||
###pp_beam/2##
|
||||
|
||||
|
||||
<pre>pp_beam(Beam::<a href="#type-filename">filename()</a>, Out::<a href="#type-filename">filename()</a>) -> ok | {error, Reason}</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
|
||||
Reads debug_info from the beam file Beam and pretty-prints it as
|
||||
Erlang source code, storing it in the file Out.<a name="pp_src-2"></a>
|
||||
|
||||
###pp_src/2##
|
||||
|
||||
|
||||
<pre>pp_src(Forms0::Forms, Out::<a href="#type-filename">filename()</a>) -> ok</pre>
|
||||
<br></br>
|
||||
|
||||
|
||||
Pretty-prints the erlang source code corresponding to Forms into Out
|
Loading…
Reference in New Issue
Block a user