I've been working my way through a Lisp textbook, Lisp In Small Pieces, by Christian Quinnec. It was originally written in French and is not that well known among English-speaking Lisperati, not in comparison to the Wizard book or Paul Graham's On Lisp, but what caught my attention was how it really was in small pieces. Each chapter ended with an interpreter described, sometimes in code, sometimes in text; if you were smart enough, you could actually piece the whole thing together and see how it worked.
I mean, it's obviously been done before. I tried once before but got lost. LiSP does me the favor of keeping me on track.
You can see all my sourcecode at Github: Lisp In Small Pieces.
Chapter "Lambda 1" contains a continuation-passing variant of the interpreter from Chapter 1. It's basically a facile reading of Lisperator's λ-language intepreter, with my own parser front-end and some CPS style. It passes all the tests, but it's a distraction.
Chapter 3 contains the same interpreter, only using the architecture Quinnec describes in Chapter 3 of his book.
Chapter 2 describes a number of different methodologies for binding, scoping, and namespaces. The material is interesting but I didn't pursue writing the various interpreters. I "got" what Quinnec was saying, and if I'm ever interested in writing something with scoping rules outside of the lexical scopes with which I'm familiar, I might revisit the material.
The next step will be to add functions to the Chapter 3 interpreter to do the various continuation management games, like call/cc, throw/catch, and so forth. Because those, I feel I need to understand.
How far will I take this project? I'm not sure. Chapter 4 is "Assignment and Side Effects," so I'll do that. Chapter 5 is theory, and 6 implementation, of a "fast interpreter" of the kind French programming language guys apparently love to study. I'll read them, but I'm not sure what code I'll generate out of that. Chapter 7, "Compilation," is interesting in that he starts by defining a VM that on top of which our bytecode will run, and implement both the VM and the compiler in Scheme. I think I want to do that chapter, and then re-write the compiler to create LLVM-compatible code instead, just to learn LLVM. Chapter 8 implements EVAL, chapter 9 has Macros, and chapter 10 has Object-Oriented Lisp. So I'll probably do those as well.
And then... we'll see. I surprised myself by doing Chapter 3 in less than two weeks.