Functions
full-test-reset

Run all the interpreter tests together. Each test should start fresh -- no variables or functions leaking in from a previous test. Easiest way: testCase makes a new Context every call.

fn testCase(input: []const u8, expected: i64) void {
    var ctx = Context{};
    const got = eval(input, &ctx);
    if (got == expected) {
        print("ok {d}\n", .{got});
    } else {
        print("FAIL got {d} want {d}\n", .{ got, expected });
    }
}

Main gets much quieter:

pub fn main() void {
    testCase("3+5", 8);
    testCase("var x: i64 = 42; x", 42);
    testCase(
        \\fn fib(n: i64) i64 {
        \\    var a: i64 = 0;
        \\    var b: i64 = 1;
        \\    var i: i64 = 0;
        \\    while (i < n) {
        \\        var t: i64 = a + b;
        \\        a = b;
        \\        b = t;
        \\        i = i + 1;
        \\    }
        \\    return b;
        \\}
        \\fib(10)
    , 89);
}

Every test is hermetic. The Context struct (varNames, fnNames, call-save stack, everything) is zeroed fresh. Yes, the struct is about 200KB on the stack per call. That's fine -- Zig's default stack has plenty of room, and the allocation is just a stack-pointer bump.

Run your full test list. All oks. The interpreter is complete.

## Part 6: The Compiler

Here's what we have: a parser that reads source text and computes answers. parseFactor reads a number, parseTerm handles * and /, parseAddSub handles + and -, parseExpression layers in comparisons. They call each other recursively, and values flow back up the call chain. It works beautifully.

Now here's the trick. What if, instead of computing values, those functions emitted instructions? What if parseFactor didn't return 42 but printed i64.const 42? What if parseTerm didn't multiply two values but printed i64.mul?

The parser structure wouldn't change at all. The recursion, the operator loops, the precedence -- all identical. Only the actions change. Crenshaw called this "syntax-directed translation," and it's one of the most satisfying ideas in all of computer science. You've already written the hard part -- the parser. The compiler is the parser wearing different shoes.

Let's build it.