From a2d0a8a0fa1f06b0e703cbdc711f9de191a490cb Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 6 Mar 2026 16:49:42 +0000 Subject: [PATCH] Fix evalCond in HTML/DOM renderers: handle scheme-style cond clauses The platform evalCond helper (used by render-to-html and render-to-dom) only handled clojure-style (test body test body ...) but components use scheme-style ((test body) (test body) ...). This caused "Not callable: true" errors when rendering cond with nested clause pairs, breaking the test dashboard and any page using scheme-style cond. Co-Authored-By: Claude Opus 4.6 --- shared/static/scripts/sx-browser.js | 22 +++++++++++++++++----- shared/sx/ref/bootstrap_js.py | 22 +++++++++++++++++----- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/shared/static/scripts/sx-browser.js b/shared/static/scripts/sx-browser.js index 40d3993..f4ce87a 100644 --- a/shared/static/scripts/sx-browser.js +++ b/shared/static/scripts/sx-browser.js @@ -506,11 +506,23 @@ return local; } function evalCond(clauses, env) { - 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]; + // 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; } diff --git a/shared/sx/ref/bootstrap_js.py b/shared/sx/ref/bootstrap_js.py index c9fec06..2667497 100644 --- a/shared/sx/ref/bootstrap_js.py +++ b/shared/sx/ref/bootstrap_js.py @@ -1836,11 +1836,23 @@ PLATFORM_JS_POST = ''' return local; } function evalCond(clauses, env) { - 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]; + // 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; }