-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlfe_gen.txt
138 lines (99 loc) · 3.47 KB
/
lfe_gen.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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]], 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 = 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)