15 KiB
#Module parse_trans#
Generic parse transform library for Erlang.
Authors: : Ulf Wiger (ulf.wiger@feuerlabs.com
).
##Description##
...
##Data Types##
###form()##
form() = any()
###forms()##
forms() = [form()]
###insp_f()##
insp_f() = fun((type(), form(), #context{}, A) -> {boolean(), A})
###options()##
options() = [{atom(), any()}]
###type()##
type() = atom()
###xform_f_df()##
xform_f_df() = fun((type(), form(), #context{}, Acc) -> {form(), Acc} | {forms(), form(), forms(), Acc})
###xform_f_rec()##
xform_f_rec() = fun((type(), form(), #context{}, Acc) -> {form(), boolean(), Acc} | {forms(), form(), forms(), boolean(), Acc})
##Function Index##
context/2 | Accessor function for the Context record. |
depth_first/4 | |
do_depth_first/4 | |
do_insert_forms/4 | |
do_inspect/4 | |
do_transform/4 | |
error/3 | . |
export_function/3 | |
format_error/1 | |
format_exception/2 | Equivalent to format_exception(Class, Reason, 4). |
format_exception/3 | Produces a few lines of user-friendly formatting of exception info. |
function_exists/3 | Checks whether the given function is defined in Forms. |
get_attribute/2 | Returns the value of the first occurence of attribute A. |
get_attribute/3 | |
get_file/1 | Returns the name of the file being compiled. |
get_module/1 | Returns the name of the module being compiled. |
get_orig_syntax_tree/1 | . |
get_pos/1 | Tries to retrieve the line number from an erl_syntax form. |
initial_context/2 | Initializes a context record. |
inspect/4 | Equvalent to do_inspect(Fun,Acc,Forms,initial_context(Forms,Options)). |
optionally_pretty_print/3 | |
plain_transform/2 |
Performs a transform of Forms using the fun Fun(Form) . |
pp_beam/1 | Reads debug_info from the beam file Beam and returns a string containing the pretty-printed corresponding erlang source code. |
pp_beam/2 | Reads debug_info from the beam file Beam and pretty-prints it as Erlang source code, storing it in the file Out. |
pp_src/2 | Pretty-prints the erlang source code corresponding to Forms into Out. |
replace_function/4 | |
return/2 | Checks the transformed result for errors and warnings. |
revert/1 | Reverts back from Syntax Tools format to Erlang forms. |
revert_form/1 | Reverts a single form back from Syntax Tools format to Erlang forms. |
top/3 | |
transform/4 | Makes one pass. |
##Function Details##
###context/2##
context(X1::Attr, Context) -> any()
Attr = module | function | arity | options
Accessor function for the Context record.
###depth_first/4##
depth_first(Fun::xform_f_df(), Acc, Forms::forms(), Options::options()) -> {forms(), Acc} | {error, list()}
###do_depth_first/4##
do_depth_first(F::xform_f_df(), Acc::term(), Forms::forms(), Context::#context{}) -> {forms(), term()}
###do_insert_forms/4##
do_insert_forms(X1::above | below, Insert::forms(), Forms::forms(), Context::#context{}) -> forms()
###do_inspect/4##
do_inspect(F::insp_f(), Acc::term(), Forms::forms(), Context::#context{}) -> term()
###do_transform/4##
do_transform(F::xform_f_rec(), Acc::term(), Forms::forms(), Context::#context{}) -> {forms(), term()}
###error/3##
error(R::Reason, F::Form, I::Info) -> throw()
Info = [{Key, Value}]
Used to report errors detected during the parse transform.
###export_function/3##
export_function(F, Arity, Forms) -> any()
###format_error/1##
format_error(Error::{atom(), term()}) -> iolist()
###format_exception/2##
format_exception(Class, Reason) -> String
Equivalent to format_exception(Class, Reason, 4)
.
###format_exception/3##
format_exception(Class, Reason, Lines) -> String
Class = error | throw | exit
Reason = term()
Lines = integer() | infinity
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
. 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.
###function_exists/3##
function_exists(Fname::atom(), Arity::integer(), Forms) -> boolean()
Checks whether the given function is defined in Forms.
###get_attribute/2##
get_attribute(A, Forms) -> any()
A = atom()
Returns the value of the first occurence of attribute A.
###get_attribute/3##
get_attribute(A, Forms, Undef) -> any()
###get_file/1##
get_file(Forms) -> string()
Returns the name of the file being compiled.
###get_module/1##
get_module(Forms) -> atom()
Returns the name of the module being compiled.
###get_orig_syntax_tree/1##
get_orig_syntax_tree(File) -> Forms
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).
###get_pos/1##
get_pos(I::list()) -> integer()
Tries to retrieve the line number from an erl_syntax form. Returns a (very high) dummy number if not successful.
###initial_context/2##
initial_context(Forms, Options) -> #context{}
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.
###inspect/4##
inspect(F::Fun, Acc::Forms, Forms::Acc, Options) -> NewAcc
Fun = function()
Equvalent to do_inspect(Fun,Acc,Forms,initial_context(Forms,Options)).
###optionally_pretty_print/3##
optionally_pretty_print(Result::forms(), Options::options(), Context::#context{}) -> ok
###plain_transform/2##
plain_transform(Fun, Forms) -> forms()
Fun = function()
Forms = forms()
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 formcontinue
- dig into the sub-expressions of the form{done, NewForm}
- ReplaceForm
withNewForm
; return all following forms unchanged{error, Reason}
- Abort transformation with an error message.Example - This transform fun would convert all instances ofP ! Msg
togproc:send(P, Msg)
:
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.
###pp_beam/1##
pp_beam(Beam::file:filename()) -> string() | {error, Reason}
Reads debug_info from the beam file Beam and returns a string containing the pretty-printed corresponding erlang source code.
###pp_beam/2##
pp_beam(Beam::filename(), Out::filename()) -> ok | {error, Reason}
Reads debug_info from the beam file Beam and pretty-prints it as Erlang source code, storing it in the file Out.
###pp_src/2##
pp_src(Res::Forms, Out::filename()) -> ok
Pretty-prints the erlang source code corresponding to Forms into Out
###replace_function/4##
replace_function(F, Arity, NewForm, Forms) -> any()
###return/2##
return(Forms, Context) -> Forms | {error, Es, Ws} | {warnings, Forms, Ws}
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 correspondingModule: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
.
###revert/1##
revert(Tree) -> Forms
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.
###revert_form/1##
revert_form(F::Tree) -> Form
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.
###top/3##
top(F::function(), Forms::forms(), Options::list()) -> forms() | {error, term()}
###transform/4##
transform(Fun, Acc, Forms, Options) -> {TransformedForms, NewAcc}
Fun = function()
Options = [{Key, Value}]
Makes one pass