This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
This adds many comments to the final interpreter, which hopefully helps
me (and anyone else reading this) understand what's going on inside the
3G interpreter.
[refactor] This last interpreter takes all the evaluate function's
"syntax" objects and moves them into a lookup table. THis prefigures the
idea of making even the syntax malleable and extensible by future code.
I have to wonder if there's a place for making some core commands (the
"holy 7" of McCarthy, for example) un-reassignable.
Probably not. I can vaguely see an interest in wrapping even some core
functions (car, cdr, cons) in contractual decorators.
This concludes the base homework for chapter 3. I might get to the
exercises someday.
This was a pain point. I had hacked the "names" of symbols into the
throw/catch representation, never appreciating how badly I was screwing
up my understanding of LiSP. The symbols are supposed to evaluate
to something. When they're self-evaluating expressions (strings and
numbers), those become the keys in the block stack that matter. Getting
SEE's right, whether they're quoted or not, was really signficant.
This is cool. Now, on to rewind/protect!
I've hit a snag with respect to self-evaluating objects, and the ad-hoc evaluation of
program labels is messed up because of it. I'm going to have to refactor.
Oddly enough, the strategy I hit upon appears to be the same one found
in Wisp, rather than Clojurescript.
This may actually be an internal detail; the version rendered for the user may actually
not care. I hope not; the performance could become hairy pretty quickly.
This passes all the basic tests provided from Lisp In Small Pieces,
chapter 3. This is a functional LiSP interpreter with limited ability
and very little bug handling, but it's a solid implementation that
matches the specification and passes the tests provided for the CPS
interpreter.
This commit does *not* provide any of the continuation variants
described in the book; it is only the base interpreter.
This also adds a number of accesory functions necessary for rationalizing
the record structure of an object in the lex/parse phase into something
more lisp-like. There's a metadata issue here that I'm not quite wrapping
my head around.