meme is a minimal scheme. It's implemented in C, has GC, and should express reasonable TCO. Run the examples like so:
$ ./meme fact.w
# Special forms
(= a b)
Evaluate `b` and store it in the current frame under the symbol `a`.
(^ args... body)
Captures the environment when invoked. Parameters are bound to the name of each `arg` in the evaluation of the `body` if called.
(- a b...)
The integers of `b` are each subtracted from the value of `a`.
(< a b)
`a` is numerically less than `b`.
(? a b c)
If `a` is not false, evaluate `b` else `c`.
(# (a...) b)
Returns a callable. Invoking it binds the arguments to each successive symbol in `a`. `b` is evaluated, and the returned expression is *again* evaluated, but this time in the macro callers environment.
Return the numerical product of all integers in `a`.
(- a b...)
If b is null, return `-a`
# Running under valgrind
Make sure to set G_SLICE=always-malloc, and possibly G_DEBUG=gc-friendly in the environment. See http://stackoverflow.com/questions/4254610/valgrind-reports-memory-possibly-lost-when-using-glib-data-types.
* Decide on the "nil" type. Void, empty, (), and others are all very similar.
* Use libreadline.
* Use GMP for numbers.
* Reintroduce tail call optimization.
* Possible optimization: reclaim empty envs if they're only referenced by other environments.
* Ditch hash tables in environments (except perhaps the top level one?)
* Use slice allocator for pairs, and possibly other types
* Cut back on unneeded loop detections.
* Remove a lot of null checks by implementing "default" behaviours for all types.
* Find out why slicing isn't as fast as raw malloc.