Frame-based dynamic scope: 870/870 — all tests passing
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 13m34s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 13m34s
provide/context and scope/emit!/emitted now use CEK continuation frames instead of an imperative global stack. Scope state is part of the continuation — captured by shift, restored by k invocation. New frame types: - ProvideFrame: holds name + value, consumed when body completes - ScopeAccFrame: holds name + mutable emitted list New CEK special forms: - context: walks kont for nearest ProvideFrame, returns value - emit!: walks kont for nearest ScopeAccFrame, appends to emitted - emitted: walks kont for nearest ScopeAccFrame, returns list Kont walkers: kont-find-provide, kont-find-scope-acc This fixes the last 2 test failures: - provide survives resume: scope captured by shift, restored by k - scope and emit across shift: accumulator preserved in continuation JS Full: 870/870 (100%) JS Standard: 747/747 (100%) Python: 679/679 (100%) 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-15T14:20:13Z";
|
||||
var SX_VERSION = "2026-03-15T14:39:41Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -913,6 +913,14 @@ PRIMITIVES["make-every-frame"] = makeEveryFrame;
|
||||
var makeScopeFrame = function(name, remaining, env) { return {"type": "scope", "name": name, "remaining": remaining, "env": env}; };
|
||||
PRIMITIVES["make-scope-frame"] = makeScopeFrame;
|
||||
|
||||
// make-provide-frame
|
||||
var makeProvideFrame = function(name, value, remaining, env) { return {"type": "provide", "name": name, "value": value, "remaining": remaining, "env": env}; };
|
||||
PRIMITIVES["make-provide-frame"] = makeProvideFrame;
|
||||
|
||||
// make-scope-acc-frame
|
||||
var makeScopeAccFrame = function(name, value, remaining, env) { return {"type": "scope-acc", "name": name, "value": sxOr(value, NIL), "emitted": [], "remaining": remaining, "env": env}; };
|
||||
PRIMITIVES["make-scope-acc-frame"] = makeScopeAccFrame;
|
||||
|
||||
// make-reset-frame
|
||||
var makeResetFrame = function(env) { return {"type": "reset", "env": env}; };
|
||||
PRIMITIVES["make-reset-frame"] = makeResetFrame;
|
||||
@@ -974,6 +982,20 @@ PRIMITIVES["scan"] = scan;
|
||||
return scan(kont, []); };
|
||||
PRIMITIVES["kont-capture-to-reset"] = kontCaptureToReset;
|
||||
|
||||
// kont-find-provide
|
||||
var kontFindProvide = function(kont, name) { return (isSxTruthy(isEmpty(kont)) ? NIL : (function() {
|
||||
var frame = first(kont);
|
||||
return (isSxTruthy((isSxTruthy((frameType(frame) == "provide")) && (get(frame, "name") == name))) ? frame : kontFindProvide(rest(kont), name));
|
||||
})()); };
|
||||
PRIMITIVES["kont-find-provide"] = kontFindProvide;
|
||||
|
||||
// kont-find-scope-acc
|
||||
var kontFindScopeAcc = function(kont, name) { return (isSxTruthy(isEmpty(kont)) ? NIL : (function() {
|
||||
var frame = first(kont);
|
||||
return (isSxTruthy((isSxTruthy((frameType(frame) == "scope-acc")) && (get(frame, "name") == name))) ? frame : kontFindScopeAcc(rest(kont), name));
|
||||
})()); };
|
||||
PRIMITIVES["kont-find-scope-acc"] = kontFindScopeAcc;
|
||||
|
||||
// has-reactive-reset-frame?
|
||||
var hasReactiveResetFrame_p = function(kont) { return (isSxTruthy(isEmpty(kont)) ? false : (isSxTruthy((frameType(first(kont)) == "reactive-reset")) ? true : hasReactiveResetFrame_p(rest(kont)))); };
|
||||
PRIMITIVES["has-reactive-reset-frame?"] = hasReactiveResetFrame_p;
|
||||
@@ -1403,10 +1425,10 @@ PRIMITIVES["step-eval"] = stepEval;
|
||||
var args = rest(expr);
|
||||
return (isSxTruthy(!isSxTruthy(sxOr((typeOf(head) == "symbol"), (typeOf(head) == "lambda"), (typeOf(head) == "list")))) ? (isSxTruthy(isEmpty(expr)) ? makeCekValue([], env, kont) : makeCekState(first(expr), env, kontPush(makeMapFrame(NIL, rest(expr), [], env), kont))) : (isSxTruthy((typeOf(head) == "symbol")) ? (function() {
|
||||
var name = symbolName(head);
|
||||
return (isSxTruthy((name == "if")) ? stepSfIf(args, env, kont) : (isSxTruthy((name == "when")) ? stepSfWhen(args, env, kont) : (isSxTruthy((name == "cond")) ? stepSfCond(args, env, kont) : (isSxTruthy((name == "case")) ? stepSfCase(args, env, kont) : (isSxTruthy((name == "and")) ? stepSfAnd(args, env, kont) : (isSxTruthy((name == "or")) ? stepSfOr(args, env, kont) : (isSxTruthy((name == "let")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "let*")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "lambda")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "fn")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "define")) ? stepSfDefine(args, env, kont) : (isSxTruthy((name == "defcomp")) ? makeCekValue(sfDefcomp(args, env), env, kont) : (isSxTruthy((name == "defisland")) ? makeCekValue(sfDefisland(args, env), env, kont) : (isSxTruthy((name == "defmacro")) ? makeCekValue(sfDefmacro(args, env), env, kont) : (isSxTruthy((name == "defstyle")) ? makeCekValue(sfDefstyle(args, env), env, kont) : (isSxTruthy((name == "defhandler")) ? makeCekValue(sfDefhandler(args, env), env, kont) : (isSxTruthy((name == "defpage")) ? makeCekValue(sfDefpage(args, env), env, kont) : (isSxTruthy((name == "defquery")) ? makeCekValue(sfDefquery(args, env), env, kont) : (isSxTruthy((name == "defaction")) ? makeCekValue(sfDefaction(args, env), env, kont) : (isSxTruthy((name == "deftype")) ? makeCekValue(sfDeftype(args, env), env, kont) : (isSxTruthy((name == "defeffect")) ? makeCekValue(sfDefeffect(args, env), env, kont) : (isSxTruthy((name == "begin")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "do")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "quote")) ? makeCekValue((isSxTruthy(isEmpty(args)) ? NIL : first(args)), env, kont) : (isSxTruthy((name == "quasiquote")) ? makeCekValue(qqExpand(first(args), env), env, kont) : (isSxTruthy((name == "->")) ? stepSfThreadFirst(args, env, kont) : (isSxTruthy((name == "set!")) ? stepSfSet(args, env, kont) : (isSxTruthy((name == "letrec")) ? makeCekValue(sfLetrec(args, env), env, kont) : (isSxTruthy((name == "reset")) ? stepSfReset(args, env, kont) : (isSxTruthy((name == "shift")) ? stepSfShift(args, env, kont) : (isSxTruthy((name == "deref")) ? stepSfDeref(args, env, kont) : (isSxTruthy((name == "scope")) ? stepSfScope(args, env, kont) : (isSxTruthy((name == "provide")) ? stepSfProvide(args, env, kont) : (isSxTruthy((name == "dynamic-wind")) ? makeCekValue(sfDynamicWind(args, env), env, kont) : (isSxTruthy((name == "map")) ? stepHoMap(args, env, kont) : (isSxTruthy((name == "map-indexed")) ? stepHoMapIndexed(args, env, kont) : (isSxTruthy((name == "filter")) ? stepHoFilter(args, env, kont) : (isSxTruthy((name == "reduce")) ? stepHoReduce(args, env, kont) : (isSxTruthy((name == "some")) ? stepHoSome(args, env, kont) : (isSxTruthy((name == "every?")) ? stepHoEvery(args, env, kont) : (isSxTruthy((name == "for-each")) ? stepHoForEach(args, env, kont) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? (function() {
|
||||
return (isSxTruthy((name == "if")) ? stepSfIf(args, env, kont) : (isSxTruthy((name == "when")) ? stepSfWhen(args, env, kont) : (isSxTruthy((name == "cond")) ? stepSfCond(args, env, kont) : (isSxTruthy((name == "case")) ? stepSfCase(args, env, kont) : (isSxTruthy((name == "and")) ? stepSfAnd(args, env, kont) : (isSxTruthy((name == "or")) ? stepSfOr(args, env, kont) : (isSxTruthy((name == "let")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "let*")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "lambda")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "fn")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "define")) ? stepSfDefine(args, env, kont) : (isSxTruthy((name == "defcomp")) ? makeCekValue(sfDefcomp(args, env), env, kont) : (isSxTruthy((name == "defisland")) ? makeCekValue(sfDefisland(args, env), env, kont) : (isSxTruthy((name == "defmacro")) ? makeCekValue(sfDefmacro(args, env), env, kont) : (isSxTruthy((name == "defstyle")) ? makeCekValue(sfDefstyle(args, env), env, kont) : (isSxTruthy((name == "defhandler")) ? makeCekValue(sfDefhandler(args, env), env, kont) : (isSxTruthy((name == "defpage")) ? makeCekValue(sfDefpage(args, env), env, kont) : (isSxTruthy((name == "defquery")) ? makeCekValue(sfDefquery(args, env), env, kont) : (isSxTruthy((name == "defaction")) ? makeCekValue(sfDefaction(args, env), env, kont) : (isSxTruthy((name == "deftype")) ? makeCekValue(sfDeftype(args, env), env, kont) : (isSxTruthy((name == "defeffect")) ? makeCekValue(sfDefeffect(args, env), env, kont) : (isSxTruthy((name == "begin")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "do")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "quote")) ? makeCekValue((isSxTruthy(isEmpty(args)) ? NIL : first(args)), env, kont) : (isSxTruthy((name == "quasiquote")) ? makeCekValue(qqExpand(first(args), env), env, kont) : (isSxTruthy((name == "->")) ? stepSfThreadFirst(args, env, kont) : (isSxTruthy((name == "set!")) ? stepSfSet(args, env, kont) : (isSxTruthy((name == "letrec")) ? makeCekValue(sfLetrec(args, env), env, kont) : (isSxTruthy((name == "reset")) ? stepSfReset(args, env, kont) : (isSxTruthy((name == "shift")) ? stepSfShift(args, env, kont) : (isSxTruthy((name == "deref")) ? stepSfDeref(args, env, kont) : (isSxTruthy((name == "scope")) ? stepSfScope(args, env, kont) : (isSxTruthy((name == "provide")) ? stepSfProvide(args, env, kont) : (isSxTruthy((name == "context")) ? stepSfContext(args, env, kont) : (isSxTruthy((name == "emit!")) ? stepSfEmit(args, env, kont) : (isSxTruthy((name == "emitted")) ? stepSfEmitted(args, env, kont) : (isSxTruthy((name == "dynamic-wind")) ? makeCekValue(sfDynamicWind(args, env), env, kont) : (isSxTruthy((name == "map")) ? stepHoMap(args, env, kont) : (isSxTruthy((name == "map-indexed")) ? stepHoMapIndexed(args, env, kont) : (isSxTruthy((name == "filter")) ? stepHoFilter(args, env, kont) : (isSxTruthy((name == "reduce")) ? stepHoReduce(args, env, kont) : (isSxTruthy((name == "some")) ? stepHoSome(args, env, kont) : (isSxTruthy((name == "every?")) ? stepHoEvery(args, env, kont) : (isSxTruthy((name == "for-each")) ? stepHoForEach(args, env, kont) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? (function() {
|
||||
var mac = envGet(env, name);
|
||||
return makeCekState(expandMacro(mac, args, env), env, kont);
|
||||
})() : (isSxTruthy((isSxTruthy(renderActiveP()) && isRenderExpr(expr))) ? makeCekValue(renderExpr(expr, env), env, kont) : stepEvalCall(head, args, env, kont))))))))))))))))))))))))))))))))))))))))))));
|
||||
})() : (isSxTruthy((isSxTruthy(renderActiveP()) && isRenderExpr(expr))) ? makeCekValue(renderExpr(expr, env), env, kont) : stepEvalCall(head, args, env, kont)))))))))))))))))))))))))))))))))))))))))))))));
|
||||
})() : stepEvalCall(head, args, env, kont)));
|
||||
})(); };
|
||||
PRIMITIVES["step-eval-list"] = stepEvalList;
|
||||
@@ -1492,13 +1514,51 @@ PRIMITIVES["step-sf-thread-first"] = stepSfThreadFirst;
|
||||
PRIMITIVES["step-sf-lambda"] = stepSfLambda;
|
||||
|
||||
// step-sf-scope
|
||||
var stepSfScope = function(args, env, kont) { return makeCekValue(sfScope(args, env), env, kont); };
|
||||
var stepSfScope = function(args, env, kont) { return (function() {
|
||||
var name = trampoline(evalExpr(first(args), env));
|
||||
var restArgs = slice(args, 1);
|
||||
var val = NIL;
|
||||
var body = NIL;
|
||||
(isSxTruthy((isSxTruthy((len(restArgs) >= 2)) && isSxTruthy((typeOf(first(restArgs)) == "keyword")) && (keywordName(first(restArgs)) == "value"))) ? ((val = trampoline(evalExpr(nth(restArgs, 1), env))), (body = slice(restArgs, 2))) : (body = restArgs));
|
||||
return (isSxTruthy(isEmpty(body)) ? makeCekValue(NIL, env, kont) : (isSxTruthy((len(body) == 1)) ? makeCekState(first(body), env, kontPush(makeScopeAccFrame(name, val, [], env), kont)) : makeCekState(first(body), env, kontPush(makeScopeAccFrame(name, val, rest(body), env), kont))));
|
||||
})(); };
|
||||
PRIMITIVES["step-sf-scope"] = stepSfScope;
|
||||
|
||||
// step-sf-provide
|
||||
var stepSfProvide = function(args, env, kont) { return makeCekValue(sfProvide(args, env), env, kont); };
|
||||
var stepSfProvide = function(args, env, kont) { return (function() {
|
||||
var name = trampoline(evalExpr(first(args), env));
|
||||
var val = trampoline(evalExpr(nth(args, 1), env));
|
||||
var body = slice(args, 2);
|
||||
return (isSxTruthy(isEmpty(body)) ? makeCekValue(NIL, env, kont) : (isSxTruthy((len(body) == 1)) ? makeCekState(first(body), env, kontPush(makeProvideFrame(name, val, [], env), kont)) : makeCekState(first(body), env, kontPush(makeProvideFrame(name, val, rest(body), env), kont))));
|
||||
})(); };
|
||||
PRIMITIVES["step-sf-provide"] = stepSfProvide;
|
||||
|
||||
// step-sf-context
|
||||
var stepSfContext = function(args, env, kont) { return (function() {
|
||||
var name = trampoline(evalExpr(first(args), env));
|
||||
var defaultVal = (isSxTruthy((len(args) >= 2)) ? trampoline(evalExpr(nth(args, 1), env)) : NIL);
|
||||
var frame = kontFindProvide(kont, name);
|
||||
return (isSxTruthy(frame) ? makeCekValue(get(frame, "value"), env, kont) : (isSxTruthy((len(args) >= 2)) ? makeCekValue(defaultVal, env, kont) : error((String("No provider for: ") + String(name)))));
|
||||
})(); };
|
||||
PRIMITIVES["step-sf-context"] = stepSfContext;
|
||||
|
||||
// step-sf-emit
|
||||
var stepSfEmit = function(args, env, kont) { return (function() {
|
||||
var name = trampoline(evalExpr(first(args), env));
|
||||
var val = trampoline(evalExpr(nth(args, 1), env));
|
||||
var frame = kontFindScopeAcc(kont, name);
|
||||
return (isSxTruthy(frame) ? (append_b(get(frame, "emitted"), val), makeCekValue(NIL, env, kont)) : error((String("No scope for emit!: ") + String(name))));
|
||||
})(); };
|
||||
PRIMITIVES["step-sf-emit"] = stepSfEmit;
|
||||
|
||||
// step-sf-emitted
|
||||
var stepSfEmitted = function(args, env, kont) { return (function() {
|
||||
var name = trampoline(evalExpr(first(args), env));
|
||||
var frame = kontFindScopeAcc(kont, name);
|
||||
return (isSxTruthy(frame) ? makeCekValue(get(frame, "emitted"), env, kont) : error((String("No scope for emitted: ") + String(name))));
|
||||
})(); };
|
||||
PRIMITIVES["step-sf-emitted"] = stepSfEmitted;
|
||||
|
||||
// step-sf-reset
|
||||
var stepSfReset = function(args, env, kont) { return makeCekState(first(args), env, kontPush(makeResetFrame(env), kont)); };
|
||||
PRIMITIVES["step-sf-reset"] = stepSfReset;
|
||||
@@ -1780,6 +1840,18 @@ PRIMITIVES["step-ho-for-each"] = stepHoForEach;
|
||||
var remaining = get(frame, "remaining");
|
||||
var fenv = get(frame, "env");
|
||||
return (isSxTruthy(isEmpty(remaining)) ? (scopePop(name), makeCekValue(value, fenv, restK)) : makeCekState(first(remaining), fenv, kontPush(makeScopeFrame(name, rest(remaining), fenv), restK)));
|
||||
})() : (isSxTruthy((ft == "provide")) ? (function() {
|
||||
var remaining = get(frame, "remaining");
|
||||
var fenv = get(frame, "env");
|
||||
return (isSxTruthy(isEmpty(remaining)) ? makeCekValue(value, fenv, restK) : makeCekState(first(remaining), fenv, kontPush(makeProvideFrame(get(frame, "name"), get(frame, "value"), rest(remaining), fenv), restK)));
|
||||
})() : (isSxTruthy((ft == "scope-acc")) ? (function() {
|
||||
var remaining = get(frame, "remaining");
|
||||
var fenv = get(frame, "env");
|
||||
return (isSxTruthy(isEmpty(remaining)) ? makeCekValue(value, fenv, restK) : makeCekState(first(remaining), fenv, kontPush((function() {
|
||||
var newFrame = makeScopeAccFrame(get(frame, "name"), get(frame, "value"), rest(remaining), fenv);
|
||||
newFrame["emitted"] = get(frame, "emitted");
|
||||
return newFrame;
|
||||
})(), restK)));
|
||||
})() : (isSxTruthy((ft == "map")) ? (function() {
|
||||
var f = get(frame, "f");
|
||||
var remaining = get(frame, "remaining");
|
||||
@@ -1824,7 +1896,7 @@ PRIMITIVES["step-ho-for-each"] = stepHoForEach;
|
||||
var remaining = get(frame, "remaining");
|
||||
var fenv = get(frame, "env");
|
||||
return (isSxTruthy(!isSxTruthy(value)) ? makeCekValue(false, fenv, restK) : (isSxTruthy(isEmpty(remaining)) ? makeCekValue(true, fenv, restK) : continueWithCall(f, [first(remaining)], fenv, [], kontPush(makeEveryFrame(f, rest(remaining), fenv), restK))));
|
||||
})() : error((String("Unknown frame type: ") + String(ft)))))))))))))))))))))))))));
|
||||
})() : error((String("Unknown frame type: ") + String(ft)))))))))))))))))))))))))))));
|
||||
})());
|
||||
})(); };
|
||||
PRIMITIVES["step-continue"] = stepContinue;
|
||||
|
||||
Reference in New Issue
Block a user