Replace invoke with cek-call in reactive island primitives
All signal operations (computed, effect, batch, etc.) now dispatch function calls through cek-call, which routes SX lambdas via cek-run and native callables via apply. This replaces the invoke shim. Key changes: - cek.sx: add cek-call (defined before reactive-shift-deref), replace invoke in subscriber disposal and ReactiveResetFrame handler - signals.sx: replace all 11 invoke calls with cek-call - js.sx: fix octal escape in js-quote-string (char-from-code 0) - platform_js.py: fix JS append to match Python (list concat semantics), add Continuation type guard in PLATFORM_CEK_JS, add scheduleIdle safety check, module ordering (cek before signals) - platform_py.py: fix ident-char regex (remove [ ] from valid chars), module ordering (cek before signals) - run_js_sx.py: emit PLATFORM_CEK_JS before transpiled spec files - page-functions.sx: add cek and provide page functions for SX URLs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -52,7 +52,7 @@ SPEC_MODULES = {
|
||||
|
||||
# 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"]
|
||||
SPEC_MODULE_ORDER = ["deps", "frames", "page-helpers", "router", "cek", "signals"]
|
||||
|
||||
|
||||
EXTENSION_NAMES = {"continuations"}
|
||||
@@ -1004,7 +1004,7 @@ PRIMITIVES_JS_MODULES: dict[str, str] = {
|
||||
PRIMITIVES["rest"] = function(c) { if (c && typeof c.slice !== "function") { console.error("[sx-debug] rest called on non-sliceable:", typeof c, c, new Error().stack); return []; } return c ? c.slice(1) : []; };
|
||||
PRIMITIVES["nth"] = function(c, n) { return c && n >= 0 && n < c.length ? c[n] : NIL; };
|
||||
PRIMITIVES["cons"] = function(x, c) { return [x].concat(c || []); };
|
||||
PRIMITIVES["append"] = function(c, x) { return (c || []).concat([x]); };
|
||||
PRIMITIVES["append"] = function(c, x) { return (c || []).concat(Array.isArray(x) ? x : [x]); };
|
||||
PRIMITIVES["append!"] = function(arr, x) { arr.push(x); return arr; };
|
||||
PRIMITIVES["chunk-every"] = function(c, n) {
|
||||
var r = []; for (var i = 0; i < c.length; i += n) r.push(c.slice(i, i + n)); return r;
|
||||
@@ -1487,6 +1487,14 @@ PLATFORM_CEK_JS = '''
|
||||
// Platform: CEK module — explicit CEK machine
|
||||
// =========================================================================
|
||||
|
||||
// Continuation type (needed by CEK even without the tree-walk shift/reset extension)
|
||||
if (typeof Continuation === "undefined") {
|
||||
function Continuation(fn) { this.fn = fn; }
|
||||
Continuation.prototype._continuation = true;
|
||||
Continuation.prototype.call = function(value) { return this.fn(value !== undefined ? value : NIL); };
|
||||
PRIMITIVES["continuation?"] = function(x) { return x != null && x._continuation === true; };
|
||||
}
|
||||
|
||||
// Standalone aliases for primitives used by cek.sx / frames.sx
|
||||
var inc = PRIMITIVES["inc"];
|
||||
var dec = PRIMITIVES["dec"];
|
||||
@@ -1608,10 +1616,10 @@ PLATFORM_PARSER_JS = r"""
|
||||
// =========================================================================
|
||||
// Character classification derived from the grammar:
|
||||
// ident-start → [a-zA-Z_~*+\-><=/!?&]
|
||||
// ident-char → ident-start + [0-9.:\/\[\]#,]
|
||||
// ident-char → ident-start + [0-9.:\/\#,]
|
||||
|
||||
var _identStartRe = /[a-zA-Z_~*+\-><=/!?&]/;
|
||||
var _identCharRe = /[a-zA-Z0-9_~*+\-><=/!?.:&/\[\]#,]/;
|
||||
var _identCharRe = /[a-zA-Z0-9_~*+\-><=/!?.:&/#,]/;
|
||||
|
||||
function isIdentStart(ch) { return _identStartRe.test(ch); }
|
||||
function isIdentChar(ch) { return _identCharRe.test(ch); }
|
||||
@@ -2436,6 +2444,10 @@ PLATFORM_ORCHESTRATION_JS = """
|
||||
}
|
||||
function scheduleIdle(fn) {
|
||||
var cb = _wrapSxFn(fn);
|
||||
if (typeof cb !== "function") {
|
||||
console.error("[sx-ref] scheduleIdle: callback not callable, fn type:", typeof fn, "fn:", fn, "_lambda:", fn && fn._lambda);
|
||||
return;
|
||||
}
|
||||
if (typeof requestIdleCallback !== "undefined") requestIdleCallback(cb);
|
||||
else setTimeout(cb, 0);
|
||||
}
|
||||
@@ -2525,8 +2537,12 @@ PLATFORM_ORCHESTRATION_JS = """
|
||||
e.preventDefault();
|
||||
// Re-read href from element at click time (not closed-over value)
|
||||
var liveHref = el.getAttribute("href") || _href;
|
||||
console.log("[sx-debug] bindBoostLink click:", liveHref, "el:", el.tagName, el.textContent.slice(0,30));
|
||||
executeRequest(el, { method: "GET", url: liveHref }).then(function() {
|
||||
console.log("[sx-debug] boost fetch OK, pushState:", liveHref);
|
||||
try { history.pushState({ sxUrl: liveHref, scrollY: window.scrollY }, "", liveHref); } catch (err) {}
|
||||
}).catch(function(err) {
|
||||
console.error("[sx-debug] boost fetch ERROR:", err);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -2551,21 +2567,25 @@ PLATFORM_ORCHESTRATION_JS = """
|
||||
// Re-read href from element at click time (not closed-over value)
|
||||
var liveHref = link.getAttribute("href") || _href;
|
||||
var pathname = urlPathname(liveHref);
|
||||
console.log("[sx-debug] bindClientRouteClick:", pathname, "el:", link.tagName, link.textContent.slice(0,30));
|
||||
// Find target selector: sx-boost ancestor, explicit sx-target, or #main-panel
|
||||
var boostEl = link.closest("[sx-boost]");
|
||||
var targetSel = boostEl ? boostEl.getAttribute("sx-boost") : null;
|
||||
if (!targetSel || targetSel === "true") {
|
||||
targetSel = link.getAttribute("sx-target") || "#main-panel";
|
||||
}
|
||||
console.log("[sx-debug] targetSel:", targetSel, "trying client route...");
|
||||
if (tryClientRoute(pathname, targetSel)) {
|
||||
console.log("[sx-debug] client route SUCCESS, pushState:", liveHref);
|
||||
try { history.pushState({ sxUrl: liveHref, scrollY: window.scrollY }, "", liveHref); } catch (err) {}
|
||||
if (typeof window !== "undefined") window.scrollTo(0, 0);
|
||||
} else {
|
||||
logInfo("sx:route server " + pathname);
|
||||
console.log("[sx-debug] client route FAILED, server fetch:", liveHref);
|
||||
executeRequest(link, { method: "GET", url: liveHref }).then(function() {
|
||||
console.log("[sx-debug] server fetch OK, pushState:", liveHref);
|
||||
try { history.pushState({ sxUrl: liveHref, scrollY: window.scrollY }, "", liveHref); } catch (err) {}
|
||||
}).catch(function(err) {
|
||||
logWarn("sx:route server fetch error: " + (err && err.message ? err.message : err));
|
||||
console.error("[sx-debug] server fetch ERROR:", err);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user