Add a post about the first real program in Valeri

This commit is contained in:
Konstantin Nazarov 2024-08-24 01:23:24 +01:00
parent 270e3f993f
commit 05157282ca
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
2 changed files with 51 additions and 1 deletions

View file

@ -4,7 +4,7 @@ Open-source tools and projects: [git.sr.ht/~knazarov](https://git.sr.ht/~knazaro
Highlights:
* [My own programming language with a VM and garbage collector](https://git.sr.ht/~knazarov/lisp.experimental) (work in progress)
* [My own programming language with a VM and garbage collector](https://git.sr.ht/~knazarov/valeri) (work in progress)
* [A swiss-army script for planning team's work on GitHub](https://git.sr.ht/~knazarov/git-plan)
* [Homebrew tap for qemu with support for 3d accelerated guests](https://github.com/knazarov/homebrew-qemu-virgl)
* [Plain-text note taking system](https://git.sr.ht/~knazarov/notes.sh)

View file

@ -0,0 +1,50 @@
X-Date: 2024-08-23T23:49:16Z
X-Note-Id: 175bdac4-8655-4b75-8205-f44b7311daa0
Subject: First real program compiled with Valeri
X-Slug: first_real_program_compiled_with_valeri
I've reached my first significant milestone with [Valeri](https://git.sr.ht/~knazarov/valeri).
It can now compile something useful to bytecode and then execute it in the virtual machine.
As an example, I've implemented a simple recursive factorial function:
```
(fn fact (n)
(if (<= n 0)
1
(* n (fact (- n 1)))))
(fact 12)
```
If you save this code as `factorial.vli`, you can then run it with `./vli factorial.vli`,
and it will give you `479001600`, as you would expect.
This may not seem impressive at a first glance, but to compile this example the compiler has to support:
- modules (at least top-level)
- functions
- recursion
- lexical scope
- globals
- constants
- arithmetic
Most importantly, this is not a recursive AST evaluator like how many people implement their first Lisp.
This in fact compiles into a bytecode which is then executed on a virtual machine. It means that the performance
is bad (due to lack of optimizations), but not completely abysmal.
The process of compilation is now 2-step:
- Read the source code into "AST" (actually the S-expression form that is a list)
- Recursively step through the AST and emit the bytecode for known special forms
- As we walk the tree, keep a linked list of lexical context (to find variable bindings)
To emit the bytecode, I'm following an approach that is close in spirit to the
[Incremental Approach to Compiler Construction paper](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf).
With the exception that the paper uses stack and an accumulator register, and my implementation is
register-based like Lua, see [Lua 5.0 paper](https://www.lua.org/doc/jucs05.pdf) for reference.
I'm very happy about the progress, but also am mindful of the fact that this is only the beginning.
For this compiler to be really useful, it should give decent error reporting (both during the compilation
phase and runtime phase). And this is where the real struggle will begin.