View Source merlin (merlin v2.0.1)

Parse transform helper library

The main function is transform/3, which let's you easily traverse an ast(), optionally modify it, and carry a state.

There's some of helperfunctions that provides easy access to commonly needed information. For example the current set of bindings and the MFA for every function call.

Finally, when you're done transforming return/1 the result in the format expected by erl_lint (or else you crash the compiler).

Link to this section Summary

Functions

Like erl_syntax_lib:analyze_forms but returns maps.

Same as analyze/1, but also extracts and appends any inline -compile options to the given one.

Annotate the given module forms according to the given options.

Returns the first form for which the given function returns true. This returns a {ok, Form} tuple on success, and {error, notfound} otherwise.
Returns a flat list with all forms for which the given function returns true, if any. They are returned in source order.

Returns the result from transform/3, or just the final forms, to an erl_lint compatible format.

Reverts back from Syntax Tools format to Erlang forms.

Calls the given function with the forms inside the given Result, while preserving any errors and/or warnings.

Transforms the given Forms using the given Transformer with the given State.

Link to this section Types

-type action() :: continue | delete | return | exceptions.
-type analysis() ::
    #{attributes := #{spec => #{atom() => ast()}, type => #{atom() => ast()}, atom() => [ast()]},
      exports := [function_name()],
      file := string(),
      functions := [{atom(), arity()}],
      imports := #{module() => [function_name()]},
      module_imports := [module()],
      records := map(),
      errors | module | warnings => _}.
-type ast() :: erl_syntax:syntaxTree().
-type error_marker() :: {error, marker_with_file()}.
-type exception_marker() :: {Position :: erl_anno:location(), Module :: module(), Reason :: term()}.
Link to this type

exceptions_grouped_by_file/0

View Source
-type exceptions_grouped_by_file() :: [{File :: string(), [exception_marker()]}].
-type function_name() :: atom() | {atom(), arity()} | {module(), atom()}.
-type marker_with_file() :: {File :: string(), exception_marker()}.
{Type, {File, {Position, Module, Reason}}}.
Link to this type

parse_transform_return/0

View Source
-type parse_transform_return() :: parse_transform_return([ast()]).
Link to this type

parse_transform_return/1

View Source
-type parse_transform_return(Forms) ::
    Forms |
    {warning, Forms, exceptions_grouped_by_file()} |
    {error, exceptions_grouped_by_file(), exceptions_grouped_by_file()}.
-type phase() :: enter | leaf | exit.
-type transformer(Extra) :: fun((phase(), ast(), Extra) -> transformer_return(Extra)).
-type transformer_return(Extra) ::
    ast() |
    {ast(), Extra} |
    continue |
    {continue, ast()} |
    {continue, ast(), Extra} |
    return |
    {return, ast()} |
    {return, ast(), Extra} |
    delete |
    {delete, Extra} |
    {error, term()} |
    {error, term(), Extra} |
    {warning, term()} |
    {warning, term(), ast()} |
    {warning, term(), ast(), Extra} |
    {exceptions, [{error | warning, term()}], ast(), Extra}.
-type warning_marker() :: {warning, marker_with_file()}.

Link to this section Functions

-spec analyze([ast()]) -> analysis().

Like erl_syntax_lib:analyze_forms but returns maps.

Also all fields are present, except module so you can determine if it exists or not. It also includes a file field and makes some fields easier to use, like records being a map from name to definition.

See also: analysis().

Link to this function

analyze(ModuleForms, Options)

View Source
-spec analyze([ast()], [compile:option()]) -> {analysis(), [compile:option()]}.
Same as analyze/1, but also extracts and appends any inline -compile options to the given one.
-spec annotate([ast()]) -> parse_transform_return().

Equivalent to annotate(ModuleForms, [bindings, resolve_calls, file]).

Link to this function

annotate(ModuleForms, Options)

View Source
-spec annotate(ModuleForms, Options) -> parse_transform_return(ModuleForms)
            when
                ModuleForms :: [ast()],
                Options :: [Option | {Option, boolean()}],
                Option :: bindings | resolve_calls | file.

Annotate the given module forms according to the given options.

It always annotates each function definition with a is_exportedannotation.

bindings
See erl_syntax_lib:annotate_bindings/2
resolve_calls
Resolves local and remote calls according to the -import attributes, if any. For all successfully resolved calls, this sets both a module and is_exportedannotation on the application form.
file
Each form is annotated with the current file, as determined by the most recent -file attribute.
Returns the first form for which the given function returns true. This returns a {ok, Form} tuple on success, and {error, notfound} otherwise.
Returns a flat list with all forms for which the given function returns true, if any. They are returned in source order.
-spec return(parse_transform_return(Forms) | {parse_transform_return(Forms), State}) ->
          parse_transform_return(Forms)
          when State :: term(), Forms :: [ast()].

Returns the result from transform/3, or just the final forms, to an erl_lint compatible format.

This reverts the forms, while respecting any errors and/or warnings.

Reverts back from Syntax Tools format to Erlang forms.

Accepts a list of forms, or a single form.

Copied from parse_trans:revert_form/1 and slightly modified. The original also handles a bug in R16B03, but that is ancient history now.
-spec then(Result, fun((Forms) -> Forms)) -> Result
        when Result :: parse_transform_return(Forms), Forms :: [ast()].
Calls the given function with the forms inside the given Result, while preserving any errors and/or warnings.
Link to this function

transform(Forms, Transformer, Extra)

View Source
-spec transform(Forms, transformer(Extra), Extra) -> {parse_transform_return(Forms), Extra}
             when Forms :: [ast()].

Transforms the given Forms using the given Transformer with the given State.

This is done through three phases: 1, When you enter a subtree 2, When you encounter a leaf node 3, When you exit a subtree

It's recommended to have a match-all clause to future proof your code.