A real parser
comparison-operators

Add comparisons: >, <, ==, !=. They return 1 for true, 0 for false, and bind more loosely than addition.

We're adding a new precedence layer above the current expression. So:

1. Rename the current parseExpression (which loops on +/-) to parseAddSub. Update the recursive call inside parseFactor.
2. Add a new parseExpression on top that handles comparisons -- it calls parseAddSub for the left operand, then checks for a comparison operator, then calls parseAddSub again for the right.

For == and !=, check two characters: source[pos.*] and source[pos.* + 1].

    testCase("5 > 3", 1);
    testCase("2 > 7", 0);
    testCase("3 == 3", 1);
    testCase("3 != 3", 0);

Rename the old expression function to parseAddSub:

fn parseAddSub(source: [*]const u8, pos: *usize) i64 {
    var val: i64 = parseTerm(source, pos);
    while (source[pos.*] == '+' or source[pos.*] == '-') {
        const op: u8 = source[pos.*];
        pos.* += 1;
        skipSpaces(source, pos);
        const right: i64 = parseTerm(source, pos);
        val = switch (op) {
            '+' => val + right,
            '-' => val - right,
            else => val,
        };
    }
    return val;
}

Then the new parseExpression on top:

fn parseExpression(source: [*]const u8, pos: *usize) i64 {
    const left: i64 = parseAddSub(source, pos);
    const c: u8 = source[pos.*];
    if (c == '>') {
        pos.* += 1;
        skipSpaces(source, pos);
        return if (left > parseAddSub(source, pos)) @as(i64, 1) else 0;
    }
    if (c == '<') {
        pos.* += 1;
        skipSpaces(source, pos);
        return if (left < parseAddSub(source, pos)) @as(i64, 1) else 0;
    }
    if (c == '=' and source[pos.* + 1] == '=') {
        pos.* += 2;
        skipSpaces(source, pos);
        return if (left == parseAddSub(source, pos)) @as(i64, 1) else 0;
    }
    if (c == '!' and source[pos.* + 1] == '=') {
        pos.* += 2;
        skipSpaces(source, pos);
        return if (left != parseAddSub(source, pos)) @as(i64, 1) else 0;
    }
    return left;
}

Don't forget to update the recursive call in parseFactor -- when we see (, we recurse into parseExpression (the new top), not parseAddSub.