Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Building the REPL

A REPL (Read-Eval-Print Loop) is an interactive environment for your language. It lets users type expressions and see results immediately.

The Basic Loop

fn repl() {
    let mut interpreter = Interpreter::new();

    loop {
        // Read
        print!(">>> ");
        let line = read_line();

        // Eval
        let program = parse(&line)?;
        let result = interpreter.run(&program)?;

        // Print
        println!("{}", result);

        // Loop (back to Read)
    }
}

Persistent State

The key insight is that we use one interpreter across all inputs. This means:

  • Variables defined in one line are available in the next
  • Functions stay defined for the session
>>> x = 42
>>> y = x + 8
>>> y
50
>>> def double(n) { return n * 2 }
>>> double(y)
100

Running the REPL

cargo run
Firstlang REPL v0.1.0
Type expressions to evaluate, or 'quit' to exit.

>>> 1 + 2
3
>>> def fib(n) { if (n < 2) { return n } else { return fib(n-1) + fib(n-2) } }
>>> fib(10)
55
>>> quit
Goodbye!

Multi-line Input

The REPL supports multi-line input by detecting unclosed brackets. When you have unclosed {, (, or [, the REPL shows a continuation prompt (...) and waits for more input:

>>> def factorial(n) {
...     if (n <= 1) {
...         return 1
...     } else {
...         return n * factorial(n - 1)
...     }
... }
>>> factorial(5)
120

This is implemented by counting bracket depth:

/// Count unmatched opening brackets in a string
fn bracket_depth(s: &str) -> i32 {
    let mut depth = 0;
    let mut in_string = false;

    for c in s.chars() {
        if c == '"' { in_string = !in_string; }
        if !in_string {
            match c {
                '{' | '(' | '[' => depth += 1,
                '}' | ')' | ']' => depth -= 1,
                _ => {}
            }
        }
    }
    depth
}

When bracket_depth is positive, we keep reading lines until all brackets are closed.

Error Handling

The REPL catches errors and keeps running:

>>> undefined_var
Runtime error: Undefined variable: undefined_var
>>> 1 / 0
Runtime error: Division by zero
>>> 1 + 2
3

The REPL is your best friend for experimenting with the language! Try computing Fibonacci interactively.

Running Examples

Firstlang comes with several example programs demonstrating different features.

Fibonacci Sequence

cargo run -- examples/fibonacci.fl

Expected output: 55

Factorial

cargo run -- examples/factorial.fl

Expected output: 120

Basics

cargo run -- examples/basics.fl

This demonstrates variables, functions, conditionals, and loops.

All Examples

for file in examples/*.fl; do
    echo "Running $file..."
    cargo run -- "$file"
done

Running Tests

Firstlang has comprehensive integration tests covering:

  • Variables and assignments
  • Functions with parameters
  • Recursion (Fibonacci, factorial)
  • Control flow (if/else, while)
  • Type errors
  • Undefined variables and functions

Run all tests:

cargo test

Run a specific test:

cargo test test_fibonacci_recursive

Run tests with verbose output:

cargo test -- --nocapture

The tests are in tests/integration_tests.rs and serve as examples of what the language can do.