correct apply check and add apply opcode
This commit is contained in:
8
mcode.cm
8
mcode.cm
@@ -2135,6 +2135,14 @@ var mcode = function(ast) {
|
||||
emit_label(guard_done)
|
||||
return a1
|
||||
}
|
||||
// apply(fn, arr) → direct opcode
|
||||
if (nargs == 2 && fname == "apply") {
|
||||
a0 = gen_expr(args_list[0], -1)
|
||||
a1 = gen_expr(args_list[1], -1)
|
||||
d = alloc_slot()
|
||||
emit_3("apply", d, a0, a1)
|
||||
return d
|
||||
}
|
||||
// Callback intrinsics → inline mcode loops
|
||||
if (fname == "arrfor" && nargs >= 2 && nargs <= 4 && inline_arrfor) {
|
||||
a0 = gen_expr(args_list[0], -1)
|
||||
|
||||
@@ -281,6 +281,7 @@ typedef enum MachOpcode {
|
||||
MACH_IS_UPPER, /* R(A) = is_upper(R(B)) */
|
||||
MACH_IS_WS, /* R(A) = is_whitespace(R(B)) */
|
||||
MACH_IS_ACTOR, /* R(A) = is_actor(R(B)) — has actor_sym property */
|
||||
MACH_APPLY, /* R(A) = apply(R(B), R(C)) — call fn with args from array (ABC) */
|
||||
|
||||
MACH_OP_COUNT
|
||||
} MachOpcode;
|
||||
@@ -405,6 +406,7 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
||||
[MACH_IS_UPPER] = "is_upper",
|
||||
[MACH_IS_WS] = "is_ws",
|
||||
[MACH_IS_ACTOR] = "is_actor",
|
||||
[MACH_APPLY] = "apply",
|
||||
};
|
||||
|
||||
/* ---- Compile-time constant pool entry ---- */
|
||||
@@ -1427,6 +1429,7 @@ vm_dispatch:
|
||||
DT(MACH_IS_DIGIT), DT(MACH_IS_LETTER),
|
||||
DT(MACH_IS_LOWER), DT(MACH_IS_UPPER),
|
||||
DT(MACH_IS_WS), DT(MACH_IS_ACTOR),
|
||||
DT(MACH_APPLY),
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
#undef DT
|
||||
@@ -2511,6 +2514,49 @@ vm_dispatch:
|
||||
frame->slots[a] = JS_NewBool(ctx, result);
|
||||
VM_BREAK();
|
||||
}
|
||||
VM_CASE(MACH_APPLY): {
|
||||
/* A=dest, B=fn, C=arr_or_val */
|
||||
JSValue fn_val = frame->slots[b];
|
||||
JSValue arg_val = frame->slots[c];
|
||||
if (!mist_is_function(fn_val)) {
|
||||
frame->slots[a] = fn_val;
|
||||
VM_BREAK();
|
||||
}
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||
JSValue ret;
|
||||
ctx->reg_current_frame = frame_ref.val;
|
||||
ctx->current_register_pc = pc > 0 ? pc - 1 : 0;
|
||||
ctx->vm_call_depth++;
|
||||
if (!mist_is_array(arg_val)) {
|
||||
/* Non-array: use as single argument */
|
||||
if (!mach_check_call_arity(ctx, fn, 1)) {
|
||||
ctx->vm_call_depth--;
|
||||
goto disrupt;
|
||||
}
|
||||
ret = JS_CallInternal(ctx, fn_val, JS_NULL, 1, &arg_val, 0);
|
||||
} else {
|
||||
JSArray *arr = JS_VALUE_GET_ARRAY(arg_val);
|
||||
int len = arr->len;
|
||||
if (!mach_check_call_arity(ctx, fn, len)) {
|
||||
ctx->vm_call_depth--;
|
||||
goto disrupt;
|
||||
}
|
||||
if (len == 0) {
|
||||
ret = JS_CallInternal(ctx, fn_val, JS_NULL, 0, NULL, 0);
|
||||
} else {
|
||||
JSValue *args = alloca(sizeof(JSValue) * len);
|
||||
for (int i = 0; i < len; i++)
|
||||
args[i] = arr->values[i];
|
||||
ret = JS_CallInternal(ctx, fn_val, JS_NULL, len, args, 0);
|
||||
}
|
||||
}
|
||||
ctx->vm_call_depth--;
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
ctx->reg_current_frame = JS_NULL;
|
||||
if (JS_IsException(ret)) goto disrupt;
|
||||
frame->slots[a] = ret;
|
||||
VM_BREAK();
|
||||
}
|
||||
/* Logical */
|
||||
VM_CASE(MACH_NOT): {
|
||||
int bval = JS_ToBool(ctx, frame->slots[b]);
|
||||
@@ -3168,6 +3214,7 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
|
||||
else if (strcmp(op, "is_upper") == 0) { AB2(MACH_IS_UPPER); }
|
||||
else if (strcmp(op, "is_ws") == 0) { AB2(MACH_IS_WS); }
|
||||
else if (strcmp(op, "is_actor") == 0) { AB2(MACH_IS_ACTOR); }
|
||||
else if (strcmp(op, "apply") == 0) { ABC3(MACH_APPLY); }
|
||||
/* Logical */
|
||||
else if (strcmp(op, "not") == 0) { AB2(MACH_NOT); }
|
||||
else if (strcmp(op, "and") == 0) { ABC3(MACH_AND); }
|
||||
|
||||
@@ -9432,15 +9432,23 @@ static JSValue js_cell_fn_apply (JSContext *ctx, JSValue this_val, int argc, JSV
|
||||
if (argc < 1) return JS_NULL;
|
||||
if (!JS_IsFunction (argv[0])) return argv[0];
|
||||
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION (argv[0]);
|
||||
|
||||
if (argc < 2)
|
||||
return JS_CallInternal (ctx, argv[0], JS_NULL, 0, NULL, 0);
|
||||
|
||||
if (!JS_IsArray (argv[1]))
|
||||
if (!JS_IsArray (argv[1])) {
|
||||
if (fn->length >= 0 && 1 > fn->length)
|
||||
return JS_RaiseDisrupt (ctx, "too many arguments for apply: expected %d, got 1", fn->length);
|
||||
return JS_CallInternal (ctx, argv[0], JS_NULL, 1, &argv[1], 0);
|
||||
}
|
||||
|
||||
JSArray *arr = JS_VALUE_GET_ARRAY (argv[1]);
|
||||
int len = arr->len;
|
||||
|
||||
if (fn->length >= 0 && len > fn->length)
|
||||
return JS_RaiseDisrupt (ctx, "too many arguments for apply: expected %d, got %d", fn->length, len);
|
||||
|
||||
if (len == 0)
|
||||
return JS_CallInternal (ctx, argv[0], JS_NULL, 0, NULL, 0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user