Write c_program() -- the top-level function. Three passes: scan globals, compile functions, compile main.
fn c_program(input: []const u8) void {
out_len = 0;
c_global_count = 0;
// Pass 1: scan for top-level globals
source = input; pos = 0; skip();
var depth: i32 = 0;
while (pos < source.len) {
if (source[pos] == '{') { depth += 1; pos += 1; continue; }
if (source[pos] == '}') { depth -= 1; pos += 1; continue; }
if (depth == 0 and is_letter(cur())) {
const s: usize = pos;
const w: []const u8 = read_name();
if (streq(w, "var") or streq(w, "const")) {
const vn: []const u8 = read_name();
if (cur() == ':') { pos += 1; skip(); _ = read_name(); }
c_global_names[c_global_count] = vn;
c_global_count += 1;
} else if (streq(w, "fn")) {
while (cur() != '{' and cur() != 0) { pos += 1; }
if (cur() == '{') { skip_block(); }
} else {
pos = s; pos += 1;
}
} else { pos += 1; }
}
// Emit globals
for (0..c_global_count) |i| {
emit_str("(global $");
emit_str(c_global_names[i]);
emit_str(" (mut i64) (i64.const 0))\n");
}
// Pass 2: compile function definitions
source = input; pos = 0; skip();
while (cur() != 0) {
if (is_letter(cur())) {
const s: usize = pos;
const w: []const u8 = read_name();
if (streq(w, "fn")) { pos = s; _ = c_stmt(); continue; }
pos = s;
}
if (cur() == '{') { skip_block(); } else { pos += 1; }
}
// Pass 3: compile top-level code into main
emit_str("(func (export \"main\") (result i64)\n");
// Scan for top-level locals
source = input; pos = 0; skip();
local_count = 0;
depth = 0;
while (pos < source.len) {
if (source[pos] == '{') { depth += 1; pos += 1; continue; }
if (source[pos] == '}') { depth -= 1; pos += 1; continue; }
if (depth == 0 and is_letter(cur())) {
const s: usize = pos;
const w: []const u8 = read_name();
if (streq(w, "var") or streq(w, "const")) {
const vn: []const u8 = read_name();
if (cur() == ':') { pos += 1; skip(); _ = read_name(); }
if (!c_is_global(vn)) {
var dup: bool = false;
for (0..local_count) |i| { if (streq(local_names[i], vn)) { dup = true; break; } }
if (!dup) { local_names[local_count] = vn; local_count += 1; }
}
} else if (streq(w, "fn")) {
while (cur() != '{' and cur() != 0) { pos += 1; }
if (cur() == '{') { skip_block(); }
} else { pos = s; pos += 1; }
} else { pos += 1; }
}
emit_locals();
// Compile top-level statements (skip fn definitions)
source = input; pos = 0; skip();
var last_had_value: bool = false;
while (cur() != 0) {
if (is_letter(cur())) {
const s: usize = pos;
const w: []const u8 = read_name();
if (streq(w, "fn")) {
while (cur() != '{' and cur() != 0) { pos += 1; }
skip_block();
continue;
}
pos = s;
}
if (last_had_value) { emit_op("drop"); }
last_had_value = c_stmt();
}
if (!last_had_value) { emit_const(0); }
emit_str(")\n");
}