Dockerfile: make Nim build one layer.
[jackhill/mal.git] / README.md
1 # mal - Make a Lisp
2
3 ## Description
4
5 Mal is a Clojure inspired Lisp interpreter.
6
7 Mal is implemented in 27 different languages:
8
9 * Bash shell
10 * C
11 * C#
12 * Clojure
13 * CoffeeScript
14 * Forth
15 * Go
16 * Haskell
17 * Java
18 * Javascript ([Online Demo](http://kanaka.github.io/mal))
19 * Lua
20 * GNU Make
21 * mal itself
22 * MATLAB
23 * [miniMAL](https://github.com/kanaka/miniMAL)
24 * Nim
25 * OCaml
26 * Perl
27 * PHP
28 * Postscript
29 * Python
30 * R
31 * Racket
32 * Ruby
33 * Rust
34 * Scala
35 * Visual Basic.NET
36
37
38 Mal is a learning tool. See the [make-a-lisp process
39 guide](process/guide.md). Each implementation of mal is separated into
40 11 incremental, self-contained (and testable) steps that demonstrate
41 core concepts of Lisp. The last step is capable of self-hosting
42 (running the mal implementation of mal).
43
44 The mal (make a lisp) steps are:
45
46 * [step0_repl](process/guide.md#step0)
47 * [step1_read_print](process/guide.md#step1)
48 * [step2_eval](process/guide.md#step2)
49 * [step3_env](process/guide.md#step3)
50 * [step4_if_fn_do](process/guide.md#step4)
51 * [step5_tco](process/guide.md#step5)
52 * [step6_file](process/guide.md#step6)
53 * [step7_quote](process/guide.md#step7)
54 * [step8_macros](process/guide.md#step8)
55 * [step9_try](process/guide.md#step9)
56 * [stepA_mal](process/guide.md#stepA)
57
58
59 Mal was presented publicly for the first time in a lightning talk at
60 Clojure West 2014 (unfortunately there is no video). See
61 mal/clojurewest2014.mal for the presentation that was given at the
62 conference (yes the presentation is a mal program).
63
64 If you are interesting in creating a mal implementation (or just
65 interested in using mal for something), please stop by the #mal
66 channel on freenode. In addition to the [make-a-lisp process
67 guide](process/guide.md) there is also a [mal/make-a-lisp
68 FAQ](docs/FAQ.md) where I attempt to answer some common questions.
69
70 ## Building/running implementations
71
72 ### Bash 4
73
74 ```
75 cd bash
76 bash stepX_YYY.sh
77 ```
78
79 ### C
80
81 The C implementation of mal requires the following libraries (lib and
82 header packages): glib, libffi6 and either the libedit or GNU readline library.
83
84 ```
85 cd c
86 make
87 ./stepX_YYY
88 ```
89
90 ### C# ###
91
92 The C# implementation of mal has been tested on Linux using the Mono
93 C# compiler (mcs) and the Mono runtime (version 2.10.8.1). Both are
94 required to build and run the C# implementation.
95
96 ```
97 cd cs
98 make
99 mono ./stepX_YYY.exe
100 ```
101
102
103 ### Clojure
104
105 ```
106 cd clojure
107 lein with-profile +stepX trampoline run
108 ```
109
110 ### CoffeeScript
111
112 ```
113 sudo npm install -g coffee-script
114 cd coffee
115 coffee ./stepX_YYY
116 ```
117
118 ### Forth
119
120 ```
121 cd forth
122 gforth stepX_YYY.fs
123 ```
124
125 ### Go
126
127 You Go implementation of mal requires that go is installed on on the
128 path. The implementation has been tested with Go 1.3.1.
129
130 ```
131 cd go
132 make
133 ./stepX_YYY
134 ```
135
136
137 ### Haskell
138
139 Install the Haskell compiler (ghc/ghci), the Haskell platform and
140 either the editline package (BSD) or the readline package (GPL). On
141 Ubuntu these packages are: ghc, haskell-platform,
142 libghc-readline-dev/libghc-editline-dev
143
144 ```
145 cd haskell
146 make
147 ./stepX_YYY
148 ```
149
150
151 ### Java 1.7
152
153 The Java implementation of mal requires maven2 to build.
154
155 ```
156 cd java
157 mvn compile
158 mvn -quiet exec:java -Dexec.mainClass=mal.stepX_YYY
159 # OR
160 mvn -quiet exec:java -Dexec.mainClass=mal.stepX_YYY -Dexec.args="CMDLINE_ARGS"
161 ```
162
163 ### Javascript/Node
164
165 ```
166 cd js
167 npm update
168 node stepX_YYY.js
169 ```
170
171 ### Lua
172
173 Running the Lua implementation of mal requires lua 5.1 or later,
174 luarocks and the lua-rex-pcre library installed.
175
176 ```
177 cd lua
178 make # to build and link linenoise.so
179 ./stepX_YYY.lua
180 ```
181
182 ### Mal
183
184 Running the mal implementation of mal involves running stepA of one of
185 the other implementations and passing the mal step to run as a command
186 line argument.
187
188 ```
189 cd IMPL
190 IMPL_STEPA_CMD ../mal/stepX_YYY.mal
191
192 ```
193
194 ### GNU Make 3.81
195
196 ```
197 cd make
198 make -f stepX_YYY.mk
199 ```
200
201 ### Nim 0.10.3
202
203 Running the Nim implementation of mal requires Nim's current devel branch
204 (0.10.3) or later, and the nre library installed.
205
206 ```
207 cd nim
208 make
209 # OR
210 nimble build
211 ./stepX_YYY
212 ```
213
214 ### OCaml 4.01.0
215
216 ```
217 cd ocaml
218 make
219 ./stepX_YYY
220 ```
221
222 ### MATLAB
223
224 The MATLAB implementation of mal has been tested with MATLAB version
225 R2014a on Linux. Note that MATLAB is a commercial product. It should
226 be fairly simple to support GNU Octave once it support classdef object
227 syntax.
228
229 ```
230 cd matlab
231 ./stepX_YYY
232 matlab -nodisplay -nosplash -nodesktop -nojvm -r "stepX_YYY();quit;"
233 # OR with command line arguments
234 matlab -nodisplay -nosplash -nodesktop -nojvm -r "stepX_YYY('arg1','arg2');quit;"
235 ```
236
237 ### miniMAL
238
239 [miniMAL](https://github.com/kanaka/miniMAL) is small Lisp interpreter
240 implemented in less than 1024 bytes of JavaScript. To run the miniMAL
241 implementation of mal you need to download/install the miniMAL
242 interpreter (which requires Node.js).
243 ```
244 cd miniMAL
245 # Download miniMAL and dependencies
246 npm install
247 export PATH=`pwd`/node_modules/minimal-lisp/:$PATH
248 # Now run mal implementation in miniMAL
249 miniMAL ./stepX_YYY
250 ```
251
252 ### Perl 5.8
253
254 For readline line editing support, install Term::ReadLine::Perl or
255 Term::ReadLine::Gnu from CPAN.
256
257 ```
258 cd perl
259 perl stepX_YYY.pl
260 ```
261
262
263 ### PHP 5.3
264
265 The PHP implementation of mal requires the php command line interface
266 to run.
267
268 ```
269 cd php
270 php stepX_YYY.php
271 ```
272
273 ### Postscript Level 2/3
274
275 The Postscript implementation of mal requires ghostscript to run. It
276 has been tested with ghostscript 9.10.
277
278 ```
279 cd ps
280 gs -q -dNODISPLAY -I./ stepX_YYY.ps
281 ```
282
283 ### Python (2 or 3)
284
285 ```
286 cd python
287 python stepX_YYY.py
288 ```
289
290 ### R
291
292 The R implementation of mal requires R (r-base-core) to run.
293
294 ```
295 cd r
296 make libs # to download and build rdyncall
297 Rscript stepX_YYY.r
298 ```
299
300 ### Racket (5.3)
301
302 The Racket implementation of mal requires the Racket
303 compiler/interpreter to run.
304
305 ```
306 cd racket
307 ./stepX_YYY.rkt
308 ```
309
310 ### Ruby (1.9+)
311
312 ```
313 cd ruby
314 ruby stepX_YYY.rb
315 ```
316
317 ### Rust (1.0.0 nightly)
318
319 The rust implementation of mal requires the rust compiler and build
320 tool (cargo) to build.
321
322 ```
323 cd rust
324 cargo run --release --bin stepX_YYY
325 ```
326
327 ### Scala ###
328
329 Install scala and sbt (http://www.scala-sbt.org/0.13/tutorial/Installing-sbt-on-Linux.html):
330
331 ```
332 cd scala
333 sbt 'run-main stepX_YYY'
334 # OR
335 sbt compile
336 scala -classpath target/scala*/classes stepX_YYY
337 ```
338
339 ### Visual Basic.NET ###
340
341 The VB.NET implementation of mal has been tested on Linux using the Mono
342 VB compiler (vbnc) and the Mono runtime (version 2.10.8.1). Both are
343 required to build and run the VB.NET implementation.
344
345 ```
346 cd vb
347 make
348 mono ./stepX_YYY.exe
349 ```
350
351
352
353 ## Running tests
354
355 ### Functional tests
356
357 The are nearly 500 generic functional tests (for all implementations)
358 in the `tests/` directory. Each step has a corresponding test file
359 containing tests specific to that step. The `runtest.py` test harness
360 uses pexpect to launch a Mal step implementation and then feeds the
361 tests one at a time to the implementation and compares the
362 output/return value to the expected output/return value.
363
364 To simplify the process of running tests, a top level Makefile is
365 provided with convenient test targets.
366
367 * To run all the tests across all implementations (be prepared to wait):
368
369 ```
370 make test
371 ```
372
373 * To run all tests against a single implementation:
374
375 ```
376 make test^IMPL
377
378 # e.g.
379 make test^clojure
380 make test^js
381 ```
382
383 * To run tests for a single step against all implementations:
384
385 ```
386 make test^stepX
387
388 # e.g.
389 make test^step2
390 make test^step7
391 ```
392
393 * To run tests for a specifc step against a single implementation:
394
395 ```
396 make test^IMPL^stepX
397
398 # e.g
399 make test^ruby^step3
400 make test^ps^step4
401 ```
402
403 ### Self-hosted functional tests
404
405 * To run the functional tests in self-hosted mode, you specify `mal`
406 as the test implementation and use the `MAL_IMPL` make variable
407 to change the underlying host language (default is JavaScript):
408 ```
409 make MAL_IMPL=IMPL test^mal^step2
410
411 # e.g.
412 make test^mal^step2 # js is default
413 make MAL_IMPL=ruby test^mal^step2
414 make MAL_IMPL=python test^mal^step2
415 ```
416
417
418 ### Performance tests
419
420 Warning: These performance tests are neither statistically valid nor
421 comprehensive; runtime performance is a not a primary goal of mal. If
422 you draw any serious conclusions from these performance tests, then
423 please contact me about some amazing oceanfront property in Kansas
424 that I'm willing to sell you for cheap.
425
426 * To run performance tests against a single implementation:
427 ```
428 make perf^IMPL
429
430 # e.g.
431 make perf^js
432 ```
433
434 * To run performance tests against all implementations:
435 ```
436 make perf
437 ```
438
439 ### Generating language statistics
440
441 * To report line and byte stastics for a single implementation:
442 ```
443 make stats^IMPL
444
445 # e.g.
446 make stats^js
447 ```
448
449 * To report line and bytes stastics for general Lisp code (env, core
450 and stepA):
451 ```
452 make stats-lisp^IMPL
453
454 # e.g.
455 make stats-lisp^js
456 ```
457
458 ## Docker test environment
459
460 There is a Dockerfile included in the `tests/docker` directory that
461 builds a docker image based on Ubuntu Utopic that contains everything
462 needed to run tests against all the implementations (except for MATLAB
463 which is proprietary/licensed).
464
465 Build the the docker image using a provided script. WARNING: this will
466 likely take over an hour to build from scratch and use more 3 GB of disk:
467 ```bash
468 ./tests/docker-build.sh
469 ```
470
471 Launch a docker container from that image built above. This will
472 volume mount the mal directory to `/mal` and then give you a bash
473 prompt in the container. You can then run individual mal
474 implementations and tests:
475 ```bash
476 ./tests/docker-run.sh
477 ```
478
479 You can also specify a command to run within the container. For
480 example, to run step2 tests for every implementation (except MATLAB):
481 ```bash
482 ./tests/docker-run.sh make SKIP_IMPLS="matlab" test^step2
483 ```
484
485 **Notes**:
486 * JVM-based language implementations (Java, Clojure, Scala): you will
487 need to run these implementations once manually first before you can
488 run tests because runtime dependencies need to be downloaded to
489 avoid the tests timing out. These dependencies are download to
490 dot-files in the /mal directory so they will persist between runs.
491 * Compiled languages: if you host system is different enough from
492 Ubuntu Utopic then you may need to re-compile your compiled
493 languages from within the container to avoid linker version
494 mismatches.
495
496
497 ## License
498
499 Mal (make-a-lisp) is licensed under the MPL 2.0 (Mozilla Public
500 License 2.0). See LICENSE.txt for more details.
501