Skip to content

Commit 9ca5250

Browse files
committed
docs: prepare some samples of lox language and also write the readme file
1 parent 7951f35 commit 9ca5250

17 files changed

Lines changed: 359 additions & 20 deletions

README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Lox Interpreter
2+
3+
A complete implementation of the Lox programming language interpreter in Kotlin, following the principles from "Crafting Interpreters".
4+
5+
## Features
6+
7+
- **Lexical Analysis**: Full tokenization with keyword and identifier distinction
8+
- **Parsing**: Recursive descent parser building an abstract syntax tree
9+
- **Variables**: Dynamic typing with `var` declarations and lexical scoping
10+
- **Functions**: First-class functions with named (`fun`) and anonymous (`fn`) syntax, closures, and proper tail behavior
11+
- **Classes**: Object-oriented programming with inheritance, instance fields, and methods
12+
- **Static Methods**: Class-level methods accessible directly on the class
13+
- **Native Functions**: Built-in functions for I/O and timing (clock, println, scan, input)
14+
- **Control Flow**: if/else statements and while loops
15+
- **Operators**: All standard arithmetic, comparison, logical, and assignment operators
16+
- **Scope Resolution**: Static analysis pass that pre-computes variable binding distances for efficient runtime lookup
17+
- **Error Handling**: Proper runtime error reporting with token information
18+
19+
## Language Syntax Basics
20+
21+
Variables and assignment:
22+
```
23+
var x = 10;
24+
x = 20;
25+
```
26+
27+
Functions:
28+
```
29+
fun greet(name) {
30+
println("Hello, " + name);
31+
}
32+
33+
greet("Alice");
34+
```
35+
36+
Anonymous functions:
37+
```
38+
var add = fn(a, b) { a + b };
39+
println(add(3, 4));
40+
```
41+
42+
Classes and inheritance:
43+
```
44+
class Animal {
45+
init(name) {
46+
this.name = name;
47+
}
48+
49+
speak() {
50+
println(this.name + " makes a sound");
51+
}
52+
}
53+
54+
class Dog > Animal {
55+
speak() {
56+
println(this.name + " barks");
57+
}
58+
}
59+
60+
var dog = Dog("Buddy");
61+
dog.speak();
62+
```
63+
64+
## Building and Running
65+
66+
Compile the Kotlin code and run the interpreter:
67+
68+
```bash
69+
kotlinc -include-runtime -d lox.jar src/*.kt
70+
java -jar lox.jar script.lox
71+
```
72+
73+
Or use the REPL for interactive mode.
74+
75+
## Implementation Highlights
76+
77+
- **Visitor Pattern**: AST traversal for both parsing and interpretation
78+
- **Environment Chains**: Linked scopes for variable storage and lookup
79+
- **Resolver**: Two-pass compilation approach (resolve then execute) for scope analysis
80+
- **LoxCallable**: Interface for both user-defined and native functions
81+
- **Exception-based Control Flow**: RuntimeReturn for return statements, RuntimeError for errors
82+
83+
## Project Structure
84+
85+
- `Interpreter.kt`: Core execution engine with expression and statement visitors
86+
- `Expr.kt`: AST node definitions for expressions
87+
- `Stmt.kt`: AST node definitions for statements
88+
- `Scanner.kt`: Lexical analysis
89+
- `Parser.kt`: Syntax analysis and AST building
90+
- `Resolver.kt`: Static scope analysis
91+
- `Environment.kt`: Scope and variable storage
92+
- `LoxCallable.kt`: Interface for callable objects
93+
- `LoxClass.kt`, `LoxInstance.kt`: Object-oriented features
94+
- `Token.kt`: Token representation
95+
96+
## References
97+
98+
This implementation closely follows the Lox language design and interpreter architecture from "Crafting Interpreters" by Robert Nystrom, adapted to Kotlin's modern language features.

samples/anonymous_functions.lox

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
var numbers = 5;
2+
var double = fn(n) { n * 2 };
3+
4+
println(double(numbers));
5+
6+
var apply = fn(func, value) {
7+
func(value)
8+
};
9+
10+
println(apply(double, 10));

samples/classes.lox

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class Person {
2+
init(name, age) {
3+
this.name = name;
4+
this.age = age;
5+
}
6+
7+
introduce() {
8+
println("Hi, I'm " + this.name + " and I'm " + this.age + " years old");
9+
}
10+
11+
birthday() {
12+
this.age = this.age + 1;
13+
println(this.name + " is now " + this.age);
14+
}
15+
}
16+
17+
var alice = Person("Alice", 30);
18+
alice.introduce();
19+
alice.birthday();

samples/control_flow.lox

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
var x = 10;
2+
var y = 20;
3+
4+
if (x < y) {
5+
println("x is less than y");
6+
}
7+
8+
var counter = 0;
9+
while (counter < 5) {
10+
println("Counter: " + counter);
11+
counter = counter + 1;
12+
}

samples/example_fibonacci.lox

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
fun fibonacci(n) {
2+
if (n <= 1) {
3+
n
4+
} else {
5+
fibonacci(n - 1) + fibonacci(n - 2)
6+
}
7+
}
8+
9+
var start = clock();
10+
var result = fibonacci(30);
11+
var elapsed = clock() - start;
12+
13+
println("fibonacci(30) = " + result);
14+
println("Computed in " + elapsed + " seconds");

samples/example_quiz.lox

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class Quiz {
2+
static run() {
3+
var score = 0;
4+
5+
var answer1 = input("What is 2 + 2? ");
6+
if (answer1 == "4") {
7+
println("Correct!");
8+
score = score + 1;
9+
} else {
10+
println("Wrong! The answer is 4");
11+
}
12+
13+
var answer2 = input("What is the capital of France? ");
14+
if (answer2 == "Paris") {
15+
println("Correct!");
16+
score = score + 1;
17+
} else {
18+
println("Wrong! The answer is Paris");
19+
}
20+
21+
var answer3 = input("Is the Earth flat? ");
22+
if (answer3 == "no") {
23+
println("Correct!");
24+
score = score + 1;
25+
} else {
26+
println("Wrong! The answer is no");
27+
}
28+
29+
println("Your score: " + score + "/3");
30+
}
31+
}
32+
33+
Quiz.run();

samples/example_user_db.lox

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
class User {
2+
init(name, email) {
3+
this.name = name;
4+
this.email = email;
5+
}
6+
7+
static create() {
8+
var name = input("Enter name: ");
9+
var email = input("Enter email: ");
10+
User(name, email)
11+
}
12+
13+
display() {
14+
println("User: " + this.name + " (" + this.email + ")");
15+
}
16+
}
17+
18+
var user1 = User.create();
19+
user1.display();
20+
21+
var user2 = User.create();
22+
user2.display();

samples/functions.lox

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
fun add(a, b) {
2+
a + b
3+
}
4+
5+
println(add(5, 3));
6+
7+
fun makeCounter() {
8+
var count = 0;
9+
return fn(step) {
10+
count = count + step;
11+
count
12+
};
13+
}
14+
15+
var counter = makeCounter();
16+
println(counter(1));
17+
println(counter(1));
18+
println(counter(5));

samples/inheritance.lox

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class Animal {
2+
init(name) {
3+
this.name = name;
4+
}
5+
6+
speak() {
7+
println(this.name + " makes a sound");
8+
}
9+
}
10+
11+
class Dog > Animal {
12+
speak() {
13+
println(this.name + " barks");
14+
}
15+
}
16+
17+
class Cat > Animal {
18+
speak() {
19+
println(this.name + " meows");
20+
}
21+
}
22+
23+
var dog = Dog("Rex");
24+
var cat = Cat("Whiskers");
25+
26+
dog.speak();
27+
cat.speak();

samples/native_input.lox

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
var age = input("How old are you? ");
2+
println("You are " + age + " years old");
3+
4+
var answer = input("Enter yes or no: ");
5+
if (answer == "yes") {
6+
println("You said yes!");
7+
}

0 commit comments

Comments
 (0)