diff --git a/sx/sx/nav-data.sx b/sx/sx/nav-data.sx index 24cada4..2cae07c 100644 --- a/sx/sx/nav-data.sx +++ b/sx/sx/nav-data.sx @@ -161,6 +161,8 @@ :summary "prove.sx — constraint solver and property prover for SX primitives, written in SX.") (dict :label "Self-Hosting Bootstrapper" :href "/plans/self-hosting-bootstrapper" :summary "py.sx — an SX-to-Python translator written in SX. The bootstrapper bootstraps itself.") + (dict :label "JS Bootstrapper" :href "/plans/js-bootstrapper" + :summary "js.sx — SX-to-JavaScript translator + ahead-of-time component compiler. Zero-runtime static sites.") (dict :label "SX-Activity" :href "/plans/sx-activity" :summary "A new web built on SX — executable content, shared components, parsers, and logic on IPFS, provenance on Bitcoin, all running within your own security context.") (dict :label "Predictive Prefetching" :href "/plans/predictive-prefetch" diff --git a/sx/sx/plans/js-bootstrapper.sx b/sx/sx/plans/js-bootstrapper.sx new file mode 100644 index 0000000..3add2e0 --- /dev/null +++ b/sx/sx/plans/js-bootstrapper.sx @@ -0,0 +1,511 @@ +;; --------------------------------------------------------------------------- +;; js.sx — Self-Hosting JavaScript Bootstrapper +;; --------------------------------------------------------------------------- + +(defcomp ~plan-js-bootstrapper-content () + (~doc-page :title "js.sx — JavaScript Bootstrapper" + + ;; ----------------------------------------------------------------------- + ;; Overview + ;; ----------------------------------------------------------------------- + + (~doc-section :title "Overview" :id "overview" + (p (code "bootstrap_js.py") " is a 4,361-line Python program that reads the " + (code ".sx") " spec files and emits " (code "sx-ref.js") " — the entire " + "browser runtime. Parser, evaluator, three rendering adapters (HTML, SX wire, DOM), " + "the engine (fetch/swap/trigger), orchestration, boot, signals, router, component " + "dependency analysis — all transpiled from " (code ".sx") " spec files into JavaScript.") + (p (code "js.sx") " replaces that Python program with an SX program. " + "Like " (code "py.sx") " for Python, " (code "js.sx") " is an SX-to-JavaScript " + "translator written in SX. But it goes further.") + (p "Because the JS bootstrapper produces " (em "browser code") ", " (code "js.sx") + " can also compile " (em "any") " SX component tree into a standalone JavaScript " + "program. The server evaluates an " (code ".sx") " page definition, calls " + (code "#js") " on the result, and gets a self-contained JS bundle that renders " + "the same output in the browser — no SX runtime needed.")) + + ;; ----------------------------------------------------------------------- + ;; Two Modes + ;; ----------------------------------------------------------------------- + + (~doc-section :title "Two Compilation Modes" :id "modes" + + (~doc-subsection :title "Mode 1: Spec Bootstrapper" + (p "Same job as " (code "bootstrap_js.py") ". Read spec " (code ".sx") " files, " + "emit " (code "sx-ref.js") ".") + (~doc-code :code (highlight ";; Translate eval.sx to JavaScript +(js-translate-file (parse-file \"eval.sx\")) +;; → \"function evalExpr(expr, env) { ... }\" + +;; Full bootstrap: all spec modules → sx-ref.js +(js-bootstrap + :adapters (list \"html\" \"sx\" \"dom\" \"engine\" \"boot\") + :modules (list \"deps\" \"router\" \"signals\"))" "lisp")) + (p "The output is identical to " (code "python bootstrap_js.py") ". " + "Verification: " (code "diff <(python bootstrap_js.py) <(python run_js_sx.py)") ".")) + + (~doc-subsection :title "Mode 2: Component Compiler" + (p "Server-side SX evaluation + " (code "js.sx") " translation = static JS output. " + "Given a component tree that the server has already evaluated (data fetched, " + "conditionals resolved, loops expanded), " (code "js.sx") " compiles the " + "resulting DOM description into a JavaScript program that builds the same DOM.") + (~doc-code :code (highlight ";; Server evaluates the page (fetches data, expands components) +;; Result is a resolved SX tree: (div :class \"...\" (h1 \"Hello\") ...) + +;; js.sx compiles that tree to standalone JS +(js-compile-component evaluated-tree) +;; → \"(function(){ +;; var el = document.createElement('div'); +;; el.className = '...'; +;; var h1 = document.createElement('h1'); +;; h1.textContent = 'Hello'; +;; el.appendChild(h1); +;; return el; +;; })()\"" "lisp")) + (p "This is ahead-of-time compilation. The browser receives JavaScript, " + "not s-expressions. No parser, no evaluator, no runtime. " + "Just DOM construction code."))) + + ;; ----------------------------------------------------------------------- + ;; Architecture + ;; ----------------------------------------------------------------------- + + (~doc-section :title "Architecture" :id "architecture" + (p "The JS bootstrapper has more moving parts than the Python one because " + "JavaScript is the " (em "client") " host. The browser runtime includes " + "things Python never needs:") + (div :class "overflow-x-auto rounded border border-stone-200 my-4" + (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" "Spec Module") + (th :class "px-4 py-2 text-left font-semibold text-stone-700" "Purpose") + (th :class "px-4 py-2 text-left font-semibold text-stone-700" "Python?") + (th :class "px-4 py-2 text-left font-semibold text-stone-700" "Browser?"))) + (tbody + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "eval.sx") + (td :class "px-4 py-2" "Core evaluator, special forms, TCO") + (td :class "px-4 py-2 text-center" "Yes") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "render.sx") + (td :class "px-4 py-2" "Tag registry, void elements, boolean attrs") + (td :class "px-4 py-2 text-center" "Yes") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "parser.sx") + (td :class "px-4 py-2" "Tokenizer, parser, serializer") + (td :class "px-4 py-2 text-center" "—") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "adapter-html.sx") + (td :class "px-4 py-2" "Render to HTML string") + (td :class "px-4 py-2 text-center" "Yes") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "adapter-sx.sx") + (td :class "px-4 py-2" "Serialize to SX wire format") + (td :class "px-4 py-2 text-center" "Yes") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100 bg-blue-50" + (td :class "px-4 py-2 font-mono" "adapter-dom.sx") + (td :class "px-4 py-2" "Render to live DOM nodes") + (td :class "px-4 py-2 text-center" "—") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100 bg-blue-50" + (td :class "px-4 py-2 font-mono" "engine.sx") + (td :class "px-4 py-2" "Fetch, swap, trigger, history") + (td :class "px-4 py-2 text-center" "—") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100 bg-blue-50" + (td :class "px-4 py-2 font-mono" "orchestration.sx") + (td :class "px-4 py-2" "Element scanning, attribute processing") + (td :class "px-4 py-2 text-center" "—") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100 bg-blue-50" + (td :class "px-4 py-2 font-mono" "boot.sx") + (td :class "px-4 py-2" "Script processing, mount, hydration") + (td :class "px-4 py-2 text-center" "—") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "signals.sx") + (td :class "px-4 py-2" "Reactive signal runtime") + (td :class "px-4 py-2 text-center" "Yes") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "deps.sx") + (td :class "px-4 py-2" "Component dependency analysis") + (td :class "px-4 py-2 text-center" "Yes") (td :class "px-4 py-2 text-center" "Yes")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "router.sx") + (td :class "px-4 py-2" "Client-side route matching") + (td :class "px-4 py-2 text-center" "Yes") (td :class "px-4 py-2 text-center" "Yes"))))) + (p "Blue rows are browser-only modules. " (code "js.sx") " must handle all of them. " + "The platform interface is also larger: DOM primitives (" (code "dom-create-element") + ", " (code "dom-append") ", " (code "dom-set-attr") ", ...), " + "browser APIs (" (code "fetch") ", " (code "history") ", " (code "localStorage") + "), and event handling.")) + + ;; ----------------------------------------------------------------------- + ;; Translation Rules + ;; ----------------------------------------------------------------------- + + (~doc-section :title "Translation Rules" :id "translation" + (p (code "js.sx") " shares the same pattern as " (code "py.sx") " — expression translator, " + "statement translator, name mangling — but with JavaScript-specific mappings:") + + (~doc-subsection :title "Name Mangling" + (p "SX uses kebab-case. JavaScript uses camelCase.") + (div :class "overflow-x-auto rounded border border-stone-200 my-4" + (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" "SX") + (th :class "px-4 py-2 text-left font-semibold text-stone-700" "JavaScript") + (th :class "px-4 py-2 text-left font-semibold text-stone-700" "Rule"))) + (tbody + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "eval-expr") + (td :class "px-4 py-2 font-mono" "evalExpr") + (td :class "px-4 py-2" "kebab → camelCase")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "nil?") + (td :class "px-4 py-2 font-mono" "isNil") + (td :class "px-4 py-2" "predicate → is-prefix")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "empty?") + (td :class "px-4 py-2 font-mono" "isEmpty") + (td :class "px-4 py-2" "? → is-prefix (general)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "set!") + (td :class "px-4 py-2 font-mono" "—") + (td :class "px-4 py-2" "assignment (no rename)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "dom-create-element") + (td :class "px-4 py-2 font-mono" "domCreateElement") + (td :class "px-4 py-2" "platform function rename")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "delete") + (td :class "px-4 py-2 font-mono" "delete_") + (td :class "px-4 py-2" "JS reserved word escape")))))) + + (~doc-subsection :title "Special Forms → JavaScript" + (div :class "overflow-x-auto rounded border border-stone-200 my-4" + (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" "SX") + (th :class "px-4 py-2 text-left font-semibold text-stone-700" "JavaScript"))) + (tbody + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "(if c t e)") + (td :class "px-4 py-2 font-mono" "(sxTruthy(c) ? t : e)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "(when c body)") + (td :class "px-4 py-2 font-mono" "(sxTruthy(c) ? body : NIL)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "(let ((a 1)) body)") + (td :class "px-4 py-2 font-mono" "(function(a) { return body; })(1)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "(fn (x) body)") + (td :class "px-4 py-2 font-mono" "function(x) { return body; }")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "(define name val)") + (td :class "px-4 py-2 font-mono" "var name = val;")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "(and a b c)") + (td :class "px-4 py-2 font-mono" "(sxTruthy(a) ? (sxTruthy(b) ? c : b) : a)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "(case x \"a\" 1 ...)") + (td :class "px-4 py-2 font-mono" "sxCase(x, [[\"a\", () => 1], ...])")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "(str a b c)") + (td :class "px-4 py-2 font-mono" "sxStr(a, b, c)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "&rest args") + (td :class "px-4 py-2 font-mono" "...args (rest params)")))))) + + (~doc-subsection :title "JavaScript Advantages" + (p "JavaScript is easier to target than Python in two key ways:") + (ul :class "list-disc pl-6 space-y-2 text-stone-700" + (li (strong "No mutation problem. ") + "JavaScript closures capture by reference, not by value. " + (code "set!") " from a nested function Just Works — no cell variable " + "hack needed. This eliminates the hardest part of " (code "py.sx") ".") + (li (strong "Expression-oriented. ") + "JavaScript's comma operator, ternary, and IIFEs make " + "almost everything expressible as an expression. " + "The statement/expression duality is less painful than Python.")))) + + ;; ----------------------------------------------------------------------- + ;; Component Compilation + ;; ----------------------------------------------------------------------- + + (~doc-section :title "Component Compilation" :id "component-compiler" + (p "Mode 2 is the interesting one. The server already evaluates SX page " + "definitions — it fetches data, resolves conditionals, expands components, " + "and produces a complete DOM description as an SX tree. Currently this tree " + "is either:") + (ul :class "list-disc pl-6 space-y-1 text-stone-700" + (li "Rendered to HTML server-side (" (code "render-to-html") ")") + (li "Serialized as SX wire format for the client to render (" (code "aser") ")")) + (p "A third option: " (strong "compile it to JavaScript") ". " + "The SX tree is already fully resolved — no data to fetch, no conditionals " + "to evaluate. It's just a description of DOM nodes. " (code "js.sx") + " walks this tree and emits imperative JavaScript that constructs the same DOM.") + + (~doc-subsection :title "What Gets Compiled" + (p "A resolved SX tree like:") + (~doc-code :code (highlight "(div :class \"container\" + (h1 \"Hello\") + (ul (map (fn (item) + (li :class \"item\" (get item \"name\"))) + items)))" "lisp")) + (p "After server-side evaluation (with " (code "items") " = " + (code "[{\"name\": \"Alice\"}, {\"name\": \"Bob\"}]") "):") + (~doc-code :code (highlight "(div :class \"container\" + (h1 \"Hello\") + (ul + (li :class \"item\" \"Alice\") + (li :class \"item\" \"Bob\")))" "lisp")) + (p "Compiles to:") + (~doc-code :code (highlight "var _0 = document.createElement('div'); +_0.className = 'container'; +var _1 = document.createElement('h1'); +_1.textContent = 'Hello'; +_0.appendChild(_1); +var _2 = document.createElement('ul'); +var _3 = document.createElement('li'); +_3.className = 'item'; +_3.textContent = 'Alice'; +_2.appendChild(_3); +var _4 = document.createElement('li'); +_4.className = 'item'; +_4.textContent = 'Bob'; +_2.appendChild(_4); +_0.appendChild(_2);" "javascript"))) + + (~doc-subsection :title "Why Not Just Use HTML?" + (p "HTML already does this — " (code "innerHTML") " parses and builds DOM. " + "Why compile to JS instead?") + (ul :class "list-disc pl-6 space-y-2 text-stone-700" + (li (strong "Event handlers. ") + "HTML can't express " (code ":on-click") " or " (code ":sx-get") + " — those need JavaScript. The compiled JS can wire up event " + "listeners inline during construction.") + (li (strong "Reactive islands. ") + "Signal bindings (" (code "deref") "), reactive text nodes, and " + "reactive attributes need to register subscriptions during construction. " + "Compiled JS can create signals and wire subscriptions as it builds the DOM.") + (li (strong "No parse overhead. ") + "The browser doesn't need to parse HTML or SX source. " + "The JavaScript engine JIT-compiles the DOM construction code. " + "For large pages, this can be faster than " (code "innerHTML") ".") + (li (strong "Tree-shakeable. ") + "The compiled output only contains what the page uses. " + "No SX parser, no evaluator, no rendering runtime. " + "A static page compiles to pure DOM API calls — zero framework overhead.") + (li (strong "Portable. ") + "The output is a JavaScript module. It works in any JS environment: " + "browser, Node, Deno, Bun. Server-side rendered pages become " + "testable JavaScript programs."))) + + (~doc-subsection :title "Hybrid Mode" + (p "Not every page is fully static. Some parts are server-rendered, " + "some are interactive. " (code "js.sx") " handles this with a hybrid approach:") + (ul :class "list-disc pl-6 space-y-2 text-stone-700" + (li (strong "Static subtrees") " → compiled to DOM construction code (no runtime)") + (li (strong "Reactive islands") " → compiled with signal creation + subscriptions " + "(needs signal runtime, ~2KB)") + (li (strong "Hypermedia attributes") " (" (code "sx-get") ", " (code "sx-post") + ") → compiled with event listeners + fetch calls " + "(needs engine, ~5KB)") + (li (strong "Client-routed pages") " → full SX runtime included")) + (p "The compiler analyzes the tree and includes only the runtime slices needed. " + "A purely static page ships zero SX runtime. " + "A page with one reactive counter ships just the signal runtime."))) + + ;; ----------------------------------------------------------------------- + ;; The Bootstrap Chain + ;; ----------------------------------------------------------------------- + + (~doc-section :title "The Bootstrap Chain" :id "chain" + (p "With both " (code "py.sx") " and " (code "js.sx") ", the full picture:") + (div :class "overflow-x-auto rounded border border-stone-200 my-4" + (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" "Translator") + (th :class "px-4 py-2 text-left font-semibold text-stone-700" "Written in") + (th :class "px-4 py-2 text-left font-semibold text-stone-700" "Outputs") + (th :class "px-4 py-2 text-left font-semibold text-stone-700" "Replaces"))) + (tbody + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "z3.sx") + (td :class "px-4 py-2" "SX") + (td :class "px-4 py-2" "SMT-LIB") + (td :class "px-4 py-2 text-stone-400 italic" "(none — new capability)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono" "prove.sx") + (td :class "px-4 py-2" "SX") + (td :class "px-4 py-2" "Constraint proofs") + (td :class "px-4 py-2 text-stone-400 italic" "(none — new capability)")) + (tr :class "border-t border-stone-100 bg-violet-50" + (td :class "px-4 py-2 font-mono text-violet-700" "py.sx") + (td :class "px-4 py-2" "SX") + (td :class "px-4 py-2" "Python") + (td :class "px-4 py-2 font-mono" "bootstrap_py.py")) + (tr :class "border-t border-stone-100 bg-blue-50" + (td :class "px-4 py-2 font-mono text-blue-700" "js.sx") + (td :class "px-4 py-2" "SX") + (td :class "px-4 py-2" "JavaScript") + (td :class "px-4 py-2 font-mono" "bootstrap_js.py")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono text-stone-400" "go.sx") + (td :class "px-4 py-2" "SX") + (td :class "px-4 py-2" "Go") + (td :class "px-4 py-2 text-stone-400 italic" "(future host)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2 font-mono text-stone-400" "rs.sx") + (td :class "px-4 py-2" "SX") + (td :class "px-4 py-2" "Rust") + (td :class "px-4 py-2 text-stone-400 italic" "(future host)"))))) + (p "Every translator is an SX program. The only Python left is the platform " + "interface (types, DOM primitives, runtime support functions) and the thin " + "runner script that loads " (code "py.sx") " or " (code "js.sx") + " and feeds it the spec files.")) + + ;; ----------------------------------------------------------------------- + ;; Implementation Plan + ;; ----------------------------------------------------------------------- + + (~doc-section :title "Implementation" :id "implementation" + + (~doc-subsection :title "Phase 1: Expression Translator" + (p "Core SX-to-JavaScript expression translation.") + (ul :class "list-disc pl-6 space-y-1 text-stone-700" + (li (code "js-mangle") " — SX name → JavaScript identifier (RENAMES + kebab→camelCase)") + (li (code "js-literal") " — atoms: numbers, strings, booleans, nil, symbols, keywords") + (li (code "js-expr") " — recursive expression translator") + (li "Ternary: " (code "if") ", " (code "when") ", " (code "cond") ", " (code "and") ", " (code "or")) + (li (code "let") " → IIFE: " (code "(function(a) { return body; })(val)")) + (li (code "fn") " → " (code "function(x) { return body; }")) + (li (code "str") " → " (code "sxStr(...)")) + (li "Infix: " (code "+") ", " (code "-") ", " (code "*") ", " (code "/") ", " + (code "===") ", " (code "!==") ", " (code "%")) + (li (code "&rest") " → " (code "...args") " (rest parameters)"))) + + (~doc-subsection :title "Phase 2: Statement Translator" + (p "Top-level and function body statement emission.") + (ul :class "list-disc pl-6 space-y-1 text-stone-700" + (li (code "js-statement") " — emit as JavaScript statement") + (li (code "define") " → " (code "var name = expr;")) + (li (code "set!") " → direct assignment (closures capture by reference)") + (li (code "for-each") " → " (code "for (var i = 0; i < arr.length; i++)") " loop") + (li (code "do") "/" (code "begin") " → comma expression or block") + (li "Function bodies with multiple expressions → explicit " (code "return")))) + + (~doc-subsection :title "Phase 3: Spec Bootstrapper" + (p "Process spec files identically to " (code "bootstrap_js.py") ".") + (ul :class "list-disc pl-6 space-y-1 text-stone-700" + (li (code "js-extract-defines") " — parse .sx source, collect top-level defines") + (li (code "js-translate-file") " — translate a list of define expressions") + (li "Adapter selection: parser, html, sx, dom, engine, orchestration, boot") + (li "Dependency resolution: engine requires dom, boot requires engine + parser") + (li "Static sections (IIFE wrapper, platform interface) stay as string templates"))) + + (~doc-subsection :title "Phase 4: Component Compiler" + (p "Ahead-of-time compilation of evaluated SX trees to JavaScript.") + (ul :class "list-disc pl-6 space-y-1 text-stone-700" + (li (code "js-compile-element") " — emit " (code "createElement") " + attribute setting") + (li (code "js-compile-text") " — emit " (code "textContent") " or " (code "createTextNode")) + (li (code "js-compile-component") " — inline-expand or emit component call") + (li (code "js-compile-island") " — emit signal creation + reactive DOM subscriptions") + (li (code "js-compile-fragment") " — emit " (code "DocumentFragment") " construction") + (li "Runtime slicing: analyze tree → include only necessary runtime modules"))) + + (~doc-subsection :title "Phase 5: Verification" + (~doc-code :code (highlight "# Mode 1: spec bootstrapper parity +python bootstrap_js.py > sx-ref-g0.js +python run_js_sx.py > sx-ref-g1.js +diff sx-ref-g0.js sx-ref-g1.js # must be empty + +# Mode 2: component compilation correctness +# Server renders page → SX tree → compile to JS +# Compare DOM output: runtime-rendered vs compiled +python test_js_compile.py # renders both, diffs DOM" "bash"))) + + ;; ----------------------------------------------------------------------- + ;; Comparison with py.sx + ;; ----------------------------------------------------------------------- + + (~doc-section :title "Comparison with py.sx" :id "comparison" + (div :class "overflow-x-auto rounded border border-stone-200 my-4" + (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" "Concern") + (th :class "px-4 py-2 text-left font-semibold text-stone-700" (code "py.sx")) + (th :class "px-4 py-2 text-left font-semibold text-stone-700" (code "js.sx")))) + (tbody + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2" "Naming convention") + (td :class "px-4 py-2" "snake_case") + (td :class "px-4 py-2" "camelCase")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2" "Closures & mutation") + (td :class "px-4 py-2" "Cell variable hack") + (td :class "px-4 py-2" "Direct (reference capture)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2" "Spec modules") + (td :class "px-4 py-2" "eval, render, html, sx, deps, signals") + (td :class "px-4 py-2" "All 12 modules")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2" "Platform interface") + (td :class "px-4 py-2" "~300 lines") + (td :class "px-4 py-2" "~1500 lines (DOM, browser APIs)")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2" "RENAMES table") + (td :class "px-4 py-2" "~200 entries") + (td :class "px-4 py-2" "~350 entries")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2" "Component compilation") + (td :class "px-4 py-2 text-stone-400" "N/A") + (td :class "px-4 py-2" "Ahead-of-time DOM compiler")) + (tr :class "border-t border-stone-100" + (td :class "px-4 py-2" "Estimated size") + (td :class "px-4 py-2" "~800-1000 lines") + (td :class "px-4 py-2" "~1200-1500 lines")))))) + + ;; ----------------------------------------------------------------------- + ;; Implications + ;; ----------------------------------------------------------------------- + + (~doc-section :title "Implications" :id "implications" + (~doc-subsection :title "Zero-Runtime Static Sites" + (p "A static page written in SX compiles to a JavaScript program with " + "no SX runtime dependency. The output is just DOM API calls — " + (code "createElement") ", " (code "appendChild") ", " (code "textContent") + ". This gives SX a compilation target competitive with Svelte's " + "approach: components compile away, the framework disappears.") + (p "Combined with the " (a :href "/plans/content-addressed-components" "content-addressed components") + " plan, a page's compiled JS could be stored on IPFS by its content hash. " + "The server returns a CID. The browser fetches and executes pre-compiled JavaScript. " + "No parser, no evaluator, no network round-trip for component definitions.")) + + (~doc-subsection :title "Progressive Enhancement Layers" + (p "The component compiler naturally supports progressive enhancement:") + (ol :class "list-decimal pl-6 space-y-1 text-stone-700" + (li (strong "HTML") " — server renders to HTML string. No JS needed. Works everywhere.") + (li (strong "Compiled JS") " — server compiles to DOM construction code. " + "Event handlers work. No SX runtime. Kilobytes, not megabytes.") + (li (strong "SX runtime") " — full evaluator + engine. Client-side routing, " + "component caching, reactive islands. The current architecture.") + (li (strong "SX + signals") " — full reactive islands. Fine-grained DOM updates.")) + (p "Each layer adds capability and weight. The right layer depends on the page. " + "A blog post needs layer 1. An interactive form needs layer 2. " + "A single-page app needs layer 3. A real-time dashboard needs layer 4. " + (code "js.sx") " makes layer 2 possible — it didn't exist before.")) + + (~doc-subsection :title "The Bootstrap Completion" + (p "With " (code "py.sx") " and " (code "js.sx") " both written in SX:") + (ul :class "list-disc pl-6 space-y-2 text-stone-700" + (li "The " (em "spec") " defines SX semantics (" (code "eval.sx") ", " (code "render.sx") ", ...)") + (li "The " (em "translators") " convert the spec to host languages (" (code "py.sx") ", " (code "js.sx") ")") + (li "The " (em "prover") " verifies the spec's properties (" (code "z3.sx") ", " (code "prove.sx") ")") + (li "All four are written " (em "in") " SX, executable " (em "by") " any SX evaluator")) + (p "The language defines itself, verifies itself, and compiles itself. " + "The Python and JavaScript \"bootstrappers\" are not programs that produce SX — " + "they are SX programs that produce Python and JavaScript. " + "The arrow points the other way.")))))) diff --git a/sx/sxc/pages/docs.sx b/sx/sxc/pages/docs.sx index 01d6aa3..2e96405 100644 --- a/sx/sxc/pages/docs.sx +++ b/sx/sxc/pages/docs.sx @@ -635,6 +635,7 @@ "reader-macro-demo" (~plan-reader-macro-demo-content) "theorem-prover" (~plan-theorem-prover-content) "self-hosting-bootstrapper" (~plan-self-hosting-bootstrapper-content) + "js-bootstrapper" (~plan-js-bootstrapper-content) "sx-activity" (~plan-sx-activity-content) "predictive-prefetch" (~plan-predictive-prefetch-content) "content-addressed-components" (~plan-content-addressed-components-content)