From f7e4e3d762b61764d4a9424003df8decf9440a8a Mon Sep 17 00:00:00 2001 From: giles Date: Mon, 16 Mar 2026 09:45:48 +0000 Subject: [PATCH] Rebuild sx-browser.js and OCaml sx_ref.ml Regenerated from refactored spec: stdlib.sx library functions, evaluator decoupling, host FFI primitives. Co-Authored-By: Claude Opus 4.6 (1M context) --- shared/static/scripts/sx-browser.js | 560 ++++++++++++++++++++++++---- 1 file changed, 482 insertions(+), 78 deletions(-) diff --git a/shared/static/scripts/sx-browser.js b/shared/static/scripts/sx-browser.js index ee8c433..93f8d5b 100644 --- a/shared/static/scripts/sx-browser.js +++ b/shared/static/scripts/sx-browser.js @@ -14,7 +14,7 @@ // ========================================================================= var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } }); - var SX_VERSION = "2026-03-15T17:07:09Z"; + var SX_VERSION = "2026-03-16T09:43:09Z"; function isNil(x) { return x === NIL || x === null || x === undefined; } function isSxTruthy(x) { return x !== false && !isNil(x); } @@ -581,10 +581,7 @@ var dict_fn = PRIMITIVES["dict"]; // HTML rendering helpers - function escapeHtml(s) { - return String(s).replace(/&/g,"&").replace(//g,">").replace(/"/g,"""); - } - function escapeAttr(s) { return escapeHtml(s); } + // escape-html and escape-attr are now library functions defined in render.sx function rawHtmlContent(r) { return r.html; } function makeRawHtml(s) { return { _raw: true, html: s }; } function sxExprSource(x) { return x && x.source ? x.source : String(x); } @@ -594,11 +591,93 @@ function isSpecialForm(n) { return false; } function isHoForm(n) { return false; } + // ----------------------------------------------------------------------- + // Host FFI — the irreducible web platform primitives + // All DOM/browser operations are built on these in web/lib/dom.sx + // ----------------------------------------------------------------------- + PRIMITIVES["host-global"] = function(name) { + if (typeof globalThis !== "undefined" && name in globalThis) return globalThis[name]; + if (typeof window !== "undefined" && name in window) return window[name]; + return NIL; + }; + PRIMITIVES["host-get"] = function(obj, prop) { + if (obj == null || obj === NIL) return NIL; + var v = obj[prop]; + return v === undefined || v === null ? NIL : v; + }; + PRIMITIVES["host-set!"] = function(obj, prop, val) { + if (obj != null && obj !== NIL) obj[prop] = val === NIL ? null : val; + }; + PRIMITIVES["host-call"] = function() { + var obj = arguments[0], method = arguments[1]; + var args = []; + for (var i = 2; i < arguments.length; i++) { + var a = arguments[i]; + args.push(a === NIL ? null : a); + } + if (obj == null || obj === NIL) { + // Global function call + var fn = typeof globalThis !== "undefined" ? globalThis[method] : window[method]; + if (typeof fn === "function") return fn.apply(null, args); + return NIL; + } + if (typeof obj[method] === "function") { + try { return obj[method].apply(obj, args); } + catch(e) { return NIL; } + } + return NIL; + }; + PRIMITIVES["host-new"] = function() { + var name = arguments[0]; + var args = Array.prototype.slice.call(arguments, 1).map(function(a) { return a === NIL ? null : a; }); + var Ctor = typeof globalThis !== "undefined" ? globalThis[name] : window[name]; + if (typeof Ctor !== "function") return NIL; + // Support 0-4 args (covers all practical cases) + switch (args.length) { + case 0: return new Ctor(); + case 1: return new Ctor(args[0]); + case 2: return new Ctor(args[0], args[1]); + case 3: return new Ctor(args[0], args[1], args[2]); + default: return new Ctor(args[0], args[1], args[2], args[3]); + } + }; + PRIMITIVES["host-callback"] = function(fn) { + // Wrap SX function/lambda as a native JS callback + if (typeof fn === "function") return fn; + if (fn && fn._type === "lambda") { + return function() { + var a = Array.prototype.slice.call(arguments); + return cekCall(fn, a); + }; + } + return function() {}; + }; + PRIMITIVES["host-typeof"] = function(obj) { + if (obj == null || obj === NIL) return "nil"; + if (obj instanceof Element) return "element"; + if (obj instanceof Text) return "text"; + if (obj instanceof DocumentFragment) return "fragment"; + if (obj instanceof Document) return "document"; + if (obj instanceof Event) return "event"; + if (obj instanceof Promise) return "promise"; + if (obj instanceof AbortController) return "abort-controller"; + return typeof obj; + }; + PRIMITIVES["host-await"] = function(promise, callback) { + if (promise && typeof promise.then === "function") { + var cb = typeof callback === "function" ? callback : + (callback && callback._type === "lambda") ? + function(v) { return cekCall(callback, [v]); } : function() {}; + promise.then(cb); + } + }; + // processBindings and evalCond — now specced in render.sx, bootstrapped above function isDefinitionForm(name) { return name === "define" || name === "defcomp" || name === "defmacro" || - name === "defstyle" || name === "defhandler"; + name === "defstyle" || name === "defhandler" || + name === "deftype" || name === "defeffect"; } function indexOf_(s, ch) { @@ -1009,6 +1088,22 @@ PRIMITIVES["scan"] = scan; return scan(kont, []); }; PRIMITIVES["kont-capture-to-reactive-reset"] = kontCaptureToReactiveReset; + // *custom-special-forms* + var _customSpecialForms = {}; +PRIMITIVES["*custom-special-forms*"] = _customSpecialForms; + + // register-special-form! + var registerSpecialForm = function(name, handler) { return dictSet(_customSpecialForms, name, handler); }; +PRIMITIVES["register-special-form!"] = registerSpecialForm; + + // *render-check* + var _renderCheck = NIL; +PRIMITIVES["*render-check*"] = _renderCheck; + + // *render-fn* + var _renderFn = NIL; +PRIMITIVES["*render-fn*"] = _renderFn; + // trampoline var trampoline = function(val) { return (function() { var result = val; @@ -1107,6 +1202,10 @@ PRIMITIVES["parse-keyword-args"] = parseKeywordArgs; var condScheme_p = function(clauses) { return isEvery(function(c) { return (isSxTruthy((typeOf(c) == "list")) && (len(c) == 2)); }, clauses); }; PRIMITIVES["cond-scheme?"] = condScheme_p; + // is-else-clause? + var isElseClause = function(test) { return sxOr((isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")), (isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else")))); }; +PRIMITIVES["is-else-clause?"] = isElseClause; + // sf-named-let var sfNamedLet = function(args, env) { return (function() { var loopName = symbolName(first(args)); @@ -1247,58 +1346,6 @@ PRIMITIVES["sf-defmacro"] = sfDefmacro; })(); }; PRIMITIVES["parse-macro-params"] = parseMacroParams; - // sf-defstyle - var sfDefstyle = function(args, env) { return (function() { - var nameSym = first(args); - var value = trampoline(evalExpr(nth(args, 1), env)); - envBind(env, symbolName(nameSym), value); - return value; -})(); }; -PRIMITIVES["sf-defstyle"] = sfDefstyle; - - // make-type-def - var makeTypeDef = function(name, params, body) { return {"name": name, "params": params, "body": body}; }; -PRIMITIVES["make-type-def"] = makeTypeDef; - - // normalize-type-body - var normalizeTypeBody = function(body) { return (isSxTruthy(isNil(body)) ? "nil" : (isSxTruthy((typeOf(body) == "symbol")) ? symbolName(body) : (isSxTruthy((typeOf(body) == "string")) ? body : (isSxTruthy((typeOf(body) == "keyword")) ? keywordName(body) : (isSxTruthy((typeOf(body) == "dict")) ? mapDict(function(k, v) { return normalizeTypeBody(v); }, body) : (isSxTruthy((typeOf(body) == "list")) ? (isSxTruthy(isEmpty(body)) ? "any" : (function() { - var head = first(body); - return (function() { - var headName = (isSxTruthy((typeOf(head) == "symbol")) ? symbolName(head) : (String(head))); - return (isSxTruthy((headName == "union")) ? cons("or", map(normalizeTypeBody, rest(body))) : cons(headName, map(normalizeTypeBody, rest(body)))); -})(); -})()) : (String(body)))))))); }; -PRIMITIVES["normalize-type-body"] = normalizeTypeBody; - - // sf-deftype - var sfDeftype = function(args, env) { return (function() { - var nameOrForm = first(args); - var bodyExpr = nth(args, 1); - var typeName = NIL; - var typeParams = []; - (isSxTruthy((typeOf(nameOrForm) == "symbol")) ? (typeName = symbolName(nameOrForm)) : (isSxTruthy((typeOf(nameOrForm) == "list")) ? ((typeName = symbolName(first(nameOrForm))), (typeParams = map(function(p) { return (isSxTruthy((typeOf(p) == "symbol")) ? symbolName(p) : (String(p))); }, rest(nameOrForm)))) : NIL)); - return (function() { - var body = normalizeTypeBody(bodyExpr); - var registry = (isSxTruthy(envHas(env, "*type-registry*")) ? envGet(env, "*type-registry*") : {}); - registry[typeName] = makeTypeDef(typeName, typeParams, body); - envBind(env, "*type-registry*", registry); - return NIL; -})(); -})(); }; -PRIMITIVES["sf-deftype"] = sfDeftype; - - // sf-defeffect - var sfDefeffect = function(args, env) { return (function() { - var effectName = (isSxTruthy((typeOf(first(args)) == "symbol")) ? symbolName(first(args)) : (String(first(args)))); - var registry = (isSxTruthy(envHas(env, "*effect-registry*")) ? envGet(env, "*effect-registry*") : []); - if (isSxTruthy(!isSxTruthy(contains(registry, effectName)))) { - registry.push(effectName); -} - envBind(env, "*effect-registry*", registry); - return NIL; -})(); }; -PRIMITIVES["sf-defeffect"] = sfDefeffect; - // qq-expand var qqExpand = function(template, env) { return (isSxTruthy(!isSxTruthy((typeOf(template) == "list"))) ? template : (isSxTruthy(isEmpty(template)) ? [] : (function() { var head = first(template); @@ -1425,10 +1472,10 @@ PRIMITIVES["step-eval"] = stepEval; var args = rest(expr); return (isSxTruthy(!isSxTruthy(sxOr((typeOf(head) == "symbol"), (typeOf(head) == "lambda"), (typeOf(head) == "list")))) ? (isSxTruthy(isEmpty(expr)) ? makeCekValue([], env, kont) : makeCekState(first(expr), env, kontPush(makeMapFrame(NIL, rest(expr), [], env), kont))) : (isSxTruthy((typeOf(head) == "symbol")) ? (function() { var name = symbolName(head); - return (isSxTruthy((name == "if")) ? stepSfIf(args, env, kont) : (isSxTruthy((name == "when")) ? stepSfWhen(args, env, kont) : (isSxTruthy((name == "cond")) ? stepSfCond(args, env, kont) : (isSxTruthy((name == "case")) ? stepSfCase(args, env, kont) : (isSxTruthy((name == "and")) ? stepSfAnd(args, env, kont) : (isSxTruthy((name == "or")) ? stepSfOr(args, env, kont) : (isSxTruthy((name == "let")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "let*")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "lambda")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "fn")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "define")) ? stepSfDefine(args, env, kont) : (isSxTruthy((name == "defcomp")) ? makeCekValue(sfDefcomp(args, env), env, kont) : (isSxTruthy((name == "defisland")) ? makeCekValue(sfDefisland(args, env), env, kont) : (isSxTruthy((name == "defmacro")) ? makeCekValue(sfDefmacro(args, env), env, kont) : (isSxTruthy((name == "defstyle")) ? makeCekValue(sfDefstyle(args, env), env, kont) : (isSxTruthy((name == "defhandler")) ? makeCekValue(sfDefhandler(args, env), env, kont) : (isSxTruthy((name == "defpage")) ? makeCekValue(sfDefpage(args, env), env, kont) : (isSxTruthy((name == "defquery")) ? makeCekValue(sfDefquery(args, env), env, kont) : (isSxTruthy((name == "defaction")) ? makeCekValue(sfDefaction(args, env), env, kont) : (isSxTruthy((name == "deftype")) ? makeCekValue(sfDeftype(args, env), env, kont) : (isSxTruthy((name == "defeffect")) ? makeCekValue(sfDefeffect(args, env), env, kont) : (isSxTruthy((name == "begin")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "do")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "quote")) ? makeCekValue((isSxTruthy(isEmpty(args)) ? NIL : first(args)), env, kont) : (isSxTruthy((name == "quasiquote")) ? makeCekValue(qqExpand(first(args), env), env, kont) : (isSxTruthy((name == "->")) ? stepSfThreadFirst(args, env, kont) : (isSxTruthy((name == "set!")) ? stepSfSet(args, env, kont) : (isSxTruthy((name == "letrec")) ? makeCekValue(sfLetrec(args, env), env, kont) : (isSxTruthy((name == "reset")) ? stepSfReset(args, env, kont) : (isSxTruthy((name == "shift")) ? stepSfShift(args, env, kont) : (isSxTruthy((name == "deref")) ? stepSfDeref(args, env, kont) : (isSxTruthy((name == "scope")) ? stepSfScope(args, env, kont) : (isSxTruthy((name == "provide")) ? stepSfProvide(args, env, kont) : (isSxTruthy((name == "context")) ? stepSfContext(args, env, kont) : (isSxTruthy((name == "emit!")) ? stepSfEmit(args, env, kont) : (isSxTruthy((name == "emitted")) ? stepSfEmitted(args, env, kont) : (isSxTruthy((name == "dynamic-wind")) ? makeCekValue(sfDynamicWind(args, env), env, kont) : (isSxTruthy((name == "map")) ? stepHoMap(args, env, kont) : (isSxTruthy((name == "map-indexed")) ? stepHoMapIndexed(args, env, kont) : (isSxTruthy((name == "filter")) ? stepHoFilter(args, env, kont) : (isSxTruthy((name == "reduce")) ? stepHoReduce(args, env, kont) : (isSxTruthy((name == "some")) ? stepHoSome(args, env, kont) : (isSxTruthy((name == "every?")) ? stepHoEvery(args, env, kont) : (isSxTruthy((name == "for-each")) ? stepHoForEach(args, env, kont) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? (function() { + return (isSxTruthy((name == "if")) ? stepSfIf(args, env, kont) : (isSxTruthy((name == "when")) ? stepSfWhen(args, env, kont) : (isSxTruthy((name == "cond")) ? stepSfCond(args, env, kont) : (isSxTruthy((name == "case")) ? stepSfCase(args, env, kont) : (isSxTruthy((name == "and")) ? stepSfAnd(args, env, kont) : (isSxTruthy((name == "or")) ? stepSfOr(args, env, kont) : (isSxTruthy((name == "let")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "let*")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "lambda")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "fn")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "define")) ? stepSfDefine(args, env, kont) : (isSxTruthy((name == "defcomp")) ? makeCekValue(sfDefcomp(args, env), env, kont) : (isSxTruthy((name == "defisland")) ? makeCekValue(sfDefisland(args, env), env, kont) : (isSxTruthy((name == "defmacro")) ? makeCekValue(sfDefmacro(args, env), env, kont) : (isSxTruthy((name == "begin")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "do")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "quote")) ? makeCekValue((isSxTruthy(isEmpty(args)) ? NIL : first(args)), env, kont) : (isSxTruthy((name == "quasiquote")) ? makeCekValue(qqExpand(first(args), env), env, kont) : (isSxTruthy((name == "->")) ? stepSfThreadFirst(args, env, kont) : (isSxTruthy((name == "set!")) ? stepSfSet(args, env, kont) : (isSxTruthy((name == "letrec")) ? makeCekValue(sfLetrec(args, env), env, kont) : (isSxTruthy((name == "reset")) ? stepSfReset(args, env, kont) : (isSxTruthy((name == "shift")) ? stepSfShift(args, env, kont) : (isSxTruthy((name == "deref")) ? stepSfDeref(args, env, kont) : (isSxTruthy((name == "scope")) ? stepSfScope(args, env, kont) : (isSxTruthy((name == "provide")) ? stepSfProvide(args, env, kont) : (isSxTruthy((name == "context")) ? stepSfContext(args, env, kont) : (isSxTruthy((name == "emit!")) ? stepSfEmit(args, env, kont) : (isSxTruthy((name == "emitted")) ? stepSfEmitted(args, env, kont) : (isSxTruthy((name == "dynamic-wind")) ? makeCekValue(sfDynamicWind(args, env), env, kont) : (isSxTruthy((name == "map")) ? stepHoMap(args, env, kont) : (isSxTruthy((name == "map-indexed")) ? stepHoMapIndexed(args, env, kont) : (isSxTruthy((name == "filter")) ? stepHoFilter(args, env, kont) : (isSxTruthy((name == "reduce")) ? stepHoReduce(args, env, kont) : (isSxTruthy((name == "some")) ? stepHoSome(args, env, kont) : (isSxTruthy((name == "every?")) ? stepHoEvery(args, env, kont) : (isSxTruthy((name == "for-each")) ? stepHoForEach(args, env, kont) : (isSxTruthy(dictHas(_customSpecialForms, name)) ? makeCekValue([get(_customSpecialForms, name), args, env], env, kont) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? (function() { var mac = envGet(env, name); return makeCekState(expandMacro(mac, args, env), env, kont); -})() : (isSxTruthy((isSxTruthy(renderActiveP()) && isRenderExpr(expr))) ? makeCekValue(renderExpr(expr, env), env, kont) : stepEvalCall(head, args, env, kont))))))))))))))))))))))))))))))))))))))))))))))); +})() : (isSxTruthy((isSxTruthy(_renderCheck) && _renderCheck(expr, env))) ? makeCekValue(_renderFn(expr, env), env, kont) : stepEvalCall(head, args, env, kont))))))))))))))))))))))))))))))))))))))))); })() : stepEvalCall(head, args, env, kont))); })(); }; PRIMITIVES["step-eval-list"] = stepEvalList; @@ -1493,10 +1540,10 @@ PRIMITIVES["step-sf-or"] = stepSfOr; return (isSxTruthy(scheme_p) ? (isSxTruthy(isEmpty(args)) ? makeCekValue(NIL, env, kont) : (function() { var clause = first(args); var test = first(clause); - return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))), (isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")))) ? makeCekState(nth(clause, 1), env, kont) : makeCekState(test, env, kontPush(makeCondFrame(args, env, true), kont))); + return (isSxTruthy(isElseClause(test)) ? makeCekState(nth(clause, 1), env, kont) : makeCekState(test, env, kontPush(makeCondFrame(args, env, true), kont))); })()) : (isSxTruthy((len(args) < 2)) ? makeCekValue(NIL, env, kont) : (function() { var test = first(args); - return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")), (isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))))) ? makeCekState(nth(args, 1), env, kont) : makeCekState(test, env, kontPush(makeCondFrame(args, env, false), kont))); + return (isSxTruthy(isElseClause(test)) ? makeCekState(nth(args, 1), env, kont) : makeCekState(test, env, kontPush(makeCondFrame(args, env, false), kont))); })())); })(); }; PRIMITIVES["step-sf-cond"] = stepSfCond; @@ -1774,13 +1821,13 @@ PRIMITIVES["step-ho-for-each"] = stepHoForEach; return (isSxTruthy(isEmpty(nextClauses)) ? makeCekValue(NIL, fenv, restK) : (function() { var nextClause = first(nextClauses); var nextTest = first(nextClause); - return (isSxTruthy(sxOr((isSxTruthy((typeOf(nextTest) == "symbol")) && sxOr((symbolName(nextTest) == "else"), (symbolName(nextTest) == ":else"))), (isSxTruthy((typeOf(nextTest) == "keyword")) && (keywordName(nextTest) == "else")))) ? makeCekState(nth(nextClause, 1), fenv, restK) : makeCekState(nextTest, fenv, kontPush(makeCondFrame(nextClauses, fenv, true), restK))); + return (isSxTruthy(isElseClause(nextTest)) ? makeCekState(nth(nextClause, 1), fenv, restK) : makeCekState(nextTest, fenv, kontPush(makeCondFrame(nextClauses, fenv, true), restK))); })()); })()) : (isSxTruthy(value) ? makeCekState(nth(remaining, 1), fenv, restK) : (function() { var next = slice(remaining, 2); return (isSxTruthy((len(next) < 2)) ? makeCekValue(NIL, fenv, restK) : (function() { var nextTest = first(next); - return (isSxTruthy(sxOr((isSxTruthy((typeOf(nextTest) == "keyword")) && (keywordName(nextTest) == "else")), (isSxTruthy((typeOf(nextTest) == "symbol")) && sxOr((symbolName(nextTest) == "else"), (symbolName(nextTest) == ":else"))))) ? makeCekState(nth(next, 1), fenv, restK) : makeCekState(nextTest, fenv, kontPush(makeCondFrame(next, fenv, false), restK))); + return (isSxTruthy(isElseClause(nextTest)) ? makeCekState(nth(next, 1), fenv, restK) : makeCekState(nextTest, fenv, kontPush(makeCondFrame(next, fenv, false), restK))); })()); })())); })() : (isSxTruthy((ft == "case")) ? (function() { @@ -1957,7 +2004,7 @@ PRIMITIVES["continue-with-call"] = continueWithCall; var sfCaseStepLoop = function(matchVal, clauses, env, kont) { return (isSxTruthy((len(clauses) < 2)) ? makeCekValue(NIL, env, kont) : (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"))))) ? makeCekState(body, env, kont) : (function() { + return (isSxTruthy(isElseClause(test)) ? makeCekState(body, env, kont) : (function() { var testVal = trampoline(evalExpr(test, env)); return (isSxTruthy((matchVal == testVal)) ? makeCekState(body, env, kont) : sfCaseStepLoop(matchVal, slice(clauses, 2), env, kont)); })()); @@ -1972,6 +2019,353 @@ PRIMITIVES["eval-expr-cek"] = evalExprCek; var trampolineCek = function(val) { return (isSxTruthy(isThunk(val)) ? evalExprCek(thunkExpr(val), thunkEnv(val)) : val); }; PRIMITIVES["trampoline-cek"] = trampolineCek; + // eval-expr + var evalExpr = function(expr, env) { return cekRun(makeCekState(expr, env, [])); }; +PRIMITIVES["eval-expr"] = evalExpr; + + // trampoline + var trampoline = function(val) { return (isSxTruthy(isThunk(val)) ? evalExpr(thunkExpr(val), thunkEnv(val)) : val); }; +PRIMITIVES["trampoline"] = trampoline; + + + // === Transpiled from stdlib (library functions from former primitives) === + + // not + var not = function(x) { return (isSxTruthy(x) ? false : true); }; +PRIMITIVES["not"] = not; + + // != + var != = function(a, b) { return !isSxTruthy((a == b)); }; +PRIMITIVES["!="] = !=; + + // <= + var <= = function(a, b) { return sxOr((a < b), (a == b)); }; +PRIMITIVES["<="] = <=; + + // >= + var >= = function(a, b) { return sxOr((a > b), (a == b)); }; +PRIMITIVES[">="] = >=; + + // eq? + var eq_p = =; +PRIMITIVES["eq?"] = eq_p; + + // eqv? + var eqv_p = =; +PRIMITIVES["eqv?"] = eqv_p; + + // equal? + var equal_p = =; +PRIMITIVES["equal?"] = equal_p; + + // nil? + var isNil = function(x) { return (typeOf(x) == "nil"); }; +PRIMITIVES["nil?"] = isNil; + + // boolean? + var boolean_p = function(x) { return (typeOf(x) == "boolean"); }; +PRIMITIVES["boolean?"] = boolean_p; + + // number? + var isNumber = function(x) { return (typeOf(x) == "number"); }; +PRIMITIVES["number?"] = isNumber; + + // string? + var isString = function(x) { return (typeOf(x) == "string"); }; +PRIMITIVES["string?"] = isString; + + // list? + var isList = function(x) { return (typeOf(x) == "list"); }; +PRIMITIVES["list?"] = isList; + + // dict? + var isDict = function(x) { return (typeOf(x) == "dict"); }; +PRIMITIVES["dict?"] = isDict; + + // continuation? + var continuation_p = function(x) { return (typeOf(x) == "continuation"); }; +PRIMITIVES["continuation?"] = continuation_p; + + // zero? + var isZero = function(n) { return (n == 0); }; +PRIMITIVES["zero?"] = isZero; + + // odd? + var isOdd = function(n) { return ((n % 2) == 1); }; +PRIMITIVES["odd?"] = isOdd; + + // even? + var isEven = function(n) { return ((n % 2) == 0); }; +PRIMITIVES["even?"] = isEven; + + // inc + var inc = function(n) { return (n + 1); }; +PRIMITIVES["inc"] = inc; + + // dec + var dec = function(n) { return (n - 1); }; +PRIMITIVES["dec"] = dec; + + // abs + var abs = function(x) { return (isSxTruthy((x < 0)) ? (-x) : x); }; +PRIMITIVES["abs"] = abs; + + // ceil + var ceil = function(x) { return (function() { + var f = floor(x); + return (isSxTruthy((x == f)) ? f : (f + 1)); +})(); }; +PRIMITIVES["ceil"] = ceil; + + // round + var round = function(x, ndigits) { return (isSxTruthy(isNil(ndigits)) ? floor((x + 0.5)) : (function() { + var f = pow(10, ndigits); + return (floor(((x * f) + 0.5)) / f); +})()); }; +PRIMITIVES["round"] = round; + + // min + var min = function(a, b) { return (isSxTruthy((a < b)) ? a : b); }; +PRIMITIVES["min"] = min; + + // max + var max = function(a, b) { return (isSxTruthy((a > b)) ? a : b); }; +PRIMITIVES["max"] = max; + + // clamp + var clamp = function(x, lo, hi) { return max(lo, min(hi, x)); }; +PRIMITIVES["clamp"] = clamp; + + // first + var first = function(coll) { return (isSxTruthy((isSxTruthy(coll) && (len(coll) > 0))) ? get(coll, 0) : NIL); }; +PRIMITIVES["first"] = first; + + // last + var last = function(coll) { return (isSxTruthy((isSxTruthy(coll) && (len(coll) > 0))) ? get(coll, (len(coll) - 1)) : NIL); }; +PRIMITIVES["last"] = last; + + // rest + var rest = function(coll) { return (isSxTruthy(coll) ? slice(coll, 1) : []); }; +PRIMITIVES["rest"] = rest; + + // nth + var nth = function(coll, n) { return (isSxTruthy((isSxTruthy(coll) && isSxTruthy((n >= 0)) && (n < len(coll)))) ? get(coll, n) : NIL); }; +PRIMITIVES["nth"] = nth; + + // empty? + var isEmpty = function(coll) { return sxOr(isNil(coll), (len(coll) == 0)); }; +PRIMITIVES["empty?"] = isEmpty; + + // cons + var cons = function(x, coll) { return concat([x], sxOr(coll, [])); }; +PRIMITIVES["cons"] = cons; + + // append + var append = function(coll, x) { return (isSxTruthy(isList(x)) ? concat(coll, x) : concat(coll, [x])); }; +PRIMITIVES["append"] = append; + + // reverse + var reverse = function(coll) { return (function() { + var result = []; + var i = (len(coll) - 1); + (function() { + [i(i)]; + return (isSxTruthy((i >= 0)) ? (append_b(result, get(coll, i)), loop((i - 1))) : NIL); +})(); + return result; +})(); }; +PRIMITIVES["reverse"] = reverse; + + // flatten + var flatten = function(coll) { return (function() { + var result = []; + { var _c = coll; for (var _i = 0; _i < _c.length; _i++) { var x = _c[_i]; (isSxTruthy(isList(x)) ? forEach(function(y) { return append_b(result, y); }, x) : append_b(result, x)); } } + return result; +})(); }; +PRIMITIVES["flatten"] = flatten; + + // range + var range = function(start, end, step) { return (function() { + var s = (isSxTruthy(isNil(step)) ? 1 : step); + var result = []; + (function() { + [i(start)]; + return (isSxTruthy((i < end)) ? (append_b(result, i), loop((i + s))) : NIL); +})(); + return result; +})(); }; +PRIMITIVES["range"] = range; + + // chunk-every + var chunkEvery = function(coll, n) { return (function() { + var result = []; + var clen = len(coll); + (function() { + [i(0)]; + return (isSxTruthy((i < clen)) ? (append_b(result, slice(coll, i, min((i + n), clen))), loop((i + n))) : NIL); +})(); + return result; +})(); }; +PRIMITIVES["chunk-every"] = chunkEvery; + + // zip-pairs + var zipPairs = function(coll) { return (function() { + var result = []; + var clen = len(coll); + (function() { + [i(0)]; + return (isSxTruthy((i < (clen - 1))) ? (append_b(result, [get(coll, i), get(coll, (i + 1))]), loop((i + 1))) : NIL); +})(); + return result; +})(); }; +PRIMITIVES["zip-pairs"] = zipPairs; + + // vals + var vals = function(d) { return (function() { + var result = []; + { var _c = keys(d); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; result.push(get(d, k)); } } + return result; +})(); }; +PRIMITIVES["vals"] = vals; + + // has-key? + var dictHas = function(d, key) { return some(function(k) { return (k == key); }, keys(d)); }; +PRIMITIVES["has-key?"] = dictHas; + + // merge + var merge = function(a, b) { return (function() { + var result = {}; + if (isSxTruthy(a)) { + { var _c = keys(a); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; result[k] = get(a, k); } } +} + if (isSxTruthy(b)) { + { var _c = keys(b); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; result[k] = get(b, k); } } +} + return result; +})(); }; +PRIMITIVES["merge"] = merge; + + // assoc + var assoc = function(d, key, val) { return (function() { + var result = {}; + if (isSxTruthy(d)) { + { var _c = keys(d); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; result[k] = get(d, k); } } +} + result[key] = val; + return result; +})(); }; +PRIMITIVES["assoc"] = assoc; + + // dissoc + var dissoc = function(d, key) { return (function() { + var result = {}; + { var _c = keys(d); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; if (isSxTruthy((k != key))) { + result[k] = get(d, k); +} } } + return result; +})(); }; +PRIMITIVES["dissoc"] = dissoc; + + // into + var into = function(target, coll) { return (isSxTruthy(isList(target)) ? (isSxTruthy(isList(coll)) ? concat(coll, []) : (function() { + var result = []; + { var _c = keys(coll); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; result.push([k, get(coll, k)]); } } + return result; +})()) : (isSxTruthy(isDict(target)) ? (function() { + var result = {}; + { var _c = coll; for (var _i = 0; _i < _c.length; _i++) { var pair = _c[_i]; if (isSxTruthy((isSxTruthy(isList(pair)) && (len(pair) >= 2)))) { + result[get(pair, 0)] = get(pair, 1); +} } } + return result; +})() : target)); }; +PRIMITIVES["into"] = into; + + // upcase + var upcase = upper; +PRIMITIVES["upcase"] = upcase; + + // downcase + var downcase = lower; +PRIMITIVES["downcase"] = downcase; + + // string-length + var stringLength = function(s) { return len(s); }; +PRIMITIVES["string-length"] = stringLength; + + // substring + var substring = function(s, start, end) { return slice(s, start, end); }; +PRIMITIVES["substring"] = substring; + + // string-contains? + var stringContains_p = function(s, needle) { return (indexOf_(s, needle) != -1); }; +PRIMITIVES["string-contains?"] = stringContains_p; + + // starts-with? + var startsWith = function(s, prefix) { return (indexOf_(s, prefix) == 0); }; +PRIMITIVES["starts-with?"] = startsWith; + + // ends-with? + var endsWith = function(s, suffix) { return (function() { + var slen = len(s); + var plen = len(suffix); + return (isSxTruthy((slen < plen)) ? false : (slice(s, (slen - plen)) == suffix)); +})(); }; +PRIMITIVES["ends-with?"] = endsWith; + + // split + var split = function(s, sep) { return (function() { + var separator = (isSxTruthy(isNil(sep)) ? " " : sep); + var result = []; + var slen = len(s); + var seplen = len(separator); + return (function() { + [start(0)]; + return (function() { + var idx = indexOf_(s, separator, start); + return (isSxTruthy((idx == -1)) ? (append_b(result, slice(s, start)), result) : (append_b(result, slice(s, start, idx)), loop((idx + seplen)))); +})(); +})(); +})(); }; +PRIMITIVES["split"] = split; + + // join + var join = function(sep, coll) { return (function() { + var result = ""; + { var _c = coll; for (var _i = 0; _i < _c.length; _i++) { var x = _c[_i]; result = (isSxTruthy((result == "")) ? (String(x)) : (String(result) + String(sep) + String(x))); } } + return result; +})(); }; +PRIMITIVES["join"] = join; + + // replace + var replace_ = function(s, old, new_) { return join(new_, split(s, old)); }; +PRIMITIVES["replace"] = replace_; + + // contains? + var contains = function(coll, key) { return (isSxTruthy(isString(coll)) ? (indexOf_(coll, (String(key))) != -1) : (isSxTruthy(isDict(coll)) ? dictHas(coll, key) : (isSxTruthy(isList(coll)) ? some(function(x) { return (x == key); }, coll) : false))); }; +PRIMITIVES["contains?"] = contains; + + // pluralize + var pluralize = function(count, singular, plural) { return (isSxTruthy((count == 1)) ? sxOr(singular, "") : sxOr(plural, "s")); }; +PRIMITIVES["pluralize"] = pluralize; + + // escape + var escape = function(s) { return >((String(s)), replace_("&", "&"), replace_("<", "<"), replace_(">", ">"), replace_("\"", """), replace_("'", "'")); }; +PRIMITIVES["escape"] = escape; + + // parse-datetime + var parseDatetime = function(s) { return (isSxTruthy(s) ? (String(s)) : NIL); }; +PRIMITIVES["parse-datetime"] = parseDatetime; + + // assert + var assert = function(condition, message) { if (isSxTruthy(!isSxTruthy(condition))) { + error(sxOr(message, "Assertion failed")); +} +return true; }; +PRIMITIVES["assert"] = assert; + + + // === Transpiled from freeze (serializable state boundaries) === + // freeze-registry var freezeRegistry = {}; PRIMITIVES["freeze-registry"] = freezeRegistry; @@ -2039,6 +2433,9 @@ PRIMITIVES["freeze-to-sx"] = freezeToSx; })(); }; PRIMITIVES["thaw-from-sx"] = thawFromSx; + + // === Transpiled from content (content-addressed computation) === + // content-store var contentStore = {}; PRIMITIVES["content-store"] = contentStore; @@ -2077,14 +2474,6 @@ PRIMITIVES["freeze-to-cid"] = freezeToCid; })(); }; PRIMITIVES["thaw-from-cid"] = thawFromCid; - // eval-expr - var evalExpr = function(expr, env) { return cekRun(makeCekState(expr, env, [])); }; -PRIMITIVES["eval-expr"] = evalExpr; - - // trampoline - var trampoline = function(val) { return (isSxTruthy(isThunk(val)) ? evalExpr(thunkExpr(val), thunkEnv(val)) : val); }; -PRIMITIVES["trampoline"] = trampoline; - // === Transpiled from render (core) === @@ -2136,7 +2525,7 @@ PRIMITIVES["eval-cond"] = evalCond; 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))); + return (isSxTruthy(isElseClause(test)) ? body : (isSxTruthy(trampoline(evalExpr(test, env))) ? body : evalCondScheme(rest(clauses), env))); })()); }; PRIMITIVES["eval-cond-scheme"] = evalCondScheme; @@ -2144,7 +2533,7 @@ PRIMITIVES["eval-cond-scheme"] = evalCondScheme; 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))); + return (isSxTruthy(isElseClause(test)) ? body : (isSxTruthy(trampoline(evalExpr(test, env))) ? body : evalCondClojure(slice(clauses, 2), env))); })()); }; PRIMITIVES["eval-cond-clojure"] = evalCondClojure; @@ -2184,6 +2573,14 @@ PRIMITIVES["is-render-expr?"] = isRenderExpr; })(); }, keys(spreadDict)); }; PRIMITIVES["merge-spread-attrs"] = mergeSpreadAttrs; + // escape-html + var escapeHtml = function(s) { return >((String(s)), replace_("&", "&"), replace_("<", "<"), replace_(">", ">"), replace_("\"", """)); }; +PRIMITIVES["escape-html"] = escapeHtml; + + // escape-attr + var escapeAttr = function(s) { return escapeHtml(s); }; +PRIMITIVES["escape-attr"] = escapeAttr; + // === Transpiled from parser === @@ -5781,6 +6178,11 @@ PRIMITIVES["resource"] = resource; _renderExprFn = function(expr, env) { return renderToDom(expr, env, null); }; _renderMode = true; // Browser always evaluates in render context. + // Wire CEK render hooks — evaluator checks _renderCheck/_renderFn instead of + // the old renderActiveP()/isRenderExpr()/renderExpr() triple. + _renderCheck = function(expr, env) { return isRenderExpr(expr); }; + _renderFn = function(expr, env) { return renderToDom(expr, env, null); }; + var SVG_NS = "http://www.w3.org/2000/svg"; var MATH_NS = "http://www.w3.org/1998/Math/MathML"; @@ -7235,9 +7637,11 @@ PRIMITIVES["resource"] = resource; if (hname === "map-indexed") return asyncRenderMapIndexed(expr, env, ns); if (hname === "for-each") return asyncRenderMap(expr, env, ns); - // define/defcomp/defmacro — eval for side effects + // define/defcomp/defmacro and custom special forms — eval for side effects if (hname === "define" || hname === "defcomp" || hname === "defmacro" || - hname === "defstyle" || hname === "defhandler") { + hname === "defstyle" || hname === "defhandler" || + hname === "deftype" || hname === "defeffect" || + (typeof _customSpecialForms !== "undefined" && _customSpecialForms[hname])) { trampoline(evalExpr(expr, env)); return null; } @@ -7900,7 +8304,7 @@ PRIMITIVES["resource"] = resource; cekValue: cekValue, makeReactiveResetFrame: makeReactiveResetFrame, evalExpr: evalExpr, - _version: "ref-2.0 (boot+dom+engine+html+orchestration+parser+sx, bootstrap-compiled)" + _version: "ref-2.0 (boot+browser-lib+dom+dom-lib+engine+html+orchestration+parser+sx, bootstrap-compiled)" };