Bootstrap CEK as default evaluator on both JS and Python sides

SPEC_MODULES + SPEC_MODULE_ORDER for frames/cek in platform_js.py,
PLATFORM_CEK_JS + CEK_FIXUPS_JS constants, auto-inclusion in
run_js_sx.py, 70+ RENAMES in js.sx. Python: CEK always-include in
bootstrap_py.py, eval_expr/trampoline overridden to cek_run in
platform_py.py with _tree_walk_* preserved for test runners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 01:13:11 +00:00
parent f3a9f3ccc0
commit 90febbd91e
7 changed files with 2005 additions and 110 deletions

View File

@@ -14,7 +14,7 @@
// =========================================================================
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
var SX_VERSION = "2026-03-13T23:56:11Z";
var SX_VERSION = "2026-03-14T01:00:32Z";
function isNil(x) { return x === NIL || x === null || x === undefined; }
function isSxTruthy(x) { return x !== false && !isNil(x); }
@@ -2428,6 +2428,37 @@ return (isSxTruthy(testFn()) ? (function() {
return domListen(el, (isSxTruthy(isCheckbox) ? "change" : "input"), function(e) { return (isSxTruthy(isCheckbox) ? reset_b(sig, domGetProp(el, "checked")) : reset_b(sig, domGetProp(el, "value"))); });
})(); };
// *use-cek-reactive*
var _useCekReactive = true;
// enable-cek-reactive!
var enableCekReactive = function() { return (_useCekReactive = true); };
// cek-reactive-text
var cekReactiveText = function(expr, env) { return (function() {
var node = createTextNode("");
var updateFn = function(val) { return domSetTextContent(node, (String(val))); };
return (function() {
var initial = cekRun(makeCekState(expr, env, [makeReactiveResetFrame(env, updateFn, true)]));
domSetTextContent(node, (String(initial)));
return node;
})();
})(); };
// cek-reactive-attr
var cekReactiveAttr = function(el, attrName, expr, env) { return (function() {
var updateFn = function(val) { return (isSxTruthy(sxOr(isNil(val), (val == false))) ? domRemoveAttr(el, attrName) : (isSxTruthy((val == true)) ? domSetAttr(el, attrName, "") : domSetAttr(el, attrName, (String(val))))); };
(function() {
var existing = sxOr(domGetAttr(el, "data-sx-reactive-attrs"), "");
var updated = (isSxTruthy(isEmpty(existing)) ? attrName : (String(existing) + String(",") + String(attrName)));
return domSetAttr(el, "data-sx-reactive-attrs", updated);
})();
return (function() {
var initial = cekRun(makeCekState(expr, env, [makeReactiveResetFrame(env, updateFn, true)]));
return invoke(updateFn, initial);
})();
})(); };
// render-dom-portal
var renderDomPortal = function(args, env, ns) { return (function() {
var selector = trampoline(evalExpr(first(args), env));
@@ -3812,6 +3843,134 @@ callExpr.push(dictGet(kwargs, k)); } }
})(); }, keys(env)); };
// === Transpiled from frames (CEK continuation frames) ===
// make-cek-state
var makeCekState = function(control, env, kont) { return {"control": control, "env": env, "kont": kont, "phase": "eval", "value": NIL}; };
// make-cek-value
var makeCekValue = function(value, env, kont) { return {"control": NIL, "env": env, "kont": kont, "phase": "continue", "value": value}; };
// cek-terminal?
var cekTerminal_p = function(state) { return (isSxTruthy((get(state, "phase") == "continue")) && isEmpty(get(state, "kont"))); };
// cek-control
var cekControl = function(s) { return get(s, "control"); };
// cek-env
var cekEnv = function(s) { return get(s, "env"); };
// cek-kont
var cekKont = function(s) { return get(s, "kont"); };
// cek-phase
var cekPhase = function(s) { return get(s, "phase"); };
// cek-value
var cekValue = function(s) { return get(s, "value"); };
// make-if-frame
var makeIfFrame = function(thenExpr, elseExpr, env) { return {"type": "if", "then": thenExpr, "else": elseExpr, "env": env}; };
// make-when-frame
var makeWhenFrame = function(bodyExprs, env) { return {"type": "when", "body": bodyExprs, "env": env}; };
// make-begin-frame
var makeBeginFrame = function(remaining, env) { return {"type": "begin", "remaining": remaining, "env": env}; };
// make-let-frame
var makeLetFrame = function(name, remaining, body, local) { return {"type": "let", "name": name, "remaining": remaining, "body": body, "env": local}; };
// make-define-frame
var makeDefineFrame = function(name, env, hasEffects, effectList) { return {"type": "define", "name": name, "env": env, "has-effects": hasEffects, "effect-list": effectList}; };
// make-set-frame
var makeSetFrame = function(name, env) { return {"type": "set", "name": name, "env": env}; };
// 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}; };
// make-call-frame
var makeCallFrame = function(f, args, env) { return {"type": "call", "f": f, "args": args, "env": env}; };
// make-cond-frame
var makeCondFrame = function(remaining, env, scheme_p) { return {"type": "cond", "remaining": remaining, "env": env, "scheme": scheme_p}; };
// make-case-frame
var makeCaseFrame = function(matchVal, remaining, env) { return {"type": "case", "match-val": matchVal, "remaining": remaining, "env": env}; };
// make-thread-frame
var makeThreadFrame = function(remaining, env) { return {"type": "thread", "remaining": remaining, "env": env}; };
// make-map-frame
var makeMapFrame = function(f, remaining, results, env) { return {"type": "map", "f": f, "remaining": remaining, "results": results, "env": env}; };
// make-filter-frame
var makeFilterFrame = function(f, remaining, results, currentItem, env) { return {"type": "filter", "f": f, "remaining": remaining, "results": results, "current-item": currentItem, "env": env}; };
// make-reduce-frame
var makeReduceFrame = function(f, remaining, env) { return {"type": "reduce", "f": f, "remaining": remaining, "env": env}; };
// make-for-each-frame
var makeForEachFrame = function(f, remaining, env) { return {"type": "for-each", "f": f, "remaining": remaining, "env": env}; };
// make-scope-frame
var makeScopeFrame = function(name, remaining, env) { return {"type": "scope", "name": name, "remaining": remaining, "env": env}; };
// make-reset-frame
var makeResetFrame = function(env) { return {"type": "reset", "env": env}; };
// make-dict-frame
var makeDictFrame = function(remaining, results, env) { return {"type": "dict", "remaining": remaining, "results": results, "env": env}; };
// make-and-frame
var makeAndFrame = function(remaining, env) { return {"type": "and", "remaining": remaining, "env": env}; };
// make-or-frame
var makeOrFrame = function(remaining, env) { return {"type": "or", "remaining": remaining, "env": env}; };
// make-dynamic-wind-frame
var makeDynamicWindFrame = function(phase, bodyThunk, afterThunk, env) { return {"type": "dynamic-wind", "phase": phase, "body-thunk": bodyThunk, "after-thunk": afterThunk, "env": env}; };
// make-reactive-reset-frame
var makeReactiveResetFrame = function(env, updateFn, firstRender_p) { return {"type": "reactive-reset", "env": env, "update-fn": updateFn, "first-render": firstRender_p}; };
// make-deref-frame
var makeDerefFrame = function(env) { return {"type": "deref", "env": env}; };
// frame-type
var frameType = function(f) { return get(f, "type"); };
// kont-push
var kontPush = function(frame, kont) { return cons(frame, kont); };
// kont-top
var kontTop = function(kont) { return first(kont); };
// kont-pop
var kontPop = function(kont) { return rest(kont); };
// kont-empty?
var kontEmpty_p = function(kont) { return isEmpty(kont); };
// kont-capture-to-reset
var kontCaptureToReset = function(kont) { var scan = function(k, captured) { return (isSxTruthy(isEmpty(k)) ? error("shift without enclosing reset") : (function() {
var frame = first(k);
return (isSxTruthy(sxOr((frameType(frame) == "reset"), (frameType(frame) == "reactive-reset"))) ? [captured, rest(k)] : scan(rest(k), append(captured, [frame])));
})()); };
return scan(kont, []); };
// 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)))); };
// kont-capture-to-reactive-reset
var kontCaptureToReactiveReset = function(kont) { var scan = function(k, captured) { return (isSxTruthy(isEmpty(k)) ? error("reactive deref without enclosing reactive-reset") : (function() {
var frame = first(k);
return (isSxTruthy((frameType(frame) == "reactive-reset")) ? [captured, frame, rest(k)] : scan(rest(k), append(captured, [frame])));
})()); };
return scan(kont, []); };
// === Transpiled from page-helpers (pure data transformation helpers) ===
// special-form-category-map
@@ -4444,6 +4603,383 @@ return (function() {
})(); };
// === Transpiled from cek (explicit CEK machine evaluator) ===
// cek-run
var cekRun = function(state) { return (isSxTruthy(cekTerminal_p(state)) ? cekValue(state) : cekRun(cekStep(state))); };
// cek-step
var cekStep = function(state) { return (isSxTruthy((cekPhase(state) == "eval")) ? stepEval(state) : stepContinue(state)); };
// step-eval
var stepEval = function(state) { return (function() {
var expr = cekControl(state);
var env = cekEnv(state);
var kont = cekKont(state);
return (function() { var _m = typeOf(expr); if (_m == "number") return makeCekValue(expr, env, kont); if (_m == "string") return makeCekValue(expr, env, kont); if (_m == "boolean") return makeCekValue(expr, env, kont); if (_m == "nil") return makeCekValue(NIL, env, kont); if (_m == "symbol") return (function() {
var name = symbolName(expr);
return (function() {
var val = (isSxTruthy(envHas(env, name)) ? envGet(env, name) : (isSxTruthy(isPrimitive(name)) ? getPrimitive(name) : (isSxTruthy((name == "true")) ? true : (isSxTruthy((name == "false")) ? false : (isSxTruthy((name == "nil")) ? NIL : error((String("Undefined symbol: ") + String(name))))))));
return makeCekValue(val, env, kont);
})();
})(); if (_m == "keyword") return makeCekValue(keywordName(expr), env, kont); if (_m == "dict") return (function() {
var ks = keys(expr);
return (isSxTruthy(isEmpty(ks)) ? makeCekValue({}, env, kont) : (function() {
var firstKey = first(ks);
var remainingEntries = [];
{ var _c = rest(ks); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; remainingEntries.push([k, get(expr, k)]); } }
return makeCekState(get(expr, firstKey), env, kontPush(makeDictFrame(remainingEntries, [[firstKey]], env), kont));
})());
})(); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? makeCekValue([], env, kont) : stepEvalList(expr, env, kont)); return makeCekValue(expr, env, kont); })();
})(); };
// step-eval-list
var stepEvalList = function(expr, env, kont) { return (function() {
var head = first(expr);
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")) ? makeCekValue(hoMapIndexed(args, env), env, kont) : (isSxTruthy((name == "filter")) ? stepHoFilter(args, env, kont) : (isSxTruthy((name == "reduce")) ? stepHoReduce(args, env, kont) : (isSxTruthy((name == "some")) ? makeCekValue(hoSome(args, env), env, kont) : (isSxTruthy((name == "every?")) ? makeCekValue(hoEvery(args, env), 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))))))))))))))))))))))))))))))))))))))))))));
})() : stepEvalCall(head, args, env, kont)));
})(); };
// step-sf-if
var stepSfIf = function(args, env, kont) { return makeCekState(first(args), env, kontPush(makeIfFrame(nth(args, 1), (isSxTruthy((len(args) > 2)) ? nth(args, 2) : NIL), env), kont)); };
// step-sf-when
var stepSfWhen = function(args, env, kont) { return makeCekState(first(args), env, kontPush(makeWhenFrame(rest(args), env), kont)); };
// step-sf-begin
var stepSfBegin = function(args, env, kont) { return (isSxTruthy(isEmpty(args)) ? makeCekValue(NIL, env, kont) : (isSxTruthy((len(args) == 1)) ? makeCekState(first(args), env, kont) : makeCekState(first(args), env, kontPush(makeBeginFrame(rest(args), env), kont)))); };
// step-sf-let
var stepSfLet = function(args, env, kont) { return (isSxTruthy((typeOf(first(args)) == "symbol")) ? makeCekValue(sfNamedLet(args, env), env, kont) : (function() {
var bindings = first(args);
var body = rest(args);
var local = envExtend(env);
return (isSxTruthy(isEmpty(bindings)) ? stepSfBegin(body, local, kont) : (function() {
var firstBinding = (isSxTruthy((isSxTruthy((typeOf(first(bindings)) == "list")) && (len(first(bindings)) == 2))) ? first(bindings) : [first(bindings), nth(bindings, 1)]);
var restBindings = (isSxTruthy((isSxTruthy((typeOf(first(bindings)) == "list")) && (len(first(bindings)) == 2))) ? rest(bindings) : (function() {
var pairs = [];
reduce(function(acc, i) { return append_b(pairs, [nth(bindings, (i * 2)), nth(bindings, ((i * 2) + 1))]); }, NIL, range(1, (len(bindings) / 2)));
return pairs;
})());
return (function() {
var vname = (isSxTruthy((typeOf(first(firstBinding)) == "symbol")) ? symbolName(first(firstBinding)) : first(firstBinding));
return makeCekState(nth(firstBinding, 1), local, kontPush(makeLetFrame(vname, restBindings, body, local), kont));
})();
})());
})()); };
// step-sf-define
var stepSfDefine = function(args, env, kont) { return (function() {
var nameSym = first(args);
var hasEffects = (isSxTruthy((len(args) >= 4)) && isSxTruthy((typeOf(nth(args, 1)) == "keyword")) && (keywordName(nth(args, 1)) == "effects"));
var valIdx = (isSxTruthy((isSxTruthy((len(args) >= 4)) && isSxTruthy((typeOf(nth(args, 1)) == "keyword")) && (keywordName(nth(args, 1)) == "effects"))) ? 3 : 1);
var effectList = (isSxTruthy((isSxTruthy((len(args) >= 4)) && isSxTruthy((typeOf(nth(args, 1)) == "keyword")) && (keywordName(nth(args, 1)) == "effects"))) ? nth(args, 2) : NIL);
return makeCekState(nth(args, valIdx), env, kontPush(makeDefineFrame(symbolName(nameSym), env, hasEffects, effectList), kont));
})(); };
// step-sf-set!
var stepSfSet = function(args, env, kont) { return makeCekState(nth(args, 1), env, kontPush(makeSetFrame(symbolName(first(args)), env), kont)); };
// step-sf-and
var stepSfAnd = function(args, env, kont) { return (isSxTruthy(isEmpty(args)) ? makeCekValue(true, env, kont) : makeCekState(first(args), env, kontPush(makeAndFrame(rest(args), env), kont))); };
// step-sf-or
var stepSfOr = function(args, env, kont) { return (isSxTruthy(isEmpty(args)) ? makeCekValue(false, env, kont) : makeCekState(first(args), env, kontPush(makeOrFrame(rest(args), env), kont))); };
// step-sf-cond
var stepSfCond = function(args, env, kont) { return (function() {
var scheme_p = condScheme_p(args);
return (isSxTruthy(scheme_p) ? (isSxTruthy(isEmpty(args)) ? makeCekValue(NIL, env, kont) : (function() {
var clause = first(args);
var test = first(clause);
return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))), (isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")))) ? makeCekState(nth(clause, 1), env, kont) : makeCekState(test, env, kontPush(makeCondFrame(args, env, true), kont)));
})()) : (isSxTruthy((len(args) < 2)) ? makeCekValue(NIL, env, kont) : (function() {
var test = first(args);
return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")), (isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))))) ? makeCekState(nth(args, 1), env, kont) : makeCekState(test, env, kontPush(makeCondFrame(args, env, false), kont)));
})()));
})(); };
// step-sf-case
var stepSfCase = function(args, env, kont) { return makeCekState(first(args), env, kontPush(makeCaseFrame(NIL, rest(args), env), kont)); };
// step-sf-thread-first
var stepSfThreadFirst = function(args, env, kont) { return makeCekState(first(args), env, kontPush(makeThreadFrame(rest(args), env), kont)); };
// step-sf-lambda
var stepSfLambda = function(args, env, kont) { return makeCekValue(sfLambda(args, env), env, kont); };
// step-sf-scope
var stepSfScope = function(args, env, kont) { return makeCekValue(sfScope(args, env), env, kont); };
// step-sf-provide
var stepSfProvide = function(args, env, kont) { return makeCekValue(sfProvide(args, env), env, kont); };
// step-sf-reset
var stepSfReset = function(args, env, kont) { return makeCekState(first(args), env, kontPush(makeResetFrame(env), kont)); };
// step-sf-shift
var stepSfShift = function(args, env, kont) { return (function() {
var kName = symbolName(first(args));
var body = nth(args, 1);
var capturedResult = kontCaptureToReset(kont);
var captured = first(capturedResult);
var restKont = nth(capturedResult, 1);
return (function() {
var k = makeCekContinuation(captured, restKont);
return (function() {
var shiftEnv = envExtend(env);
envSet(shiftEnv, kName, k);
return makeCekState(body, shiftEnv, restKont);
})();
})();
})(); };
// step-sf-deref
var stepSfDeref = function(args, env, kont) { return makeCekState(first(args), env, kontPush(makeDerefFrame(env), kont)); };
// reactive-shift-deref
var reactiveShiftDeref = function(sig, env, kont) { return (function() {
var scanResult = kontCaptureToReactiveReset(kont);
var capturedFrames = first(scanResult);
var resetFrame = nth(scanResult, 1);
var remainingKont = nth(scanResult, 2);
var updateFn = get(resetFrame, "update-fn");
return (function() {
var subDisposers = [];
return (function() {
var subscriber = function() { { var _c = subDisposers; for (var _i = 0; _i < _c.length; _i++) { var d = _c[_i]; invoke(d); } }
subDisposers = [];
return (function() {
var newReset = makeReactiveResetFrame(env, updateFn, false);
var newKont = concat(capturedFrames, [newReset], remainingKont);
return withIslandScope(function(d) { return append_b(subDisposers, d); }, function() { return cekRun(makeCekValue(signalValue(sig), env, newKont)); });
})(); };
signalAddSub(sig, subscriber);
registerInScope(function() { signalRemoveSub(sig, subscriber);
return forEach(function(d) { return invoke(d); }, subDisposers); });
return (function() {
var initialKont = concat(capturedFrames, [resetFrame], remainingKont);
return makeCekValue(signalValue(sig), env, initialKont);
})();
})();
})();
})(); };
// step-eval-call
var stepEvalCall = function(head, args, env, kont) { return makeCekState(head, env, kontPush(makeArgFrame(NIL, [], args, env, args), kont)); };
// step-ho-map
var stepHoMap = function(args, env, kont) { return makeCekValue(hoMap(args, env), env, kont); };
// step-ho-filter
var stepHoFilter = function(args, env, kont) { return makeCekValue(hoFilter(args, env), env, kont); };
// step-ho-reduce
var stepHoReduce = function(args, env, kont) { return makeCekValue(hoReduce(args, env), env, kont); };
// step-ho-for-each
var stepHoForEach = function(args, env, kont) { return makeCekValue(hoForEach(args, env), env, kont); };
// step-continue
var stepContinue = function(state) { return (function() {
var value = cekValue(state);
var env = cekEnv(state);
var kont = cekKont(state);
return (isSxTruthy(kontEmpty_p(kont)) ? state : (function() {
var frame = kontTop(kont);
var restK = kontPop(kont);
var ft = frameType(frame);
return (isSxTruthy((ft == "if")) ? (isSxTruthy((isSxTruthy(value) && !isSxTruthy(isNil(value)))) ? makeCekState(get(frame, "then"), get(frame, "env"), restK) : (isSxTruthy(isNil(get(frame, "else"))) ? makeCekValue(NIL, env, restK) : makeCekState(get(frame, "else"), get(frame, "env"), restK))) : (isSxTruthy((ft == "when")) ? (isSxTruthy((isSxTruthy(value) && !isSxTruthy(isNil(value)))) ? (function() {
var body = get(frame, "body");
var fenv = get(frame, "env");
return (isSxTruthy(isEmpty(body)) ? makeCekValue(NIL, fenv, restK) : (isSxTruthy((len(body) == 1)) ? makeCekState(first(body), fenv, restK) : makeCekState(first(body), fenv, kontPush(makeBeginFrame(rest(body), fenv), restK))));
})() : makeCekValue(NIL, env, restK)) : (isSxTruthy((ft == "begin")) ? (function() {
var remaining = get(frame, "remaining");
var fenv = get(frame, "env");
return (isSxTruthy(isEmpty(remaining)) ? makeCekValue(value, fenv, restK) : (isSxTruthy((len(remaining) == 1)) ? makeCekState(first(remaining), fenv, restK) : makeCekState(first(remaining), fenv, kontPush(makeBeginFrame(rest(remaining), fenv), restK))));
})() : (isSxTruthy((ft == "let")) ? (function() {
var name = get(frame, "name");
var remaining = get(frame, "remaining");
var body = get(frame, "body");
var local = get(frame, "env");
envSet(local, name, value);
return (isSxTruthy(isEmpty(remaining)) ? stepSfBegin(body, local, restK) : (function() {
var nextBinding = first(remaining);
var vname = (isSxTruthy((typeOf(first(nextBinding)) == "symbol")) ? symbolName(first(nextBinding)) : first(nextBinding));
return makeCekState(nth(nextBinding, 1), local, kontPush(makeLetFrame(vname, rest(remaining), body, local), restK));
})());
})() : (isSxTruthy((ft == "define")) ? (function() {
var name = get(frame, "name");
var fenv = get(frame, "env");
var hasEffects = get(frame, "has-effects");
var effectList = get(frame, "effect-list");
if (isSxTruthy((isSxTruthy(isLambda(value)) && isNil(lambdaName(value))))) {
value.name = name;
}
envSet(fenv, name, value);
if (isSxTruthy(hasEffects)) {
(function() {
var effectNames = (isSxTruthy((typeOf(effectList) == "list")) ? map(function(e) { return (isSxTruthy((typeOf(e) == "symbol")) ? symbolName(e) : (String(e))); }, effectList) : [(String(effectList))]);
var effectAnns = (isSxTruthy(envHas(fenv, "*effect-annotations*")) ? envGet(fenv, "*effect-annotations*") : {});
effectAnns[name] = effectNames;
return envSet(fenv, "*effect-annotations*", effectAnns);
})();
}
return makeCekValue(value, fenv, restK);
})() : (isSxTruthy((ft == "set")) ? (function() {
var name = get(frame, "name");
var fenv = get(frame, "env");
envSet(fenv, name, value);
return makeCekValue(value, env, restK);
})() : (isSxTruthy((ft == "and")) ? (isSxTruthy(!isSxTruthy(value)) ? makeCekValue(value, env, restK) : (function() {
var remaining = get(frame, "remaining");
return (isSxTruthy(isEmpty(remaining)) ? makeCekValue(value, env, restK) : makeCekState(first(remaining), get(frame, "env"), (isSxTruthy((len(remaining) == 1)) ? restK : kontPush(makeAndFrame(rest(remaining), get(frame, "env")), restK))));
})()) : (isSxTruthy((ft == "or")) ? (isSxTruthy(value) ? makeCekValue(value, env, restK) : (function() {
var remaining = get(frame, "remaining");
return (isSxTruthy(isEmpty(remaining)) ? makeCekValue(false, env, restK) : makeCekState(first(remaining), get(frame, "env"), (isSxTruthy((len(remaining) == 1)) ? restK : kontPush(makeOrFrame(rest(remaining), get(frame, "env")), restK))));
})()) : (isSxTruthy((ft == "cond")) ? (function() {
var remaining = get(frame, "remaining");
var fenv = get(frame, "env");
var scheme_p = get(frame, "scheme");
return (isSxTruthy(scheme_p) ? (isSxTruthy(value) ? makeCekState(nth(first(remaining), 1), fenv, restK) : (function() {
var nextClauses = rest(remaining);
return (isSxTruthy(isEmpty(nextClauses)) ? makeCekValue(NIL, fenv, restK) : (function() {
var nextClause = first(nextClauses);
var nextTest = first(nextClause);
return (isSxTruthy(sxOr((isSxTruthy((typeOf(nextTest) == "symbol")) && sxOr((symbolName(nextTest) == "else"), (symbolName(nextTest) == ":else"))), (isSxTruthy((typeOf(nextTest) == "keyword")) && (keywordName(nextTest) == "else")))) ? makeCekState(nth(nextClause, 1), fenv, restK) : makeCekState(nextTest, fenv, kontPush(makeCondFrame(nextClauses, fenv, true), restK)));
})());
})()) : (isSxTruthy(value) ? makeCekState(nth(remaining, 1), fenv, restK) : (function() {
var next = slice(remaining, 2);
return (isSxTruthy((len(next) < 2)) ? makeCekValue(NIL, fenv, restK) : (function() {
var nextTest = first(next);
return (isSxTruthy(sxOr((isSxTruthy((typeOf(nextTest) == "keyword")) && (keywordName(nextTest) == "else")), (isSxTruthy((typeOf(nextTest) == "symbol")) && sxOr((symbolName(nextTest) == "else"), (symbolName(nextTest) == ":else"))))) ? makeCekState(nth(next, 1), fenv, restK) : makeCekState(nextTest, fenv, kontPush(makeCondFrame(next, fenv, false), restK)));
})());
})()));
})() : (isSxTruthy((ft == "case")) ? (function() {
var matchVal = get(frame, "match-val");
var remaining = get(frame, "remaining");
var fenv = get(frame, "env");
return (isSxTruthy(isNil(matchVal)) ? sfCaseStepLoop(value, remaining, fenv, restK) : sfCaseStepLoop(matchVal, remaining, fenv, restK));
})() : (isSxTruthy((ft == "thread")) ? (function() {
var remaining = get(frame, "remaining");
var fenv = get(frame, "env");
return (isSxTruthy(isEmpty(remaining)) ? makeCekValue(value, fenv, restK) : (function() {
var form = first(remaining);
var restForms = rest(remaining);
return (function() {
var result = (isSxTruthy((typeOf(form) == "list")) ? (function() {
var f = trampoline(evalExpr(first(form), fenv));
var rargs = map(function(a) { return trampoline(evalExpr(a, fenv)); }, rest(form));
var allArgs = cons(value, rargs);
return (isSxTruthy((isSxTruthy(isCallable(f)) && !isSxTruthy(isLambda(f)))) ? apply(f, allArgs) : (isSxTruthy(isLambda(f)) ? trampoline(callLambda(f, allArgs, fenv)) : error((String("-> form not callable: ") + String(inspect(f))))));
})() : (function() {
var f = trampoline(evalExpr(form, fenv));
return (isSxTruthy((isSxTruthy(isCallable(f)) && !isSxTruthy(isLambda(f)))) ? f(value) : (isSxTruthy(isLambda(f)) ? trampoline(callLambda(f, [value], fenv)) : error((String("-> form not callable: ") + String(inspect(f))))));
})());
return (isSxTruthy(isEmpty(restForms)) ? makeCekValue(result, fenv, restK) : makeCekValue(result, fenv, kontPush(makeThreadFrame(restForms, fenv), restK)));
})();
})());
})() : (isSxTruthy((ft == "arg")) ? (function() {
var f = get(frame, "f");
var evaled = get(frame, "evaled");
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 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)));
})());
})() : (isSxTruthy((ft == "dict")) ? (function() {
var remaining = get(frame, "remaining");
var results = get(frame, "results");
var fenv = get(frame, "env");
return (function() {
var lastResult = last(results);
var completed = append(slice(results, 0, (len(results) - 1)), [[first(lastResult), value]]);
return (isSxTruthy(isEmpty(remaining)) ? (function() {
var d = {};
{ var _c = completed; for (var _i = 0; _i < _c.length; _i++) { var pair = _c[_i]; d[first(pair)] = nth(pair, 1); } }
return makeCekValue(d, fenv, restK);
})() : (function() {
var nextEntry = first(remaining);
return makeCekState(nth(nextEntry, 1), fenv, kontPush(makeDictFrame(rest(remaining), append(completed, [[first(nextEntry)]]), fenv), restK));
})());
})();
})() : (isSxTruthy((ft == "reset")) ? makeCekValue(value, env, restK) : (isSxTruthy((ft == "deref")) ? (function() {
var val = value;
var fenv = get(frame, "env");
return (isSxTruthy(!isSxTruthy(isSignal(val))) ? makeCekValue(val, fenv, restK) : (isSxTruthy(hasReactiveResetFrame_p(restK)) ? reactiveShiftDeref(val, fenv, restK) : ((function() {
var ctx = sxContext("sx-reactive", NIL);
return (isSxTruthy(ctx) ? (function() {
var depList = get(ctx, "deps");
var notifyFn = get(ctx, "notify");
return (isSxTruthy(!isSxTruthy(contains(depList, val))) ? (append_b(depList, val), signalAddSub(val, notifyFn)) : NIL);
})() : NIL);
})(), makeCekValue(signalValue(val), fenv, restK))));
})() : (isSxTruthy((ft == "reactive-reset")) ? (function() {
var updateFn = get(frame, "update-fn");
var first_p = get(frame, "first-render");
if (isSxTruthy((isSxTruthy(updateFn) && !isSxTruthy(first_p)))) {
invoke(updateFn, value);
}
return makeCekValue(value, env, restK);
})() : (isSxTruthy((ft == "scope")) ? (function() {
var name = get(frame, "name");
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)));
})() : error((String("Unknown frame type: ") + String(ft))))))))))))))))))));
})());
})(); };
// continue-with-call
var continueWithCall = function(f, args, env, rawArgs, kont) { return (isSxTruthy(continuation_p(f)) ? (function() {
var arg = (isSxTruthy(isEmpty(args)) ? NIL : first(args));
var contData = continuationData(f);
return (function() {
var captured = get(contData, "captured");
var restK = get(contData, "rest-kont");
return makeCekValue(arg, env, concat(captured, restK));
})();
})() : (isSxTruthy((isSxTruthy(isCallable(f)) && isSxTruthy(!isSxTruthy(isLambda(f))) && isSxTruthy(!isSxTruthy(isComponent(f))) && !isSxTruthy(isIsland(f)))) ? makeCekValue(apply(f, args), env, kont) : (isSxTruthy(isLambda(f)) ? (function() {
var params = lambdaParams(f);
var local = envMerge(lambdaClosure(f), env);
return (isSxTruthy((len(args) > len(params))) ? error((String(sxOr(lambdaName(f), "lambda")) + String(" expects ") + String(len(params)) + String(" args, got ") + String(len(args)))) : (forEach(function(pair) { return envSet(local, first(pair), nth(pair, 1)); }, zip(params, args)), forEach(function(p) { return envSet(local, p, NIL); }, slice(params, len(args))), makeCekState(lambdaBody(f), local, kont)));
})() : (isSxTruthy(sxOr(isComponent(f), isIsland(f))) ? (function() {
var parsed = parseKeywordArgs(rawArgs, env);
var kwargs = first(parsed);
var children = nth(parsed, 1);
var local = envMerge(componentClosure(f), env);
{ var _c = componentParams(f); for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; envSet(local, p, sxOr(dictGet(kwargs, p), NIL)); } }
if (isSxTruthy(componentHasChildren(f))) {
envSet(local, "children", children);
}
return makeCekState(componentBody(f), local, kont);
})() : error((String("Not callable: ") + String(inspect(f)))))))); };
// sf-case-step-loop
var sfCaseStepLoop = function(matchVal, clauses, env, kont) { return (isSxTruthy((len(clauses) < 2)) ? makeCekValue(NIL, env, kont) : (function() {
var test = first(clauses);
var body = nth(clauses, 1);
return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")), (isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))))) ? makeCekState(body, env, kont) : (function() {
var testVal = trampoline(evalExpr(test, env));
return (isSxTruthy((matchVal == testVal)) ? makeCekState(body, env, kont) : sfCaseStepLoop(matchVal, slice(clauses, 2), env, kont));
})());
})()); };
// eval-expr-cek
var evalExprCek = function(expr, env) { return cekRun(makeCekState(expr, env, [])); };
// trampoline-cek
var trampolineCek = function(val) { return (isSxTruthy(isThunk(val)) ? evalExprCek(thunkExpr(val), thunkEnv(val)) : val); };
// =========================================================================
// Platform interface — DOM adapter (browser-only)
// =========================================================================
@@ -5754,6 +6290,27 @@ return (function() {
// =========================================================================
// Platform: CEK module — explicit CEK machine
// =========================================================================
// Standalone aliases for primitives used by cek.sx / frames.sx
var inc = PRIMITIVES["inc"];
var dec = PRIMITIVES["dec"];
var zip_pairs = PRIMITIVES["zip-pairs"];
var continuation_p = PRIMITIVES["continuation?"];
function makeCekContinuation(captured, restKont) {
var c = new Continuation(function(v) { return v !== undefined ? v : NIL; });
c._cek_data = {"captured": captured, "rest-kont": restKont};
return c;
}
function continuationData(c) {
return (c && c._cek_data) ? c._cek_data : {};
}
// =========================================================================
// Post-transpilation fixups
// =========================================================================
@@ -5878,6 +6435,94 @@ return (function() {
PRIMITIVES["build-routing-analysis"] = buildRoutingAnalysis;
PRIMITIVES["build-affinity-analysis"] = buildAffinityAnalysis;
// Override recursive cekRun with iterative loop (avoids stack overflow)
cekRun = function(state) {
while (!cekTerminal_p(state)) { state = cekStep(state); }
return cekValue(state);
};
// =========================================================================
// Extension: Delimited continuations (shift/reset)
// =========================================================================
function Continuation(fn) { this.fn = fn; }
Continuation.prototype._continuation = true;
Continuation.prototype.call = function(value) { return this.fn(value !== undefined ? value : NIL); };
function ShiftSignal(kName, body, env) {
this.kName = kName;
this.body = body;
this.env = env;
}
PRIMITIVES["continuation?"] = function(x) { return x != null && x._continuation === true; };
var _resetResume = [];
function sfReset(args, env) {
var body = args[0];
try {
return trampoline(evalExpr(body, env));
} catch (e) {
if (e instanceof ShiftSignal) {
var sig = e;
var cont = new Continuation(function(value) {
if (value === undefined) value = NIL;
_resetResume.push(value);
try {
return trampoline(evalExpr(body, env));
} finally {
_resetResume.pop();
}
});
var sigEnv = merge(sig.env);
sigEnv[sig.kName] = cont;
return trampoline(evalExpr(sig.body, sigEnv));
}
throw e;
}
}
function sfShift(args, env) {
if (_resetResume.length > 0) {
return _resetResume[_resetResume.length - 1];
}
var kName = symbolName(args[0]);
var body = args[1];
throw new ShiftSignal(kName, body, env);
}
// Wrap evalList to intercept reset/shift
var _baseEvalList = evalList;
evalList = function(expr, env) {
var head = expr[0];
if (isSym(head)) {
var name = head.name;
if (name === "reset") return sfReset(expr.slice(1), env);
if (name === "shift") return sfShift(expr.slice(1), env);
}
return _baseEvalList(expr, env);
};
// Wrap aserSpecial to handle reset/shift in SX wire mode
if (typeof aserSpecial === "function") {
var _baseAserSpecial = aserSpecial;
aserSpecial = function(name, expr, env) {
if (name === "reset") return sfReset(expr.slice(1), env);
if (name === "shift") return sfShift(expr.slice(1), env);
return _baseAserSpecial(name, expr, env);
};
}
// Wrap typeOf to recognize continuations
var _baseTypeOf = typeOf;
typeOf = function(x) {
if (x != null && x._continuation) return "continuation";
return _baseTypeOf(x);
};
// =========================================================================
// Async IO: Promise-aware rendering for client-side IO primitives
// =========================================================================

View File

@@ -1122,6 +1122,7 @@ try:
from .platform_py import (
PREAMBLE, PLATFORM_PY, PRIMITIVES_PY_PRE, PRIMITIVES_PY_POST,
PRIMITIVES_PY_MODULES, _ALL_PY_MODULES,
PLATFORM_PARSER_PY,
PLATFORM_DEPS_PY, PLATFORM_CEK_PY, CEK_FIXUPS_PY, PLATFORM_ASYNC_PY,
FIXUPS_PY, CONTINUATIONS_PY,
_assemble_primitives_py, public_api_py,
@@ -1132,6 +1133,7 @@ except ImportError:
from shared.sx.ref.platform_py import (
PREAMBLE, PLATFORM_PY, PRIMITIVES_PY_PRE, PRIMITIVES_PY_POST,
PRIMITIVES_PY_MODULES, _ALL_PY_MODULES,
PLATFORM_PARSER_PY,
PLATFORM_DEPS_PY, PLATFORM_CEK_PY, CEK_FIXUPS_PY, PLATFORM_ASYNC_PY,
FIXUPS_PY, CONTINUATIONS_PY,
_assemble_primitives_py, public_api_py,
@@ -1224,7 +1226,7 @@ def compile_ref_to_py(
Args:
adapters: List of adapter names to include.
Valid names: html, sx.
Valid names: parser, html, sx.
None = include all server-side adapters.
modules: List of primitive module names to include.
core.* are always included. stdlib.* are opt-in.
@@ -1277,9 +1279,9 @@ def compile_ref_to_py(
spec_mod_set.add("page-helpers")
if "router" in SPEC_MODULES:
spec_mod_set.add("router")
# cek module requires frames
if "cek" in spec_mod_set:
spec_mod_set.add("frames")
# CEK is the canonical evaluator — always include
spec_mod_set.add("cek")
spec_mod_set.add("frames")
has_deps = "deps" in spec_mod_set
has_cek = "cek" in spec_mod_set
@@ -1289,6 +1291,9 @@ def compile_ref_to_py(
("forms.sx", "forms (server definition forms)"),
("render.sx", "render (core)"),
]
# Parser before html/sx — provides serialize used by adapters
if "parser" in adapter_set:
sx_files.append(ADAPTER_FILES["parser"])
for name in ("html", "sx"):
if name in adapter_set:
sx_files.append(ADAPTER_FILES[name])
@@ -1348,6 +1353,7 @@ def compile_ref_to_py(
# Build output
has_html = "html" in adapter_set
has_sx = "sx" in adapter_set
has_parser = "parser" in adapter_set
parts = []
parts.append(PREAMBLE)
@@ -1356,6 +1362,9 @@ def compile_ref_to_py(
parts.append(_assemble_primitives_py(prim_modules))
parts.append(PRIMITIVES_PY_POST)
if has_parser:
parts.append(PLATFORM_PARSER_PY)
if has_deps:
parts.append(PLATFORM_DEPS_PY)

View File

@@ -214,6 +214,10 @@
"render-dom-island" "renderDomIsland"
"reactive-text" "reactiveText"
"reactive-attr" "reactiveAttr"
"cek-reactive-text" "cekReactiveText"
"cek-reactive-attr" "cekReactiveAttr"
"*use-cek-reactive*" "_useCekReactive"
"enable-cek-reactive!" "enableCekReactive"
"reactive-fragment" "reactiveFragment"
"reactive-list" "reactiveList"
"dom-create-element" "domCreateElement"
@@ -520,6 +524,80 @@
"collect!" "sxCollect"
"collected" "sxCollected"
"clear-collected!" "sxClearCollected"
"make-cek-continuation" "makeCekContinuation"
"continuation-data" "continuationData"
"make-cek-state" "makeCekState"
"make-cek-value" "makeCekValue"
"cek-terminal?" "cekTerminal_p"
"cek-run" "cekRun"
"cek-step" "cekStep"
"cek-control" "cekControl"
"cek-env" "cekEnv"
"cek-kont" "cekKont"
"cek-phase" "cekPhase"
"cek-value" "cekValue"
"kont-push" "kontPush"
"kont-top" "kontTop"
"kont-pop" "kontPop"
"kont-empty?" "kontEmpty_p"
"kont-capture-to-reset" "kontCaptureToReset"
"kont-capture-to-reactive-reset" "kontCaptureToReactiveReset"
"has-reactive-reset-frame?" "hasReactiveResetFrame_p"
"frame-type" "frameType"
"make-if-frame" "makeIfFrame"
"make-when-frame" "makeWhenFrame"
"make-begin-frame" "makeBeginFrame"
"make-let-frame" "makeLetFrame"
"make-define-frame" "makeDefineFrame"
"make-set-frame" "makeSetFrame"
"make-arg-frame" "makeArgFrame"
"make-call-frame" "makeCallFrame"
"make-cond-frame" "makeCondFrame"
"make-case-frame" "makeCaseFrame"
"make-thread-frame" "makeThreadFrame"
"make-map-frame" "makeMapFrame"
"make-filter-frame" "makeFilterFrame"
"make-reduce-frame" "makeReduceFrame"
"make-for-each-frame" "makeForEachFrame"
"make-scope-frame" "makeScopeFrame"
"make-reset-frame" "makeResetFrame"
"make-dict-frame" "makeDictFrame"
"make-and-frame" "makeAndFrame"
"make-or-frame" "makeOrFrame"
"make-dynamic-wind-frame" "makeDynamicWindFrame"
"make-reactive-reset-frame" "makeReactiveResetFrame"
"make-deref-frame" "makeDerefFrame"
"step-eval" "stepEval"
"step-continue" "stepContinue"
"step-eval-list" "stepEvalList"
"step-eval-call" "stepEvalCall"
"step-sf-if" "stepSfIf"
"step-sf-when" "stepSfWhen"
"step-sf-begin" "stepSfBegin"
"step-sf-let" "stepSfLet"
"step-sf-define" "stepSfDefine"
"step-sf-set!" "stepSfSet"
"step-sf-and" "stepSfAnd"
"step-sf-or" "stepSfOr"
"step-sf-cond" "stepSfCond"
"step-sf-case" "stepSfCase"
"step-sf-thread-first" "stepSfThreadFirst"
"step-sf-lambda" "stepSfLambda"
"step-sf-scope" "stepSfScope"
"step-sf-provide" "stepSfProvide"
"step-sf-reset" "stepSfReset"
"step-sf-shift" "stepSfShift"
"step-sf-deref" "stepSfDeref"
"step-ho-map" "stepHoMap"
"step-ho-filter" "stepHoFilter"
"step-ho-reduce" "stepHoReduce"
"step-ho-for-each" "stepHoForEach"
"continue-with-call" "continueWithCall"
"sf-case-step-loop" "sfCaseStepLoop"
"eval-expr-cek" "evalExprCek"
"trampoline-cek" "trampolineCek"
"reactive-shift-deref" "reactiveShiftDeref"
"cond-scheme?" "condScheme_p"
"scope-push!" "scopePush"
"scope-pop!" "scopePop"
"provide-push!" "providePush"

View File

@@ -46,8 +46,14 @@ SPEC_MODULES = {
"router": ("router.sx", "router (client-side route matching)"),
"signals": ("signals.sx", "signals (reactive signal runtime)"),
"page-helpers": ("page-helpers.sx", "page-helpers (pure data transformation helpers)"),
"frames": ("frames.sx", "frames (CEK continuation frames)"),
"cek": ("cek.sx", "cek (explicit CEK machine evaluator)"),
}
# Explicit ordering for spec modules with dependencies.
# Modules listed here are emitted in this order; any not listed use alphabetical.
SPEC_MODULE_ORDER = ["deps", "frames", "page-helpers", "router", "signals", "cek"]
EXTENSION_NAMES = {"continuations"}
CONTINUATIONS_JS = '''
@@ -1476,6 +1482,38 @@ PLATFORM_JS_POST = '''
};'''
PLATFORM_CEK_JS = '''
// =========================================================================
// Platform: CEK module — explicit CEK machine
// =========================================================================
// Standalone aliases for primitives used by cek.sx / frames.sx
var inc = PRIMITIVES["inc"];
var dec = PRIMITIVES["dec"];
var zip_pairs = PRIMITIVES["zip-pairs"];
var continuation_p = PRIMITIVES["continuation?"];
function makeCekContinuation(captured, restKont) {
var c = new Continuation(function(v) { return v !== undefined ? v : NIL; });
c._cek_data = {"captured": captured, "rest-kont": restKont};
return c;
}
function continuationData(c) {
return (c && c._cek_data) ? c._cek_data : {};
}
'''
# Iterative override for cek_run — replaces transpiled recursive version
CEK_FIXUPS_JS = '''
// Override recursive cekRun with iterative loop (avoids stack overflow)
cekRun = function(state) {
while (!cekTerminal_p(state)) { state = cekStep(state); }
return cekValue(state);
};
'''
PLATFORM_DEPS_JS = '''
// =========================================================================
// Platform: deps module — component dependency analysis

View File

@@ -659,51 +659,6 @@ def escape_string(s):
.replace("</script", "<\\\\/script"))
def serialize(val):
"""Serialize an SX value to SX source text.
Note: parser.sx defines sx-serialize with a serialize alias, but parser.sx
is only included in JS builds (for client-side parsing). Python builds
provide this as a platform function.
"""
t = type_of(val)
if t == "sx-expr":
return val.source
if t == "nil":
return "nil"
if t == "boolean":
return "true" if val else "false"
if t == "number":
return str(val)
if t == "string":
return '"' + escape_string(val) + '"'
if t == "symbol":
return symbol_name(val)
if t == "keyword":
return ":" + keyword_name(val)
if t == "raw-html":
escaped = escape_string(raw_html_content(val))
return '(raw! "' + escaped + '")'
if t == "list":
if not val:
return "()"
items = [serialize(x) for x in val]
return "(" + " ".join(items) + ")"
if t == "dict":
items = []
for k, v in val.items():
items.append(":" + str(k))
items.append(serialize(v))
return "{" + " ".join(items) + "}"
if callable(val):
return "nil"
return str(val)
# Aliases for transpiled code — parser.sx defines sx-serialize/sx-serialize-dict
# but parser.sx is JS-only. Provide aliases so transpiled render.sx works.
sx_serialize = serialize
sx_serialize_dict = lambda d: serialize(d)
_SPECIAL_FORM_NAMES = frozenset() # Placeholder — overridden by transpiled adapter-sx.sx
_HO_FORM_NAMES = frozenset()
@@ -1066,6 +1021,55 @@ has_key_p = PRIMITIVES["has-key?"]
dict_p = PRIMITIVES["dict?"]
dissoc = PRIMITIVES["dissoc"]
index_of = PRIMITIVES["index-of"]
lower = PRIMITIVES["lower"]
char_from_code = PRIMITIVES["char-from-code"]
'''
# ---------------------------------------------------------------------------
# Platform: parser module — character classification, number parsing,
# reader macro registry
# ---------------------------------------------------------------------------
PLATFORM_PARSER_PY = '''
# =========================================================================
# Platform interface — Parser
# =========================================================================
import re as _re_parser
_IDENT_START_RE = _re_parser.compile(r"[a-zA-Z_~*+\\-><=/!?&]")
_IDENT_CHAR_RE = _re_parser.compile(r"[a-zA-Z0-9_~*+\\-><=/!?.:&/\\[\\]#,]")
def ident_start_p(ch):
return bool(_IDENT_START_RE.match(ch))
def ident_char_p(ch):
return bool(_IDENT_CHAR_RE.match(ch))
def parse_number(s):
"""Parse a numeric string to int or float."""
try:
if "." in s or "e" in s or "E" in s:
return float(s)
return int(s)
except (ValueError, TypeError):
return float(s)
# Reader macro registry
_reader_macros = {}
def reader_macro_get(name):
return _reader_macros.get(name, NIL)
def reader_macro_set_b(name, handler):
_reader_macros[name] = handler
return NIL
'''
# ---------------------------------------------------------------------------
@@ -1159,6 +1163,23 @@ def cek_run(state):
while not cek_terminal_p(state):
state = cek_step(state)
return cek_value(state)
# CEK is the canonical evaluator — override eval_expr to use it.
# The tree-walk evaluator (eval_expr from eval.sx) is superseded.
_tree_walk_eval_expr = eval_expr
def eval_expr(expr, env):
"""Evaluate expr using the CEK machine."""
return cek_run(make_cek_state(expr, env, []))
# CEK never produces thunks — trampoline becomes identity
_tree_walk_trampoline = trampoline
def trampoline(val):
"""In CEK mode, values are immediate — resolve any legacy thunks."""
if is_thunk(val):
return eval_expr(thunk_expr(val), thunk_env(val))
return val
'''
# ---------------------------------------------------------------------------
@@ -1258,11 +1279,6 @@ def number_p(x):
return isinstance(x, (int, float)) and not isinstance(x, bool)
def sx_parse(src):
from shared.sx.parser import parse_all
return parse_all(src)
def is_async_coroutine(x):
return _inspect.iscoroutine(x)
@@ -1590,9 +1606,10 @@ def public_api_py(has_html: bool, has_sx: bool, has_deps: bool = False,
# ---------------------------------------------------------------------------
ADAPTER_FILES = {
"html": ("adapter-html.sx", "adapter-html"),
"sx": ("adapter-sx.sx", "adapter-sx"),
"async": ("adapter-async.sx", "adapter-async"),
"parser": ("parser.sx", "parser"),
"html": ("adapter-html.sx", "adapter-html"),
"sx": ("adapter-sx.sx", "adapter-sx"),
"async": ("adapter-async.sx", "adapter-async"),
}
SPEC_MODULES = {

View File

@@ -24,11 +24,12 @@ from shared.sx.parser import parse_all
from shared.sx.types import Symbol
from shared.sx.ref.platform_js import (
extract_defines,
ADAPTER_FILES, ADAPTER_DEPS, SPEC_MODULES, EXTENSION_NAMES,
ADAPTER_FILES, ADAPTER_DEPS, SPEC_MODULES, SPEC_MODULE_ORDER, EXTENSION_NAMES,
PREAMBLE, PLATFORM_JS_PRE, PLATFORM_JS_POST,
PRIMITIVES_JS_MODULES, _ALL_JS_MODULES, _assemble_primitives_js,
PLATFORM_DEPS_JS, PLATFORM_PARSER_JS, PLATFORM_DOM_JS,
PLATFORM_ENGINE_PURE_JS, PLATFORM_ORCHESTRATION_JS, PLATFORM_BOOT_JS,
PLATFORM_CEK_JS, CEK_FIXUPS_JS,
CONTINUATIONS_JS, ASYNC_IO_JS,
fixups_js, public_api_js, EPILOGUE,
)
@@ -105,9 +106,17 @@ def compile_ref_to_js(
spec_mod_set.add("deps")
if "page-helpers" in SPEC_MODULES:
spec_mod_set.add("page-helpers")
# CEK needed for reactive rendering (deref-as-shift)
if "dom" in adapter_set:
spec_mod_set.add("cek")
spec_mod_set.add("frames")
# cek module requires frames
if "cek" in spec_mod_set:
spec_mod_set.add("frames")
has_deps = "deps" in spec_mod_set
has_router = "router" in spec_mod_set
has_page_helpers = "page-helpers" in spec_mod_set
has_cek = "cek" in spec_mod_set
# Resolve extensions
ext_set = set()
@@ -126,8 +135,14 @@ def compile_ref_to_js(
for name in ("parser", "html", "sx", "dom", "engine", "orchestration", "boot"):
if name in adapter_set:
sx_files.append(ADAPTER_FILES[name])
# Use explicit ordering for spec modules (respects dependencies)
for name in SPEC_MODULE_ORDER:
if name in spec_mod_set:
sx_files.append(SPEC_MODULES[name])
# Any spec modules not in the order list (future-proofing)
for name in sorted(spec_mod_set):
sx_files.append(SPEC_MODULES[name])
if name not in SPEC_MODULE_ORDER:
sx_files.append(SPEC_MODULES[name])
has_html = "html" in adapter_set
has_sx = "sx" in adapter_set
@@ -201,7 +216,12 @@ def compile_ref_to_js(
if name in adapter_set and name in adapter_platform:
parts.append(adapter_platform[name])
if has_cek:
parts.append(PLATFORM_CEK_JS)
parts.append(fixups_js(has_html, has_sx, has_dom, has_signals, has_deps, has_page_helpers))
if has_cek:
parts.append(CEK_FIXUPS_JS)
if has_continuations:
parts.append(CONTINUATIONS_JS)
if has_dom:

File diff suppressed because it is too large Load Diff