The Monkey Programming Language & Interpreter written in PHP.
Features:
- A REPL;
- Integers (
10
), floats (10.5
), booleans (false
,true
), strings ("foo"
), arrays ([2016, "foo"]
), hash maps ( TODO); - Arithmetic expressions (
+
,-
,*
,%
,/
,**
); - Postfix operators (
i++
,i--
) - Comparison operators (
>
,<
,>=
,<=
,==
,!=
) - Conditional expressions (
if else
); - Logical operators (
&&
,||
) - Loop (
while
); - Let statements (
let a = 1
); - First-class and higher-order functions (
let foo = fn(x) { x + 1 }
); - Built-in functions (
puts()
, etc); - Recursion;
- Closures;
Future scope:
- Enums;
- Classes and Objects;
- Match Expression;
- Regex support;
Basic syntax:
A Fibonacci sequence using recursion:
let fibonacci = fn(x) {
if (x == 0 || x == 1) {
return x;
}
return fibonacci(x - 1) + fibonacci(x - 2);
};
puts(fibonacci(10));
A Fibonacci sequence using loop (much faster):
let fibonacci = fn(num) {
let a = 0;
let b = 1;
let temp = 0;
while (num > 0) {
temp = b;
b = b + a;
a = temp;
num--;
}
return a;
};
puts(fibonacci(32));
A raw implementation of mapping an array:
let rawMap = fn(arr, callback) {
let iter = fn(arr, accumulated) {
if (len(arr) == 0) {
return accumulated;
}
return iter(slice(arr, 1), push(accumulated, callback(first(arr))));
};
return iter(arr, []);
};
let foo = rawMap([1, 2, 3, 4], fn(x) {
x * 2
});
puts(foo); // [2, 4, 6, 8]
Or, you can just use the builtin function map()
:
let foo = map([1, 2, 3, 4], fn(x) {
x * 2
});
puts(foo); // [2, 4, 6, 8]
See more examples here.
(A working in progress. More features and docs soon.)
This is just a C-like language and its interpreter that I built to learn and understand how lexers and parsers work. I hope that could be useful to you, at least, inspire you to create your interpreter to learn those things.
It's not so fast because this is a pure tree-walk interpreter (which is notable slow) written in a PHP (a high-level programming language), and PHP compiles to an intermediate code that runs on top of a Virtual Machine written in C. Also, speed isn't the goal. The goal here is to learn, play, and have fun with the foundation of interpreters.
This interpreter uses an approach called Tree-Walking, it parses the source code, builds an abstract syntax tree (AST), and then evaluates this tree.
The steps are:
- Lexical analysis: from source code (free text) to Tokens/Lexemes;
- Parsing: uses the generated tokens to create an Abstract Syntax Tree;
- Abstract Syntax Tree (AST): a structural representation of the source code with its precedence level, associativity, etc;
- Evaluator: runs through the AST evaluating all expressions.
Running the tests:
docker run --rm -v $(pwd):/monkey -w /monkey php:8.4-cli ./vendor/bin/pest
Running from a file contents of the examples folder:
docker run --rm -v (pwd):/monkey -w /monkey php:8.4-cli ./monkey --stats run examples/fibo_while.monkey
Clone this repository, execute composer install
, then:
docker run -it --rm -v (pwd):/monkey -w /monkey php:8.4-cli ./monkey repl
Example:
+---------------------------------------+
| 🐒 Monkey Programming Language v1.0.0 |
| |
| Type :c for clear, :q to quit |
+---------------------------------------+
➜ let a = 20 + fn(x){ return x + 10; }(2);
32
➜
Or, if you want to execute a file:
docker run --rm -v (pwd):/monkey -w /monkey php:8.4-cli ./monkey --stats run examples/closure.monkey
I'll be pleased to have you contributing to any aspect of this project. You can fix a bug, implement new functionality, or add more tests.
This language is a version of the incredible Monkey Lang with some extra batteries included.