This project is currently in development and is not production-ready. Although it draws inspiration from the Lox language as described in Crafting Interpreters, it does not exactly replicate the original book's implementation. This version may include deviations, bugs, incomplete features, or experimental code.
Lox is a dynamically-typed, interpreted programming language created specifically for teaching purposes in the book Crafting Interpreters by Robert Nystrom. It combines a simple, readable syntax with enough expressive power to support real programming constructs like functions, classes, and closures. It supports first-class functions, lexical scoping, dynamic typing, and a small standard library. Its object model supports classes, inheritance, and method dispatch. Lox also emphasizes simplicity in its grammar and implementation, making it easy to experiment with and extend.
This project is a Rust implementation of the Lox programming language interpreter, inspired by Robert Nystrom's Crafting Interpreters. It serves as both a learning exercise and a foundation for further experimentation in language design and implementation.
The interpreter encompasses several core components:
- Scanning (Lexical Analysis): Transforms raw source code into a sequence of tokens, identifying keywords, literals, and symbols.β
- Parsing: Processes tokens to construct an Abstract Syntax Tree (AST) that represents the program's grammatical structure.β
- Evaluation: Traverses the AST to execute expressions and statements, producing the desired program behavior.
- Error Handling: Manages syntax and runtime errors gracefully, providing meaningful feedback to the user.β
- Environment and Scope Management: Handles variable declarations, scoping rules, and maintains state across different blocks and functions.β
- Rust toolchain (cargo, rustc)
cargo build --release
cargo run -- run path/to/your/program.lox
Example
// This program creates a function that returns another function
// and uses it to filter a list of numbers
fun makeFilter(min) {
fun filter(n) {
if (n < min) {
return false;
}
return true;
}
return filter;
}
fun applyToNumbers(f, count) {
var n = 0;
while (n < count) {
if (f(n)) {
print n;
}
n = n + 1;
}
}
var greaterThanX = makeFilter(21);
var greaterThanY = makeFilter(45);
print "Numbers >= 21:";
applyToNumbers(greaterThanX, 21 + 4);
print "Numbers >= 45:";
applyToNumbers(greaterThanY, 45 + 4);
Numbers >= 21:
21
22
23
24
Numbers >= 45:
45
46
47
48
cargo run -- tokenize path/to/program.lox
Example
var a = "hello";
VAR var null
IDENTIFIER a null
EQUAL = null
STRING "hello" hello
SEMICOLON ; null
EOF null
var greeting = "Hello"
if (greeting == "Hello") {
return true
} else {
return false
}
VAR var null
IDENTIFIER greeting null
EQUAL = null
STRING "Hello" Hello
IF if null
LEFT_PAREN ( null
IDENTIFIER greeting null
EQUAL_EQUAL == null
STRING "Hello" Hello
RIGHT_PAREN ) null
LEFT_BRACE { null
RETURN return null
TRUE true null
RIGHT_BRACE } null
ELSE else null
LEFT_BRACE { null
RETURN return null
FALSE false null
RIGHT_BRACE } null
EOF null
cargo run -- parse path/to/program.lox
Example
85 - 96 * 47 - 58
(- (- 85.0 (* 96.0 47.0)) 58.0)
(23 != 60) == ((-24 + 57) >= (14 * 40))
(>= (group (- 83.0 62.0)) (- (group (+ (/ 66.0 33.0) 86.0))))
cargo run -- evaluate path/to/program.lox
Example
(83 - 62) >= -(66 / 33 + 86)
true
10 + 35 - (-(81 - 80))
46
print "Hello, Lox!";
Hello, Lox!
var name = "Lox";
print name;
name = "Crafting";
print name;
Lox
Crafting
print 3 + 2 * (4 - 1);
9
var x = 10;
if (x > 5) {
print "Greater";
} else {
print "Smaller";
}
Greater
var i = 0;
while (i < 3) {
print i;
i = i + 1;
}
0
1
2
fun square(n) {
return n * n;
}
print square(5);
25
fun factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
print factorial(4);
24
fun makeCounter() {
var count = 0;
fun inc() {
count = count + 1;
return count;
}
return inc;
}
var counter = makeCounter();
print counter();
print counter();
1
2
class Greeter {
greet() {
print "Hello from object!";
}
}
var g = Greeter();
g.greet();
Hello from object!
class Counter {
init() {
this.count = 0;
}
inc() {
this.count = this.count + 1;
print this.count;
}
}
var c = Counter();
c.inc();
c.inc();
1
2
class A {
speak() {
print "A";
}
}
class B < A {
speak() {
super.speak();
print "B";
}
}
var obj = B();
obj.speak();
A
B
MIT