ms_transform(3)

MODULE
ms_transform - Parse_transform that translates fun syntax into match specifications.

DESCRIPTION

This module implements the parse_transform that makes calls to ets and dbg:fun2ms/1 translate into literal match specifications. It also implements the backend for the same functions when called from the erlang shell.

The translations from fun's to match_specs is accessed through the two "pseudo functions" ets:fun2ms/1 and dbg:fun2ms/1.

  Warning:

To use the pseudo functions triggering the translation, one has to include the header file ms_transform.hrl in the source code. Failure to do so will possibly result in runtime errors rather than compile time, as the expression may be valid as a plain erlang program without translation.

  Warning:

The fun has to be literally constructed inside the parameter list to the pseudo functions. The fun cannot be bound to a variable first and then passed to ets:fun2ms or dbg:fun2ms, i.e this will work: ets:fun2ms(fun(A) -> A end) but not this: F = fun(A) -> A end, ets:fun2ms(F). The later will result in a compile time error if the header is included, otherwise a runtime error. Even if the later construction would ever appear to work, it really doesn't, so don't ever use it.

Several restrictions apply to the fun that is beeing translated into a match_spec. To put it simple you cannot use anything in the fun that you cannot use in a match_spec. This means that, among others, the following restrictions apply to the fun itself:

    *   Functions wriiten in erlang cannot be called, neither local functions, global functions or real fun's

    *   Everything that is written as a function call will be translated into a match_spec call to a builtin function, so that the call is_list(X) will be translated to {'is_list', '$1'} ('$1' is just an example, the numbering may vary). If one tries to call a function that is not a match_spec builtin, it will cause an error.

    *   Variables occuring in the head of the fun will be replaced by match_spec variables in the order of occurence, so that the fragment fun({A, B, C}) will be replaced by {'$1', '$2', '$3'} etc. Every occurence of such a variable later in the match_spec will be replaced by a match_spec variable in the same way, so that the fun fun({A, B}) when is_atom(A) -> B end will be translated into [{{'$1', '$2'}, [{is_atom, '$1'}], ['$2']}].

    *   Variables that are not appearing in the head are imported from the environment and made into match_spec const expressions. Example from the shell:
        1> X = 25.
        25
        2> ets:fun2ms(fun({A,B}) when A > X -> B end).
        [{{'$1','$2'},[{'>','$1',{const,25}}],['$2']}]

    *   Matching with = cannot be used, neither in the head nor in the body. Example from the shell again:
        1> ets:fun2ms(fun({A,[B|C]=D}) when A > X -> B end).
        Error: fun with head matching ('=' in head) cannot be translated into
        match_spec
        {error,transform_error}
        2> ets:fun2ms(fun({A,[B|C]}) when A > X -> D = [B|C], D end).
        Error: fun with body matching ('=' in body) is illegal as match_spec
        {error,transform_error}

         All variables are bound in the head and the match_spec syntax does not allow multible bindings.

    *   The special match_spec variables '$_' and '$*' are accessed through the pseudo functions object() (for '$_') and bindings() (for '$*'). as an example, one could translate the following ets:match_object/2 call to a ets:select call:
        ets:match_object(Table, {'$1',test,'$2'}).

        ...is the same as...
        ets:select(Table, ets:fun2ms(fun({A,test,B}) -> object() end)).

        (This was just an example, in this simple case the former expression is probably prefferable in terms of readability). The ets:select/2 call will conceptually look like this in the resulting code:
        ets:select(Table, [{{'$1',test,'$2'},[],['$_']}]).

    *   Term constructions/literals are translated as much as is needed to get thewm into valid match_specs, so that tuples are made into match_spec tuple constructions (a one element tuple containing the tuple) and constant expressions are used when importing variables from the environment. Records are also translated into plain tuple constructions, calls to element etc. The guard test is_record/2 is translated into match_spec code using the three parameter version that's built into match_specs, so that is_record(A, t) is translated into {is_record, '$1', t, 5} given that the record size of record type t is 5. Records are of course still not accessible from the shell...

    *   Language constructions like case, if, catch etc that are not present in match_spec's are not allowed.

    *   The old names for the guard type tests (list, integer, float etc) are not allowed. All guard tests must be written with the new names is_list, is_tuple, is_record etc.

    *   If the header file ms_transform.hrl is not included, the fun won't be translated, which may result in a runtime error (depending on if the fun is valid in a pure erlang context). Be absolutely sure that the header is included when using ets and dbg:fun2ms/1 in compiled code.

    *   If the pseudo function triggering the translation is ets:fun2ms/1, the fun's head must contain a single variable or a single tuple. If the pseudo function is dbg:fun2ms/1 the fun's head must contain a single varaiable or a single list.

The translation from fun's to match_spec's is done at compile time, so runtime performance is not affected by using these pseudo functions. The compile time might be somewhat longer though.

For more information about match_specs, please read about them in erts users guide.

EXPORTS

parse_transform(Forms,_Options) -> Forms

    Types
        Forms = Erlang abstract code format, see the erl_parse module description
        _Options = Option list, required but not used

    Implements the actual transformation at compile time. This function is called by the compiler to do the source code transformation if and when the ms_transform.hrl header file is included in your source code. See the ets and dbg:fun2ms/1 function manual pages for documentation on how to use this parse_transform, see the match_spec chapter in ERTS users guide for a description of match specifications.

transform_from_shell(Dialect,Clauses,BoundEnvironment) -> term()

    Types
        Dialect = ets | dbg
        Clauses = Erlang abstract form for a single fun
        BoundEnvironment = [{atom(), term()}, ...], list of variable bindings in the shell environment

    Implements the actual transformation when the fun2ms functions are called from the shell. In this case the abstract form is for one single fun (parsed by the erlang shell), and all imported variables should be in the key-value list passed ass BoundEnvironment. The result is a term, normalized, i.e. not in abstract format.

format_error(Errcode) -> ErrMessage

    Types
        Errcode = term()
        ErrMessage = string()

    Takes an error code returned by one of the other functions in the module and creates a textual description of the error. Fairly uninteresting function actually.

AUTHOR
 Patrik Nyblom - support@erlang.ericsson.se