Skip to content

Zone-Infinity/YeyLoxrs

Repository files navigation

YeyLoxrs (Rust Lox Interpreter)

A full interpreter for the Lox programming language — this is my submission for the CodeCrafters “Build Your Own Interpreter” challenge.

     )              (                         
  ( /(              )\ )                      
  )\())   (   (    (()/(          )  (        
 ((_)\   ))\  )\ )  /(_))  (   ( /(  )(   (   
__ ((_) /((_)(()/( (_))    )\  )\())(()\  )\  
\ \ / /(_))   )(_))| |    ((_)((_)\  ((_)((_) 
 \ V / / -_) | || || |__ / _ \\ \ / | '_|(_-< 
  |_|  \___|  \_, ||____|\___//_\_\ |_|  /__/ 
              |__/                            

A idiomatic Rust implementation of Lox from Robert Nystrom’s legendary book Crafting Interpreters, extended and sharpened through the CodeCrafters challenge.


🚀 Badges

Rust CI Interpreter Status


🧠 About This Project

This repository is my solution to the CodeCrafters — Build Your Own Interpreter challenge.
The challenge mirrors the journey in the book Crafting Interpreters and requires building Lox step-by-step:

  • Tokenizer
  • Parser (expressions + statements)
  • AST
  • Resolver (lexical scoping)
  • Tree-walk Interpreter
  • Classes, inheritance, this, super
  • Closures, callables, bound methods
  • Native functions (clock)
  • Proper error handling & exit codes

This project became a (not so) complete, working interpreter for the Lox language.


📘 The Book: Crafting Interpreters

This interpreter follows the structure of Crafting Interpreters by Robert Nystrom:

Before coding, the challenge recommends reading:

  • Chapter 1 - Introduction
  • Chapter 2 - A Map of the Territory
  • Chapter 3 - The Lox Language

The implementation begins at Chapter 4 - Scanning.


🏗️ Features Implemented

✔ Lox language support

  • Variables, scopes
  • Functions & closures
  • Classes, objects, methods
  • Inheritance & super
  • this binding
  • Logical ops, arithmetic, comparisons
  • While, for-desugaring, if
  • Return statements
  • Error handling

✔ Complete Resolver (static binding)

Lox requires static resolution of variable references before interpretation.
The resolver tracks: expr_id: lexical distance (# of scopes outward)

This ensures:

  • Closures capture the right variable
  • Late declarations don’t break earlier closures
  • this / super are used only in valid contexts
  • Shadowing works correctly
  • Runtime avoids dynamic scope lookup bugs

✔ Native functions

Example:

print clock();

✔ Clean CLI

tokenize   # print tokens
parse      # print AST
evaluate   # print value of single expression
run        # run full program

📁 Project Structure

src/
  ast.rs            # AST + runtime structures (Expr, Stmt, LiteralValue, classes, functions)
  tokenizer.rs      # Scanner / lexer
  parser.rs         # Pratt parser (expressions) + statement parser
  resolver.rs       # Lexical scope resolver (expr_id → distance)
  interpreter.rs    # Tree-walk interpreter + environments
  natives.rs        # Native functions (clock, etc.)
  value.rs          # Helpers for LiteralValue (truthiness, debug helpers)
  error.rs          # Error structs, utilities, exit-code helpers
  debug_guard.rs    # Debug-only utilities + debug! macro
  main.rs           # CLI entrypoint: tokenize / parse / evaluate / run

samples/
  *.lox             # Example Lox programs used for testing

scripts/
  test-samples.sh   # Test harness for running all sample programs

.github/
  workflows/
    ci.yml          # GitHub Actions: build + test automation

✨ Example (from samples/print-modify.lox)

var a = 46;
fun printAndModify() {
  print a;
  var a = 33;
  print a;
}

print a;
a = 65;
printAndModify();

Output:

46
65
33

🧪 Testing

A simple test harness is included:

./scripts/test-samples.sh

You can add expected-output diffs as needed.

GitHub Actions CI runs:

cargo build
scripts/test-samples.sh

🌱 Extending the Interpreter

Here are some fun ideas/upgrades (which are and aren't in lox): I'll try to update

Beginner Friendly

  • Add arrays: [1, 2, 3]
  • Add map/object literals: { "x": 10 }
  • Add a REPL with rustyline
  • Add more built-ins (string ops, math ops)

Intermediate

  • Add anonymous lambda expressions
  • Add modules & imports
  • Add for-each loops
  • Improve error reporting with line/column info

Advanced

  • Build a bytecode compiler + VM (as in Crafting Interpreters Part III)
  • Add type checking / type inference (Hindley-Milner or gradual types)
  • Add a basic LSP (syntax highlighting + autocompletion for Lox)
  • Build a WebAssembly port
  • Add garbage collection (mark-sweep or arena-based)

Tests

  • Build tests in rust