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

@@ -493,39 +493,7 @@
"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" ||
@@ -1082,6 +1050,36 @@ return append_b(inits, nth(binding, 1)); }, bindings) : reduce(function(acc, pai
return (isSxTruthy((isSxTruthy(contains(BOOLEAN_ATTRS, key)) && val)) ? (String(" ") + String(key)) : (isSxTruthy((isSxTruthy(contains(BOOLEAN_ATTRS, key)) && !val)) ? "" : (isSxTruthy(isNil(val)) ? "" : (isSxTruthy((isSxTruthy((key == "style")) && isStyleValue(val))) ? (String(" class=\"") + String(styleValueClass(val)) + String("\"")) : (String(" ") + String(key) + String("=\"") + String(escapeAttr((String(val)))) + String("\""))))));
})(); }, keys(attrs))); };
// eval-cond
var evalCond = function(clauses, env) { return (isSxTruthy((isSxTruthy(!isEmpty(clauses)) && isSxTruthy((typeOf(first(clauses)) == "list")) && (len(first(clauses)) == 2))) ? evalCondScheme(clauses, env) : evalCondClojure(clauses, env)); };
// eval-cond-scheme
var evalCondScheme = function(clauses, env) { return (isSxTruthy(isEmpty(clauses)) ? NIL : (function() {
var clause = first(clauses);
var test = first(clause);
var body = nth(clause, 1);
return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))), (isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")))) ? body : (isSxTruthy(trampoline(evalExpr(test, env))) ? body : evalCondScheme(rest(clauses), env)));
})()); };
// eval-cond-clojure
var evalCondClojure = function(clauses, env) { return (isSxTruthy((len(clauses) < 2)) ? NIL : (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"))))) ? body : (isSxTruthy(trampoline(evalExpr(test, env))) ? body : evalCondClojure(slice(clauses, 2), env)));
})()); };
// process-bindings
var processBindings = function(bindings, env) { return (function() {
var local = merge(env);
{ var _c = bindings; for (var _i = 0; _i < _c.length; _i++) { var pair = _c[_i]; if (isSxTruthy((isSxTruthy((typeOf(pair) == "list")) && (len(pair) >= 2)))) {
(function() {
var name = (isSxTruthy((typeOf(first(pair)) == "symbol")) ? symbolName(first(pair)) : (String(first(pair))));
return envSet(local, name, trampoline(evalExpr(nth(pair, 1), local)));
})();
} } }
return local;
})(); };
// === Transpiled from parser ===