The Compiler, in Its Own Language
self-c-term-expression

c_term, c_add_sub, c_expression:

fn c_term() i64 {
    c_factor();
    while (cur() == '*' or cur() == '/' or cur() == '%') {
        var op: i64 = cur();
        src_pos += 1; skip();
        c_factor();
        if (op == '*') { emit_s("  i64.mul\n"); }
        if (op == '/') { emit_s("  i64.div_s\n"); }
        if (op == '%') { emit_s("  i64.rem_s\n"); }
    }
    return 0;
}

fn c_add_sub() i64 {
    c_term();
    while (cur() == '+' or cur() == '-') {
        var op: i64 = cur();
        src_pos += 1; skip();
        c_term();
        if (op == '+') { emit_s("  i64.add\n"); }
        if (op == '-') { emit_s("  i64.sub\n"); }
    }
    return 0;
}

fn c_comparison() i64 {
    c_add_sub();
    if (cur() == '>' and load8(src_pos + 1) == '=') {
        src_pos += 2; skip(); c_add_sub(); emit_s("  i64.ge_s\n");
    }
    if (cur() == '<' and load8(src_pos + 1) == '=') {
        src_pos += 2; skip(); c_add_sub(); emit_s("  i64.le_s\n");
    }
    if (cur() == '>') { src_pos += 1; skip(); c_add_sub(); emit_s("  i64.gt_s\n"); }
    if (cur() == '<') { src_pos += 1; skip(); c_add_sub(); emit_s("  i64.lt_s\n"); }
    if (cur() == '=' and load8(src_pos + 1) == '=') {
        src_pos += 2; skip(); c_add_sub(); emit_s("  i64.eq\n");
    }
    if (cur() == '!' and load8(src_pos + 1) == '=') {
        src_pos += 2; skip(); c_add_sub(); emit_s("  i64.ne\n");
    }
    return 0;
}

fn c_and_expr() i64 {
    c_comparison();
    while (is_letter(cur()) == 1) {
        var s: i64 = src_pos;
        var w: i64 = read_name();
        if (streq_mem(w, "and") == 1) {
            emit_s("  i64.const 0\n  i64.ne\n");
            c_comparison();
            emit_s("  i64.const 0\n  i64.ne\n  i64.and\n");
        } else { src_pos = s; break; }
    }
    return 0;
}

fn c_or_expr() i64 {
    c_and_expr();
    while (is_letter(cur()) == 1) {
        var s: i64 = src_pos;
        var w: i64 = read_name();
        if (streq_mem(w, "or") == 1) {
            emit_s("  i64.const 0\n  i64.ne\n");
            c_and_expr();
            emit_s("  i64.const 0\n  i64.ne\n  i64.or\n");
        } else { src_pos = s; break; }
    }
    return 0;
}

fn c_expression() i64 {
    c_or_expr();
    return 0;
}

cur() == '*' or cur() == '/' -- inline condition using or, no helper function needed. The full precedence chain: expression -> or_expr -> and_expr -> comparison -> add_sub -> term -> factor. The self-hosted compiler handles every operator the Zig compiler handles.

### The statement compiler