The original motivation is to fix the new (= nil ()) and
core_apply_accepts_macros tests.
Improve speed and warnings with byte compilation.
mal/core.el:
Wrap core functions during the loop in main, instead of writing the
conversion in each line of core-ns.
Use apply built-in concatenation of last argument.
Move handling of metadata to types.el.
mal/env.el:
Represent environments as cons cells instead of vectors.
mal/func.el:
Merged into types.el, it is not a special case anymore.
mal/printer.el:
Add macro case.
Define a pr-join helper for sequences and core.el.
mal/reader.el:
Rename the tokens local variable in reader.el (compiler warning).
mal/types.el:
Use type-specific accessors returning nil for the wrong type
(structural pattern matching would be better, but is too slow).
Represent native types directly when possible, and inline some trivial
accessors.
Use dedicated records instead of vectors.
Implement metadata only when required.
Represent keywords as strings (easyer, no counterpart).
run:
Run byte-compiled version.
steps:
Backport good ideas from stepA to step1, reducing the diff between
steps for future maintenance.
Implement 'do with a simple iteration (without map and butlast).
Make the repl-env local to main (compiler warning).
Make the code more idiomatic
* prefer loop over recursion (search in environments)
* declare variable and reassign them when convenient (exit of the TCO loop)
* car cdr cadr and so on instead of nth
* remove various vector <-> list conversions.
Use plain LUA strings as keys in environments.
Search outers environments with a loop.
Remove the now unneeded Env:find trick.
Let DEBUG-EVAL show the contents of all outer environments but repl_env.
Check the whole code with flake8, pylint and mypy.
Report all possible errors with extensive context.
Demonstrate iterators, decorators, functional tools, chain maps,
dataclasses, match statements, assignments expressions.
Implement environments with python chain maps.
Rewrite the reader without external dependencies (but inspired by the
ptk library). The motivation was that no external library is fully
type-checked for now.
Avoid name clashes when possible (print, read, readline, types).
Write the readline history file at exit, not after each prompt.
Replace printer.pr_str as methods of MAL objects. This is idiomatic
python, and improves the error reporting.
Change some representations so that the python equality matches the
MAL equality. The recursion is now implicit.
Remove -O from ./run. It took me a while to understand that run-time
assertions were disabled! MAL is about development, not performance.
Dispatch the special forms from a dict, for readability (pylint
rightfully complains that there are too many return statements in
eval_()).
Copy the recursion overflow fix, the python interaction from the first
python implementation.
Add tests detecting that nil false 0 () [] "" are distinct, and that 0
() are not False when tested (in python False == 0 and an empty
container is tested ).
Add tests checking that metadata does not affect equality (they do
with a naive python dataclass).
In mlton mode, syntax errors caught in the try/catch block were being
processed as "SyntaxError" without any additional context/message.
Explicitly pass the full message always.
xslt:
- The reader was returning the an odd args error when a hash-map literal
was not closed. This was because the the parsing error happened and
then the odd args test happened after and overwrote the parsing error.
- Also, fix the read-string function so that if an error is set by the
reader, this is converted to a full error that bubbles up.
c:
- read_list errors were not being detected/propagated in read_hash_map
after calling read_list.
zig:
- reader errors were not being caught in the rep loop until step 8, so
those errors in step6 and step7 were causing the REPL to exit.
The mal implementation uses the defmacro! function from the host
language/environment and assumes that it returns a macro function (and
ignores the environment modification effect). The vala implementation
was setting the is_macro flag at the wrong time so that the final
returned value from defmacro! was a function without the macro flag set.
Also, add a deferrable test of `defmacro!` to make sure it returns
a macro.
Two problems were causing powershell self-hosting to fail:
* Some mal core functions are declared using `Get-Command` to hoist the
lower level function and this didn't work with the `fn?` command. So
add a stepA test for `(fn? list?)` and fix the `fn?` command to check for
CommandInfo types too.
* A list with a single `$null` is treated specially by Powershell in
a pipeline and was resulting in an empty Vector anywhere that `[nil]`
was evaluated. Change all the pipelined uses of `ForEach` to
`ForEach-Object` and wrap the result in an array construct `@( ... )`.
Add a step2 test to make sure that `[nil]` is evaluated correctly.
In common-lisp, self-hosted test4 was failing and it appeared that nil
and empty list () were being conflated. The root cause is that in
common-lisp the form `(list? nil)` was returning true. Fix this in the
core `list?` function.
There was no test for this case so add one to step4 tests.
These implementations were double evaluating the last position of a do
form (off by one). Mostly this is just a performance issue until you
have something with side-effect in the last position such as prn's,
swap!'s or readline's. In self-hosted mode this become apparent with
large chunks of mal code in the last position. The symptoms were
repeated prns and multiple levels of readline being called, etc.
Add a step6 test that uses atoms to test this (should be in step
4 using prn side-effects but it's difficult to match across multiple
lines in a cross-platform way so we test using an atom in step6.
Also, remove cast in Kotlin that was causing a compile warning.
The try block needs to happen and be returned and not continue the TCO
loop. If it does then the successful result of a try block gets
evaluated an extra time so something like this `(try* (list 1) (catch*
e (prn :e e)))` will cause an exception. If an exception occurs, then
the catch block of a try/catch can loop/TCO without issue but not the
initial try form/block.
Newer versions of sbcl now have the same sxhash issue on compound types
as the other common lisp implementations. So always dereference the
underlying base type when generating a hash. This fixes the bug in newer
sbcl that was resulting in `get` and `contains?` not working for
hash-maps.