Spec eval-cond and process-bindings in render.sx (remove platform implementations)

eval-cond and process-bindings were hand-written platform JS in
bootstrap_js.py rather than specced in .sx files. This violated the
SX host architecture principle. Now specced in render.sx as shared
render adapter helpers, bootstrapped to both JS and Python.

eval-cond handles both scheme-style ((test body) ...) and clojure-style
(test body test body ...) cond clauses. Returns unevaluated body
expression for the adapter to render in its own mode.

process-bindings evaluates let-binding pairs and returns extended env.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 16:58:53 +00:00
parent a2d0a8a0fa
commit 20ac0fe948
5 changed files with 117 additions and 66 deletions

View File

@@ -273,6 +273,8 @@ class JSEmitter:
"dict-delete!": "dictDelete",
"process-bindings": "processBindings",
"eval-cond": "evalCond",
"eval-cond-scheme": "evalCondScheme",
"eval-cond-clojure": "evalCondClojure",
"for-each-indexed": "forEachIndexed",
"index-of": "indexOf_",
"component-has-children?": "componentHasChildren",
@@ -1823,39 +1825,7 @@ PLATFORM_JS_POST = '''
"map":1,"map-indexed":1,"filter":1,"reduce":1,"some":1,"every?":1,"for-each":1
}; }
// processBindings and evalCond — exposed for DOM adapter render forms
function processBindings(bindings, env) {
var local = merge(env);
for (var i = 0; i < bindings.length; i++) {
var pair = bindings[i];
if (Array.isArray(pair) && pair.length >= 2) {
var name = isSym(pair[0]) ? pair[0].name : String(pair[0]);
local[name] = trampoline(evalExpr(pair[1], local));
}
}
return local;
}
function evalCond(clauses, env) {
// Detect scheme-style ((test body) ...) vs clojure-style (test body test body ...)
var scheme = clauses.length > 0 && Array.isArray(clauses[0]) && clauses[0].length === 2;
if (scheme) {
for (var i = 0; i < clauses.length; i++) {
var clause = clauses[i];
var test = clause[0], body = clause[1];
if (isSym(test) && (test.name === "else" || test.name === ":else")) return body;
if (isKw(test) && test.name === "else") return body;
if (isSxTruthy(trampoline(evalExpr(test, env)))) return body;
}
} else {
for (var i = 0; i < clauses.length; i += 2) {
var test = clauses[i];
if (isSym(test) && test.name === ":else") return clauses[i + 1];
if (isKw(test) && test.name === "else") return clauses[i + 1];
if (isSxTruthy(trampoline(evalExpr(test, env)))) return clauses[i + 1];
}
}
return null;
}
// processBindings and evalCond — now specced in render.sx, bootstrapped above
function isDefinitionForm(name) {
return name === "define" || name === "defcomp" || name === "defmacro" ||