Lisp like interpreter in Go
A month back I wrote a chip8 interpreter with both command line and SDL2 display adapters (even I started writing a Web-cavas based adapter for experiments). Then I did the same for NES. That was like Java VM, in the sense interpreting, the byte-code instructions. Each byte has a purpose. But then I thought why not write a simple interpreted language which I can program in English instead of in asm of a particular machine. I didn’t do a formal course in compiler design. So writing lexer and A-S-T from scratch was a daunting task for a C-style language. So the easiest language that came to my mind was Lisp. I have been using Emacs for like 3 years. Writing my own functions and customization, I got familiar with that language.
Basically function names and arguments are separated by a space and surrounded by a bracket pair. Tokenizing this was easy. A simple functions call tokens will have a function name at the 0th index and their arguments in subsequent indices.
Now the VM struct : Generally lisp (at-least emacs lisp) is a non-scoped language operating in a global namespace. ie., If you set a value in a function, it exists in the VM’s memory through out the VM’s lifetime unless we explicitly delete the variable. But I tried implementing ligo as a scoped language. So the variables local to a given scope will be deleted after the function’s termination. But still can access and modify the parent scope’s variables. The VM needs 4 basic members for a scoped operation. Namely,
- pointer to the parent scope (another VM struct)
- Vars : map of string to another struct, Variable
- Funcs : map of string to InBuilt funciton type (ie., functions defined in go)
- LFuncs : map of string to struct denoting defined function (ie., functions defined in ligo)
This has many methods to handle the in language calls like loops (loop,in), conditionals (if..else), forks, returns, progns etc., One such main method is the GetVariable method. GetVariable is used to fetch a token’s (string) value with respect to the VM.
In the above VM struct new go functions can be defined by writing and adding new native go functions to the map. Refer this document for more details.
And this is just an experiment of how generally a interpreter works.
Where have I used this
- I have used this for my internal projects for as configuration file language.
- Wrote a experimental web based interactive interpreter. That is in the repo. Run ligo with web flag ie, (GNU style : 2 hyphens)
- I have used it for simple scripting instead of python or shell as a dare :P
By the way, this is the sample syntax of how to do things in this language.
Feel free to file issues and make a pull request. Here is the project : github://aki237/ligo.