Skip to content

Latest commit

 

History

History
590 lines (236 loc) · 15.7 KB

parse_trans.md

File metadata and controls

590 lines (236 loc) · 15.7 KB

#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/2Equivalent to format_exception(Class, Reason, 4).
format_exception/3Produces 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/2Pretty-prints the erlang source code corresponding to Forms into Out.
replace_function/4
return/2Checks the transformed result for errors and warnings.
revert/1Reverts back from Syntax Tools format to Erlang forms.
revert_form/1Reverts 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()

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):
  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 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.

###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.

Note2: R16B03 introduced a bug, where forms produced by erl_syntax:revert/1 (specifically, implicit funs) could crash the linter. This function works around that limitation, after first verifying that it's necessary to do so. Use of the workaround can be forced with the help of the parse_trans environment variable {revert_workaround, true}. This variable will be removed when R16B03 is no longer 'supported'.

###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.

Note2: R16B03 introduced a bug, where forms produced by erl_syntax:revert/1 (specifically, implicit funs) could crash the linter. This function works around that limitation, after first verifying that it's necessary to do so. Use of the workaround can be forced with the help of the parse_trans environment variable {revert_workaround, true}. This variable will be removed when R16B03 is no longer 'supported'.

###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