LFE Documentation

Dynamic Code Generator

    MODULE

        lfe_gen

    MODULE SUMMARY

        Lisp Flavoured Erlang (LFE) dynamic code generator

    DESCRIPTION

        This module provides an experimental interface for dynamically
        generating modules.

    DATA TYPES

        sexpr()
            An LFE s-expression, a list structure.

    EXPORTS

    compile_forms(Forms) -> CompRet

        where
          Forms = [sexpr()]
          CompRet = BinRet | ErrRet
          BinRet = {ok,ModuleName,Binary,Warnings}
          ErrRet = {error,Errors,Warnings}

        Compile a list of LFE forms which comprise an LFE module. For
        example:

        lfe_gen:compile_forms([[defmodule,foo,[export,[a,0]]],
                       [defun,a,[],[quote,yes]]])

        Both WarningList and ErrorList have the following format:

        [{FileName,[ErrorInfo]}]

        ErrorInfo is described below. When generating Errors and
        Warnings the "line number" is the index of the form in which
        the error occured.

    new_module(Name) -> ModDef.
    add_exports([{Name,Arity}], ModDef) -> ModDef.
    add_imports({from,Module,[{Name,Arity}]}, ModDef) -> ModDef.
    add_form(Form, ModDef) -> ModDef.
    print_mod(ModDef) -> iolist().
    compile_mod(Mod) -> CompRet

        where
          CompRet = BinRet | ErrRet
          BinRet = {ok,ModuleName,Binary,Warnings}
          ErrRet = {error,Errors,Warnings}

        These functions are used to incrementally create a module
        which can at the end be compiled by compile_mod/1. The same
        example as above could be written:

        M0 = lfe_gen:new_module(foo),
        M1 = lfe_gen:add_exports([{a,0}], M0),
        M2 = lfe_gen:add_form([defun,a,[],[quote,yes]], M2),
        lfe_gen:compile_mod(M2)

    Example

        In this example we build a module of parameters where each
        parameter has a number of features which each have a value. We
        will create one function for each parameter and the feature is
        the functions argument. The value for each feature is
        returned.

        We are creating code equivalent to:

        -module(Name).
        -export([<param1>/1,...]).

        <param1>(Feature) ->
            case Feature of
            <feature1> -> <value1>;
            ...
            _ -> erlang:error({unknown_feature,<param1>,Feature)
            end.
        ...

        but generating it and compiling it directly in memory without
        generating a text file. We assume that we have collected the
        data and have it in the form:

        Params = [{Parameter,[{Feature,Value}]}]

        The equivalent LFE code which we will be generating is:

        (defmodule Name
          (export (<param1> 1) (<param2> 1) ... ))

        (defun <param1> (f)
          (case f
            ('<feature1> '<value1>)
            ...
            (f (: erlang error (tuple 'unknown_feature '<param1> f)))))

        ...

        The following code builds and compiles a module from the
        parameter data:

        make_module(Name, Params) ->
            Mod0 = lfe_gen:new_module(Name),
            Exps = map(fun ({F,_}) -> {F,1} end, Params),
            Mod1 = lfe_gen:add_exports(Exps, Mod0),
            Mod2 = make_funcs(Params, Mod1),
            lfe_gen:compile_mod(Mod2).

        make_funcs([{Param,Fs}|Ps], Mod) ->
            %% Define catch-all which generates more explicit exit value.
            CatchAll = [f,[':',erlang,error,
                   [tuple,unknown_feature,[quote,Param],f]]],
            %% Build case clauses
            Cls = foldr(fun ({Feature,Value}, Cls) ->
                    [[[quote,Feature],[quote,Value]]|Cls]
                end, [CatchAll], Params),
            %% Build function.
            Func = [defun,Param,[f],['case',f,Cls]],
            make_funcs(Ps, lfe_gen:add_form(Func, Mod));
        make_funcs([], Mod) -> Mod.            %All done


    Error Information

        The ErrorInfo mentioned above is the standard ErrorInfo
        structure which is returned from all IO modules. It has the
        following format:

        {ErrorLine,Module,ErrorDescriptor}

        A string describing the error is obtained with the following call:

        apply(Module, format_error, ErrorDescriptor)