Phase 1: CEK is now the sole evaluator on JavaScript
- Override evalExpr/trampoline in CEK_FIXUPS_JS to route through cekRun (matching what Python already does) - Always include frames+cek in JS builds (not just when DOM present) - Remove CONTINUATIONS_JS extension (CEK handles shift/reset natively) - Remove Continuation constructor guard (always define it) - Add strict-mode type checking to CEK call path via head-name propagation through ArgFrame Standard build: 746/747 passing (1 dotimes macro edge case) Full build: 858/870 passing (6 continuation edge cases, 5 deftype issues, 1 dotimes — all pre-existing CEK behavioral differences) The tree-walk eval-expr, eval-list, eval-call, and all sf-*/ho-* forms in eval.sx are now dead code — never reached at runtime. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
// =========================================================================
|
||||
|
||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||
var SX_VERSION = "2026-03-15T12:23:29Z";
|
||||
var SX_VERSION = "2026-03-15T12:48:42Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -775,18 +775,15 @@
|
||||
// Platform: CEK module — explicit CEK machine
|
||||
// =========================================================================
|
||||
|
||||
// Continuation type (needed by CEK even without the tree-walk shift/reset extension)
|
||||
// Continuations must be callable as JS functions so isCallable/apply work.
|
||||
if (typeof Continuation === "undefined") {
|
||||
function Continuation(fn) {
|
||||
var c = function(value) { return fn(value !== undefined ? value : NIL); };
|
||||
c.fn = fn;
|
||||
c._continuation = true;
|
||||
c.call = function(value) { return fn(value !== undefined ? value : NIL); };
|
||||
return c;
|
||||
}
|
||||
// Continuation type — callable as JS function so isCallable/apply work.
|
||||
// CEK is the canonical evaluator; continuations are always available.
|
||||
function Continuation(fn) {
|
||||
var c = function(value) { return fn(value !== undefined ? value : NIL); };
|
||||
c.fn = fn;
|
||||
c._continuation = true;
|
||||
c.call = function(value) { return fn(value !== undefined ? value : NIL); };
|
||||
return c;
|
||||
}
|
||||
// Always register the predicate (may be overridden by continuations extension)
|
||||
PRIMITIVES["continuation?"] = function(x) { return x != null && x._continuation === true; };
|
||||
|
||||
// Standalone aliases for primitives used by cek.sx / frames.sx
|
||||
@@ -4275,7 +4272,7 @@ PRIMITIVES["make-define-frame"] = makeDefineFrame;
|
||||
PRIMITIVES["make-set-frame"] = makeSetFrame;
|
||||
|
||||
// make-arg-frame
|
||||
var makeArgFrame = function(f, evaled, remaining, env, rawArgs) { return {"type": "arg", "f": f, "evaled": evaled, "remaining": remaining, "env": env, "raw-args": rawArgs}; };
|
||||
var makeArgFrame = function(f, evaled, remaining, env, rawArgs, headName) { return {"type": "arg", "f": f, "evaled": evaled, "remaining": remaining, "env": env, "raw-args": rawArgs, "head-name": sxOr(headName, NIL)}; };
|
||||
PRIMITIVES["make-arg-frame"] = makeArgFrame;
|
||||
|
||||
// make-call-frame
|
||||
@@ -5057,7 +5054,10 @@ return forEach(function(d) { return cekCall(d, NIL); }, subDisposers); });
|
||||
PRIMITIVES["reactive-shift-deref"] = reactiveShiftDeref;
|
||||
|
||||
// step-eval-call
|
||||
var stepEvalCall = function(head, args, env, kont) { return makeCekState(head, env, kontPush(makeArgFrame(NIL, [], args, env, args), kont)); };
|
||||
var stepEvalCall = function(head, args, env, kont) { return (function() {
|
||||
var hname = (isSxTruthy((typeOf(head) == "symbol")) ? symbolName(head) : NIL);
|
||||
return makeCekState(head, env, kontPush(makeArgFrame(NIL, [], args, env, args, hname), kont));
|
||||
})(); };
|
||||
PRIMITIVES["step-eval-call"] = stepEvalCall;
|
||||
|
||||
// step-ho-map
|
||||
@@ -5222,9 +5222,10 @@ PRIMITIVES["step-ho-for-each"] = stepHoForEach;
|
||||
var remaining = get(frame, "remaining");
|
||||
var fenv = get(frame, "env");
|
||||
var rawArgs = get(frame, "raw-args");
|
||||
return (isSxTruthy(isNil(f)) ? (isSxTruthy(isEmpty(remaining)) ? continueWithCall(value, [], fenv, rawArgs, restK) : makeCekState(first(remaining), fenv, kontPush(makeArgFrame(value, [], rest(remaining), fenv, rawArgs), restK))) : (function() {
|
||||
var hname = get(frame, "head-name");
|
||||
return (isSxTruthy(isNil(f)) ? ((isSxTruthy((isSxTruthy(_strict_) && hname)) ? strictCheckArgs(hname, []) : NIL), (isSxTruthy(isEmpty(remaining)) ? continueWithCall(value, [], fenv, rawArgs, restK) : makeCekState(first(remaining), fenv, kontPush(makeArgFrame(value, [], rest(remaining), fenv, rawArgs, hname), restK)))) : (function() {
|
||||
var newEvaled = append(evaled, [value]);
|
||||
return (isSxTruthy(isEmpty(remaining)) ? continueWithCall(f, newEvaled, fenv, rawArgs, restK) : makeCekState(first(remaining), fenv, kontPush(makeArgFrame(f, newEvaled, rest(remaining), fenv, rawArgs), restK)));
|
||||
return (isSxTruthy(isEmpty(remaining)) ? ((isSxTruthy((isSxTruthy(_strict_) && hname)) ? strictCheckArgs(hname, newEvaled) : NIL), continueWithCall(f, newEvaled, fenv, rawArgs, restK)) : makeCekState(first(remaining), fenv, kontPush(makeArgFrame(f, newEvaled, rest(remaining), fenv, rawArgs, hname), restK)));
|
||||
})());
|
||||
})() : (isSxTruthy((ft == "dict")) ? (function() {
|
||||
var remaining = get(frame, "remaining");
|
||||
@@ -5848,6 +5849,20 @@ PRIMITIVES["resource"] = resource;
|
||||
return cekValue(state);
|
||||
};
|
||||
|
||||
// CEK is the canonical evaluator — override evalExpr to use it.
|
||||
// The tree-walk evaluator (evalExpr from eval.sx) is superseded.
|
||||
var _treeWalkEvalExpr = evalExpr;
|
||||
evalExpr = function(expr, env) {
|
||||
return cekRun(makeCekState(expr, env, []));
|
||||
};
|
||||
|
||||
// CEK never produces thunks — trampoline resolves any legacy thunks
|
||||
var _treeWalkTrampoline = trampoline;
|
||||
trampoline = function(val) {
|
||||
if (isThunk(val)) return evalExpr(thunkExpr(val), thunkEnv(val));
|
||||
return val;
|
||||
};
|
||||
|
||||
// Platform functions — defined in platform_js.py, not in .sx spec files.
|
||||
// Spec defines self-register via js-emit-define; these are the platform interface.
|
||||
PRIMITIVES["type-of"] = typeOf;
|
||||
|
||||
Reference in New Issue
Block a user