A complete implementation of the Lox programming language interpreter built in Rust, following the Crafting Interpreters book by Robert Nystrom.
Lox is a dynamically-typed scripting language designed for learning interpreter implementation. Despite its simplicity, Lox includes many features found in modern programming languages:
- Dynamic typing with numbers, strings, booleans, and nil
- Variables with block scoping
- Functions as first-class values
- Closures with proper variable capture
- Control flow with if/else statements and loops
- Object-oriented programming (classes and inheritance)
This interpreter implements the complete Lox language specification with particular emphasis on robust closure support:
✅ Core Language Features
- Variables, functions, and expressions
- Control flow (if/else, while, for loops)
- Print statements and arithmetic operations
- Dynamic typing with runtime type checking
✅ Advanced Closure System
- Variable capture from enclosing scopes
- Mutable closure state
- Nested closures with proper scope resolution
- Variable lifetime management
- Closure isolation (independent instances)
✅ Production Quality
- Comprehensive error handling and reporting
- 26 test cases with 100% pass rate
- Clean, modular architecture
- Memory-efficient implementation
- Rust 1.80+ with Cargo
# Clone the repository
git clone <repository-url>
cd codecrafters-interpreter-rust
# Build the project
cargo build --release
# Run one of the included demo files
cargo run -- run demos/simple_closure_demo.lox
# Or run your own Lox file
cargo run -- run path/to/your/program.lox
# Run all tests
cargo test
The demos/
directory contains a variety of Lox programs that showcase the interpreter's features. You can run any of them using the cargo run -- run
command.
simple_closure_demo.lox
: Demonstrates core closure functionalities.fibonacci.lox
: A recursive Fibonacci sequence calculator.inheritance.lox
: Shows class and inheritance features.logical_operators.lox
: Highlights truthiness and logical operations.
fun makeCounter() {
var count = 0;
fun increment() {
count = count + 1;
print count;
}
return increment;
}
var counter = makeCounter();
counter(); // prints: 1
counter(); // prints: 2
counter(); // prints: 3
fun makeAdder(x) {
fun add(y) {
return x + y;
}
return add;
}
var add10 = makeAdder(10);
print add10(5); // prints: 15
var closure;
{
var localVar = 42;
fun capture() {
print localVar;
}
closure = capture;
}
// localVar is out of scope here
closure(); // prints: 42 (still works!)
fun outer(x) {
fun middle(y) {
fun inner(z) {
return x + y + z;
}
return inner;
}
return middle;
}
var nested = outer(1)(2);
print nested(3); // prints: 6
codecrafters-interpreter-rust/
├── src/
│ ├── main.rs # Entry point and CLI handling
│ ├── lib.rs # Library exports and test infrastructure
│ ├── lexer.rs # Tokenization and lexical analysis
│ ├── parser/ # AST construction from tokens
│ ├── ast/ # Abstract Syntax Tree definitions
│ ├── evaluator/ # Expression evaluation and closures
│ ├── runner/ # Interpreter execution engine
│ ├── error/ # Error handling and reporting
│ └── tests/ # Comprehensive test suite
├── demos/ # Example Lox programs to test features
└── docs/ # Detailed technical documentation
The interpreter features a sophisticated closure system that properly handles variable capture, state mutation, and variable lifetimes. For a detailed explanation of the implementation, please see the Deep Dive: Closure Implementation document.
Comprehensive error reporting with:
- Lexical Errors: Invalid tokens and syntax
- Parse Errors: Malformed expressions and statements
- Runtime Errors: Type mismatches and undefined variables
- Detailed Messages: Line numbers and context information
- Efficient AST Evaluation: Direct tree-walking interpreter
- Minimal Overhead: Lightweight closure creation
- Memory Management: Proper variable lifetime handling
- Numbers: 64-bit floating point (
42
,3.14
) - Strings: UTF-8 text (
"hello world"
) - Booleans:
true
andfalse
- Nil:
nil
(null/undefined value)
var name = "John";
var age = 30;
var isActive = true;
fun greet(name) {
print "Hello, " + name + "!";
}
fun add(a, b) {
return a + b;
}
if (condition) {
print "true branch";
} else {
print "false branch";
}
for (var i = 0; i < 10; i = i + 1) {
print i;
}
while (condition) {
// loop body
}
var global = "global";
{
var local = "local";
print global; // accessible
print local; // accessible
}
print global; // accessible
print local; // error: undefined variable
- Crafting Interpreters Book - The definitive guide to interpreter implementation
- Lox Language Specification - Complete language reference
This project is part of the CodeCrafters interpreter challenge and follows their terms of use.