https://github.com/andreev-io/monkey-compiler
A single-pass compiler for a toy language with custom byte code intermediate representation and a stack-based virtual machine.
https://github.com/andreev-io/monkey-compiler
compilers monkey-programming-language rust
Last synced: 4 months ago
JSON representation
A single-pass compiler for a toy language with custom byte code intermediate representation and a stack-based virtual machine.
- Host: GitHub
- URL: https://github.com/andreev-io/monkey-compiler
- Owner: andreev-io
- Created: 2021-02-03T14:24:21.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2021-02-06T20:41:34.000Z (about 5 years ago)
- Last Synced: 2025-09-13T04:52:10.097Z (5 months ago)
- Topics: compilers, monkey-programming-language, rust
- Language: Rust
- Homepage:
- Size: 66.4 KB
- Stars: 4
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Monkey Compiler in Rust
This project is a single-pass custom bytecode compiler and a stack-based virtual machine that runs code written in Monkey. Under the hood, the parser uses Pratt parsing.
The language supports first-class functions (with arguments), anonymous functions, closures, return statements, if clauses, strings, integers, booleans, and arrays.
Run `cargo run --release` to bring up a REPL.
The following are examples of some amazing Monkey programs:
```
>>> let fibonacci = fn(x) {
if (x == 0) {
0
} else {
if (x == 1) {
return 1;
} else {
fibonacci(x - 1) + fibonacci(x - 2);
}
}
};
fibonacci(35);
```
```
>>> let wrapper = fn() {
let countDown = fn(x) {
if (x == 0) {
return 0;
} else {
countDown(x - 1);
}
};
countDown(1);
};
wrapper();
```
Arrays and indexing:
```
>>> let x = [1, 2, fn(x) { x }(5)];
>>> x[2]
5
```
Nulls and truthy values:
```
>>> !!fn() {}();
false
>>> !!"hi"
true
```
Strings:
```
>>> let x = "good";
>>> let y = "bye";
>>> let goodbye = fn(x, y) { if (x+y == "goodbye") { 1 } else { 0 }};
>>> goodbye(x, y)
1
```
As shown above, the language supports anonymous functions and function literals.
The language doesn't have garbage collection and relies on Rust's ownership
semantics for memory management.
As far as the virtual machine goes, it correctly cleans up the call frame whenever a closure is exited.
```
>>> let v = [1, 2, 3];
let superfunc = fn(a) {
let b = a;
b[0] + b[1]
};
3 == superfunc(v)
```
When `superfunc` is called, `b` is created by cloning the array `a`, but is deallocated when superfunc returns.
```
let factorial = fn(x) {
if (x == 0) {
1
} else {
x * factorial(x-1)
}
}
factorial(5)
```
Note that we could've allocated anything within the recursively called
function, and the values would be successfully deallocated on return.