Commit | Line | Data |
---|---|---|
60154d24 JM |
1 | # mal - Make a Lisp |
2 | ||
bcddc3e4 JM |
3 | ## Description |
4 | ||
5 | Mal is an interpreter for a subset of the Clojure programming | |
9b3362e8 | 6 | language. Mal is implemented from scratch in 16 different languages: |
bcddc3e4 | 7 | |
edc3b064 | 8 | * Bash shell |
bcddc3e4 | 9 | * C |
edc3b064 JM |
10 | * C# |
11 | * Clojure | |
1771ab50 | 12 | * Go |
bcddc3e4 | 13 | * Java |
d32f9b87 | 14 | * Javascript ([Online Demo](http://kanaka.github.io/mal)) |
bcddc3e4 JM |
15 | * GNU Make |
16 | * mal itself | |
6301e0b6 | 17 | * Perl |
edc3b064 JM |
18 | * PHP |
19 | * Postscript | |
20 | * Python | |
9b3362e8 | 21 | * R |
8adb0827 | 22 | * Ruby |
abdd56eb | 23 | * Rust |
bcddc3e4 JM |
24 | |
25 | ||
8d8679f2 | 26 | Mal is also a learning tool. Each implementation of mal is separated |
bcddc3e4 JM |
27 | into 11 incremental, self-contained (and testable) steps that |
28 | demonstrate core concepts of Lisp. The last step is capable of | |
29 | self-hosting (running the mal implemenation of mal). | |
30 | ||
31 | The mal (make a lisp) steps are: | |
32 | ||
33 | * step0_repl | |
34 | * step1_read_print | |
35 | * step2_eval | |
36 | * step3_env | |
37 | * step4_if_fn_do | |
38 | * step5_tco | |
39 | * step6_file | |
40 | * step7_quote | |
41 | * step8_macros | |
f41866db JM |
42 | * step9_try |
43 | * stepA_interop | |
bcddc3e4 JM |
44 | |
45 | ||
46 | Mal was presented publicly for the first time in a lightning talk at | |
47 | Clojure West 2014 (unfortunately there is no video). See | |
48 | mal/clojurewest2014.mal for the presentation that was given at the | |
49 | conference (yes the presentation is a mal program). | |
60154d24 JM |
50 | |
51 | ## Building/running implementations | |
52 | ||
bcddc3e4 | 53 | ### Bash 4 |
60154d24 JM |
54 | |
55 | ``` | |
56 | cd bash | |
57 | bash stepX_YYY.sh | |
58 | ``` | |
59 | ||
bcddc3e4 | 60 | ### C |
60154d24 | 61 | |
01c97316 JM |
62 | The C implementation of mal requires the following libraries (lib and |
63 | header packages): glib, libffi6 and either the libedit or GNU readline library. | |
54c75382 | 64 | |
60154d24 JM |
65 | ``` |
66 | cd c | |
67 | make | |
68 | ./stepX_YYY | |
69 | ``` | |
70 | ||
9b1563a3 | 71 | ### C# ### |
edc3b064 JM |
72 | |
73 | The C# implementation of mal has been tested on Linux using the Mono | |
74 | C# compiler (mcs) and the Mono runtime (version 2.10.8.1). Both are | |
75 | required to build and run the C# implementation. | |
76 | ||
77 | ``` | |
78 | cd cs | |
79 | make | |
80 | mono ./stepX_YYY | |
81 | ``` | |
82 | ||
83 | ||
bcddc3e4 | 84 | ### Clojure |
60154d24 JM |
85 | |
86 | ``` | |
87 | cd clojure | |
88 | lein with-profile +stepX trampoline run | |
89 | ``` | |
90 | ||
1771ab50 JM |
91 | ### Go |
92 | ||
93 | ``` | |
94 | cd go | |
95 | make | |
96 | ./stepX_YYY | |
97 | ``` | |
98 | ||
99 | ||
bcddc3e4 | 100 | ### Java 1.7 |
60154d24 | 101 | |
01c97316 JM |
102 | The Java implementation of mal requires maven2 to build. |
103 | ||
60154d24 JM |
104 | ``` |
105 | cd java | |
106 | mvn compile | |
107 | mvn -quiet exec:java -Dexec.mainClass=mal.stepX_YYY | |
108 | # OR | |
109 | mvn -quiet exec:java -Dexec.mainClass=mal.stepX_YYY -Dexec.args="CMDLINE_ARGS" | |
110 | ``` | |
111 | ||
bcddc3e4 | 112 | ### Javascript/Node |
60154d24 JM |
113 | |
114 | ``` | |
115 | cd js | |
54c75382 | 116 | npm update |
60154d24 JM |
117 | node stepX_YYY.js |
118 | ``` | |
119 | ||
bcddc3e4 | 120 | ### Mal |
60154d24 JM |
121 | |
122 | Running the mal implementation of mal involves running stepA of one of | |
123 | the other implementations and passing the mal step to run as a command | |
5d446bd8 | 124 | line argument. |
60154d24 JM |
125 | |
126 | ``` | |
127 | cd IMPL | |
128 | IMPL_STEPA_CMD ../mal/stepX_YYY.mal | |
129 | ||
130 | ``` | |
131 | ||
bcddc3e4 | 132 | ### GNU Make 3.81 |
60154d24 JM |
133 | |
134 | ``` | |
135 | cd make | |
136 | make -f stepX_YYY.mk | |
137 | ``` | |
138 | ||
9b1563a3 | 139 | ### Perl 5.8 |
9e5b2151 JM |
140 | |
141 | For readline line editing support, install Term::ReadLine::Perl or | |
142 | Term::ReadLine::Gnu from CPAN. | |
143 | ||
144 | ``` | |
145 | cd perl | |
146 | perl stepX_YYY.pl | |
147 | ``` | |
148 | ||
149 | ||
bcddc3e4 | 150 | ### PHP 5.3 |
60154d24 | 151 | |
01c97316 JM |
152 | The PHP implementation of mal requires the php command line interface |
153 | to run. | |
154 | ||
60154d24 JM |
155 | ``` |
156 | cd php | |
157 | php stepX_YYY.php | |
158 | ``` | |
159 | ||
bcddc3e4 | 160 | ### Postscript Level 2/3 |
60154d24 | 161 | |
01c97316 JM |
162 | The Postscript implementation of mal requires ghostscript to run. It |
163 | has been tested with ghostscript 9.10. | |
164 | ||
60154d24 JM |
165 | ``` |
166 | cd ps | |
fa64b741 | 167 | gs -q -dNODISPLAY -I./ stepX_YYY.ps |
60154d24 JM |
168 | ``` |
169 | ||
a05f7822 | 170 | ### Python (2 or 3) |
60154d24 JM |
171 | |
172 | ``` | |
173 | cd python | |
174 | python stepX_YYY.py | |
175 | ``` | |
8adb0827 | 176 | |
9b3362e8 JM |
177 | ### R |
178 | ||
179 | The R implementation of mal requires R (r-base-core) to run. | |
180 | ||
181 | ``` | |
182 | cd r | |
183 | make libs | |
184 | Rscript stepX_YYY.rb | |
185 | ``` | |
186 | ||
8adb0827 JM |
187 | ### Ruby (1.8) |
188 | ||
189 | ``` | |
190 | cd ruby | |
191 | ruby stepX_YYY.rb | |
192 | ``` | |
592eb5cf | 193 | |
abdd56eb JM |
194 | ### Rust (0.13) |
195 | ||
196 | The rust implementation of mal requires the rust compiler and build | |
197 | tool (cargo) to build. | |
198 | ||
199 | ``` | |
200 | cd rust | |
111dbaf1 JM |
201 | # Need patched pcre lib (should be temporary) |
202 | git clone https://github.com/kanaka/rust-pcre cadencemarseille-pcre | |
abdd56eb JM |
203 | cargo build |
204 | ./target/stepX_YYY | |
205 | ``` | |
206 | ||
592eb5cf JM |
207 | ## Running tests |
208 | ||
209 | The are nearly 400 generic Mal tests (for all implementations) in the | |
210 | `tests/` directory. Each step has a corresponding test file containing | |
211 | tests specific to that step. The `runtest.py` test harness uses | |
212 | pexpect to launch a Mal step implementation and then feeds the tests | |
213 | one at a time to the implementation and compares the output/return | |
214 | value to the expected output/return value. | |
215 | ||
216 | To simplify the process of running tests, a top level Makefile is | |
217 | provided with convenient test targets. | |
218 | ||
219 | * To run all the tests across all implementations (be prepared to wait): | |
220 | ||
221 | ``` | |
222 | make test | |
223 | ``` | |
224 | ||
225 | * To run all tests against a single implementation: | |
226 | ||
227 | ``` | |
228 | make test^IMPL | |
229 | ||
230 | # e.g. | |
231 | make test^clojure | |
232 | make test^js | |
233 | ``` | |
234 | ||
235 | * To run tests for a single step against all implementations: | |
236 | ||
237 | ``` | |
238 | make test^stepX | |
239 | ||
240 | # e.g. | |
241 | make test^step2 | |
242 | make test^step7 | |
243 | ``` | |
244 | ||
245 | * To run a specifc step against a single implementation: | |
246 | ||
247 | ``` | |
248 | make test^IMPL^stepX | |
249 | ||
250 | # e.g | |
251 | make test^ruby^step3 | |
252 | make test^ps^step4 | |
253 | ``` |