I'm inclined to agree. Implemented a Lisp in a Lisp always feels like a certain amount of hand-waving without feeling like I've really made something. Look, here's how to implement a JavaScript interpreter in JavaScript: eval(someCode);
What I like is seeing all of the steps a typical real-world language implementation goes through, just in minimal form. To that end, a while back I wrote an interpreter for a BASIC-like language in a single Java source file. It tokenizes, parses, and interprets. It uses common real-world techniques for all of those:It uses a hand-rolled state machine for tokenizing. Recursive descent for parsing. And the interpreter uses the visitor pattern to walk the AST. Mine also, strangely unlike many of these so-called "teaching" toy languages, has documentation. I don't understand the point of a tiny language for people to learn from if you made it tiny by removing all of the comments. :( And, to try to avoid leading the reader astray, it calls out any shortcuts it makes. Those are hints where you'd want to do something more robust if you weren't trying to be minimal. It's here: https://github.com/munificent/jasic If you work your way through that, you'll be a long way towards being able to find your way around a real-world interpreter. The main things it doesn't do is: 1. GC. It leans on Java for that. 2. Compile to bytecode or some other representation. It's a simple tree walker, like Ruby 1.8. If you want to learn more about those, take a look at: https://github.com/munificent/wren |