var json = use("json")

var mcode = function(ast) {
  // Translation tables
  var binop_map = {
    "+": "add", "-": "subtract", "*": "multiply", "/": "divide",
    "%": "modulo", "&": "bitand", "|": "bitor", "^": "bitxor",
    "<<": "shl", ">>": "shr", ">>>": "ushr",
    "==": "eq", "===": "eq", "!=": "ne", "!==": "ne",
    "<": "lt", "<=": "le", ">": "gt", ">=": "ge",
    "**": "pow", "in": "in"
  }

  var functino_map = {
    "+!": "add", "-!": "subtract", "*!": "multiply", "/!": "divide",
    "%!": "modulo", "**!": "pow",
    "<!": "lt", ">!": "gt", "<=!": "le", ">=!": "ge",
    "=!": "eq", "!=!": "ne",
    "&!": "bitand", "|!": "bitor", "^!": "bitxor",
    "<<!": "shl", ">>!": "shr", ">>>!": "ushr",
    "&&!": "and", "||!": "or",
    "~!": "bitnot", "[]!": "load"
  }

  var binop_sym = {
    add: "+", subtract: "-", multiply: "*", divide: "/",
    modulo: "%", pow: "**",
    lt: "<", le: "<=", gt: ">", ge: ">="
  }

  var compound_map = {
    "+=": "add", "-=": "subtract", "*=": "multiply", "/=": "divide",
    "%=": "modulo", "&=": "bitand", "|=": "bitor", "^=": "bitxor",
    "<<=": "shl", ">>=": "shr", ">>>=": "ushr"
  }

  var sensory_ops = {
    is_array: "is_array", is_function: "is_func", is_object: "is_record",
    is_stone: "is_stone", is_integer: "is_int", is_text: "is_text",
    is_number: "is_num", is_logical: "is_bool", is_null: "is_null",
    length: "length"
  }

  // Compiler state
  var s_instructions = null
  var s_data = null
  var s_functions = null
  var s_vars = null
  var s_this_slot = 0
  var s_nr_args = 0
  var s_nr_close_slots = 0
  var s_nr_local_slots = 0
  var s_next_temp_slot = 0
  var s_max_slot = 0
  var s_label_counter = 0
  var s_func_counter = 0
  var s_loop_break = null
  var s_loop_continue = null
  var s_label_map = {}
  var s_pending_label = null
  var s_is_arrow = false
  var s_function_nr = 0
  var s_scopes = null
  var s_intrinsic_cache = null
  var s_cur_line = 0
  var s_cur_col = 0
  var s_filename = null
  var s_has_disruption = false

  // Shared closure vars for binop helpers (avoids >4 param functions)
  var _bp_dest = 0
  var _bp_left = 0
  var _bp_right = 0
  var _bp_ln = null
  var _bp_rn = null
  var _bp_op_sym = null

  // State save/restore for nested function compilation
  var save_state = function() {
    return {
      instructions: s_instructions,
      vars: s_vars,
      this_slot: s_this_slot,
      nr_args: s_nr_args,
      nr_close_slots: s_nr_close_slots,
      nr_local_slots: s_nr_local_slots,
      next_temp_slot: s_next_temp_slot,
      max_slot: s_max_slot,
      loop_break: s_loop_break,
      loop_continue: s_loop_continue,
      label_map: s_label_map,
      is_arrow: s_is_arrow,
      function_nr: s_function_nr,
      intrinsic_cache: s_intrinsic_cache,
      cur_line: s_cur_line,
      cur_col: s_cur_col,
      has_disruption: s_has_disruption
    }
  }

  var restore_state = function(saved) {
    s_instructions = saved.instructions
    s_vars = saved.vars
    s_this_slot = saved.this_slot
    s_nr_args = saved.nr_args
    s_nr_close_slots = saved.nr_close_slots
    s_nr_local_slots = saved.nr_local_slots
    s_next_temp_slot = saved.next_temp_slot
    s_max_slot = saved.max_slot
    s_loop_break = saved.loop_break
    s_loop_continue = saved.loop_continue
    s_label_map = saved.label_map
    s_is_arrow = saved.is_arrow
    s_function_nr = saved.function_nr
    s_intrinsic_cache = saved.intrinsic_cache
    s_cur_line = saved.cur_line
    s_cur_col = saved.cur_col
    s_has_disruption = saved.has_disruption
  }

  // Slot allocation
  var alloc_slot = function() {
    var slot = s_next_temp_slot
    s_next_temp_slot = s_next_temp_slot + 1
    if (slot > s_max_slot) {
      s_max_slot = slot
    }
    return slot
  }

  // Variable tracking
  var add_var = function(name, slot, is_const) {
    push(s_vars, {name: name, slot: slot, is_const: is_const, is_closure: false})
  }

  var find_var = function(name) {
    var _i = 0
    while (_i < length(s_vars)) {
      if (s_vars[_i].name == name) {
        return s_vars[_i].slot
      }
      _i = _i + 1
    }
    return -1
  }

  // Intrinsic cache
  var find_intrinsic = function(name) {
    var _i = 0
    while (_i < length(s_intrinsic_cache)) {
      if (s_intrinsic_cache[_i].name == name) {
        return s_intrinsic_cache[_i].slot
      }
      _i = _i + 1
    }
    return -1
  }

  // Scope helpers
  var find_scope_record = function(fn_nr) {
    if (s_scopes == null) {
      return null
    }
    var _i = 0
    var scope = null
    while (_i < length(s_scopes)) {
      scope = s_scopes[_i]
      if (scope.function_nr == fn_nr) {
        return scope
      }
      _i = _i + 1
    }
    return null
  }

  // Label generation
  var gen_label = function(prefix) {
    var label = prefix + "_" + text(s_label_counter)
    s_label_counter = s_label_counter + 1
    return label
  }

  // Position tracking
  var set_pos = function(node) {
    if (node.from_row != null) {
      s_cur_line = node.from_row + 1
    }
    if (node.from_column != null) {
      s_cur_col = node.from_column + 1
    }
  }

  // Instruction emission
  var add_instr = function(instr) {
    push(instr, s_cur_line)
    push(instr, s_cur_col)
    push(s_instructions, instr)
  }

  var emit_label = function(label) {
    push(s_instructions, label)
  }

  var emit_0 = function(op) {
    add_instr([op])
  }

  var emit_1 = function(op, a) {
    add_instr([op, a])
  }

  var emit_2 = function(op, a, b) {
    add_instr([op, a, b])
  }

  var emit_3 = function(op, a, b, c) {
    add_instr([op, a, b, c])
  }

  var emit_4 = function(op, a, b, c) {
    // 4th operand passed via closure - use emit_4_full instead
    add_instr([op, a, b, c])
  }

  var emit_4_full = function(op, abcd) {
    var instr = [op, abcd[0], abcd[1], abcd[2], abcd[3]]
    add_instr(instr)
  }

  var emit_const_num = function(dest, val) {
    add_instr(["access", dest, val])
  }

  var emit_const_str = function(dest, val) {
    add_instr(["access", dest, val])
  }

  var emit_const_bool = function(dest, val) {
    if (val) {
      emit_1("true", dest)
    } else {
      emit_1("false", dest)
    }
  }

  var emit_const_null = function(dest) {
    emit_1("null", dest)
  }

  var emit_log_error = function(msg) {
    var log_slot = alloc_slot()
    add_instr(["access", log_slot, {kind: "name", name: "log", make: "intrinsic"}])
    var name_slot = alloc_slot()
    emit_const_str(name_slot, "error")
    var msg_slot = alloc_slot()
    emit_const_str(msg_slot, msg)
    var args_arr = alloc_slot()
    add_instr(["array", args_arr, 0])
    emit_2("push", args_arr, msg_slot)
    var result = alloc_slot()
    var frame_slot = alloc_slot()
    emit_3("frame", frame_slot, log_slot, 2)
    var null_slot = alloc_slot()
    emit_1("null", null_slot)
    emit_3("setarg", frame_slot, 0, null_slot)
    emit_3("setarg", frame_slot, 1, name_slot)
    emit_3("setarg", frame_slot, 2, args_arr)
    emit_2("invoke", frame_slot, result)
  }

  var emit_jump = function(label) {
    add_instr(["jump", label])
  }

  var emit_jump_cond = function(op, slot, label) {
    add_instr([op, slot, label])
  }

  // ---- Decomposed op emission helpers ----

  // Helper: check if an AST node is a known-int literal
  var is_known_int = function(node) {
    if (node == null) { return false }
    return node.kind == "number" && is_integer(node.number)
  }

  // Helper: check if an AST node is a known-text literal
  var is_known_text = function(node) {
    if (node == null) { return false }
    return node.kind == "text" || node.kind == "text literal"
  }

  // Helper: check if an AST node is a known-number literal (int or float)
  var is_known_number = function(node) {
    if (node == null) { return false }
    return node.kind == "number"
  }

  // Helper: check if an AST node is a known-bool literal
  var is_known_bool = function(node) {
    if (node == null) { return false }
    return node.kind == "true" || node.kind == "false"
  }

  // Helper: check if an AST node is a known-null literal
  var is_known_null = function(node) {
    if (node == null) { return false }
    return node.kind == "null"
  }

  // emit_add_decomposed: emit type-dispatched add (text → concat, num → add)
  // reads _bp_dest, _bp_left, _bp_right, _bp_ln, _bp_rn from closure
  var emit_add_decomposed = function() {
    if (is_known_text(_bp_ln) && is_known_text(_bp_rn)) {
      emit_3("concat", _bp_dest, _bp_left, _bp_right)
      return null
    }
    if (is_known_number(_bp_ln) && is_known_number(_bp_rn)) {
      emit_3("add", _bp_dest, _bp_left, _bp_right)
      return null
    }
    // If either operand is a known number, concat is impossible
    if (is_known_number(_bp_ln) || is_known_number(_bp_rn)) {
      emit_numeric_binop("add")
      return null
    }
    // Unknown types: emit full dispatch
    var t0 = alloc_slot()
    var t1 = alloc_slot()
    var done = gen_label("add_done")
    var check_num = gen_label("add_cn")

    // Check text path first (since add doubles as concat)
    emit_2("is_text", t0, _bp_left)
    emit_jump_cond("jump_false", t0, check_num)
    emit_2("is_text", t1, _bp_right)
    emit_jump_cond("jump_false", t1, check_num)
    emit_3("concat", _bp_dest, _bp_left, _bp_right)
    emit_jump(done)

    // Numeric path
    var err = gen_label("add_err")
    emit_label(check_num)
    emit_2("is_num", t0, _bp_left)
    emit_jump_cond("jump_false", t0, err)
    emit_2("is_num", t1, _bp_right)
    emit_jump_cond("jump_false", t1, err)
    emit_3("add", _bp_dest, _bp_left, _bp_right)
    emit_jump(done)

    emit_label(err)
    emit_log_error("cannot apply '+': operands must both be text or both be numbers")
    emit_0("disrupt")
    emit_label(done)
    return null
  }

  // emit_numeric_binop: emit type-guarded numeric binary op
  // reads _bp_dest, _bp_left, _bp_right, _bp_ln, _bp_rn from closure
  var emit_numeric_binop = function(op_str) {
    if (is_known_number(_bp_ln) && is_known_number(_bp_rn)) {
      emit_3(op_str, _bp_dest, _bp_left, _bp_right)
      return null
    }
    var t0 = alloc_slot()
    var t1 = alloc_slot()
    var err = gen_label("num_err")
    var done = gen_label("num_done")
    emit_2("is_num", t0, _bp_left)
    emit_jump_cond("jump_false", t0, err)
    emit_2("is_num", t1, _bp_right)
    emit_jump_cond("jump_false", t1, err)
    emit_3(op_str, _bp_dest, _bp_left, _bp_right)
    emit_jump(done)

    emit_label(err)
    emit_log_error("cannot apply '" + _bp_op_sym + "': operands must be numbers")
    emit_0("disrupt")
    emit_label(done)
    return null
  }

  // emit_eq_decomposed: identical -> int -> float -> text -> null -> bool -> mismatch(false)
  // reads _bp_dest, _bp_left, _bp_right from closure
  var emit_eq_decomposed = function() {
    var dest = _bp_dest
    var left = _bp_left
    var right = _bp_right
    var t0 = 0
    var t1 = 0
    var done = gen_label("eq_done")
    var not_int = gen_label("eq_ni")
    var not_num = gen_label("eq_nn")
    var not_text = gen_label("eq_nt")
    var not_null = gen_label("eq_nnl")
    var not_bool = gen_label("eq_nb")

    // Identical check
    emit_3("is_identical", dest, left, right)
    emit_jump_cond("jump_true", dest, done)

    // Int path
    t0 = alloc_slot()
    emit_2("is_int", t0, left)
    emit_jump_cond("jump_false", t0, not_int)
    t1 = alloc_slot()
    emit_2("is_int", t1, right)
    emit_jump_cond("jump_false", t1, not_int)
    emit_3("eq_int", dest, left, right)
    emit_jump(done)

    // Float path
    emit_label(not_int)
    emit_2("is_num", t0, left)
    emit_jump_cond("jump_false", t0, not_num)
    emit_2("is_num", t1, right)
    emit_jump_cond("jump_false", t1, not_num)
    emit_3("eq_float", dest, left, right)
    emit_jump(done)

    // Text path
    emit_label(not_num)
    emit_2("is_text", t0, left)
    emit_jump_cond("jump_false", t0, not_text)
    emit_2("is_text", t1, right)
    emit_jump_cond("jump_false", t1, not_text)
    emit_3("eq_text", dest, left, right)
    emit_jump(done)

    // Null path
    emit_label(not_text)
    emit_2("is_null", t0, left)
    emit_jump_cond("jump_false", t0, not_null)
    emit_2("is_null", t1, right)
    emit_jump_cond("jump_false", t1, not_null)
    emit_1("true", dest)
    emit_jump(done)

    // Bool path
    emit_label(not_null)
    emit_2("is_bool", t0, left)
    emit_jump_cond("jump_false", t0, not_bool)
    emit_2("is_bool", t1, right)
    emit_jump_cond("jump_false", t1, not_bool)
    emit_3("eq_bool", dest, left, right)
    emit_jump(done)

    // Mismatch -> false
    emit_label(not_bool)
    emit_1("false", dest)
    emit_label(done)
    return null
  }

  // emit_ne_decomposed: identical -> int -> float -> text -> null -> bool -> mismatch(true)
  // reads _bp_dest, _bp_left, _bp_right from closure
  var emit_ne_decomposed = function() {
    var dest = _bp_dest
    var left = _bp_left
    var right = _bp_right
    var t0 = 0
    var t1 = 0
    var done = gen_label("ne_done")
    var not_ident = gen_label("ne_nid")
    var not_int = gen_label("ne_ni")
    var not_num = gen_label("ne_nn")
    var not_text = gen_label("ne_nt")
    var not_null = gen_label("ne_nnl")
    var not_bool = gen_label("ne_nb")

    // Identical -> false
    emit_3("is_identical", dest, left, right)
    emit_jump_cond("jump_true", dest, not_ident)
    // If jump_true doesn't fire, dest already holds false, continue to checks
    emit_jump(not_int)

    emit_label(not_ident)
    emit_1("false", dest)
    emit_jump(done)

    // Int path
    emit_label(not_int)
    t0 = alloc_slot()
    emit_2("is_int", t0, left)
    emit_jump_cond("jump_false", t0, not_num)
    t1 = alloc_slot()
    emit_2("is_int", t1, right)
    emit_jump_cond("jump_false", t1, not_num)
    emit_3("ne_int", dest, left, right)
    emit_jump(done)

    // Float path
    emit_label(not_num)
    emit_2("is_num", t0, left)
    emit_jump_cond("jump_false", t0, not_text)
    emit_2("is_num", t1, right)
    emit_jump_cond("jump_false", t1, not_text)
    emit_3("ne_float", dest, left, right)
    emit_jump(done)

    // Text path
    emit_label(not_text)
    emit_2("is_text", t0, left)
    emit_jump_cond("jump_false", t0, not_null)
    emit_2("is_text", t1, right)
    emit_jump_cond("jump_false", t1, not_null)
    emit_3("ne_text", dest, left, right)
    emit_jump(done)

    // Null path
    emit_label(not_null)
    emit_2("is_null", t0, left)
    emit_jump_cond("jump_false", t0, not_bool)
    emit_2("is_null", t1, right)
    emit_jump_cond("jump_false", t1, not_bool)
    emit_1("false", dest)
    emit_jump(done)

    // Bool path
    var mismatch = gen_label("ne_mis")
    emit_label(not_bool)
    emit_2("is_bool", t0, left)
    emit_jump_cond("jump_false", t0, mismatch)
    emit_2("is_bool", t1, right)
    emit_jump_cond("jump_false", t1, mismatch)
    emit_3("ne_bool", dest, left, right)
    emit_jump(done)

    // Mismatch -> true (ne of different types is true)
    emit_label(mismatch)
    emit_1("true", dest)
    emit_label(done)
    return null
  }

  // emit_relational: int -> float -> text -> disrupt
  // reads _bp_dest, _bp_left, _bp_right, _bp_ln, _bp_rn from closure
  var emit_relational = function(int_op, float_op, text_op) {
    var dest = _bp_dest
    var left = _bp_left
    var right = _bp_right
    var t0 = 0
    var t1 = 0
    var left_is_int = is_known_int(_bp_ln)
    var left_is_num = is_known_number(_bp_ln)
    var left_is_text = is_known_text(_bp_ln)
    var right_is_int = is_known_int(_bp_rn)
    var right_is_num = is_known_number(_bp_rn)
    var right_is_text = is_known_text(_bp_rn)
    var not_int = null
    var not_num = null
    var done = null
    var err = null

    // Both known int
    if (left_is_int && right_is_int) {
      emit_3(int_op, dest, left, right)
      return null
    }
    // Both known number
    if (left_is_num && right_is_num) {
      emit_3(float_op, dest, left, right)
      return null
    }
    // Both known text
    if (left_is_text && right_is_text) {
      emit_3(text_op, dest, left, right)
      return null
    }

    not_int = gen_label("rel_ni")
    not_num = gen_label("rel_nn")
    done = gen_label("rel_done")
    err = gen_label("rel_err")

    t0 = alloc_slot()
    emit_2("is_int", t0, left)
    emit_jump_cond("jump_false", t0, not_int)
    t1 = alloc_slot()
    emit_2("is_int", t1, right)
    emit_jump_cond("jump_false", t1, not_int)
    emit_3(int_op, dest, left, right)
    emit_jump(done)

    emit_label(not_int)
    emit_2("is_num", t0, left)
    emit_jump_cond("jump_false", t0, not_num)
    emit_2("is_num", t1, right)
    emit_jump_cond("jump_false", t1, not_num)
    emit_3(float_op, dest, left, right)
    emit_jump(done)

    emit_label(not_num)
    emit_2("is_text", t0, left)
    emit_jump_cond("jump_false", t0, err)
    emit_2("is_text", t1, right)
    emit_jump_cond("jump_false", t1, err)
    emit_3(text_op, dest, left, right)
    emit_jump(done)

    emit_label(err)
    emit_log_error("cannot compare with '" + _bp_op_sym + "': operands must be same type")
    emit_0("disrupt")
    emit_label(done)
    return null
  }

  // emit_neg_decomposed: emit type-guarded negate
  var emit_neg_decomposed = function(dest, src, src_node) {
    if (is_known_number(src_node)) {
      emit_2("negate", dest, src)
      return null
    }
    var t0 = alloc_slot()
    var err = gen_label("neg_err")
    var done = gen_label("neg_done")
    emit_2("is_num", t0, src)
    emit_jump_cond("jump_false", t0, err)
    emit_2("negate", dest, src)
    emit_jump(done)

    emit_label(err)
    emit_log_error("cannot negate: operand must be a number")
    emit_0("disrupt")
    emit_label(done)
    return null
  }

  // Central router: maps op string to decomposition helper
  // Sets _bp_* closure vars then calls helper with reduced args
  var relational_ops = {
    lt: ["lt_int", "lt_float", "lt_text"],
    le: ["le_int", "le_float", "le_text"],
    gt: ["gt_int", "gt_float", "gt_text"],
    ge: ["ge_int", "ge_float", "ge_text"]
  }
  var emit_binop = function(op_str, dest, left, right) {
    var rel = null
    _bp_dest = dest
    _bp_left = left
    _bp_right = right
    _bp_op_sym = binop_sym[op_str] || op_str
    if (op_str == "add") {
      emit_add_decomposed()
    } else if (op_str == "eq") {
      emit_eq_decomposed()
    } else if (op_str == "ne") {
      emit_ne_decomposed()
    } else {
      rel = relational_ops[op_str]
      if (rel != null) {
        emit_relational(rel[0], rel[1], rel[2])
      } else if (op_str == "subtract" || op_str == "multiply" ||
                 op_str == "divide" || op_str == "modulo" || op_str == "pow") {
        emit_numeric_binop(op_str)
      } else {
        // Passthrough for bitwise, in, etc.
        emit_3(op_str, dest, left, right)
      }
    }
    return null
  }

  var emit_get_prop = function(dest, obj, prop) {
    add_instr(["load_field", dest, obj, prop])
  }

  var emit_set_prop = function(obj, prop, val) {
    add_instr(["store_field", obj, val, prop])
  }

  var emit_get_elem = function(dest, obj, idx, access_kind) {
    if (access_kind == "index") {
      emit_3("load_index", dest, obj, idx)
    } else if (access_kind == "field") {
      emit_3("load_field", dest, obj, idx)
    } else {
      emit_3("load_dynamic", dest, obj, idx)
    }
  }

  var emit_set_elem = function(obj, idx, val, access_kind) {
    if (access_kind == "index") {
      emit_3("store_index", obj, val, idx)
    } else if (access_kind == "field") {
      emit_3("store_field", obj, val, idx)
    } else {
      emit_3("store_dynamic", obj, val, idx)
    }
  }

  var emit_call = function(dest, func_slot, args) {
    var argc = length(args)
    var frame_slot = alloc_slot()
    emit_3("frame", frame_slot, func_slot, argc)
    var null_slot = alloc_slot()
    emit_1("null", null_slot)
    emit_3("setarg", frame_slot, 0, null_slot)
    var arg_idx = 1
    var _i = 0
    while (_i < argc) {
      emit_3("setarg", frame_slot, arg_idx, args[_i])
      arg_idx = arg_idx + 1
      _i = _i + 1
    }
    emit_2("invoke", frame_slot, dest)
  }

  var emit_call_method = function(dest, obj, prop, args) {
    var argc = length(args)
    var check = alloc_slot()
    var record_path = gen_label("record_path")
    var done_label = gen_label("call_done")
    var _i = 0
    var arg_idx = 0

    // Check if obj is a proxy function (arity 2)
    emit_2("is_proxy", check, obj)
    emit_jump_cond("jump_false", check, record_path)

    // Function proxy path: call obj(prop_name, [args...]) with this=null
    var null_slot = alloc_slot()
    emit_const_null(null_slot)
    var name_str = alloc_slot()
    emit_const_str(name_str, prop)
    var args_arr = alloc_slot()
    add_instr(["array", args_arr, 0])
    _i = 0
    while (_i < argc) {
      emit_2("push", args_arr, args[_i])
      _i = _i + 1
    }
    var pf = alloc_slot()
    emit_3("frame", pf, obj, 2)
    emit_3("setarg", pf, 0, null_slot)
    emit_3("setarg", pf, 1, name_str)
    emit_3("setarg", pf, 2, args_arr)
    emit_2("invoke", pf, dest)
    emit_jump(done_label)

    // Record path: load method, call with this=obj
    emit_label(record_path)
    var method_slot = alloc_slot()
    add_instr(["load_field", method_slot, obj, prop])
    var frame_slot = alloc_slot()
    emit_3("frame", frame_slot, method_slot, argc)
    emit_3("setarg", frame_slot, 0, obj)
    arg_idx = 1
    _i = 0
    while (_i < argc) {
      emit_3("setarg", frame_slot, arg_idx, args[_i])
      arg_idx = arg_idx + 1
      _i = _i + 1
    }
    emit_2("invoke", frame_slot, dest)

    emit_label(done_label)
  }

  var emit_call_method_dyn = function(dest, obj, key_reg, args) {
    var argc = length(args)
    var check = alloc_slot()
    var record_path = gen_label("dyn_record_path")
    var done_label = gen_label("dyn_call_done")
    var _i = 0
    var arg_idx = 0

    // Check if obj is a proxy function (arity 2)
    emit_2("is_proxy", check, obj)
    emit_jump_cond("jump_false", check, record_path)

    // Function proxy path (dynamic key): must be text
    var key_ok = alloc_slot()
    var error_path = gen_label("dyn_error")
    emit_2("is_text", key_ok, key_reg)
    emit_jump_cond("jump_false", key_ok, error_path)
    var null_slot = alloc_slot()
    emit_const_null(null_slot)
    var args_arr = alloc_slot()
    add_instr(["array", args_arr, 0])
    _i = 0
    while (_i < argc) {
      emit_2("push", args_arr, args[_i])
      _i = _i + 1
    }
    var pf = alloc_slot()
    emit_3("frame", pf, obj, 2)
    emit_3("setarg", pf, 0, null_slot)
    emit_3("setarg", pf, 1, key_reg)
    emit_3("setarg", pf, 2, args_arr)
    emit_2("invoke", pf, dest)
    emit_jump(done_label)

    // Error path: non-text key on function disrupts
    emit_label(error_path)
    emit_log_error("cannot access: key must be text")
    emit_0("disrupt")
    emit_jump(done_label)

    // Record path: load method dynamically, call with this=obj
    emit_label(record_path)
    var method_slot = alloc_slot()
    emit_3("load_dynamic", method_slot, obj, key_reg)
    var frame_slot = alloc_slot()
    emit_3("frame", frame_slot, method_slot, argc)
    emit_3("setarg", frame_slot, 0, obj)
    arg_idx = 1
    _i = 0
    while (_i < argc) {
      emit_3("setarg", frame_slot, arg_idx, args[_i])
      arg_idx = arg_idx + 1
      _i = _i + 1
    }
    emit_2("invoke", frame_slot, dest)

    emit_label(done_label)
  }

  var emit_go_call = function(func_slot, args) {
    var argc = length(args)
    var frame_slot = alloc_slot()
    emit_3("goframe", frame_slot, func_slot, argc)
    var null_slot = alloc_slot()
    emit_1("null", null_slot)
    emit_3("setarg", frame_slot, 0, null_slot)
    var arg_idx = 1
    var _i = 0
    while (_i < argc) {
      emit_3("setarg", frame_slot, arg_idx, args[_i])
      arg_idx = arg_idx + 1
      _i = _i + 1
    }
    emit_1("goinvoke", frame_slot)
  }

  var emit_go_call_method = function(obj, prop, args) {
    var func_slot = alloc_slot()
    emit_get_prop(func_slot, obj, prop)
    var argc = length(args)
    var frame_slot = alloc_slot()
    emit_3("goframe", frame_slot, func_slot, argc)
    emit_3("setarg", frame_slot, 0, obj)
    var arg_idx = 1
    var _i = 0
    while (_i < argc) {
      emit_3("setarg", frame_slot, arg_idx, args[_i])
      arg_idx = arg_idx + 1
      _i = _i + 1
    }
    emit_1("goinvoke", frame_slot)
  }

  // Pre-load intrinsics from AST intrinsics array
  var load_intrinsics = function(intrinsics) {
    if (intrinsics == null) {
      return null
    }
    var _i = 0
    var name = null
    var slot = 0
    var lit = null
    while (_i < length(intrinsics)) {
      name = intrinsics[_i]
      if (name == null || length(s_intrinsic_cache) >= 64) {
        _i = _i + 1
        continue
      }
      if (find_intrinsic(name) >= 0) {
        _i = _i + 1
        continue
      }
      slot = alloc_slot()
      lit = {kind: "name", name: name, make: "intrinsic"}
      add_instr(["access", slot, lit])
      push(s_intrinsic_cache, {name: name, slot: slot})
      _i = _i + 1
    }
  }

  // Scan scope record for variable declarations
  var scan_scope = function() {
    var scope = find_scope_record(s_function_nr)
    if (scope == null) {
      return null
    }
    var keys = sort(array(scope))
    var _i = 0
    var name = null
    var v = null
    var make = null
    var is_const = false
    var slot = 0
    while (_i < length(keys)) {
      name = keys[_i]
      if (name == "function_nr" || name == "nr_close_slots") {
        _i = _i + 1
        continue
      }
      v = scope[name]
      make = v.make
      if (make == null || make == "input") {
        _i = _i + 1
        continue
      }
      if (find_var(name) < 0) {
        is_const = (make == "def" || make == "function")
        slot = 1 + s_nr_args + s_nr_local_slots
        s_nr_local_slots = s_nr_local_slots + 1
        add_var(name, slot, is_const)
        if (v.closure == true) {
          s_vars[length(s_vars) - 1].is_closure = true
        }
      }
      _i = _i + 1
    }
  }

  // Find variable in a parent's saved state
  var find_var_in_saved = function(saved, name) {
    var _i = 0
    while (_i < length(saved.vars)) {
      if (saved.vars[_i].name == name) {
        return saved.vars[_i].slot
      }
      _i = _i + 1
    }
    return -1
  }

  // --- Inline expansion toggle flags ---
  var inline_arrfor = true
  var inline_filter = true
  var inline_every = true
  var inline_some = true
  var inline_reduce = true

  // --- Helper: emit a reduce loop body ---
  // r = {acc, i, arr, fn, len}; emits loop updating acc in-place.
  // Caller must emit the done_label after calling this.
  var emit_reduce_loop = function(r, forward, done_label) {
    var acc = r.acc
    var i = r.i
    var arr_slot = r.arr
    var fn_slot = r.fn
    var len = r.len
    var check = alloc_slot()
    var item = alloc_slot()
    var null_s = alloc_slot()
    var one = alloc_slot()
    var zero = alloc_slot()
    var f = alloc_slot()
    var loop_label = gen_label("reduce_loop")
    emit_2("int", one, 1)
    emit_1("null", null_s)
    emit_label(loop_label)
    if (forward) {
      emit_3("lt_int", check, i, len)
    } else {
      emit_2("int", zero, 0)
      emit_3("ge_int", check, i, zero)
    }
    emit_jump_cond("jump_false", check, done_label)
    emit_3("load_index", item, arr_slot, i)
    emit_3("frame", f, fn_slot, 2)
    emit_3("setarg", f, 0, null_s)
    emit_3("setarg", f, 1, acc)
    emit_3("setarg", f, 2, item)
    emit_2("invoke", f, acc)
    if (forward) {
      emit_3("add", i, i, one)
    } else {
      emit_3("subtract", i, i, one)
    }
    emit_jump(loop_label)
  }

  // --- Inline expansion: arrfor(arr, fn) ---
  var expand_inline_arrfor = function(dest, arr_slot, fn_slot) {
    var len = alloc_slot()
    var i = alloc_slot()
    var check = alloc_slot()
    var item = alloc_slot()
    var null_s = alloc_slot()
    var one = alloc_slot()
    var f = alloc_slot()
    var discard = alloc_slot()
    var loop_label = gen_label("arrfor_loop")
    var done_label = gen_label("arrfor_done")
    emit_2("length", len, arr_slot)
    emit_2("int", i, 0)
    emit_2("int", one, 1)
    emit_1("null", null_s)
    emit_label(loop_label)
    emit_3("lt_int", check, i, len)
    emit_jump_cond("jump_false", check, done_label)
    emit_3("load_index", item, arr_slot, i)
    emit_3("frame", f, fn_slot, 2)
    emit_3("setarg", f, 0, null_s)
    emit_3("setarg", f, 1, item)
    emit_3("setarg", f, 2, i)
    emit_2("invoke", f, discard)
    emit_3("add", i, i, one)
    emit_jump(loop_label)
    emit_label(done_label)
    emit_1("null", dest)
    return dest
  }

  // --- Inline expansion: every(arr, fn) ---
  var expand_inline_every = function(dest, arr_slot, fn_slot) {
    var len = alloc_slot()
    var i = alloc_slot()
    var check = alloc_slot()
    var item = alloc_slot()
    var null_s = alloc_slot()
    var one = alloc_slot()
    var f = alloc_slot()
    var val = alloc_slot()
    var loop_label = gen_label("every_loop")
    var ret_true = gen_label("every_true")
    var ret_false = gen_label("every_false")
    var done_label = gen_label("every_done")
    emit_2("length", len, arr_slot)
    emit_2("int", i, 0)
    emit_2("int", one, 1)
    emit_1("null", null_s)
    emit_label(loop_label)
    emit_3("lt_int", check, i, len)
    emit_jump_cond("jump_false", check, ret_true)
    emit_3("load_index", item, arr_slot, i)
    emit_3("frame", f, fn_slot, 1)
    emit_3("setarg", f, 0, null_s)
    emit_3("setarg", f, 1, item)
    emit_2("invoke", f, val)
    emit_jump_cond("jump_false", val, ret_false)
    emit_3("add", i, i, one)
    emit_jump(loop_label)
    emit_label(ret_true)
    emit_1("true", dest)
    emit_jump(done_label)
    emit_label(ret_false)
    emit_1("false", dest)
    emit_label(done_label)
    return dest
  }

  // --- Inline expansion: some(arr, fn) ---
  var expand_inline_some = function(dest, arr_slot, fn_slot) {
    var len = alloc_slot()
    var i = alloc_slot()
    var check = alloc_slot()
    var item = alloc_slot()
    var null_s = alloc_slot()
    var one = alloc_slot()
    var f = alloc_slot()
    var val = alloc_slot()
    var loop_label = gen_label("some_loop")
    var ret_true = gen_label("some_true")
    var ret_false = gen_label("some_false")
    var done_label = gen_label("some_done")
    emit_2("length", len, arr_slot)
    emit_2("int", i, 0)
    emit_2("int", one, 1)
    emit_1("null", null_s)
    emit_label(loop_label)
    emit_3("lt_int", check, i, len)
    emit_jump_cond("jump_false", check, ret_false)
    emit_3("load_index", item, arr_slot, i)
    emit_3("frame", f, fn_slot, 1)
    emit_3("setarg", f, 0, null_s)
    emit_3("setarg", f, 1, item)
    emit_2("invoke", f, val)
    emit_jump_cond("jump_true", val, ret_true)
    emit_3("add", i, i, one)
    emit_jump(loop_label)
    emit_label(ret_true)
    emit_1("true", dest)
    emit_jump(done_label)
    emit_label(ret_false)
    emit_1("false", dest)
    emit_label(done_label)
    return dest
  }

  // --- Inline expansion: filter(arr, fn) ---
  var expand_inline_filter = function(dest, arr_slot, fn_slot) {
    var result = alloc_slot()
    var len = alloc_slot()
    var i = alloc_slot()
    var check = alloc_slot()
    var item = alloc_slot()
    var null_s = alloc_slot()
    var one = alloc_slot()
    var f = alloc_slot()
    var val = alloc_slot()
    var loop_label = gen_label("filter_loop")
    var skip_label = gen_label("filter_skip")
    var done_label = gen_label("filter_done")
    add_instr(["array", result, 0])
    emit_2("length", len, arr_slot)
    emit_2("int", i, 0)
    emit_2("int", one, 1)
    emit_1("null", null_s)
    emit_label(loop_label)
    emit_3("lt_int", check, i, len)
    emit_jump_cond("jump_false", check, done_label)
    emit_3("load_index", item, arr_slot, i)
    emit_3("frame", f, fn_slot, 2)
    emit_3("setarg", f, 0, null_s)
    emit_3("setarg", f, 1, item)
    emit_3("setarg", f, 2, i)
    emit_2("invoke", f, val)
    emit_jump_cond("jump_false", val, skip_label)
    emit_2("push", result, item)
    emit_label(skip_label)
    emit_3("add", i, i, one)
    emit_jump(loop_label)
    emit_label(done_label)
    emit_2("move", dest, result)
    return dest
  }

  // --- Inline expansion: reduce(arr, fn[, initial[, reverse]]) ---
  var expand_inline_reduce = function(dest, args, nargs) {
    var arr_slot = args.arr
    var fn_slot = args.fn
    var init_slot = args.init
    var rev_slot = args.rev
    var len = alloc_slot()
    var acc = alloc_slot()
    var i = alloc_slot()
    var check = alloc_slot()
    var zero = alloc_slot()
    var one = alloc_slot()
    var final_label = gen_label("reduce_final")
    var has_init = null
    var no_init_rev = null
    var init_rev = null
    var null_label = null
    var d1 = null
    var d2 = null
    var d3 = null
    var d4 = null
    var r = null
    emit_2("length", len, arr_slot)
    emit_2("int", zero, 0)
    emit_2("int", one, 1)
    r = {acc: acc, i: i, arr: arr_slot, fn: fn_slot, len: len}
    if (nargs == 2) {
      null_label = gen_label("reduce_null")
      d1 = gen_label("reduce_d1")
      emit_3("lt_int", check, zero, len)
      emit_jump_cond("jump_false", check, null_label)
      emit_3("load_index", acc, arr_slot, zero)
      emit_2("move", i, one)
      emit_reduce_loop(r, true, d1)
      emit_label(d1)
      emit_2("move", dest, acc)
      emit_jump(final_label)
      emit_label(null_label)
      emit_1("null", dest)
      emit_label(final_label)
    } else if (nargs == 3) {
      has_init = gen_label("reduce_has_init")
      null_label = gen_label("reduce_null")
      d1 = gen_label("reduce_d1")
      d2 = gen_label("reduce_d2")
      emit_2("is_null", check, init_slot)
      emit_jump_cond("jump_false", check, has_init)
      // No initial, forward
      emit_3("lt_int", check, zero, len)
      emit_jump_cond("jump_false", check, null_label)
      emit_3("load_index", acc, arr_slot, zero)
      emit_2("move", i, one)
      emit_reduce_loop(r, true, d1)
      emit_label(d1)
      emit_2("move", dest, acc)
      emit_jump(final_label)
      emit_label(null_label)
      emit_1("null", dest)
      emit_jump(final_label)
      // Has initial, forward
      emit_label(has_init)
      emit_2("move", acc, init_slot)
      emit_2("int", i, 0)
      emit_reduce_loop(r, true, d2)
      emit_label(d2)
      emit_2("move", dest, acc)
      emit_label(final_label)
    } else {
      // nargs == 4: full branching
      has_init = gen_label("reduce_has_init")
      no_init_rev = gen_label("reduce_no_init_rev")
      init_rev = gen_label("reduce_init_rev")
      null_label = gen_label("reduce_null")
      d1 = gen_label("reduce_d1")
      d2 = gen_label("reduce_d2")
      d3 = gen_label("reduce_d3")
      d4 = gen_label("reduce_d4")
      emit_2("is_null", check, init_slot)
      emit_jump_cond("jump_false", check, has_init)
      // No initial
      emit_3("lt_int", check, zero, len)
      emit_jump_cond("jump_false", check, null_label)
      emit_jump_cond("jump_true", rev_slot, no_init_rev)
      // No initial, forward
      emit_3("load_index", acc, arr_slot, zero)
      emit_2("move", i, one)
      emit_reduce_loop(r, true, d1)
      emit_label(d1)
      emit_2("move", dest, acc)
      emit_jump(final_label)
      // No initial, reverse
      emit_label(no_init_rev)
      emit_3("subtract", i, len, one)
      emit_3("load_index", acc, arr_slot, i)
      emit_3("subtract", i, i, one)
      emit_reduce_loop(r, false, d2)
      emit_label(d2)
      emit_2("move", dest, acc)
      emit_jump(final_label)
      emit_label(null_label)
      emit_1("null", dest)
      emit_jump(final_label)
      // Has initial
      emit_label(has_init)
      emit_jump_cond("jump_true", rev_slot, init_rev)
      // Has initial, forward
      emit_2("move", acc, init_slot)
      emit_2("int", i, 0)
      emit_reduce_loop(r, true, d3)
      emit_label(d3)
      emit_2("move", dest, acc)
      emit_jump(final_label)
      // Has initial, reverse
      emit_label(init_rev)
      emit_2("move", acc, init_slot)
      emit_3("subtract", i, len, one)
      emit_reduce_loop(r, false, d4)
      emit_label(d4)
      emit_2("move", dest, acc)
      emit_label(final_label)
    }
    return dest
  }

  // Forward declarations via var
  var gen_expr = null
  var gen_statement = null
  var gen_function = null

  // Emit an access instruction for an intrinsic name
  var emit_access_intrinsic = function(dest, name) {
    var lit = {kind: "name", name: name, make: "intrinsic"}
    add_instr(["access", dest, lit])
  }

  // Binary expression compilation
  var gen_binary = function(node, target) {
    var kind = node.kind
    var left = node.left
    var right = node.right
    var end_label = null
    var left_slot = 0
    var right_slot = 0
    var dest = 0
    var op = null

    if (kind == "&&") {
      end_label = gen_label("and_end")
      left_slot = gen_expr(left, -1)
      dest = alloc_slot()
      emit_2("move", dest, left_slot)
      emit_jump_cond("jump_false", dest, end_label)
      right_slot = gen_expr(right, -1)
      emit_2("move", dest, right_slot)
      emit_label(end_label)
      return dest
    }

    if (kind == "||") {
      end_label = gen_label("or_end")
      left_slot = gen_expr(left, -1)
      dest = alloc_slot()
      emit_2("move", dest, left_slot)
      emit_jump_cond("jump_true", dest, end_label)
      right_slot = gen_expr(right, -1)
      emit_2("move", dest, right_slot)
      emit_label(end_label)
      return dest
    }

    if (kind == "??") {
      end_label = gen_label("nullish_end")
      left_slot = gen_expr(left, -1)
      dest = alloc_slot()
      emit_2("move", dest, left_slot)
      emit_jump_cond("jump_not_null", dest, end_label)
      right_slot = gen_expr(right, -1)
      emit_2("move", dest, right_slot)
      emit_label(end_label)
      return dest
    }

    // Comma operator
    if (kind == ",") {
      gen_expr(left, -1)
      return gen_expr(right, -1)
    }

    // Standard binary ops
    left_slot = gen_expr(left, -1)
    right_slot = gen_expr(right, -1)
    // Use target slot for ops without multi-type dispatch (add has text+num paths)
    dest = (target >= 0 && kind != "+") ? target : alloc_slot()
    op = binop_map[kind]
    if (op == null) {
      op = "add"
    }
    _bp_ln = left
    _bp_rn = right
    emit_binop(op, dest, left_slot, right_slot)
    return dest
  }

  // Compound assignment helper
  // parent_vars is an array of saved states for parent chain lookup
  var parent_states = []

  var gen_compound_assign = function(node, op) {
    var left = node.left
    var right = node.right
    var left_kind = left.kind
    var name = null
    var level = 0
    var left_slot = 0
    var local = 0
    var _lv = 0
    var pstate = null
    var pslot = 0
    var right_slot = 0
    var dest = 0
    var obj = null
    var prop = null
    var obj_slot = 0
    var old_val = 0
    var idx_expr = null
    var idx_slot = 0

    if (left_kind == "name") {
      name = left.name
      level = left.level
      if (level == null) {
        level = -1
      }
      left_slot = alloc_slot()
      if (level == 0 || level == -1) {
        local = find_var(name)
        if (local >= 0) {
          emit_2("move", left_slot, local)
          level = 0
        }
      }
      if (level > 0) {
        _lv = level - 1
        pstate = parent_states[length(parent_states) - 1 - _lv]
        pslot = find_var_in_saved(pstate, name)
        emit_3("get", left_slot, pslot, level)
      } else if (level == -1) {
        emit_access_intrinsic(left_slot, name)
      }
      right_slot = gen_expr(right, -1)
      dest = alloc_slot()
      _bp_ln = null
      _bp_rn = right
      emit_binop(op, dest, left_slot, right_slot)
      if (level == 0) {
        local = find_var(name)
        if (local >= 0) {
          emit_2("move", local, dest)
        }
      } else if (level > 0) {
        _lv = level - 1
        pstate = parent_states[length(parent_states) - 1 - _lv]
        pslot = find_var_in_saved(pstate, name)
        emit_3("put", dest, pslot, level)
      }
      return dest
    } else if (left_kind == ".") {
      obj = left.left
      prop = left.right
      obj_slot = gen_expr(obj, -1)
      old_val = alloc_slot()
      emit_get_prop(old_val, obj_slot, prop)
      right_slot = gen_expr(right, -1)
      dest = alloc_slot()
      _bp_ln = null
      _bp_rn = right
      emit_binop(op, dest, old_val, right_slot)
      emit_set_prop(obj_slot, prop, dest)
      return dest
    } else if (left_kind == "[") {
      obj = left.left
      idx_expr = left.right
      obj_slot = gen_expr(obj, -1)
      idx_slot = gen_expr(idx_expr, -1)
      old_val = alloc_slot()
      emit_get_elem(old_val, obj_slot, idx_slot, left.access_kind)
      right_slot = gen_expr(right, -1)
      dest = alloc_slot()
      _bp_ln = null
      _bp_rn = right
      emit_binop(op, dest, old_val, right_slot)
      emit_set_elem(obj_slot, idx_slot, dest, left.access_kind)
      return dest
    }
    return -1
  }

  // Assignment compilation
  var gen_assign = function(node) {
    var kind = node.kind
    var left = node.left
    var right = node.right
    var cop = compound_map[kind]
    var arr_expr = null
    var arr_slot = 0
    var val_slot = 0
    var left_kind = null
    var name = null
    var level = 0
    var slot = 0
    var _lv = 0
    var pstate = null
    var pslot = 0
    var obj = null
    var prop = null
    var obj_slot = 0
    var idx_expr = null
    var idx_slot = 0
    var guard_t = 0
    var guard_err = null
    var guard_done = null

    if (cop != null) {
      return gen_compound_assign(node, cop)
    }

    // Push syntax: arr[] = val (guarded)
    if (node.push == true) {
      arr_expr = left.left
      arr_slot = gen_expr(arr_expr, -1)
      val_slot = gen_expr(right, -1)
      guard_t = alloc_slot()
      guard_err = gen_label("push_err")
      guard_done = gen_label("push_done")
      emit_2("is_array", guard_t, arr_slot)
      emit_jump_cond("jump_false", guard_t, guard_err)
      emit_2("push", arr_slot, val_slot)
      emit_jump(guard_done)
      emit_label(guard_err)
      emit_log_error("cannot push: target must be an array")
      emit_0("disrupt")
      emit_label(guard_done)
      return val_slot
    }

    left_kind = left.kind

    // For local name assignments, try to write directly to the var's slot
    if (left_kind == "name") {
      name = left.name
      level = left.level
      if (level == null) {
        level = -1
      }
      if (level == 0 || level == -1) {
        slot = find_var(name)
        if (slot >= 0) {
          val_slot = gen_expr(right, slot)
          if (val_slot != slot) {
            emit_2("move", slot, val_slot)
          }
          return val_slot
        }
        val_slot = gen_expr(right, -1)
      } else {
        val_slot = gen_expr(right, -1)
        if (level > 0) {
          _lv = level - 1
          pstate = parent_states[length(parent_states) - 1 - _lv]
          pslot = find_var_in_saved(pstate, name)
          emit_3("put", val_slot, pslot, level)
        }
      }
      return val_slot
    }

    val_slot = gen_expr(right, -1)
    if (left_kind == ".") {
      obj = left.left
      prop = left.right
      obj_slot = gen_expr(obj, -1)
      emit_set_prop(obj_slot, prop, val_slot)
    } else if (left_kind == "[") {
      obj = left.left
      idx_expr = left.right
      obj_slot = gen_expr(obj, -1)
      idx_slot = gen_expr(idx_expr, -1)
      emit_set_elem(obj_slot, idx_slot, val_slot, left.access_kind)
    }
    return val_slot
  }

  // Expression compilation
  gen_expr = function(expr, target) {
    var kind = null
    var slot = 0
    var val = null
    var list = null
    var nexpr = 0
    var expr_slots = null
    var _i = 0
    var arr_slot = 0
    var arr_instr = null
    var fmt_func_slot = 0
    var fmt = null
    var fmt_str_slot = 0
    var result_slot = 0
    var pattern = null
    var flags = null
    var name = null
    var level = 0
    var cached = 0
    var dest = 0
    var _lv = 0
    var pstate = null
    var parent_slot = 0
    var obj = null
    var prop = null
    var obj_slot = 0
    var idx = null
    var idx_slot = 0
    var callee = null
    var args_list = null
    var callee_kind = null
    var fname = null
    var mop = null
    var nargs = 0
    var a0 = 0
    var a1 = 0
    var a2 = 0
    var a3 = 0
    var d = 0
    var top = null
    var arg_slots = null
    var key_expr = null
    var key_slot = 0
    var func_slot = 0
    var operand_slot = 0
    var operand = null
    var postfix = false
    var arith_op = null
    var operand_kind = null
    var one_slot = 0
    var one_node = null
    var old_slot = 0
    var local = 0
    var new_slot = 0
    var pslot = 0
    var idx_expr = null
    var cond = null
    var then_expr = null
    var else_expr = null
    var else_label = null
    var end_label = null
    var cond_slot = 0
    var then_slot = 0
    var else_slot = 0
    var count = 0
    var elem_slots = null
    var instr = null
    var pair = null
    var key = null
    var val_slot = 0
    var key_kind = null
    var kname = null
    var func = null
    var func_id = 0
    var guard_t = 0
    var guard_err = null
    var guard_done = null

    if (expr == null) {
      return -1
    }
    set_pos(expr)
    kind = expr.kind
    if (kind == null) {
      return -1
    }

    // Literals
    if (kind == "number") {
      slot = target >= 0 ? target : alloc_slot()
      emit_const_num(slot, expr.number)
      return slot
    }
    if (kind == "text") {
      slot = target >= 0 ? target : alloc_slot()
      val = expr.value
      if (val == null) {
        val = ""
      }
      emit_const_str(slot, val)
      return slot
    }
    // Template literal
    if (kind == "text literal") {
      list = expr.list
      nexpr = list != null ? length(list) : 0
      expr_slots = []
      _i = 0
      while (_i < nexpr) {
        push(expr_slots, gen_expr(list[_i], -1))
        _i = _i + 1
      }
      // Create array from expression results
      arr_slot = alloc_slot()
      add_instr(["array", arr_slot, 0])
      _i = 0
      while (_i < nexpr) {
        emit_2("push", arr_slot, expr_slots[_i])
        _i = _i + 1
      }
      // Load format intrinsic
      fmt_func_slot = find_intrinsic("format")
      if (fmt_func_slot < 0) {
        fmt_func_slot = alloc_slot()
        emit_access_intrinsic(fmt_func_slot, "format")
      }
      // Load format string
      fmt = expr.value
      if (fmt == null) {
        fmt = ""
      }
      fmt_str_slot = alloc_slot()
      emit_const_str(fmt_str_slot, fmt)
      // Call format(fmt_str, array)
      result_slot = target >= 0 ? target : alloc_slot()
      emit_call(result_slot, fmt_func_slot, [fmt_str_slot, arr_slot])
      return result_slot
    }
    if (kind == "regexp") {
      slot = target >= 0 ? target : alloc_slot()
      pattern = expr.pattern
      if (pattern == null) {
        pattern = ""
      }
      flags = expr.flags
      if (flags == null) {
        flags = ""
      }
      add_instr(["regexp", slot, pattern, flags])
      return slot
    }
    if (kind == "true") {
      slot = target >= 0 ? target : alloc_slot()
      emit_const_bool(slot, true)
      return slot
    }
    if (kind == "false") {
      slot = target >= 0 ? target : alloc_slot()
      emit_const_bool(slot, false)
      return slot
    }
    if (kind == "null") {
      slot = target >= 0 ? target : alloc_slot()
      emit_const_null(slot)
      return slot
    }
    if (kind == "this") {
      return s_this_slot
    }

    // Variable reference
    if (kind == "name") {
      name = expr.name
      level = expr.level
      if (level == null) {
        level = -1
      }
      if (level == 0 || level == -1) {
        slot = find_var(name)
        if (slot >= 0) {
          return slot
        }
      } else if (level > 0) {
        _lv = level - 1
        pstate = parent_states[length(parent_states) - 1 - _lv]
        parent_slot = find_var_in_saved(pstate, name)
        dest = alloc_slot()
        emit_3("get", dest, parent_slot, level)
        return dest
      }
      // Unbound — check intrinsic cache
      cached = find_intrinsic(name)
      if (cached >= 0) {
        return cached
      }
      dest = alloc_slot()
      emit_access_intrinsic(dest, name)
      return dest
    }

    // Property access
    if (kind == ".") {
      obj = expr.left
      prop = expr.right
      obj_slot = gen_expr(obj, -1)
      slot = alloc_slot()
      emit_get_prop(slot, obj_slot, prop)
      return slot
    }

    // Element access
    if (kind == "[") {
      obj = expr.left
      idx = expr.right
      obj_slot = gen_expr(obj, -1)
      idx_slot = gen_expr(idx, -1)
      slot = alloc_slot()
      emit_get_elem(slot, obj_slot, idx_slot, expr.access_kind)
      return slot
    }

    // Function call
    if (kind == "(") {
      callee = expr.expression
      args_list = expr.list
      callee_kind = callee.kind

      // Functino: inline operator call
      if (callee_kind == "name" && callee.make == "functino") {
        fname = callee.name
        mop = functino_map[fname]
        nargs = args_list != null ? length(args_list) : 0

        if (fname == "~!") {
          a0 = gen_expr(args_list[0], -1)
          d = alloc_slot()
          emit_2(mop, d, a0)
          return d
        }
        if (fname == "[]!") {
          a0 = gen_expr(args_list[0], -1)
          a1 = gen_expr(args_list[1], -1)
          d = alloc_slot()
          emit_get_elem(d, a0, a1)
          return d
        }
        if ((fname == "=!" || fname == "!=!") && nargs == 3) {
          a0 = gen_expr(args_list[0], -1)
          a1 = gen_expr(args_list[1], -1)
          a2 = gen_expr(args_list[2], -1)
          d = alloc_slot()
          top = fname == "=!" ? "eq_tol" : "ne_tol"
          emit_4_full(top, [d, a0, a1, a2])
          return d
        }
        if (fname == "&&!") {
          a0 = gen_expr(args_list[0], -1)
          a1 = gen_expr(args_list[1], -1)
          d = alloc_slot()
          emit_3("and", d, a0, a1)
          return d
        }
        if (fname == "||!") {
          a0 = gen_expr(args_list[0], -1)
          a1 = gen_expr(args_list[1], -1)
          d = alloc_slot()
          emit_3("or", d, a0, a1)
          return d
        }
        // Standard 2-arg binary functino
        a0 = gen_expr(args_list[0], -1)
        a1 = gen_expr(args_list[1], -1)
        d = alloc_slot()
        _bp_ln = args_list[0]
        _bp_rn = args_list[1]
        emit_binop(mop, d, a0, a1)
        return d
      }

      // Tier 1 intrinsic inlining: emit direct opcodes instead of frame/invoke
      if (callee_kind == "name" && callee.intrinsic == true) {
        fname = callee.name
        nargs = args_list != null ? length(args_list) : 0
        // 1-arg type check intrinsics → direct opcode
        if (nargs == 1 && sensory_ops[fname] != null) {
            a0 = gen_expr(args_list[0], -1)
            d = alloc_slot()
            emit_2(sensory_ops[fname], d, a0)
            return d
        }
        // 2-arg push: push(arr, val) → guarded direct opcode
        if (nargs == 2 && fname == "push") {
          a0 = gen_expr(args_list[0], -1)
          a1 = gen_expr(args_list[1], -1)
          guard_t = alloc_slot()
          guard_err = gen_label("push_err")
          guard_done = gen_label("push_done")
          emit_2("is_array", guard_t, a0)
          emit_jump_cond("jump_false", guard_t, guard_err)
          emit_2("push", a0, a1)
          emit_jump(guard_done)
          emit_label(guard_err)
          emit_log_error("cannot push: target must be an array")
          emit_0("disrupt")
          emit_label(guard_done)
          return a1
        }
        // Callback intrinsics → inline mcode loops
        if (nargs == 2 && fname == "arrfor" && inline_arrfor) {
          a0 = gen_expr(args_list[0], -1)
          a1 = gen_expr(args_list[1], -1)
          d = alloc_slot()
          return expand_inline_arrfor(d, a0, a1)
        }
        if (nargs == 2 && fname == "every" && inline_every) {
          a0 = gen_expr(args_list[0], -1)
          a1 = gen_expr(args_list[1], -1)
          d = alloc_slot()
          return expand_inline_every(d, a0, a1)
        }
        if (nargs == 2 && fname == "some" && inline_some) {
          a0 = gen_expr(args_list[0], -1)
          a1 = gen_expr(args_list[1], -1)
          d = alloc_slot()
          return expand_inline_some(d, a0, a1)
        }
        if (nargs == 2 && fname == "filter" && inline_filter) {
          a0 = gen_expr(args_list[0], -1)
          a1 = gen_expr(args_list[1], -1)
          d = alloc_slot()
          return expand_inline_filter(d, a0, a1)
        }
        if (fname == "reduce" && nargs >= 2 && nargs <= 4 && inline_reduce) {
          a0 = gen_expr(args_list[0], -1)
          a1 = gen_expr(args_list[1], -1)
          a2 = nargs >= 3 ? gen_expr(args_list[2], -1) : -1
          a3 = nargs >= 4 ? gen_expr(args_list[3], -1) : -1
          d = alloc_slot()
          return expand_inline_reduce(d, {arr: a0, fn: a1, init: a2, rev: a3}, nargs)
        }
      }

      // Collect arg slots
      arg_slots = []
      _i = 0
      nargs = args_list != null ? length(args_list) : 0
      while (_i < nargs) {
        push(arg_slots, gen_expr(args_list[_i], -1))
        _i = _i + 1
      }
      dest = alloc_slot()
      if (callee_kind == ".") {
        obj = callee.left
        prop = callee.right
        obj_slot = gen_expr(obj, -1)
        emit_call_method(dest, obj_slot, prop, arg_slots)
      } else if (callee_kind == "[") {
        obj = callee.left
        key_expr = callee.right
        obj_slot = gen_expr(obj, -1)
        key_slot = gen_expr(key_expr, -1)
        emit_call_method_dyn(dest, obj_slot, key_slot, arg_slots)
      } else {
        func_slot = gen_expr(callee, -1)
        emit_call(dest, func_slot, arg_slots)
      }
      return dest
    }

    // Unary operators
    if (kind == "!") {
      operand_slot = gen_expr(expr.expression, -1)
      slot = alloc_slot()
      emit_2("not", slot, operand_slot)
      return slot
    }
    if (kind == "~") {
      operand_slot = gen_expr(expr.expression, -1)
      slot = alloc_slot()
      emit_2("bitnot", slot, operand_slot)
      return slot
    }
    if (kind == "-unary") {
      operand_slot = gen_expr(expr.expression, -1)
      slot = alloc_slot()
      emit_neg_decomposed(slot, operand_slot, expr.expression)
      return slot
    }
    if (kind == "+unary") {
      return gen_expr(expr.expression, -1)
    }

    // Increment/Decrement
    if (kind == "++" || kind == "--") {
      operand = expr.expression
      postfix = expr.postfix == true
      arith_op = kind == "++" ? "add" : "subtract"
      operand_kind = operand.kind
      one_slot = alloc_slot()
      emit_2("int", one_slot, 1)
      one_node = {kind: "number", number: 1}

      if (operand_kind == "name") {
        name = operand.name
        level = operand.level
        if (level == null) {
          level = -1
        }
        old_slot = alloc_slot()
        if (level == 0) {
          local = find_var(name)
          if (local >= 0) {
            emit_2("move", old_slot, local)
          }
        } else if (level > 0) {
          _lv = level - 1
          pstate = parent_states[length(parent_states) - 1 - _lv]
          pslot = find_var_in_saved(pstate, name)
          emit_3("get", old_slot, pslot, level)
        } else {
          emit_access_intrinsic(old_slot, name)
        }
        new_slot = alloc_slot()
        _bp_ln = null
        _bp_rn = one_node
        emit_binop(arith_op, new_slot, old_slot, one_slot)
        if (level == 0) {
          local = find_var(name)
          if (local >= 0) {
            emit_2("move", local, new_slot)
          }
        } else if (level > 0) {
          _lv = level - 1
          pstate = parent_states[length(parent_states) - 1 - _lv]
          pslot = find_var_in_saved(pstate, name)
          emit_3("put", new_slot, pslot, level)
        }
        return postfix ? old_slot : new_slot
      } else if (operand_kind == ".") {
        obj = operand.left
        prop = operand.right
        obj_slot = gen_expr(obj, -1)
        old_slot = alloc_slot()
        emit_get_prop(old_slot, obj_slot, prop)
        new_slot = alloc_slot()
        _bp_ln = null
        _bp_rn = one_node
        emit_binop(arith_op, new_slot, old_slot, one_slot)
        emit_set_prop(obj_slot, prop, new_slot)
        return postfix ? old_slot : new_slot
      } else if (operand_kind == "[") {
        obj = operand.left
        idx_expr = operand.right
        obj_slot = gen_expr(obj, -1)
        idx_slot = gen_expr(idx_expr, -1)
        old_slot = alloc_slot()
        emit_get_elem(old_slot, obj_slot, idx_slot, operand.access_kind)
        new_slot = alloc_slot()
        _bp_ln = null
        _bp_rn = one_node
        emit_binop(arith_op, new_slot, old_slot, one_slot)
        emit_set_elem(obj_slot, idx_slot, new_slot, operand.access_kind)
        return postfix ? old_slot : new_slot
      }
    }

    // Delete operator
    if (kind == "delete") {
      operand = expr.expression
      operand_kind = operand.kind
      slot = alloc_slot()
      if (operand_kind == ".") {
        obj = operand.left
        prop = operand.right
        obj_slot = gen_expr(obj, -1)
        push(s_instructions, ["delete", slot, obj_slot, prop])
      } else if (operand_kind == "[") {
        obj = operand.left
        idx = operand.right
        obj_slot = gen_expr(obj, -1)
        idx_slot = gen_expr(idx, -1)
        emit_3("delete", slot, obj_slot, idx_slot)
      } else {
        emit_const_bool(slot, true)
      }
      return slot
    }

    // Ternary
    if (kind == "then") {
      cond = expr.expression
      then_expr = expr.then
      else_expr = expr["else"]
      else_label = gen_label("tern_else")
      end_label = gen_label("tern_end")
      cond_slot = gen_expr(cond, -1)
      emit_jump_cond("jump_false", cond_slot, else_label)
      dest = alloc_slot()
      then_slot = gen_expr(then_expr, -1)
      emit_2("move", dest, then_slot)
      emit_jump(end_label)
      emit_label(else_label)
      else_slot = gen_expr(else_expr, -1)
      emit_2("move", dest, else_slot)
      emit_label(end_label)
      return dest
    }

    // Array literal
    if (kind == "array") {
      list = expr.list
      count = length(list)
      elem_slots = []
      _i = 0
      while (_i < count) {
        push(elem_slots, gen_expr(list[_i], -1))
        _i = _i + 1
      }
      dest = alloc_slot()
      add_instr(["array", dest, count])
      _i = 0
      while (_i < count) {
        emit_2("push", dest, elem_slots[_i])
        _i = _i + 1
      }
      return dest
    }

    // Object literal
    if (kind == "record") {
      list = expr.list
      dest = alloc_slot()
      push(s_instructions, ["record", dest, length(list)])
      _i = 0
      while (_i < length(list)) {
        pair = list[_i]
        key = pair.left
        val = pair.right
        val_slot = gen_expr(val, -1)
        key_kind = key.kind
        if (key_kind == "name") {
          emit_set_prop(dest, key.name, val_slot)
        } else if (key_kind == "text") {
          kname = key.value
          if (kname == null) {
            kname = ""
          }
          emit_set_prop(dest, kname, val_slot)
        } else {
          key_slot = gen_expr(key, -1)
          emit_set_elem(dest, key_slot, val_slot)
        }
        _i = _i + 1
      }
      return dest
    }

    // Function expression
    if (kind == "function") {
      func = gen_function(expr)
      func_id = s_func_counter
      s_func_counter = s_func_counter + 1
      push(s_functions, func)
      dest = alloc_slot()
      emit_2("function", dest, func_id)
      return dest
    }

    // Assignment operators
    if (kind == "assign" ||
        kind == "+=" || kind == "-=" ||
        kind == "*=" || kind == "/=" ||
        kind == "%=" || kind == "**=" ||
        kind == "&=" || kind == "|=" ||
        kind == "^=" || kind == "<<=" ||
        kind == ">>=" || kind == ">>>=" ||
        kind == "&&=" || kind == "||=" ||
        kind == "??=") {
      return gen_assign(expr)
    }

    // Binary operators (fallback)
    return gen_binary(expr, target)
  }

  // Statement compilation
  gen_statement = function(stmt) {
    var kind = null
    var left = null
    var right = null
    var name = null
    var local_slot = 0
    var arr_expr = null
    var arr_slot = 0
    var val_slot = 0
    var list = null
    var _i = 0
    var stmts = null
    var cond = null
    var then_stmts = null
    var else_stmts = null
    var else_label = null
    var end_label = null
    var cond_slot = 0
    var start_label = null
    var old_break = null
    var old_continue = null
    var cond_label = null
    var init = null
    var test = null
    var update = null
    var update_label = null
    var init_kind = null
    var test_slot = 0
    var expr = null
    var slot = 0
    var null_slot = 0
    var call_expr = null
    var callee = null
    var args_list = null
    var arg_slots = null
    var nargs = 0
    var callee_kind = null
    var obj_node = null
    var prop = null
    var obj_slot = 0
    var func_slot = 0
    var cases = null
    var switch_val = 0
    var default_label = null
    var case_labels = null
    var case_node = null
    var case_kind = null
    var case_label = null
    var case_expr = null
    var case_val = 0
    var cmp_slot = 0
    var case_stmts = null
    var _j = 0
    var func = null
    var func_id = 0
    var dest = 0
    var guard_t = 0
    var guard_err = null
    var guard_done = null
    var last_instr = null

    if (stmt == null) {
      return null
    }
    set_pos(stmt)
    kind = stmt.kind
    if (kind == null) {
      return null
    }

    if (kind == "var" || kind == "def") {
      left = stmt.left
      right = stmt.right
      name = left.name
      local_slot = find_var(name)
      // Pop: var val = arr[] (guarded)
      if (stmt.pop == true && right != null) {
        arr_expr = right.left
        arr_slot = gen_expr(arr_expr, -1)
        if (local_slot >= 0) {
          guard_t = alloc_slot()
          guard_err = gen_label("pop_err")
          guard_done = gen_label("pop_done")
          emit_2("is_array", guard_t, arr_slot)
          emit_jump_cond("jump_false", guard_t, guard_err)
          emit_2("pop", local_slot, arr_slot)
          emit_jump(guard_done)
          emit_label(guard_err)
          emit_log_error("cannot pop: target must be an array")
          emit_0("disrupt")
          emit_label(guard_done)
        }
        return null
      }
      if (right != null) {
        val_slot = gen_expr(right, local_slot)
        if (local_slot >= 0 && val_slot != local_slot) {
          emit_2("move", local_slot, val_slot)
        }
      } else if (local_slot >= 0) {
        emit_const_null(local_slot)
      }
      return null
    }

    if (kind == "var_list" || kind == "def_list") {
      list = stmt.list
      _i = 0
      while (_i < length(list)) {
        gen_statement(list[_i])
        _i = _i + 1
      }
      return null
    }

    if (kind == "block") {
      stmts = stmt.statements
      _i = 0
      while (_i < length(stmts)) {
        gen_statement(stmts[_i])
        _i = _i + 1
      }
      return null
    }

    if (kind == "if") {
      cond = stmt.expression
      then_stmts = stmt.then
      else_stmts = stmt["else"]
      if (else_stmts == null) {
        else_stmts = stmt.list
      }
      else_label = gen_label("if_else")
      end_label = gen_label("if_end")
      cond_slot = gen_expr(cond, -1)
      emit_jump_cond("jump_false", cond_slot, else_label)
      _i = 0
      while (_i < length(then_stmts)) {
        gen_statement(then_stmts[_i])
        _i = _i + 1
      }
      emit_jump(end_label)
      emit_label(else_label)
      if (else_stmts != null) {
        _i = 0
        while (_i < length(else_stmts)) {
          gen_statement(else_stmts[_i])
          _i = _i + 1
        }
      }
      emit_label(end_label)
      return null
    }

    if (kind == "label") {
      s_pending_label = stmt.name
      gen_statement(stmt.statement)
      s_pending_label = null
      return null
    }

    if (kind == "while") {
      cond = stmt.expression
      stmts = stmt.statements
      start_label = gen_label("while_start")
      end_label = gen_label("while_end")
      old_break = s_loop_break
      old_continue = s_loop_continue
      s_loop_break = end_label
      s_loop_continue = start_label
      if (s_pending_label != null) {
        s_label_map[s_pending_label] = {break_target: end_label, continue_target: start_label}
        s_pending_label = null
      }
      emit_label(start_label)
      cond_slot = gen_expr(cond, -1)
      emit_jump_cond("jump_false", cond_slot, end_label)
      _i = 0
      while (_i < length(stmts)) {
        gen_statement(stmts[_i])
        _i = _i + 1
      }
      emit_jump(start_label)
      emit_label(end_label)
      s_loop_break = old_break
      s_loop_continue = old_continue
      return null
    }

    if (kind == "do") {
      cond = stmt.expression
      stmts = stmt.statements
      start_label = gen_label("do_start")
      cond_label = gen_label("do_cond")
      end_label = gen_label("do_end")
      old_break = s_loop_break
      old_continue = s_loop_continue
      s_loop_break = end_label
      s_loop_continue = cond_label
      if (s_pending_label != null) {
        s_label_map[s_pending_label] = {break_target: end_label, continue_target: cond_label}
        s_pending_label = null
      }
      emit_label(start_label)
      _i = 0
      while (_i < length(stmts)) {
        gen_statement(stmts[_i])
        _i = _i + 1
      }
      emit_label(cond_label)
      cond_slot = gen_expr(cond, -1)
      emit_jump_cond("jump_true", cond_slot, start_label)
      emit_label(end_label)
      s_loop_break = old_break
      s_loop_continue = old_continue
      return null
    }

    if (kind == "for") {
      init = stmt.init
      test = stmt.test
      update = stmt.update
      stmts = stmt.statements
      start_label = gen_label("for_start")
      update_label = gen_label("for_update")
      end_label = gen_label("for_end")
      old_break = s_loop_break
      old_continue = s_loop_continue
      s_loop_break = end_label
      s_loop_continue = update_label
      if (s_pending_label != null) {
        s_label_map[s_pending_label] = {break_target: end_label, continue_target: update_label}
        s_pending_label = null
      }
      if (init != null) {
        init_kind = init.kind
        if (init_kind == "var" || init_kind == "def") {
          gen_statement(init)
        } else {
          gen_expr(init, -1)
        }
      }
      emit_label(start_label)
      if (test != null) {
        test_slot = gen_expr(test, -1)
        emit_jump_cond("jump_false", test_slot, end_label)
      }
      _i = 0
      while (_i < length(stmts)) {
        gen_statement(stmts[_i])
        _i = _i + 1
      }
      emit_label(update_label)
      if (update != null) {
        gen_expr(update, -1)
      }
      emit_jump(start_label)
      emit_label(end_label)
      s_loop_break = old_break
      s_loop_continue = old_continue
      return null
    }

    if (kind == "return") {
      expr = stmt.expression
      if (expr != null) {
        slot = gen_expr(expr, -1)
        // Mark tail calls: rename last invoke to tail_invoke
        if (stmt.tail == true && !s_has_disruption) {
          last_instr = s_instructions[length(s_instructions) - 1]
          if (is_array(last_instr) && last_instr[0] == "invoke") {
            last_instr[0] = "tail_invoke"
          }
        }
        emit_1("return", slot)
      } else {
        null_slot = alloc_slot()
        emit_1("null", null_slot)
        emit_1("return", null_slot)
      }
      return null
    }

    if (kind == "go") {
      call_expr = stmt.expression
      if (call_expr == null || call_expr.kind != "(") {
        return null
      }
      callee = call_expr.expression
      args_list = call_expr.list
      arg_slots = []
      _i = 0
      nargs = args_list != null ? length(args_list) : 0
      while (_i < nargs) {
        push(arg_slots, gen_expr(args_list[_i], -1))
        _i = _i + 1
      }
      callee_kind = callee.kind
      if (callee_kind == ".") {
        obj_node = callee.left
        prop = callee.right
        obj_slot = gen_expr(obj_node, -1)
        emit_go_call_method(obj_slot, prop, arg_slots)
      } else {
        func_slot = gen_expr(callee, -1)
        emit_go_call(func_slot, arg_slots)
      }
      return null
    }

    if (kind == "disrupt") {
      emit_0("disrupt")
      return null
    }

    if (kind == "break") {
      if (stmt.name != null && s_label_map[stmt.name] != null) {
        emit_jump(s_label_map[stmt.name].break_target)
      } else if (s_loop_break != null) {
        emit_jump(s_loop_break)
      }
      return null
    }

    if (kind == "continue") {
      if (stmt.name != null && s_label_map[stmt.name] != null) {
        emit_jump(s_label_map[stmt.name].continue_target)
      } else if (s_loop_continue != null) {
        emit_jump(s_loop_continue)
      }
      return null
    }

    if (kind == "switch") {
      expr = stmt.expression
      cases = stmt.cases
      switch_val = gen_expr(expr, -1)
      end_label = gen_label("switch_end")
      default_label = null
      old_break = s_loop_break
      s_loop_break = end_label
      // Phase 1: emit comparisons, collect labels
      case_labels = []
      _i = 0
      while (_i < length(cases)) {
        case_node = cases[_i]
        case_kind = case_node.kind
        if (case_kind == "default") {
          default_label = gen_label("switch_default")
          push(case_labels, default_label)
        } else {
          case_label = gen_label("switch_case")
          case_expr = case_node.expression
          case_val = gen_expr(case_expr, -1)
          cmp_slot = alloc_slot()
          _bp_ln = null
          _bp_rn = case_expr
          emit_binop("eq", cmp_slot, switch_val, case_val)
          emit_jump_cond("jump_true", cmp_slot, case_label)
          push(case_labels, case_label)
        }
        _i = _i + 1
      }
      if (default_label != null) {
        emit_jump(default_label)
      } else {
        emit_jump(end_label)
      }
      // Phase 2: emit case bodies
      _i = 0
      while (_i < length(cases)) {
        emit_label(case_labels[_i])
        case_stmts = cases[_i].statements
        _j = 0
        while (_j < length(case_stmts)) {
          gen_statement(case_stmts[_j])
          _j = _j + 1
        }
        _i = _i + 1
      }
      emit_label(end_label)
      s_loop_break = old_break
      return null
    }

    if (kind == "function") {
      name = stmt.name
      if (name != null) {
        func = gen_function(stmt)
        func_id = s_func_counter
        s_func_counter = s_func_counter + 1
        push(s_functions, func)
        local_slot = find_var(name)
        dest = alloc_slot()
        emit_2("function", dest, func_id)
        if (local_slot >= 0) {
          emit_2("move", local_slot, dest)
        }
      }
      return null
    }

    if (kind == "call") {
      gen_expr(stmt.expression, -1)
      return null
    }

    gen_expr(stmt, -1)
    return null
  }

  // Function compilation
  gen_function = function(func_node) {
    var saved = save_state()
    var is_arrow = func_node.arrow == true
    var fn_nr_node = func_node.function_nr
    var params = func_node.list
    var nr_params = 0
    var param_slot = 1
    var _i = 0
    var param = null
    var param_name = null
    var ps = 1
    var default_expr = null
    var end_label = null
    var default_slot = 0
    var hoisted = null
    var fn = null
    var fname = null
    var compiled = null
    var func_id = 0
    var local_slot = 0
    var dest = 0
    var stmts = null
    var body = null
    var null_slot = 0
    var disruption_start = 0
    var disrupt_clause = func_node.disruption
    var null_slot2 = null
    var fn_name = func_node.name
    var fn_scope = null
    var nr_cs = 0
    var result = null
    var saved_label = 0
    var saved_func = 0

    push(parent_states, saved)

    s_instructions = []
    s_vars = []
    s_intrinsic_cache = []
    s_loop_break = null
    s_loop_continue = null
    s_label_map = {}

    s_is_arrow = is_arrow
    s_has_disruption = disrupt_clause != null && is_array(disrupt_clause)

    s_function_nr = fn_nr_node != null ? fn_nr_node : 0

    // Parameters
    if (params == null) {
      params = func_node.parameters
    }
    nr_params = params != null ? length(params) : 0
    s_nr_args = nr_params
    s_this_slot = 0
    s_nr_close_slots = 0
    s_nr_local_slots = 0

    param_slot = 1
    _i = 0
    while (_i < nr_params) {
      param = params[_i]
      param_name = param.name
      if (param_name == null && is_text(param)) {
        param_name = param
      }
      if (param_name != null) {
        add_var(param_name, param_slot, true)
        param_slot = param_slot + 1
      }
      _i = _i + 1
    }

    s_next_temp_slot = 1 + s_nr_args
    s_max_slot = 1 + s_nr_args

    // Scan scope
    scan_scope()

    s_next_temp_slot = 1 + s_nr_args + s_nr_local_slots
    if (s_next_temp_slot > s_max_slot) {
      s_max_slot = s_next_temp_slot
    }

    // Default parameter initialization
    ps = 1
    _i = 0
    while (_i < nr_params) {
      param = params[_i]
      default_expr = param.expression
      if (default_expr != null) {
        end_label = gen_label("default_end")
        emit_jump_cond("jump_not_null", ps, end_label)
        default_slot = gen_expr(default_expr, -1)
        emit_2("move", ps, default_slot)
        emit_label(end_label)
      }
      ps = ps + 1
      _i = _i + 1
    }

    // Pre-load intrinsics
    load_intrinsics(func_node.intrinsics)

    // Compile hoisted function declarations
    hoisted = func_node.functions
    if (hoisted != null) {
      _i = 0
      while (_i < length(hoisted)) {
        fn = hoisted[_i]
        fname = fn.name
        if (fname != null) {
          compiled = gen_function(fn)
          func_id = s_func_counter
          s_func_counter = s_func_counter + 1
          push(s_functions, compiled)
          local_slot = find_var(fname)
          dest = alloc_slot()
          emit_2("function", dest, func_id)
          if (local_slot >= 0) {
            emit_2("move", local_slot, dest)
          }
        }
        _i = _i + 1
      }
    }

    // Compile body
    stmts = func_node.statements
    if (stmts == null) {
      body = func_node.body
      if (body != null) {
        stmts = body.statements
        if (stmts == null) {
          stmts = body
        }
      }
    }
    if (stmts != null && is_array(stmts)) {
      _i = 0
      while (_i < length(stmts)) {
        gen_statement(stmts[_i])
        _i = _i + 1
      }
    }

    // Implicit return null
    null_slot = alloc_slot()
    emit_1("null", null_slot)
    emit_1("return", null_slot)

    // Compile disruption clause
    if (disrupt_clause != null && is_array(disrupt_clause)) {
      emit_label(gen_label("disruption"))
      disruption_start = length(s_instructions)
      _i = 0
      while (_i < length(disrupt_clause)) {
        gen_statement(disrupt_clause[_i])
        _i = _i + 1
      }
      null_slot2 = alloc_slot()
      emit_1("null", null_slot2)
      emit_1("return", null_slot2)
    }

    // Build result
    if (fn_name == null) {
      fn_name = "<anonymous>"
    }

    fn_scope = find_scope_record(s_function_nr)
    if (fn_scope != null && fn_scope.nr_close_slots != null) {
      nr_cs = fn_scope.nr_close_slots
    }

    result = {
      name: fn_name,
      nr_args: nr_params,
      nr_close_slots: nr_cs,
      nr_slots: s_max_slot + 1,
      disruption_pc: disruption_start,
      instructions: s_instructions
    }

    if (s_filename != null) {
      result.filename = s_filename
    }

    // Propagate counters back
    saved_label = s_label_counter
    saved_func = s_func_counter

    // Pop parent state
    pop(parent_states)
    restore_state(saved)
    s_label_counter = saved_label
    s_func_counter = saved_func

    return result
  }

  // Program compilation (top-level entry)
  var gen_program = function(ast) {
    var filename = ast.filename
    var hoisted = ast.functions
    var _i = 0
    var fn = null
    var name = null
    var compiled = null
    var func_id = 0
    var local_slot = 0
    var dest = 0
    var statements = ast.statements
    var last_expr_slot = -1
    var stmt = null
    var kind = null
    var null_slot = 0
    var result = null

    s_filename = filename

    s_instructions = []
    s_data = {}
    s_functions = []
    s_vars = []
    s_intrinsic_cache = []
    s_scopes = ast.scopes
    s_this_slot = 0
    s_nr_args = 0
    s_nr_close_slots = 0
    s_nr_local_slots = 0
    s_next_temp_slot = 1
    s_max_slot = 1
    s_label_counter = 0
    s_func_counter = 0
    s_loop_break = null
    s_loop_continue = null
    s_label_map = {}
    s_function_nr = 0

    // Scan scope
    scan_scope()

    s_next_temp_slot = 1 + s_nr_local_slots
    if (s_next_temp_slot > s_max_slot) {
      s_max_slot = s_next_temp_slot
    }

    // Compile hoisted function declarations from ast.functions
    if (hoisted != null) {
      _i = 0
      while (_i < length(hoisted)) {
        fn = hoisted[_i]
        name = fn.name
        if (name != null) {
          compiled = gen_function(fn)
          func_id = s_func_counter
          s_func_counter = s_func_counter + 1
          push(s_functions, compiled)
          local_slot = find_var(name)
          dest = alloc_slot()
          emit_2("function", dest, func_id)
          if (local_slot >= 0) {
            emit_2("move", local_slot, dest)
          }
        }
        _i = _i + 1
      }
    }

    // Generate main code
    _i = 0
    while (_i < length(statements)) {
      stmt = statements[_i]
      kind = stmt.kind
      if (kind != null) {
        if (kind == "call") {
          last_expr_slot = gen_expr(stmt.expression, -1)
        } else if (kind == "return" || kind == "disrupt" ||
                   kind == "break" || kind == "continue") {
          gen_statement(stmt)
          last_expr_slot = -1
        } else if (kind == "var" || kind == "def" ||
                   kind == "var_list" || kind == "def_list" ||
                   kind == "function" || kind == "block" ||
                   kind == "if" || kind == "while" ||
                   kind == "do" || kind == "for" ||
                   kind == "switch") {
          gen_statement(stmt)
          last_expr_slot = -1
        } else {
          last_expr_slot = gen_expr(stmt, -1)
        }
      } else {
        gen_statement(stmt)
      }
      _i = _i + 1
    }

    if (last_expr_slot >= 0) {
      emit_1("return", last_expr_slot)
    } else {
      null_slot = alloc_slot()
      emit_1("null", null_slot)
      emit_1("return", null_slot)
    }

    result = {}
    result.name = filename != null ? filename : "<eval>"
    result.data = s_data
    result.functions = s_functions
    result.main = {
      nr_args: 0,
      nr_close_slots: 0,
      nr_slots: s_max_slot + 1,
      instructions: s_instructions
    }

    if (filename != null) {
      result.filename = filename
    }

    return result
  }

  return gen_program(ast)
}

return mcode
