c_stmt -- returns 1 if it left a value on the stack, 0 if not:
fn c_stmt() i64 {
if (is_letter(cur()) == 1) {
var save: i64 = src_pos;
var word: i64 = read_name();
if (streq_mem(word, "var") == 1 or streq_mem(word, "const") == 1) {
var vname: i64 = read_name();
if (cur() == ':') { src_pos += 1; skip(); read_name(); }
if (cur() == '=') { src_pos += 1; skip(); }
c_expression();
if (is_global(vname) == 1) { emit_s(" global.set $"); }
else { emit_s(" local.set $"); }
emit_s(vname); emit_byte('\n');
if (cur() == ';') { src_pos += 1; skip(); }
return 0;
}
if (streq_mem(word, "return") == 1) {
c_expression();
emit_s(" return\n");
if (cur() == ';') { src_pos += 1; skip(); }
return 0;
}
if (streq_mem(word, "if") == 1) {
if (cur() == '(') { src_pos += 1; skip(); }
c_expression();
if (cur() == ')') { src_pos += 1; skip(); }
emit_s(" if (result i64)\n");
c_block();
if (is_letter(cur()) == 1) {
var s2: i64 = src_pos;
var w2: i64 = read_name();
if (streq_mem(w2, "else") == 1) {
emit_s(" else\n");
c_block();
} else {
src_pos = s2;
emit_s(" else\n i64.const 0\n");
}
} else {
emit_s(" else\n i64.const 0\n");
}
emit_s(" end\n");
return 1;
}
if (streq_mem(word, "while") == 1) {
emit_s(" block\n loop\n");
if (cur() == '(') { src_pos += 1; skip(); }
c_expression();
if (cur() == ')') { src_pos += 1; skip(); }
emit_s(" i64.eqz\n br_if 1\n");
c_block();
emit_s(" drop\n br 0\n end\n end\n");
return 0;
}
if (streq_mem(word, "for") == 1) {
if (cur() == '(') { src_pos += 1; skip(); }
c_expression();
if (cur() == '.') { src_pos += 1; }
if (cur() == '.') { src_pos += 1; }
skip();
c_expression();
emit_s(" local.set $__for_end\n");
if (cur() == ')') { src_pos += 1; skip(); }
if (cur() == '|') { src_pos += 1; skip(); }
var loop_var: i64 = read_name();
if (cur() == '|') { src_pos += 1; skip(); }
emit_s(" local.set $"); emit_s(loop_var); emit_byte('\n');
emit_s(" block\n loop\n");
emit_s(" local.get $"); emit_s(loop_var); emit_byte('\n');
emit_s(" local.get $__for_end\n i64.ge_s\n br_if 1\n");
c_block();
emit_s(" drop\n");
emit_s(" local.get $"); emit_s(loop_var); emit_byte('\n');
emit_s(" i64.const 1\n i64.add\n");
emit_s(" local.set $"); emit_s(loop_var); emit_byte('\n');
emit_s(" br 0\n end\n end\n");
return 0;
}
if (streq_mem(word, "break") == 1) {
if (cur() == ';') { src_pos += 1; skip(); }
emit_s(" br 1\n");
return 0;
}
if (streq_mem(word, "fn") == 1) {
c_fn();
return 0;
}
// compound assignment: name += expr
if (cur() == '+' and load8(src_pos + 1) == '=') {
src_pos += 2; skip();
if (is_global(word) == 1) { emit_s(" global.get $"); }
else { emit_s(" local.get $"); }
emit_s(word); emit_byte('\n');
c_expression();
emit_s(" i64.add\n");
if (is_global(word) == 1) { emit_s(" global.set $"); }
else { emit_s(" local.set $"); }
emit_s(word); emit_byte('\n');
if (cur() == ';') { src_pos += 1; skip(); }
return 0;
}
if (cur() == '-' and load8(src_pos + 1) == '=') {
src_pos += 2; skip();
if (is_global(word) == 1) { emit_s(" global.get $"); }
else { emit_s(" local.get $"); }
emit_s(word); emit_byte('\n');
c_expression();
emit_s(" i64.sub\n");
if (is_global(word) == 1) { emit_s(" global.set $"); }
else { emit_s(" local.set $"); }
emit_s(word); emit_byte('\n');
if (cur() == ';') { src_pos += 1; skip(); }
return 0;
}
// assignment: name = expr (not ==)
if (cur() == '=' and load8(src_pos + 1) != '=') {
src_pos += 1; skip();
c_expression();
if (is_global(word) == 1) { emit_s(" global.set $"); }
else { emit_s(" local.set $"); }
emit_s(word); emit_byte('\n');
if (cur() == ';') { src_pos += 1; skip(); }
return 0;
}
src_pos = save;
}
c_expression();
if (cur() == ';') { src_pos += 1; skip(); }
return 1;
}
Every keyword check uses streq_mem with string literals. var and const are handled together with or. for parses the (start..end) |name| syntax. break emits br 1. Compound assignment (+=, -=) emits get-compute-set. The = vs == check uses load8(src_pos + 1) != '='.