Feeding the Snake
vm-data-sections

Update the VM to handle data sections and the print_str import.

When the VM sees (data (i32.const ADDR) "..."), it copies the string bytes into vm_memory at the given address.

When the VM hits call $print_str, it pops addr and len, reads bytes from vm_memory, and prints them.

fn vm_load_data() void {
    for (0..vm_line_count) |i| {
        const line: []const u8 = vm_trim(vm_lines[i]);
        if (starts_with(line, "(data (i32.const ")) {
            const addr_start: usize = 17; // after "(data (i32.const "
            const addr: usize = @as(usize, @intCast(parse_int(line, addr_start)));
            // find the string content between quotes
            var q1: usize = 0;
            while (q1 < line.len and line[q1] != '"') { q1 += 1; }
            q1 += 1; // skip first quote
            var q2: usize = q1;
            while (q2 < line.len and line[q2] != '"') {
                if (line[q2] == '\\' and q2 + 2 < line.len) {
                    // hex escape
                    const hi: u8 = hex_val(line[q2 + 1]);
                    const lo: u8 = hex_val(line[q2 + 2]);
                    vm_memory[addr + (q2 - q1)] = hi * 16 + lo;
                    q2 += 3;
                } else {
                    vm_memory[addr + (q2 - q1)] = line[q2];
                    q2 += 1;
                }
            }
        }
    }
}

fn hex_val(c: u8) u8 {
    if (c >= '0' and c <= '9') { return c - '0'; }
    if (c >= 'a' and c <= 'f') { return c - 'a' + 10; }
    return 0;
}

Call vm_load_data() from vm_run_wat() after vm_scan_functions().