Merge branch 'mach' into mcode2
This commit is contained in:
339
source/quickjs.c
339
source/quickjs.c
@@ -560,6 +560,9 @@ typedef enum MachOpcode {
|
||||
|
||||
MACH_THROW, /* disrupt — trigger disruption */
|
||||
|
||||
MACH_PUSH, /* push R(B) onto array R(A) */
|
||||
MACH_POP, /* R(A) = pop last element from array R(B) */
|
||||
|
||||
MACH_NOP,
|
||||
|
||||
MACH_OP_COUNT
|
||||
@@ -615,6 +618,8 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
||||
[MACH_NEWARRAY] = "newarray",
|
||||
[MACH_CLOSURE] = "closure",
|
||||
[MACH_THROW] = "throw",
|
||||
[MACH_PUSH] = "push",
|
||||
[MACH_POP] = "pop",
|
||||
[MACH_NOP] = "nop",
|
||||
};
|
||||
|
||||
@@ -29932,6 +29937,18 @@ static void ast_sem_check_assign_target (ASTSemState *st, ASTSemScope *scope, cJ
|
||||
} else {
|
||||
cJSON_AddNumberToObject (left, "level", -1);
|
||||
}
|
||||
} else if (strcmp (kind, ".") == 0 || strcmp (kind, "[") == 0 ||
|
||||
strcmp (kind, "?.") == 0 || strcmp (kind, "?.[") == 0) {
|
||||
/* Property access as assignment target: resolve the object expression */
|
||||
cJSON *obj_expr = cJSON_GetObjectItem (left, "expression");
|
||||
if (!obj_expr) obj_expr = cJSON_GetObjectItem (left, "left");
|
||||
ast_sem_check_expr (st, scope, obj_expr);
|
||||
/* Also resolve the index expression for computed access */
|
||||
cJSON *idx_expr = cJSON_GetObjectItem (left, "index");
|
||||
if (!idx_expr && strcmp (kind, "[") == 0)
|
||||
idx_expr = cJSON_GetObjectItem (left, "right");
|
||||
if (idx_expr && cJSON_IsObject (idx_expr))
|
||||
ast_sem_check_expr (st, scope, idx_expr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30024,7 +30041,9 @@ static void ast_sem_check_expr (ASTSemState *st, ASTSemScope *scope, cJSON *expr
|
||||
/* Unary ops */
|
||||
if (strcmp (kind, "!") == 0 || strcmp (kind, "~") == 0 ||
|
||||
strcmp (kind, "delete") == 0 || strcmp (kind, "neg") == 0 ||
|
||||
strcmp (kind, "pos") == 0 || strcmp (kind, "spread") == 0) {
|
||||
strcmp (kind, "pos") == 0 || strcmp (kind, "spread") == 0 ||
|
||||
strcmp (kind, "-unary") == 0 || strcmp (kind, "+unary") == 0 ||
|
||||
strcmp (kind, "unary_-") == 0) {
|
||||
ast_sem_check_expr (st, scope, cJSON_GetObjectItem (expr, "expression"));
|
||||
return;
|
||||
}
|
||||
@@ -30039,10 +30058,12 @@ static void ast_sem_check_expr (ASTSemState *st, ASTSemScope *scope, cJSON *expr
|
||||
}
|
||||
|
||||
/* Object literal */
|
||||
if (strcmp (kind, "object") == 0) {
|
||||
if (strcmp (kind, "object") == 0 || strcmp (kind, "record") == 0) {
|
||||
cJSON *prop;
|
||||
cJSON_ArrayForEach (prop, cJSON_GetObjectItem (expr, "list")) {
|
||||
ast_sem_check_expr (st, scope, cJSON_GetObjectItem (prop, "value"));
|
||||
cJSON *val = cJSON_GetObjectItem (prop, "value");
|
||||
if (!val) val = cJSON_GetObjectItem (prop, "right");
|
||||
ast_sem_check_expr (st, scope, val);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -31075,7 +31096,7 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
mach_free_reg_to(cs, save);
|
||||
return dest;
|
||||
}
|
||||
if (strcmp(kind, "unary_-") == 0 || (strcmp(kind, "-") == 0 && !cJSON_GetObjectItem(node, "left"))) {
|
||||
if (strcmp(kind, "unary_-") == 0 || strcmp(kind, "-unary") == 0 || (strcmp(kind, "-") == 0 && !cJSON_GetObjectItem(node, "left"))) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
cJSON *operand = cJSON_GetObjectItem(node, "expression");
|
||||
if (!operand) operand = cJSON_GetObjectItem(node, "right");
|
||||
@@ -31086,10 +31107,160 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Unary plus: identity for numbers */
|
||||
if (strcmp(kind, "+unary") == 0 || strcmp(kind, "pos") == 0) {
|
||||
cJSON *operand = cJSON_GetObjectItem(node, "expression");
|
||||
return mach_compile_expr(cs, operand, dest);
|
||||
}
|
||||
|
||||
/* Comma operator: compile left for side effects, return right */
|
||||
if (strcmp(kind, ",") == 0) {
|
||||
cJSON *left = cJSON_GetObjectItem(node, "left");
|
||||
cJSON *right = cJSON_GetObjectItem(node, "right");
|
||||
int save = cs->freereg;
|
||||
mach_compile_expr(cs, left, -1);
|
||||
mach_free_reg_to(cs, save);
|
||||
return mach_compile_expr(cs, right, dest);
|
||||
}
|
||||
|
||||
/* Increment/Decrement as expression */
|
||||
if (strcmp(kind, "++") == 0 || strcmp(kind, "--") == 0) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
MachOpcode inc_op = (kind[0] == '+') ? MACH_INC : MACH_DEC;
|
||||
cJSON *operand = cJSON_GetObjectItem(node, "expression");
|
||||
cJSON *postfix_node = cJSON_GetObjectItem(node, "postfix");
|
||||
int is_postfix = postfix_node && cJSON_IsTrue(postfix_node);
|
||||
|
||||
const char *op_kind = cJSON_GetStringValue(cJSON_GetObjectItem(operand, "kind"));
|
||||
if (op_kind && strcmp(op_kind, "name") == 0) {
|
||||
const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(operand, "name"));
|
||||
cJSON *level_node = cJSON_GetObjectItem(operand, "level");
|
||||
int level = level_node ? (int)cJSON_GetNumberValue(level_node) : -1;
|
||||
if (level == 0 && name) {
|
||||
int slot = mach_find_var(cs, name);
|
||||
if (slot >= 0) {
|
||||
if (is_postfix) {
|
||||
/* Return old value, then increment */
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, slot, 0));
|
||||
mach_emit(cs, MACH_ABC(inc_op, slot, slot, 0));
|
||||
} else {
|
||||
/* Increment, then return new value */
|
||||
mach_emit(cs, MACH_ABC(inc_op, slot, slot, 0));
|
||||
if (dest != slot)
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, slot, 0));
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Fallback: just compile operand */
|
||||
return mach_compile_expr(cs, operand, dest);
|
||||
}
|
||||
|
||||
/* Compound assignment operators */
|
||||
if (strcmp(kind, "+=") == 0 || strcmp(kind, "-=") == 0 ||
|
||||
strcmp(kind, "*=") == 0 || strcmp(kind, "/=") == 0 ||
|
||||
strcmp(kind, "%=") == 0 || strcmp(kind, "**=") == 0 ||
|
||||
strcmp(kind, "&=") == 0 || strcmp(kind, "|=") == 0 ||
|
||||
strcmp(kind, "^=") == 0 || strcmp(kind, "<<=") == 0 ||
|
||||
strcmp(kind, ">>=") == 0 || strcmp(kind, ">>>=") == 0) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
cJSON *left = cJSON_GetObjectItem(node, "left");
|
||||
cJSON *right = cJSON_GetObjectItem(node, "right");
|
||||
|
||||
/* Map compound op to binary op */
|
||||
MachOpcode binop;
|
||||
if (strcmp(kind, "+=") == 0) binop = MACH_ADD;
|
||||
else if (strcmp(kind, "-=") == 0) binop = MACH_SUB;
|
||||
else if (strcmp(kind, "*=") == 0) binop = MACH_MUL;
|
||||
else if (strcmp(kind, "/=") == 0) binop = MACH_DIV;
|
||||
else if (strcmp(kind, "%=") == 0) binop = MACH_MOD;
|
||||
else if (strcmp(kind, "**=") == 0) binop = MACH_POW;
|
||||
else if (strcmp(kind, "&=") == 0) binop = MACH_BAND;
|
||||
else if (strcmp(kind, "|=") == 0) binop = MACH_BOR;
|
||||
else if (strcmp(kind, "^=") == 0) binop = MACH_BXOR;
|
||||
else if (strcmp(kind, "<<=") == 0) binop = MACH_SHL;
|
||||
else if (strcmp(kind, ">>=") == 0) binop = MACH_SHR;
|
||||
else binop = MACH_USHR; /* >>>= */
|
||||
|
||||
const char *lk = cJSON_GetStringValue(cJSON_GetObjectItem(left, "kind"));
|
||||
if (lk && strcmp(lk, "name") == 0) {
|
||||
const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(left, "name"));
|
||||
cJSON *level_node = cJSON_GetObjectItem(left, "level");
|
||||
int level = level_node ? (int)cJSON_GetNumberValue(level_node) : -1;
|
||||
if (level == 0 && name) {
|
||||
int slot = mach_find_var(cs, name);
|
||||
if (slot >= 0) {
|
||||
int save = cs->freereg;
|
||||
int rr = mach_compile_expr(cs, right, -1);
|
||||
mach_emit(cs, MACH_ABC(binop, slot, slot, rr));
|
||||
mach_free_reg_to(cs, save);
|
||||
if (dest != slot)
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, slot, 0));
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Fallback: load null */
|
||||
mach_emit(cs, MACH_ABx(MACH_LOADNULL, dest, 0));
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* In operator */
|
||||
if (strcmp(kind, "in") == 0) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
cJSON *left = cJSON_GetObjectItem(node, "left");
|
||||
cJSON *right = cJSON_GetObjectItem(node, "right");
|
||||
int save = cs->freereg;
|
||||
int lr = mach_compile_expr(cs, left, -1);
|
||||
int rr = mach_compile_expr(cs, right, -1);
|
||||
/* Use MACH_ABC with a new opcode or use GETINDEX + check null.
|
||||
For now, emit a HAS instruction (MACH_GETINDEX) and check if result is non-null.
|
||||
Actually, we need a proper HAS check. Let's use a call to a runtime helper. */
|
||||
/* We'll emit GETFIELD/GETINDEX then JMPNULL to check existence.
|
||||
But "in" checks presence, not value. For string keys, use GETFIELD and check non-null.
|
||||
This is an approximation that works for most cases. */
|
||||
mach_emit(cs, MACH_ABC(MACH_GETINDEX, dest, rr, lr));
|
||||
/* Check if result is null — if null, property doesn't exist → false
|
||||
But this is wrong because a property CAN be set to null.
|
||||
We need a proper HASPROP opcode. For now let's use JMPNULL. */
|
||||
int jmpnull_pc = mach_current_pc(cs);
|
||||
mach_emit(cs, MACH_AsBx(MACH_JMPNULL, dest, 0));
|
||||
mach_emit(cs, MACH_ABx(MACH_LOADTRUE, dest, 0));
|
||||
int jmpend_pc = mach_current_pc(cs);
|
||||
mach_emit(cs, MACH_sJ(MACH_JMP, 0));
|
||||
/* Patch jmpnull to false */
|
||||
int offset = mach_current_pc(cs) - (jmpnull_pc + 1);
|
||||
cs->code[jmpnull_pc] = MACH_AsBx(MACH_JMPNULL, dest, (int16_t)offset);
|
||||
mach_emit(cs, MACH_ABx(MACH_LOADFALSE, dest, 0));
|
||||
/* Patch jmpend */
|
||||
offset = mach_current_pc(cs) - (jmpend_pc + 1);
|
||||
cs->code[jmpend_pc] = MACH_sJ(MACH_JMP, offset);
|
||||
mach_free_reg_to(cs, save);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Assignment */
|
||||
if (strcmp(kind, "assign") == 0) {
|
||||
cJSON *left = cJSON_GetObjectItem(node, "left");
|
||||
cJSON *right = cJSON_GetObjectItem(node, "right");
|
||||
|
||||
/* Push: arr[] = val */
|
||||
cJSON *push_node = cJSON_GetObjectItem(node, "push");
|
||||
if (push_node && cJSON_IsTrue(push_node)) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
int save = cs->freereg;
|
||||
cJSON *arr_expr = cJSON_GetObjectItem(left, "left");
|
||||
if (!arr_expr) arr_expr = cJSON_GetObjectItem(left, "expression");
|
||||
int arr_r = mach_compile_expr(cs, arr_expr, -1);
|
||||
int val_r = mach_compile_expr(cs, right, -1);
|
||||
mach_emit(cs, MACH_ABC(MACH_PUSH, arr_r, val_r, 0));
|
||||
if (dest >= 0)
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, val_r, 0));
|
||||
mach_free_reg_to(cs, save);
|
||||
return dest;
|
||||
}
|
||||
|
||||
const char *lk = cJSON_GetStringValue(cJSON_GetObjectItem(left, "kind"));
|
||||
|
||||
if (lk && strcmp(lk, "name") == 0) {
|
||||
@@ -31131,10 +31302,14 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
int save = cs->freereg;
|
||||
cJSON *obj_expr = cJSON_GetObjectItem(left, "expression");
|
||||
if (!obj_expr) obj_expr = cJSON_GetObjectItem(left, "left");
|
||||
cJSON *prop = cJSON_GetObjectItem(left, "name");
|
||||
if (!prop) prop = cJSON_GetObjectItem(left, "right");
|
||||
const char *prop_name = NULL;
|
||||
if (cJSON_IsString(prop)) prop_name = cJSON_GetStringValue(prop);
|
||||
else prop_name = cJSON_GetStringValue(cJSON_GetObjectItem(left, "value"));
|
||||
else if (prop) prop_name = cJSON_GetStringValue(cJSON_GetObjectItem(prop, "value"));
|
||||
if (!prop_name && prop) prop_name = cJSON_GetStringValue(cJSON_GetObjectItem(prop, "name"));
|
||||
if (!prop_name) prop_name = cJSON_GetStringValue(cJSON_GetObjectItem(left, "value"));
|
||||
|
||||
int obj_r = mach_compile_expr(cs, obj_expr, -1);
|
||||
int val_r = mach_compile_expr(cs, right, dest);
|
||||
@@ -31151,6 +31326,7 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
int save = cs->freereg;
|
||||
cJSON *obj_expr = cJSON_GetObjectItem(left, "expression");
|
||||
if (!obj_expr) obj_expr = cJSON_GetObjectItem(left, "left");
|
||||
cJSON *idx_expr = cJSON_GetObjectItem(left, "index");
|
||||
if (!idx_expr) idx_expr = cJSON_GetObjectItem(left, "right");
|
||||
|
||||
@@ -31173,10 +31349,14 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
int save = cs->freereg;
|
||||
cJSON *obj_expr = cJSON_GetObjectItem(node, "expression");
|
||||
if (!obj_expr) obj_expr = cJSON_GetObjectItem(node, "left");
|
||||
cJSON *prop = cJSON_GetObjectItem(node, "name");
|
||||
if (!prop) prop = cJSON_GetObjectItem(node, "right");
|
||||
const char *prop_name = NULL;
|
||||
if (cJSON_IsString(prop)) prop_name = cJSON_GetStringValue(prop);
|
||||
else prop_name = cJSON_GetStringValue(cJSON_GetObjectItem(node, "value"));
|
||||
else if (prop) prop_name = cJSON_GetStringValue(cJSON_GetObjectItem(prop, "value"));
|
||||
if (!prop_name && prop) prop_name = cJSON_GetStringValue(cJSON_GetObjectItem(prop, "name"));
|
||||
if (!prop_name) prop_name = cJSON_GetStringValue(cJSON_GetObjectItem(node, "value"));
|
||||
|
||||
int obj_r = mach_compile_expr(cs, obj_expr, -1);
|
||||
if (prop_name) {
|
||||
@@ -31192,6 +31372,7 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
int save = cs->freereg;
|
||||
cJSON *obj_expr = cJSON_GetObjectItem(node, "expression");
|
||||
if (!obj_expr) obj_expr = cJSON_GetObjectItem(node, "left");
|
||||
cJSON *idx_expr = cJSON_GetObjectItem(node, "index");
|
||||
if (!idx_expr) idx_expr = cJSON_GetObjectItem(node, "right");
|
||||
|
||||
@@ -31202,8 +31383,8 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Object literal: kind="object" */
|
||||
if (strcmp(kind, "object") == 0) {
|
||||
/* Object literal: kind="object" or "record" */
|
||||
if (strcmp(kind, "object") == 0 || strcmp(kind, "record") == 0) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
mach_emit(cs, MACH_ABC(MACH_NEWOBJECT, dest, 0, 0));
|
||||
cJSON *props = cJSON_GetObjectItem(node, "list");
|
||||
@@ -31212,11 +31393,13 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
cJSON *prop = cJSON_GetArrayItem(props, i);
|
||||
cJSON *key_node = cJSON_GetObjectItem(prop, "key");
|
||||
if (!key_node) key_node = cJSON_GetObjectItem(prop, "left");
|
||||
cJSON *val_node = cJSON_GetObjectItem(prop, "value");
|
||||
if (!val_node) val_node = cJSON_GetObjectItem(prop, "right");
|
||||
if (!val_node) val_node = cJSON_GetObjectItem(prop, "expression");
|
||||
const char *key = cJSON_GetStringValue(key_node);
|
||||
if (!key) key = cJSON_GetStringValue(cJSON_GetObjectItem(key_node, "value"));
|
||||
if (!key) key = cJSON_GetStringValue(cJSON_GetObjectItem(key_node, "name"));
|
||||
if (!key && key_node) key = cJSON_GetStringValue(cJSON_GetObjectItem(key_node, "value"));
|
||||
if (!key && key_node) key = cJSON_GetStringValue(cJSON_GetObjectItem(key_node, "name"));
|
||||
if (key && val_node) {
|
||||
int save = cs->freereg;
|
||||
int vr = mach_compile_expr(cs, val_node, -1);
|
||||
@@ -31237,7 +31420,7 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
|
||||
/* Reserve consecutive regs for elements starting at dest+1 */
|
||||
int save = cs->freereg;
|
||||
if (cs->freereg <= dest) cs->freereg = dest + 1;
|
||||
cs->freereg = dest + 1;
|
||||
for (int i = 0; i < count; i++) {
|
||||
int er = mach_reserve_reg(cs);
|
||||
cJSON *elem = cJSON_GetArrayItem(elems, i);
|
||||
@@ -31249,8 +31432,8 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Ternary: kind="?" */
|
||||
if (strcmp(kind, "?") == 0) {
|
||||
/* Ternary: kind="?" or "then" */
|
||||
if (strcmp(kind, "?") == 0 || strcmp(kind, "then") == 0) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
cJSON *cond = cJSON_GetObjectItem(node, "expression");
|
||||
if (!cond) cond = cJSON_GetObjectItem(node, "condition");
|
||||
@@ -31405,6 +31588,17 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
||||
slot = mach_reserve_reg(cs);
|
||||
mach_add_var(cs, name, slot, strcmp(kind, "def") == 0);
|
||||
}
|
||||
/* Pop: var x = arr[] */
|
||||
cJSON *pop_node = cJSON_GetObjectItem(stmt, "pop");
|
||||
if (pop_node && cJSON_IsTrue(pop_node) && right) {
|
||||
cJSON *arr_expr = cJSON_GetObjectItem(right, "left");
|
||||
if (!arr_expr) arr_expr = cJSON_GetObjectItem(right, "expression");
|
||||
int save = cs->freereg;
|
||||
int arr_r = mach_compile_expr(cs, arr_expr, -1);
|
||||
mach_emit(cs, MACH_ABC(MACH_POP, slot, arr_r, 0));
|
||||
mach_free_reg_to(cs, save);
|
||||
return;
|
||||
}
|
||||
if (right) {
|
||||
int r = mach_compile_expr(cs, right, slot);
|
||||
if (r != slot)
|
||||
@@ -31413,6 +31607,17 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* var_list: multiple declarations in one statement */
|
||||
if (strcmp(kind, "var_list") == 0) {
|
||||
cJSON *list = cJSON_GetObjectItem(stmt, "list");
|
||||
if (list && cJSON_IsArray(list)) {
|
||||
int count = cJSON_GetArraySize(list);
|
||||
for (int i = 0; i < count; i++)
|
||||
mach_compile_stmt(cs, cJSON_GetArrayItem(list, i));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Function declaration statement */
|
||||
if (strcmp(kind, "function") == 0) {
|
||||
const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(stmt, "name"));
|
||||
@@ -32045,6 +32250,39 @@ static JSValue reg_vm_binop(JSContext *ctx, int op, JSValue a, JSValue b) {
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
/* String comparisons */
|
||||
if (JS_IsText(a) && JS_IsText(b)) {
|
||||
int cmp = js_string_compare_value(ctx, a, b, FALSE);
|
||||
switch (op) {
|
||||
case MACH_EQ: return JS_NewBool(ctx, cmp == 0);
|
||||
case MACH_NEQ: return JS_NewBool(ctx, cmp != 0);
|
||||
case MACH_LT: return JS_NewBool(ctx, cmp < 0);
|
||||
case MACH_LE: return JS_NewBool(ctx, cmp <= 0);
|
||||
case MACH_GT: return JS_NewBool(ctx, cmp > 0);
|
||||
case MACH_GE: return JS_NewBool(ctx, cmp >= 0);
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
/* Null comparisons */
|
||||
if (JS_IsNull(a) && JS_IsNull(b)) {
|
||||
if (op == MACH_EQ || op == MACH_LE || op == MACH_GE)
|
||||
return JS_TRUE;
|
||||
return JS_FALSE;
|
||||
}
|
||||
/* Boolean comparisons */
|
||||
if (JS_IsBool(a) && JS_IsBool(b)) {
|
||||
int ba = JS_VALUE_GET_BOOL(a);
|
||||
int bb = JS_VALUE_GET_BOOL(b);
|
||||
switch (op) {
|
||||
case MACH_EQ: return JS_NewBool(ctx, ba == bb);
|
||||
case MACH_NEQ: return JS_NewBool(ctx, ba != bb);
|
||||
case MACH_LT: return JS_NewBool(ctx, ba < bb);
|
||||
case MACH_LE: return JS_NewBool(ctx, ba <= bb);
|
||||
case MACH_GT: return JS_NewBool(ctx, ba > bb);
|
||||
case MACH_GE: return JS_NewBool(ctx, ba >= bb);
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
/* Different types: EQ→false, NEQ→true, others→false */
|
||||
if (op == MACH_NEQ) return JS_NewBool(ctx, 1);
|
||||
return JS_NewBool(ctx, 0);
|
||||
@@ -32056,12 +32294,38 @@ static JSValue reg_vm_binop(JSContext *ctx, int op, JSValue a, JSValue b) {
|
||||
JS_ToFloat64(ctx, &da, a);
|
||||
JS_ToFloat64(ctx, &db, b);
|
||||
switch (op) {
|
||||
case MACH_ADD: return JS_NewFloat64(ctx, da + db);
|
||||
case MACH_SUB: return JS_NewFloat64(ctx, da - db);
|
||||
case MACH_MUL: return JS_NewFloat64(ctx, da * db);
|
||||
case MACH_DIV: return JS_NewFloat64(ctx, da / db);
|
||||
case MACH_MOD: return JS_NewFloat64(ctx, fmod(da, db));
|
||||
case MACH_POW: return JS_NewFloat64(ctx, pow(da, db));
|
||||
case MACH_ADD: {
|
||||
double r = da + db;
|
||||
if (!isfinite(r)) return JS_NULL;
|
||||
return JS_NewFloat64(ctx, r);
|
||||
}
|
||||
case MACH_SUB: {
|
||||
double r = da - db;
|
||||
if (!isfinite(r)) return JS_NULL;
|
||||
return JS_NewFloat64(ctx, r);
|
||||
}
|
||||
case MACH_MUL: {
|
||||
double r = da * db;
|
||||
if (!isfinite(r)) return JS_NULL;
|
||||
return JS_NewFloat64(ctx, r);
|
||||
}
|
||||
case MACH_DIV: {
|
||||
if (db == 0.0) return JS_NULL;
|
||||
double r = da / db;
|
||||
if (!isfinite(r)) return JS_NULL;
|
||||
return JS_NewFloat64(ctx, r);
|
||||
}
|
||||
case MACH_MOD: {
|
||||
if (db == 0.0) return JS_NULL;
|
||||
double r = fmod(da, db);
|
||||
if (!isfinite(r)) return JS_NULL;
|
||||
return JS_NewFloat64(ctx, r);
|
||||
}
|
||||
case MACH_POW: {
|
||||
double r = pow(da, db);
|
||||
if (!isfinite(r) && isfinite(da) && isfinite(db)) return JS_NULL;
|
||||
return JS_NewFloat64(ctx, r);
|
||||
}
|
||||
case MACH_BAND: case MACH_BOR: case MACH_BXOR:
|
||||
case MACH_SHL: case MACH_SHR: case MACH_USHR: {
|
||||
int32_t ia = (int32_t)da;
|
||||
@@ -32571,11 +32835,12 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
JSValue arr = JS_NewArray(ctx);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(arr)) { goto disrupt; }
|
||||
/* Store array in dest immediately so GC can track it */
|
||||
frame->slots[a] = arr;
|
||||
for (int i = 0; i < count; i++) {
|
||||
JS_SetPropertyUint32(ctx, arr, i, frame->slots[a + 1 + i]);
|
||||
JS_SetPropertyUint32(ctx, frame->slots[a], i, frame->slots[a + 1 + i]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
}
|
||||
frame->slots[a] = arr;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -32592,6 +32857,30 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
break;
|
||||
}
|
||||
|
||||
case MACH_PUSH: {
|
||||
/* push R(B) onto array R(A) */
|
||||
JSValue arr = frame->slots[a];
|
||||
JSValue val = frame->slots[b];
|
||||
if (!JS_IsArray(arr)) goto disrupt;
|
||||
JSValue arr_ref = arr;
|
||||
int rc = JS_ArrayPush(ctx, &arr_ref, val);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (rc < 0) goto disrupt;
|
||||
if (arr_ref != arr) frame->slots[a] = arr_ref;
|
||||
break;
|
||||
}
|
||||
|
||||
case MACH_POP: {
|
||||
/* R(A) = pop last element from array R(B) */
|
||||
JSValue arr = frame->slots[b];
|
||||
if (!JS_IsArray(arr)) goto disrupt;
|
||||
JSValue val = JS_ArrayPop(ctx, arr);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(val)) goto disrupt;
|
||||
frame->slots[a] = val;
|
||||
break;
|
||||
}
|
||||
|
||||
case MACH_THROW:
|
||||
goto disrupt;
|
||||
|
||||
@@ -35771,6 +36060,14 @@ static void dump_register_code(JSContext *ctx, JSCodeRegister *code, int indent)
|
||||
printf("r%d, %d", a, b);
|
||||
break;
|
||||
|
||||
/* Push/Pop */
|
||||
case MACH_PUSH:
|
||||
printf("r%d, r%d", a, b);
|
||||
break;
|
||||
case MACH_POP:
|
||||
printf("r%d, r%d", a, b);
|
||||
break;
|
||||
|
||||
/* Closure */
|
||||
case MACH_CLOSURE: {
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
|
||||
3376
vm_suite.ce
Normal file
3376
vm_suite.ce
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user