remove typed ops

This commit is contained in:
2026-02-21 02:52:17 -06:00
parent ac707bc399
commit fea76ecac5
12 changed files with 48748 additions and 121796 deletions

317
mcode.cm
View File

@@ -354,28 +354,29 @@ var mcode = function(ast) {
// 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)) {
var left_is_num = is_known_number(_bp_ln) || slot_is_num(_bp_left)
var left_is_text = is_known_text(_bp_ln) || slot_is_text(_bp_left)
var right_is_num = is_known_number(_bp_rn) || slot_is_num(_bp_right)
var right_is_text = is_known_text(_bp_rn) || slot_is_text(_bp_right)
// Both known text → concat
if (left_is_text && right_is_text) {
emit_3("concat", _bp_dest, _bp_left, _bp_right)
mark_slot(_bp_dest, "text")
return null
}
if (is_known_number(_bp_ln) && is_known_number(_bp_rn)) {
// Both known number → add
if (left_is_num && right_is_num) {
emit_3("add", _bp_dest, _bp_left, _bp_right)
mark_slot(_bp_dest, "num")
return null
}
// If either operand is a known number (AST or slot), concat is impossible
if (is_known_number(_bp_ln) || is_known_number(_bp_rn)
|| slot_is_num(_bp_left) || slot_is_num(_bp_right)) {
// One known number, other unknown → emit_numeric_binop (guard on unknown side)
if (left_is_num || right_is_num) {
emit_numeric_binop("add")
mark_slot(_bp_dest, "num")
return null
}
if (slot_is_text(_bp_left) && slot_is_text(_bp_right)) {
emit_3("concat", _bp_dest, _bp_left, _bp_right)
mark_slot(_bp_dest, "text")
return null
}
// Unknown types: emit full dispatch
var t0 = alloc_slot()
var t1 = alloc_slot()
@@ -410,8 +411,8 @@ var mcode = function(ast) {
// 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))
|| (slot_is_num(_bp_left) && slot_is_num(_bp_right))) {
if ((is_known_number(_bp_ln) || slot_is_num(_bp_left))
&& (is_known_number(_bp_rn) || slot_is_num(_bp_right))) {
emit_3(op_str, _bp_dest, _bp_left, _bp_right)
mark_slot(_bp_dest, "num")
return null
@@ -435,239 +436,21 @@ var mcode = function(ast) {
return null
}
// emit_eq_decomposed: identical -> int -> float -> text -> null -> bool -> mismatch(false)
// reads _bp_dest, _bp_left, _bp_right from closure
// emit_eq_decomposed: VM eq handles all types (int fast path, text memcmp, identity, mixed→false)
var emit_eq_decomposed = function() {
var dest = _bp_dest
var left = _bp_left
var right = _bp_right
var t0 = 0
var t1 = 0
// Known-num fast path
if ((is_known_number(_bp_ln) || slot_is_num(left))
&& (is_known_number(_bp_rn) || slot_is_num(right))) {
emit_3("eq_float", dest, left, right)
return null
}
// Known-text fast path
if ((is_known_text(_bp_ln) || slot_is_text(left))
&& (is_known_text(_bp_rn) || slot_is_text(right))) {
emit_3("eq_text", dest, left, right)
return null
}
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)
emit_3("eq", _bp_dest, _bp_left, _bp_right)
return null
}
// emit_ne_decomposed: identical -> int -> float -> text -> null -> bool -> mismatch(true)
// reads _bp_dest, _bp_left, _bp_right from closure
// emit_ne_decomposed: VM ne handles all types (int fast path, text memcmp, identity, mixed→true)
var emit_ne_decomposed = function() {
var dest = _bp_dest
var left = _bp_left
var right = _bp_right
var t0 = 0
var t1 = 0
// Known-num fast path
if ((is_known_number(_bp_ln) || slot_is_num(left))
&& (is_known_number(_bp_rn) || slot_is_num(right))) {
emit_3("ne_float", dest, left, right)
return null
}
// Known-text fast path
if ((is_known_text(_bp_ln) || slot_is_text(left))
&& (is_known_text(_bp_rn) || slot_is_text(right))) {
emit_3("ne_text", dest, left, right)
return null
}
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)
emit_3("ne", _bp_dest, _bp_left, _bp_right)
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(poly_op, 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_num = is_known_number(_bp_ln) || slot_is_num(left)
var left_is_text = is_known_text(_bp_ln) || slot_is_text(left)
var right_is_num = is_known_number(_bp_rn) || slot_is_num(right)
var right_is_text = is_known_text(_bp_rn) || slot_is_text(right)
var not_num = null
var done = null
var err = null
// Both known number
if (left_is_num && right_is_num) {
emit_3(poly_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_num = gen_label("rel_nn")
done = gen_label("rel_done")
err = gen_label("rel_err")
t0 = alloc_slot()
emit_2("is_num", t0, left)
emit_jump_cond("jump_false", t0, not_num)
t1 = alloc_slot()
emit_2("is_num", t1, right)
emit_jump_cond("jump_false", t1, not_num)
emit_3(poly_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)
// emit_relational: VM lt/le/gt/ge handle numbers and text, disrupt on mismatch
var emit_relational = function(op_str) {
emit_3(op_str, _bp_dest, _bp_left, _bp_right)
return null
}
@@ -696,14 +479,7 @@ var mcode = function(ast) {
// Central router: maps op string to decomposition helper
// Sets _bp_* closure vars then calls helper with reduced args
var relational_ops = {
lt: ["lt", "lt_int", "lt_float", "lt_text"],
le: ["le", "le_int", "le_float", "le_text"],
gt: ["gt", "gt_int", "gt_float", "gt_text"],
ge: ["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
@@ -714,18 +490,15 @@ var mcode = function(ast) {
emit_eq_decomposed()
} else if (op_str == "ne") {
emit_ne_decomposed()
} else if (op_str == "lt" || op_str == "le" || op_str == "gt" || op_str == "ge") {
emit_relational(op_str)
} else if (op_str == "subtract" || op_str == "multiply" ||
op_str == "divide" || op_str == "modulo" || op_str == "remainder" ||
op_str == "pow") {
emit_numeric_binop(op_str)
} else {
rel = relational_ops[op_str]
if (rel != null) {
emit_relational(rel[0], rel[1], rel[2], rel[3])
} else if (op_str == "subtract" || op_str == "multiply" ||
op_str == "divide" || op_str == "modulo" || op_str == "remainder" ||
op_str == "pow") {
emit_numeric_binop(op_str)
} else {
// Passthrough for bitwise, in, etc.
emit_3(op_str, dest, left, right)
}
// Passthrough for bitwise, in, etc.
emit_3(op_str, dest, left, right)
}
return null
}
@@ -1103,20 +876,20 @@ var mcode = function(ast) {
emit_1("null", null_s)
emit_label(loop_label)
if (forward) {
emit_3("lt_int", check, i, len)
emit_3("lt", check, i, len)
} else {
emit_3("ge_int", check, i, zero)
emit_3("ge", check, i, zero)
}
emit_jump_cond("jump_false", check, done_label)
emit_3("load_index", item, arr_slot, i)
emit_3("eq_int", arity_is_zero, fn_arity, zero)
emit_3("eq", arity_is_zero, fn_arity, zero)
emit_jump_cond("jump_false", arity_is_zero, call_one_label)
emit_3("frame", f, fn_slot, 0)
emit_3("setarg", f, 0, null_s)
emit_2("invoke", f, acc)
emit_jump(call_done_label)
emit_label(call_one_label)
emit_3("eq_int", arity_is_one, fn_arity, one)
emit_3("eq", arity_is_one, fn_arity, one)
emit_jump_cond("jump_false", arity_is_one, call_two_label)
emit_3("frame", f, fn_slot, 1)
emit_3("setarg", f, 0, null_s)
@@ -1164,17 +937,17 @@ var mcode = function(ast) {
emit_1("null", null_s)
emit_2("length", fn_arity, fn_slot)
emit_label(loop_label)
emit_3("lt_int", check, i, len)
emit_3("lt", check, i, len)
emit_jump_cond("jump_false", check, done_label)
emit_3("load_index", item, arr_slot, i)
emit_3("eq_int", arity_is_zero, fn_arity, zero)
emit_3("eq", arity_is_zero, fn_arity, zero)
emit_jump_cond("jump_false", arity_is_zero, call_one_label)
emit_3("frame", f, fn_slot, 0)
emit_3("setarg", f, 0, null_s)
emit_2("invoke", f, discard)
emit_jump(call_done_label)
emit_label(call_one_label)
emit_3("eq_int", arity_is_one, fn_arity, one)
emit_3("eq", arity_is_one, fn_arity, one)
emit_jump_cond("jump_false", arity_is_one, call_two_label)
emit_3("frame", f, fn_slot, 1)
emit_3("setarg", f, 0, null_s)
@@ -1221,10 +994,10 @@ var mcode = function(ast) {
emit_1("null", null_s)
emit_2("length", fn_arity, fn_slot)
emit_label(loop_label)
emit_3("lt_int", check, i, len)
emit_3("lt", check, i, len)
emit_jump_cond("jump_false", check, ret_true)
emit_3("load_index", item, arr_slot, i)
emit_3("eq_int", arity_is_zero, fn_arity, zero)
emit_3("eq", arity_is_zero, fn_arity, zero)
emit_jump_cond("jump_false", arity_is_zero, call_one_label)
emit_3("frame", f, fn_slot, 0)
emit_3("setarg", f, 0, null_s)
@@ -1274,10 +1047,10 @@ var mcode = function(ast) {
emit_1("null", null_s)
emit_2("length", fn_arity, fn_slot)
emit_label(loop_label)
emit_3("lt_int", check, i, len)
emit_3("lt", check, i, len)
emit_jump_cond("jump_false", check, ret_false)
emit_3("load_index", item, arr_slot, i)
emit_3("eq_int", arity_is_zero, fn_arity, zero)
emit_3("eq", arity_is_zero, fn_arity, zero)
emit_jump_cond("jump_false", arity_is_zero, call_one_label)
emit_3("frame", f, fn_slot, 0)
emit_3("setarg", f, 0, null_s)
@@ -1330,17 +1103,17 @@ var mcode = function(ast) {
emit_1("null", null_s)
emit_2("length", fn_arity, fn_slot)
emit_label(loop_label)
emit_3("lt_int", check, i, len)
emit_3("lt", check, i, len)
emit_jump_cond("jump_false", check, done_label)
emit_3("load_index", item, arr_slot, i)
emit_3("eq_int", arity_is_zero, fn_arity, zero)
emit_3("eq", arity_is_zero, fn_arity, zero)
emit_jump_cond("jump_false", arity_is_zero, call_one_label)
emit_3("frame", f, fn_slot, 0)
emit_3("setarg", f, 0, null_s)
emit_2("invoke", f, val)
emit_jump(call_done_label)
emit_label(call_one_label)
emit_3("eq_int", arity_is_one, fn_arity, one)
emit_3("eq", arity_is_one, fn_arity, one)
emit_jump_cond("jump_false", arity_is_one, call_two_label)
emit_3("frame", f, fn_slot, 1)
emit_3("setarg", f, 0, null_s)
@@ -1395,7 +1168,7 @@ var mcode = function(ast) {
if (nargs == 2) {
null_label = gen_label("reduce_null")
d1 = gen_label("reduce_d1")
emit_3("lt_int", check, zero, len)
emit_3("lt", check, zero, len)
emit_jump_cond("jump_false", check, null_label)
emit_3("load_index", acc, arr_slot, zero)
emit_2("move", i, one)
@@ -1414,7 +1187,7 @@ var mcode = function(ast) {
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_3("lt", check, zero, len)
emit_jump_cond("jump_false", check, null_label)
emit_3("load_index", acc, arr_slot, zero)
emit_2("move", i, one)
@@ -1446,7 +1219,7 @@ var mcode = function(ast) {
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_3("lt", check, zero, len)
emit_jump_cond("jump_false", check, null_label)
emit_jump_cond("jump_true", rev_slot, no_init_rev)
// No initial, forward