Jérôme Mahuet's Blog

Monkey language interpreter made in Rust

Monkey has a C-like syntax, supports variable bindings, prefix and infix operators, has first-class and higher-order functions, can handle closures with ease and has integers, booleans, arrays and hashes built-in.

There is a book about learning how to make an interpreter: Writing An Interpreter In Go. This is where the Monkey programming language come from.

Software model

The most important part of this project is that both the lexer and parser are made with the Nom library. Then everything is built up into an AST for execution. It has several unit tests to ensure it doesn't break when I update the libraries or add new features.

Examples of code you can run

1let map = fn(f, arr) { 2 if (len(arr) == 0) { 3 [] 4 } else { 5 let h = head(arr); 6 cons(f(h), map(f, tail(arr))); 7 } 8}; 9 10 11let reduce = fn(f, init, arr) { 12 if (len(arr) == 0) { 13 init 14 } else { 15 let newInit = f(init, head(arr)); 16 reduce(f, newInit, tail(arr)); 17 } 18}; 19 20let double = fn(x) { 21 2 * x 22}; 23 24let add = fn(x, y) { 25 x + y 26}; 27 28let mapped = map(double, [1, 2, 3, 4]); 29print(mapped); 30 31let sum = fn(arr) { 32 reduce(add, 0, arr); 33}; 34 35let summed = sum([1, 2, 3, 4, 5]); 36print(summed);

This is totally valid code and will run like so:

1cargo run --release --bin monkey_exe -- --src examples/map-reduce.mk 2 Finished release [optimized] target(s) in 0.02s 3 Running `target/release/monkey_exe --src examples/map-reduce.mk` 4[2, 4, 6, 8] 515 6null

How to run

Build and test

1$ cargo build 2$ cargo test

Running the REPL

1$ cargo run --release --bin monkey_repl

Running the Interpreter

1$ cargo run --release --bin monkey_exe -- --src examples/hash.mk

Source code

You can find it on my Github page related to the project: here.

Made in France in 2024 with NextJS, Typescript, Strapi, Tailwind etc.