An interpreter and JIT compiler for the Monkey language, written in C11.
make
The Makefile auto-detects llvm-config and /usr/include/libgccjit.h. Backends that are not found are silently disabled and the build proceeds with whatever is available.
To force a specific LLVM version:
make LLVM_CONFIG=llvm-config-17
monkey <file.mk> # interpret a file
monkey --jit <file.mk> # JIT-compile (picks first available backend)
monkey --backend=llvm <file.mk>
monkey --backend=gccjit <file.mk>
monkey # REPL
monkey -e 'puts(1 + 2)' # evaluate expression
let x = 5;
let add = fn(a, b) { a + b };
puts(add(x, 10));
let fib = fn(n) {
if (n < 2) { return n; }
fib(n - 1) + fib(n - 2)
};
puts(fib(20));
let arr = [1, 2, 3];
puts(first(arr), last(arr), len(arr));
let h = {"key": 42};
puts(h["key"]);
Both JIT backends compile Monkey control flow (if/else, return, block sequencing) to native code while delegating all value operations to C runtime helpers in jit_runtime.c. This is the standard approach for dynamic-language JITs: native branches + runtime dispatch.
Values are opaque void* pointers from the JIT perspective; the runtime helpers encode all semantic knowledge about Value*. Function literals delegate to the interpreter for closure creation; their call sites are compiled to native code that calls jrt_call.
GPL-3.0-only.