This is rather contrary to the guide, which expects a loop in EVAL, but
perl is unusual in having native support for (manual) tail-call
optimisation and it would seem a shame not to take advantage of this.
This leaves macros broken since all functions are now implemented as
core functions, and we don't yet have support for turning them into
macros.
Rather than attaching metadata directly to objects, hold it in a
auxiliary hash keyed by object ID. Perl's Hash::Util::FieldHash
provides a means to do this with proper garbage-collection. This does
mean that cloning an object no longer brings its metadata along, but I
think the only use of _clone outside of attaching metadata is to make
macros, and (for now) mal doesn't require that 'defmacro!' preserve
metadata.
This commit only adds the new metadata system. Most of the old one is
still lying around.
The `_map?` function was introduced when transitioning the macro
property being stored in metadata to uinsg a regular map with
a special key. The `_map?` function causes issues in a few places but
the biggest issue is that it breaks the `_macro?` function for the
second order self-hosted mal instance. The `_macro?` function contains
a `(map? x)` call that returns false resulting in the `_macro?` call
returning false. I'll push something later that fixes this and also
that activates second order self-hosted tests so we can catch this
sort of issue in the future.
Let `load-file` append a new line in case last line contains a
comment.
Also append `nil` so that the return value is predictible. Remove the
existing explicit `nil` from existing sources.
Adapt documentation and tests.
It now uses "unless" rather than "if", uses "isa" rather than
_sequential_Q, doesn't bother with temporary variables for the types
of the arguments, and doesn't special-case symbols.
The guide says that 'quux-eval', which the perl implementation calls
'pl*', should be a core function. I can't see any good reason why it
shouldn't be, so I've turned it into one.
I kept not knowing where to add things, so I've roughly sorted them into
pragmas, then external modules, then internal modules. This helps with
the situation that internal modules are named in lower case, which is
odd for Perl (but normal for mal).
It's not safe to call "isa" on unblessed references, and not all
reference types are valid mal values. Now only actual mal values get
treated as such and everything else gets printed as-is or converted to a
Mal::String.
Perl package names (and hence class names) are global, meaning that if
any module that we use loads a module called "Symbol", it will clash
with mal's Symbol class. It turns out that something does this already,
which breaks inheritance from mal's Symbol class. Since most of mal's
class names are very generic, it seems wise to rename all of them.
Specifically, the hash-map case now uses 'pairmap' to avoid the need for
a 'for' loop. The code for sequences is now shared between lists and
vectors, since only the destination type differs.
Instead, the file itself does the def of -*ARGS*-. The behavior that
the final value of a loaded file is returned is not necessarily
something we want to assume.