suite passes now with mcode->mach lowering

This commit is contained in:
2026-02-12 09:40:24 -06:00
parent 68fb440502
commit b771b2b5d8
16 changed files with 346 additions and 48 deletions

122
mcode.cm
View File

@@ -43,6 +43,8 @@ var mcode = function(ast) {
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
@@ -71,6 +73,7 @@ var mcode = function(ast) {
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,
@@ -90,6 +93,7 @@ var mcode = function(ast) {
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
@@ -761,37 +765,114 @@ var mcode = function(ast) {
}
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()
var arr_instr = ["array", args_arr, argc]
_i = 0
while (_i < argc) {
push(arr_instr, args[_i])
_i = _i + 1
}
add_instr(arr_instr)
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 argc = length(args)
var frame_slot = alloc_slot()
emit_3("frame", frame_slot, method_slot, argc)
emit_3("setarg", frame_slot, 0, obj)
var arg_idx = 1
var _i = 0
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()
var arr_instr = ["array", args_arr, argc]
_i = 0
while (_i < argc) {
push(arr_instr, args[_i])
_i = _i + 1
}
add_instr(arr_instr)
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_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 argc = length(args)
var frame_slot = alloc_slot()
emit_3("frame", frame_slot, method_slot, argc)
emit_3("setarg", frame_slot, 0, obj)
var arg_idx = 1
var _i = 0
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) {
@@ -1813,6 +1894,13 @@ var mcode = function(ast) {
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
@@ -1822,6 +1910,10 @@ var mcode = function(ast) {
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)
@@ -1847,6 +1939,10 @@ var mcode = function(ast) {
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)) {
@@ -1874,6 +1970,10 @@ var mcode = function(ast) {
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") {
@@ -1949,14 +2049,18 @@ var mcode = function(ast) {
}
if (kind == "break") {
if (s_loop_break != null) {
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 (s_loop_continue != null) {
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
@@ -2082,6 +2186,7 @@ var mcode = function(ast) {
s_intrinsic_cache = []
s_loop_break = null
s_loop_continue = null
s_label_map = {}
s_is_arrow = is_arrow
@@ -2275,6 +2380,7 @@ var mcode = function(ast) {
s_func_counter = 0
s_loop_break = null
s_loop_continue = null
s_label_map = {}
s_function_nr = 0
// Scan scope