I wanted to see if I could create a programming language. It worked!
This project can be divided into two parts:
- The runtime, a simple stack machine that runs custom bytecode.
- The compiler, that can compile my custom language's source code into bytecode for the runtime.
fib(n)
return = 1
if >(n, 2)
return = add(fib(add(n, -1)), fib(add(n, -2)))
This computes the n-th Fibonacci number.
You need the following tools:
After checking out the git repository, run npm install to install the dependencies.
deno run --allow-read run.ts <filename> [<function name> [program arguments]]Example:
-
Save the following in a text file called
myprogram.txt:myfunction(a, b, c) return = add(a, mul(b, c)) -
Open the console inside the project directory and execute
deno run --allow-read run.ts myprogram.txt myfunction 1 2 3
This should print
7to the console. If you stored your file in a diffent location, simply changemyprogram.txtto the actual path of your file.
You can also add a main() function to the end of your file:
myfunction(a, b, c)
return = add(a, mul(b, c))
main()
return = myfunction(1, 2, 3)
The runtime looks for a "main" function by default. Therefore, you can now simply run:
deno run --allow-read run.ts myprogram.txtTo see what the compiler does, add the --debug flag when running your program from the console. This will show you:
- debug information while the compiler is compiling your code
- the compiler output (bytecode)
- debug information while the runtime is executing the bytecode
For the Fibonacci example above, the bytecode will look something like this:
[0] load 1
[1] write -1
[2] read 0
[3] push
[4] load 2
[5] push
[6] native greater
[7] jumpIfNot 30
[8] load 0
[9] push
[10] read 0
[11] push
[12] load -1
[13] push
[14] native add
[15] push
[16] jumpFunction 0
[17] push
[18] load 0
[19] push
[20] read 0
[21] push
[22] load -2
[23] push
[24] native add
[25] push
[26] jumpFunction 0
[27] push
[28] native add
[29] write -1
[30] pop
[31] pop
[32] return