Temporary chapter name for all chapters
four-ops-vm

The VM only knows i64.add. Extend the dispatch with i64.sub, i64.mul, and i64.div_s. Each is its own else if branch with the same pop-pop-compute-push shape.

To test, set write_wat_manually = true and try this WAT:

i64.const 8
i64.const 2
i64.div_s

Then try i64.sub (with 5 then 3) and i64.mul.

if (stringStartsWith(line, "i64.const ")) {
    stack[stack_pointer] = @as(i64, line[line.len - 1]) - '0';
    stack_pointer += 1;
} else if (stringsEqual(line, "i64.add")) {
    const y: i64 = stack[stack_pointer - 1];
    const x: i64 = stack[stack_pointer - 2];
    stack_pointer -= 2;
    stack[stack_pointer] = x + y;
    stack_pointer += 1;
}
// YOU: else if "i64.sub" -> pop, pop, push x - y
// YOU: else if "i64.mul" -> pop, pop, push x * y
// YOU: else if "i64.div_s" -> pop, pop, push @divTrunc(x, y)
else {
    printString("error: unknown instruction\n");
    return;
}
} else if (stringsEqual(line, "i64.sub")) {
    const y: i64 = stack[stack_pointer - 1];
    const x: i64 = stack[stack_pointer - 2];
    stack_pointer -= 2;
    stack[stack_pointer] = x - y;
    stack_pointer += 1;
} else if (stringsEqual(line, "i64.mul")) {
    const y: i64 = stack[stack_pointer - 1];
    const x: i64 = stack[stack_pointer - 2];
    stack_pointer -= 2;
    stack[stack_pointer] = x * y;
    stack_pointer += 1;
} else if (stringsEqual(line, "i64.div_s")) {
    const y: i64 = stack[stack_pointer - 1];
    const x: i64 = stack[stack_pointer - 2];
    stack_pointer -= 2;
    stack[stack_pointer] = @divTrunc(x, y);
    stack_pointer += 1;
}

Order matters now. Walk through 5 - 3:

1. Source order is 5, then -, then 3.
2. Push 5. Stack: [5].
3. Push 3. Stack: [5, 3] -- 3 is on top.
4. Pop into y: gets 3 (top). Pop into x: gets 5.
5. Compute x - y = 5 - 3 = 2. Push. Stack: [2].

The order in the source flows straight to the order on the stack. That's why we name y first -- it's the one on top, the one pushed last, the right-hand operand. Same shape for i64.div_s: x / y where y is the divisor. Get this wrong once and 8 / 2 becomes 2 / 8 = 0.

The repetition is real -- four branches that almost do the same thing. Hold off the urge to factor it. Once we're solid on stack semantics, a refactor is cheap.