Add js.sx bootstrapper docs page with G0 bug discovery writeup

Documents the self-hosting process for js.sx including the G0 bug
where Python's `if fn_expr` treated 0/False/"" as falsy, emitting
NIL instead of the correct value. Adds live verification page,
translation differences table, and nav entry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-09 01:44:02 +00:00
parent e6ca1a5f44
commit cad65bcdf1
6 changed files with 182 additions and 9 deletions

View File

@@ -439,6 +439,116 @@ router.sx (standalone — pure string/list ops)")))
(pre :class "text-xs leading-relaxed whitespace-pre-wrap break-words"
(code (highlight g1-output "python"))))))))
;; ---------------------------------------------------------------------------
;; Self-hosting JS bootstrapper (js.sx) — live verification
;; ---------------------------------------------------------------------------
;; @css bg-green-100 text-green-800 bg-green-50 border-green-200 text-green-700 bg-amber-50 border-amber-200 text-amber-700 text-amber-800 bg-amber-100
(defcomp ~bootstrapper-self-hosting-js-content (&key js-sx-source defines-matched defines-total js-sx-lines verification-status)
(~doc-page :title "Self-Hosting Bootstrapper (js.sx)"
(div :class "space-y-8"
(div :class "space-y-3"
(p :class "text-stone-600"
(code :class "text-violet-700 text-sm" "js.sx")
" is an SX-to-JavaScript translator written in SX. "
"This page runs it live: loads js.sx into the evaluator, translates every spec file, "
"and verifies each define matches " (code :class "text-violet-700 text-sm" "bootstrap_js.py") "'s JSEmitter.")
(div :class "rounded-lg p-4"
:class (if (= verification-status "identical")
"bg-green-50 border border-green-200"
"bg-red-50 border border-red-200")
(div :class "flex items-center gap-3"
(span :class "inline-flex items-center rounded-full px-3 py-1 text-sm font-semibold"
:class (if (= verification-status "identical")
"bg-green-100 text-green-800"
"bg-red-100 text-red-800")
(if (= verification-status "identical") "G0 == G1" "MISMATCH"))
(p :class "text-sm"
:class (if (= verification-status "identical") "text-green-700" "text-red-700")
defines-matched "/" defines-total " defines match across all spec files. "
js-sx-lines " lines of SX."))))
;; G0 Bug Discovery
(div :class "space-y-3"
(h2 :class "text-2xl font-semibold text-stone-800" "G0 Bug Discovery")
(div :class "rounded-lg bg-amber-50 border border-amber-200 p-4"
(div :class "flex items-start gap-3"
(span :class "inline-flex items-center rounded-full bg-amber-100 px-3 py-1 text-sm font-semibold text-amber-800"
"Fixed")
(div :class "text-sm text-amber-700 space-y-2"
(p "Building js.sx revealed a bug in " (code "bootstrap_js.py") "'s "
(code "_emit_define") " method. The Python code:")
(pre :class "bg-amber-100 rounded p-2 text-xs font-mono"
"val = self.emit(fn_expr) if fn_expr else \"NIL\"")
(p "Python's " (code "if fn_expr") " treats " (code "0") ", "
(code "False") ", and " (code "\"\"") " as falsy. So "
(code "(define *batch-depth* 0)") " emitted "
(code "var _batchDepth = NIL") " instead of "
(code "var _batchDepth = 0") ". Similarly, "
(code "(define _css-hash \"\")") " emitted "
(code "var _cssHash = NIL") " instead of "
(code "var _cssHash = \"\"") ".")
(p "Fix: " (code "if fn_expr is not None") " — explicit None check. "
"js.sx never had this bug because SX's " (code "nil?") " only matches "
(code "nil") ", not " (code "0") " or " (code "false") ". "
"The self-hosting bootstrapper caught a host language bug.")))))
;; JS vs Python differences
(div :class "space-y-3"
(h2 :class "text-2xl font-semibold text-stone-800" "Translation Differences from py.sx")
(p :class "text-sm text-stone-500"
"Both py.sx and js.sx translate the same SX ASTs, but target languages differ:")
(div :class "overflow-x-auto rounded border border-stone-200"
(table :class "w-full text-sm"
(thead :class "bg-stone-50"
(tr
(th :class "px-4 py-2 text-left font-semibold text-stone-700" "Feature")
(th :class "px-4 py-2 text-left font-semibold text-stone-700" "py.sx → Python")
(th :class "px-4 py-2 text-left font-semibold text-stone-700" "js.sx → JavaScript")))
(tbody
(tr :class "border-t border-stone-100"
(td :class "px-4 py-2 text-stone-600" "Name mangling")
(td :class "px-4 py-2 font-mono text-xs" "eval-expr → eval_expr")
(td :class "px-4 py-2 font-mono text-xs" "eval-expr → evalExpr"))
(tr :class "border-t border-stone-100"
(td :class "px-4 py-2 text-stone-600" "Declarations")
(td :class "px-4 py-2 font-mono text-xs" "name = value")
(td :class "px-4 py-2 font-mono text-xs" "var name = value;"))
(tr :class "border-t border-stone-100"
(td :class "px-4 py-2 text-stone-600" "Functions")
(td :class "px-4 py-2 font-mono text-xs" "lambda x: body")
(td :class "px-4 py-2 font-mono text-xs" "function(x) { return body; }"))
(tr :class "border-t border-stone-100"
(td :class "px-4 py-2 text-stone-600" "set! (mutation)")
(td :class "px-4 py-2 font-mono text-xs" "_cells dict (closure hack)")
(td :class "px-4 py-2 font-mono text-xs" "Direct assignment (JS captures by ref)"))
(tr :class "border-t border-stone-100"
(td :class "px-4 py-2 text-stone-600" "Tail recursion")
(td :class "px-4 py-2 font-mono text-xs" "—")
(td :class "px-4 py-2 font-mono text-xs" "while(true) { continue; }"))
(tr :class "border-t border-stone-100"
(td :class "px-4 py-2 text-stone-600" "let binding")
(td :class "px-4 py-2 font-mono text-xs" "(lambda x: body)(val)")
(td :class "px-4 py-2 font-mono text-xs" "(function() { var x = val; return body; })()"))
(tr :class "border-t border-stone-100"
(td :class "px-4 py-2 text-stone-600" "and/or")
(td :class "px-4 py-2 font-mono text-xs" "ternary chains")
(td :class "px-4 py-2 font-mono text-xs" "&& / sxOr()"))))))
;; Source
(div :class "space-y-3"
(div :class "flex items-baseline gap-3"
(h2 :class "text-2xl font-semibold text-stone-800" "js.sx Source")
(span :class "text-sm text-stone-400 font-mono" "shared/sx/ref/js.sx"))
(p :class "text-sm text-stone-500"
"The SX-to-JavaScript translator — 61 " (code "define") " forms. "
"camelCase mangling (500+ RENAMES), expression/statement emission, "
"self-tail-recursive while loop optimization.")
(div :class "not-prose bg-stone-100 rounded-lg p-5 max-h-96 overflow-y-auto border border-stone-200"
(pre :class "text-xs leading-relaxed whitespace-pre-wrap break-words"
(code (highlight js-sx-source "lisp"))))))))
;; ---------------------------------------------------------------------------
;; Python bootstrapper detail
;; ---------------------------------------------------------------------------