If you look close at that sample, you may notice the thing that distinguishes this lisp from other lisps, and the idea I wanted to play with that had me writing this in the first place: There are no functions in this LISP. Or rather there is no distinction between lists and functions. You put a list as the first item of an execution list, it just interprets it as a list of lines of LISP and executes them one by one. I was trying to make "TCL but LISP" and this is what I thought that would mean
I've been writing all my new language's test code prepped to work with the regression test runner script I used with Emily and Emily2. I didn't actually have the test script itself in because I had to fuss with it a bit to teach it to run cargo before invoking the interpreter (so that the interpreter exists). Ran it and…
Yesterday I wrote a copying garbage collector in 52 lines of code and in about an hour. It was I was *so* happy and satisfied and the code was so clean and elegant. Then I realized the way I had done it was incompatible with the Rust borrow checker and spent another hour or two trying to figure out how to work around it. The Rust Experience.
Today I fixed it and now I have a 62 line GC (7 lines whitespace/comments) which is *slightly* less efficient than it could be due to every object being temporarily copied to a temporary heap object before the new space.
The original design *could* be made to work if I write my own implementation of Vec, which would be easy but annoying. The problem is I need to push to the end of a Vec while a mutable ref is held to one of its members, which *is* Rust invariant-safe, but not borrow-check-legal
Okay the garbage collector now "works"! In the sense that it can remove garbage from the system. (The problem before was I have a list of roots which includes any item the VM is currently operating on,, and roots were… never… getting removed… from the root list.)
It still does *not* work, in the sense that after the collection every pointer in the system is pointing to the wrong object. Oops!
So I added some debug prints to the GC and upon looking at the outputs I *immediately*, intuitively understood what was wrong and how to fix it (you'll be unsurprised to learn it was an off-by-one error… every pointer was being updated to its correct new value minus one).