Derived from kanaka/mal Go implementation of a Lisp interpreter.
kanaka/mal Lisp is Clojure inspired.
Keeping 100% backwards compatibility with kanaka/mal.
There almost 100 implementations on almost 100 languages available on repository kanaka/mal.
This derived implementation is focused on embedability in Go projects.
See mal main for an example on how to embed it in Go code.
Tested on Go version 1.17.
This implementation uses chzyer/readline instead of C implented readline or libedit, making this implementation pure Go.
Changes
atom is multithread
- Tests executed using Go test library. Original implementation uses a
runtest.py in Python to keep all implementations compatible. But it makes the Go development less enjoyable. Tests files are the original ones, there is simply a new runtest_test.go that substitutes the original Python script
- Some tests are actually in mal, using the macros commented in Additions section (now only the test library itself). Well, actually not many at this moment, see "Test file specs" below
- Reader regexp's are compiled once
core library moved to lib/core
- Using chzyer/readline instead of C
readline for the mal REPL
- Multiline REPL
- REPL history stored in
~/.mal_history (instead of kanaka/mal's ~/.mal-history)
(let* () A B C) returns C as Clojure let instead of A, and evaluates A, B and C
(do) returns nil as Clojure instead of panicking
To test the implementation use:
go test ./...
go test actually validates the step*.mal files.
There are some benchmarks as well:
go test -benchmem -benchtime 5s -bench '^.+$' github.com/jig/lisp
Additions
(range a b) returns a vector of integers from a to b-1
(merge hm1 hm2) returns the merge of two hash maps, second takes precedence
(unbase64 string), (unbase64 byteString), (str2binary string), (binary2str byteString) to deal with []byte variables
(sleep ms) sleeps ms milliseconds
- Support of
¬ as string terminator to simplify JSON strings. Strings that start with {" and end with "} are printed using ¬, otherwise strings are printed as usual (with "). To escape a ¬ character in a ¬ delimited string you must escape it by doubling it: ¬Hello¬¬World!¬ would be printed as Hello¬World. This behaviour allows to not to have to escape " nor \ characters.
(jsondecode ¬{"key": "value"}¬) to decode JSON to MAL data and (jsonencode ...) does the opposite. Example: (jsonencode (jsondecode ¬{"key":"value","key1": [{"a":"b","c":"d"},2,3]}¬)). Note that MAL vectors (e.g. [1 2 3]) and MAL lists (e.g. (list 1 2 3) are both converted to JSON vectors always. Decoding a JSON vector is done on a MAL vector always though
(context* (do ...)) provides a Go context. Context contents depend on Go, and might be passed to specific functions context compatible
- Test minimal library to be used with
maltest interpreter (see ./cmd/maltest/ folder). See below test specs
- Project compatible with GitHub CodeSpaces. Press
. on your keyboard and you are ready to deploy a CodeSpace with mal in it
(trace expr) to trace the expr code
(assert expr & optional-error) asserts expression is not nil nor false, otherwise it success returning nil
- Errors are decorated with line numbers
Test file specs
Execute the testfile with:
$ mal --test .
And a minimal test example sample_test.mal:
(test.suite "complete tests"
(assert-true "2 + 2 = 4 is true" (= 4 (+ 2 2)))
(assert-false "2 + 2 = 5 is false" (= 5 (+ 2 2)))
(assert-throws "0 / 0 throws an error" (/ 0 0)))
Some benchmark of the implementations:
$ go test -bench ".+" -benchtime 2s