The Compiler, in Its Own Language
self-helpers

Helper functions:

fn skip_past_block() i64 {
    while (cur() != '{') {
        if (cur() == 0) { return 0; }
        src_pos += 1;
    }
    src_pos += 1; skip();
    var depth: i64 = 1;
    while (depth > 0) {
        if (cur() == 0) { return 0; }
        if (cur() == '{') { depth += 1; }
        if (cur() == '}') { depth -= 1; }
        if (depth > 0) { src_pos += 1; }
    }
    if (cur() == '}') { src_pos += 1; skip(); }
    return 0;
}

fn skip_stmt() i64 {
    while (cur() != ';') {
        if (cur() == 0) { return 0; }
        if (cur() == '{') { skip_past_block(); return 0; }
        src_pos += 1;
    }
    src_pos += 1; skip();
    return 0;
}

fn scan_locals() i64 {
    var save: i64 = src_pos;
    if (cur() == '{') { src_pos += 1; skip(); }
    var depth: i64 = 0;
    while (cur() != 0) {
        if (cur() == '{') { depth += 1; }
        if (cur() == '}') {
            if (depth == 0) {
                emit_s("  (local $__tmp i64)\n");
                emit_s("  (local $__for_end i64)\n");
                src_pos = save;
                return 0;
            }
            depth -= 1;
        }
        if (is_letter(cur()) == 1) {
            var w: i64 = read_name();
            if (streq_mem(w, "var") == 1 or streq_mem(w, "const") == 1) {
                var vname: i64 = read_name();
                if (cur() == ':') { src_pos += 1; skip(); read_name(); }
                if (is_global(vname) == 0) {
                    emit_s("  (local $"); emit_s(vname); emit_s(" i64)\n");
                }
            }
            if (streq_mem(w, "for") == 1) {
                // skip to |name| and register the capture variable
                while (cur() != '|' and cur() != 0) { src_pos += 1; }
                if (cur() == '|') { src_pos += 1; skip(); }
                var capname: i64 = read_name();
                if (cur() == '|') { src_pos += 1; skip(); }
                emit_s("  (local $"); emit_s(capname); emit_s(" i64)\n");
            }
        } else {
            src_pos += 1;
        }
    }
    emit_s("  (local $__tmp i64)\n");
    emit_s("  (local $__for_end i64)\n");
    src_pos = save;
    return 0;
}

scan_locals now also detects for loops and registers their capture variables as locals. It emits $__tmp and $__for_end for every function.