Martin Karlsson / prog.re

Notes to self


Make A Lisp (step 6)

Continued from step 5. This step introduces user mutable atoms, file reads and eval.

File reading and eval presented no challenges. File reading (function named "slurp", lovely) was simply mapped to php:s built in file_get_contets, which is already in the main environment name space since I auto-loaded all php functions in a previous step. The implementation of "slurp" is thus (fn* (path) (file_get_contents path))

Related to eval, the actual main eval function in the REPL gets exposed as a function in the environment, and the main reader function also gets exposed as "read-string". These two allows us to now do things like (eval (read-string "(+ 1 1)")). In addition, combined with "slurp" we can now read and eval mal programs from files. To get even more functionality, the command line arguments to the mal interpreter gets their own entry in the environment as *ARGS*.

Mutable atoms seemed simple at first, and the type itself was easy, as was the simple mutability function reset!. The major challenge I encountered in this step was the swap! function. This is supposed to take as arguments: an atom, a function that will produce the new value for the atom and any additional arguments that the function might need. The big problem was that the atom in this case becomes an implicit first argument and those additional arguments should come after. Optional arguments can be handled with the & operator but without a way to then unpack the resulting array in place this is not of much help to us. This was eventually solved by explicitly building a mini-ast out of the parts and doing eval on it. Not beautiful exactly, and I strongly suspect that this functionality will be replaces by something else once macros are in place.

Previous posts


Get in touch: martin [at] prog.re