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