lfe_gen(3)

NAME

lfe_gen - Lisp Flavoured Erlang (LFE) dynamic code generator

SYNOPSIS

This module provides an experimental interface for dynamically generating modules.

DATA TYPES

sexpr()

An LFE s-expression, a list structure.

EXPORTS

new_module(Name) -> ModDef.

add_exports([[Name,Arity]], ModDef) -> ModDef.

add_imports([from,Module|Functions], ModDef) -> ModDef.

add_imports([rename,Module|Renames], ModDef) -> ModDef.

add_attribute(Attribute, ModDef) -> ModDef.

add_form(Form, ModDef) -> ModDef.

build_mod(ModDef) -> Forms.

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 various components have the same formats as they do when defining a module in a file. A simple module which defines one function a/0 could be defined with:

    M0 = lfe_gen:new_module(foo),
    M1 = lfe_gen:add_exports([[a,0]], M0),
    M2 = lfe_gen:add_form([defun,a,[],[quote,yes]], M1),
    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 = lists:map(fun ({Param,_}) -> [Param,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
        Fold = fun ({Feature,Value}, Cls) ->
                       [[[quote,Feature],[quote,Value]]|Cls]
               end
        Cls = lists:foldr(Fold, [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

This module could be generated and then be loaded into the system by doing:

    {ok,ModuleName,Binary,Warnings} = make_module(Name, Params),
    code:load_binary(ModuleName, "nofile", Binary)

The second argument to code:load_binary/3, here "nofile", is irrelevant in this case.

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)

SEE ALSO

lfe_comp(3), lfe_macro(3)

AUTHORS
Robert Virding.