Merge branch 'worktree-api-urls' into macros
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
// =========================================================================
|
||||
|
||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||
var SX_VERSION = "2026-03-13T12:16:43Z";
|
||||
var SX_VERSION = "2026-03-13T15:35:20Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -180,8 +180,6 @@
|
||||
function sxEmit(name, value) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||||
_provideStacks[name][_provideStacks[name].length - 1].emitted.push(value);
|
||||
} else {
|
||||
throw new Error("No provider for emit!: " + name);
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
@@ -1523,10 +1521,10 @@ continue; } else { return NIL; } } };
|
||||
|
||||
// render-to-html
|
||||
var renderToHtml = function(expr, env) { setRenderActiveB(true);
|
||||
return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m == "string") return escapeHtml(expr); if (_m == "number") return (String(expr)); if (_m == "boolean") return (isSxTruthy(expr) ? "true" : "false"); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? "" : renderListToHtml(expr, env)); if (_m == "symbol") return renderValueToHtml(trampoline(evalExpr(expr, env)), env); if (_m == "keyword") return escapeHtml(keywordName(expr)); if (_m == "raw-html") return rawHtmlContent(expr); if (_m == "spread") return expr; return renderValueToHtml(trampoline(evalExpr(expr, env)), env); })(); };
|
||||
return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m == "string") return escapeHtml(expr); if (_m == "number") return (String(expr)); if (_m == "boolean") return (isSxTruthy(expr) ? "true" : "false"); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? "" : renderListToHtml(expr, env)); if (_m == "symbol") return renderValueToHtml(trampoline(evalExpr(expr, env)), env); if (_m == "keyword") return escapeHtml(keywordName(expr)); if (_m == "raw-html") return rawHtmlContent(expr); if (_m == "spread") return (sxEmit("element-attrs", spreadAttrs(expr)), ""); return renderValueToHtml(trampoline(evalExpr(expr, env)), env); })(); };
|
||||
|
||||
// render-value-to-html
|
||||
var renderValueToHtml = function(val, env) { return (function() { var _m = typeOf(val); if (_m == "nil") return ""; if (_m == "string") return escapeHtml(val); if (_m == "number") return (String(val)); if (_m == "boolean") return (isSxTruthy(val) ? "true" : "false"); if (_m == "list") return renderListToHtml(val, env); if (_m == "raw-html") return rawHtmlContent(val); if (_m == "spread") return val; return escapeHtml((String(val))); })(); };
|
||||
var renderValueToHtml = function(val, env) { return (function() { var _m = typeOf(val); if (_m == "nil") return ""; if (_m == "string") return escapeHtml(val); if (_m == "number") return (String(val)); if (_m == "boolean") return (isSxTruthy(val) ? "true" : "false"); if (_m == "list") return renderListToHtml(val, env); if (_m == "raw-html") return rawHtmlContent(val); if (_m == "spread") return (sxEmit("element-attrs", spreadAttrs(val)), ""); return escapeHtml((String(val))); })(); };
|
||||
|
||||
// RENDER_HTML_FORMS
|
||||
var RENDER_HTML_FORMS = ["if", "when", "cond", "case", "let", "let*", "begin", "do", "define", "defcomp", "defisland", "defmacro", "defstyle", "defhandler", "deftype", "defeffect", "map", "map-indexed", "filter", "for-each", "provide"];
|
||||
@@ -1537,10 +1535,10 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m =
|
||||
// render-list-to-html
|
||||
var renderListToHtml = function(expr, env) { return (isSxTruthy(isEmpty(expr)) ? "" : (function() {
|
||||
var head = first(expr);
|
||||
return (isSxTruthy(!isSxTruthy((typeOf(head) == "symbol"))) ? join("", filter(function(x) { return !isSxTruthy(isSpread(x)); }, map(function(x) { return renderValueToHtml(x, env); }, expr))) : (function() {
|
||||
return (isSxTruthy(!isSxTruthy((typeOf(head) == "symbol"))) ? join("", map(function(x) { return renderValueToHtml(x, env); }, expr)) : (function() {
|
||||
var name = symbolName(head);
|
||||
var args = rest(expr);
|
||||
return (isSxTruthy((name == "<>")) ? join("", filter(function(x) { return !isSxTruthy(isSpread(x)); }, map(function(x) { return renderToHtml(x, env); }, args))) : (isSxTruthy((name == "raw!")) ? join("", map(function(x) { return (String(trampoline(evalExpr(x, env)))); }, args)) : (isSxTruthy((name == "lake")) ? renderHtmlLake(args, env) : (isSxTruthy((name == "marsh")) ? renderHtmlMarsh(args, env) : (isSxTruthy(contains(HTML_TAGS, name)) ? renderHtmlElement(name, args, env) : (isSxTruthy((isSxTruthy(startsWith(name, "~")) && isSxTruthy(envHas(env, name)) && isIsland(envGet(env, name)))) ? renderHtmlIsland(envGet(env, name), args, env) : (isSxTruthy(startsWith(name, "~")) ? (function() {
|
||||
return (isSxTruthy((name == "<>")) ? join("", map(function(x) { return renderToHtml(x, env); }, args)) : (isSxTruthy((name == "raw!")) ? join("", map(function(x) { return (String(trampoline(evalExpr(x, env)))); }, args)) : (isSxTruthy((name == "lake")) ? renderHtmlLake(args, env) : (isSxTruthy((name == "marsh")) ? renderHtmlMarsh(args, env) : (isSxTruthy(contains(HTML_TAGS, name)) ? renderHtmlElement(name, args, env) : (isSxTruthy((isSxTruthy(startsWith(name, "~")) && isSxTruthy(envHas(env, name)) && isIsland(envGet(env, name)))) ? renderHtmlIsland(envGet(env, name), args, env) : (isSxTruthy(startsWith(name, "~")) ? (function() {
|
||||
var val = envGet(env, name);
|
||||
return (isSxTruthy(isComponent(val)) ? renderHtmlComponent(val, args, env) : (isSxTruthy(isMacro(val)) ? renderToHtml(expandMacro(val, args, env), env) : error((String("Unknown component: ") + String(name)))));
|
||||
})() : (isSxTruthy(isRenderHtmlForm(name)) ? dispatchHtmlForm(name, expr, env) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? renderToHtml(expandMacro(envGet(env, name), args, env), env) : renderValueToHtml(trampoline(evalExpr(expr, env)), env))))))))));
|
||||
@@ -1551,33 +1549,24 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m =
|
||||
var dispatchHtmlForm = function(name, expr, env) { return (isSxTruthy((name == "if")) ? (function() {
|
||||
var condVal = trampoline(evalExpr(nth(expr, 1), env));
|
||||
return (isSxTruthy(condVal) ? renderToHtml(nth(expr, 2), env) : (isSxTruthy((len(expr) > 3)) ? renderToHtml(nth(expr, 3), env) : ""));
|
||||
})() : (isSxTruthy((name == "when")) ? (isSxTruthy(!isSxTruthy(trampoline(evalExpr(nth(expr, 1), env)))) ? "" : (isSxTruthy((len(expr) == 3)) ? renderToHtml(nth(expr, 2), env) : (function() {
|
||||
var results = map(function(i) { return renderToHtml(nth(expr, i), env); }, range(2, len(expr)));
|
||||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, results));
|
||||
})())) : (isSxTruthy((name == "cond")) ? (function() {
|
||||
})() : (isSxTruthy((name == "when")) ? (isSxTruthy(!isSxTruthy(trampoline(evalExpr(nth(expr, 1), env)))) ? "" : (isSxTruthy((len(expr) == 3)) ? renderToHtml(nth(expr, 2), env) : join("", map(function(i) { return renderToHtml(nth(expr, i), env); }, range(2, len(expr)))))) : (isSxTruthy((name == "cond")) ? (function() {
|
||||
var branch = evalCond(rest(expr), env);
|
||||
return (isSxTruthy(branch) ? renderToHtml(branch, env) : "");
|
||||
})() : (isSxTruthy((name == "case")) ? renderToHtml(trampoline(evalExpr(expr, env)), env) : (isSxTruthy(sxOr((name == "let"), (name == "let*"))) ? (function() {
|
||||
var local = processBindings(nth(expr, 1), env);
|
||||
return (isSxTruthy((len(expr) == 3)) ? renderToHtml(nth(expr, 2), local) : (function() {
|
||||
var results = map(function(i) { return renderToHtml(nth(expr, i), local); }, range(2, len(expr)));
|
||||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, results));
|
||||
})());
|
||||
})() : (isSxTruthy(sxOr((name == "begin"), (name == "do"))) ? (isSxTruthy((len(expr) == 2)) ? renderToHtml(nth(expr, 1), env) : (function() {
|
||||
var results = map(function(i) { return renderToHtml(nth(expr, i), env); }, range(1, len(expr)));
|
||||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, results));
|
||||
})()) : (isSxTruthy(isDefinitionForm(name)) ? (trampoline(evalExpr(expr, env)), "") : (isSxTruthy((name == "map")) ? (function() {
|
||||
return (isSxTruthy((len(expr) == 3)) ? renderToHtml(nth(expr, 2), local) : join("", map(function(i) { return renderToHtml(nth(expr, i), local); }, range(2, len(expr)))));
|
||||
})() : (isSxTruthy(sxOr((name == "begin"), (name == "do"))) ? (isSxTruthy((len(expr) == 2)) ? renderToHtml(nth(expr, 1), env) : join("", map(function(i) { return renderToHtml(nth(expr, i), env); }, range(1, len(expr))))) : (isSxTruthy(isDefinitionForm(name)) ? (trampoline(evalExpr(expr, env)), "") : (isSxTruthy((name == "map")) ? (function() {
|
||||
var f = trampoline(evalExpr(nth(expr, 1), env));
|
||||
var coll = trampoline(evalExpr(nth(expr, 2), env));
|
||||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, map(function(item) { return (isSxTruthy(isLambda(f)) ? renderLambdaHtml(f, [item], env) : renderToHtml(apply(f, [item]), env)); }, coll)));
|
||||
return join("", map(function(item) { return (isSxTruthy(isLambda(f)) ? renderLambdaHtml(f, [item], env) : renderToHtml(apply(f, [item]), env)); }, coll));
|
||||
})() : (isSxTruthy((name == "map-indexed")) ? (function() {
|
||||
var f = trampoline(evalExpr(nth(expr, 1), env));
|
||||
var coll = trampoline(evalExpr(nth(expr, 2), env));
|
||||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, mapIndexed(function(i, item) { return (isSxTruthy(isLambda(f)) ? renderLambdaHtml(f, [i, item], env) : renderToHtml(apply(f, [i, item]), env)); }, coll)));
|
||||
return join("", mapIndexed(function(i, item) { return (isSxTruthy(isLambda(f)) ? renderLambdaHtml(f, [i, item], env) : renderToHtml(apply(f, [i, item]), env)); }, coll));
|
||||
})() : (isSxTruthy((name == "filter")) ? renderToHtml(trampoline(evalExpr(expr, env)), env) : (isSxTruthy((name == "for-each")) ? (function() {
|
||||
var f = trampoline(evalExpr(nth(expr, 1), env));
|
||||
var coll = trampoline(evalExpr(nth(expr, 2), env));
|
||||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, map(function(item) { return (isSxTruthy(isLambda(f)) ? renderLambdaHtml(f, [item], env) : renderToHtml(apply(f, [item]), env)); }, coll)));
|
||||
return join("", map(function(item) { return (isSxTruthy(isLambda(f)) ? renderLambdaHtml(f, [item], env) : renderToHtml(apply(f, [item]), env)); }, coll));
|
||||
})() : (isSxTruthy((name == "provide")) ? (function() {
|
||||
var provName = trampoline(evalExpr(nth(expr, 1), env));
|
||||
var provVal = trampoline(evalExpr(nth(expr, 2), env));
|
||||
@@ -1585,7 +1574,7 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m =
|
||||
var bodyCount = (len(expr) - 3);
|
||||
providePush(provName, provVal);
|
||||
return (function() {
|
||||
var result = (isSxTruthy((bodyCount == 1)) ? renderToHtml(nth(expr, bodyStart), env) : join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, map(function(i) { return renderToHtml(nth(expr, i), env); }, range(bodyStart, (bodyStart + bodyCount))))));
|
||||
var result = (isSxTruthy((bodyCount == 1)) ? renderToHtml(nth(expr, bodyStart), env) : join("", map(function(i) { return renderToHtml(nth(expr, i), env); }, range(bodyStart, (bodyStart + bodyCount)))));
|
||||
providePop(provName);
|
||||
return result;
|
||||
})();
|
||||
@@ -1614,14 +1603,7 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m =
|
||||
var local = envMerge(componentClosure(comp), env);
|
||||
{ var _c = componentParams(comp); for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; envSet(local, p, (isSxTruthy(dictHas(kwargs, p)) ? dictGet(kwargs, p) : NIL)); } }
|
||||
if (isSxTruthy(componentHasChildren(comp))) {
|
||||
(function() {
|
||||
var parts = [];
|
||||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||||
var r = renderToHtml(c, env);
|
||||
return (isSxTruthy(!isSxTruthy(isSpread(r))) ? append_b(parts, r) : NIL);
|
||||
})(); } }
|
||||
return envSet(local, "children", makeRawHtml(join("", parts)));
|
||||
})();
|
||||
envSet(local, "children", makeRawHtml(join("", map(function(c) { return renderToHtml(c, env); }, children))));
|
||||
}
|
||||
return renderToHtml(componentBody(comp), local);
|
||||
})();
|
||||
@@ -1633,14 +1615,12 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m =
|
||||
var attrs = first(parsed);
|
||||
var children = nth(parsed, 1);
|
||||
var isVoid = contains(VOID_ELEMENTS, tag);
|
||||
return (isSxTruthy(isVoid) ? (String("<") + String(tag) + String(renderAttrs(attrs)) + String(" />")) : (function() {
|
||||
var contentParts = [];
|
||||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||||
var result = renderToHtml(c, env);
|
||||
return (isSxTruthy(isSpread(result)) ? mergeSpreadAttrs(attrs, spreadAttrs(result)) : append_b(contentParts, result));
|
||||
})(); } }
|
||||
return (String("<") + String(tag) + String(renderAttrs(attrs)) + String(">") + String(join("", contentParts)) + String("</") + String(tag) + String(">"));
|
||||
})());
|
||||
return (isSxTruthy(isVoid) ? (String("<") + String(tag) + String(renderAttrs(attrs)) + String(" />")) : (providePush("element-attrs", NIL), (function() {
|
||||
var content = join("", map(function(c) { return renderToHtml(c, env); }, children));
|
||||
{ var _c = sxEmitted("element-attrs"); for (var _i = 0; _i < _c.length; _i++) { var spreadDict = _c[_i]; mergeSpreadAttrs(attrs, spreadDict); } }
|
||||
providePop("element-attrs");
|
||||
return (String("<") + String(tag) + String(renderAttrs(attrs)) + String(">") + String(content) + String("</") + String(tag) + String(">"));
|
||||
})()));
|
||||
})(); };
|
||||
|
||||
// render-html-lake
|
||||
@@ -1659,12 +1639,13 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m =
|
||||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||||
return (function() {
|
||||
var lakeAttrs = {["data-sx-lake"]: sxOr(lakeId, "")};
|
||||
var contentParts = [];
|
||||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||||
var result = renderToHtml(c, env);
|
||||
return (isSxTruthy(isSpread(result)) ? mergeSpreadAttrs(lakeAttrs, spreadAttrs(result)) : append_b(contentParts, result));
|
||||
})(); } }
|
||||
return (String("<") + String(lakeTag) + String(renderAttrs(lakeAttrs)) + String(">") + String(join("", contentParts)) + String("</") + String(lakeTag) + String(">"));
|
||||
providePush("element-attrs", NIL);
|
||||
return (function() {
|
||||
var content = join("", map(function(c) { return renderToHtml(c, env); }, children));
|
||||
{ var _c = sxEmitted("element-attrs"); for (var _i = 0; _i < _c.length; _i++) { var spreadDict = _c[_i]; mergeSpreadAttrs(lakeAttrs, spreadDict); } }
|
||||
providePop("element-attrs");
|
||||
return (String("<") + String(lakeTag) + String(renderAttrs(lakeAttrs)) + String(">") + String(content) + String("</") + String(lakeTag) + String(">"));
|
||||
})();
|
||||
})();
|
||||
})(); };
|
||||
|
||||
@@ -1684,12 +1665,13 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m =
|
||||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||||
return (function() {
|
||||
var marshAttrs = {["data-sx-marsh"]: sxOr(marshId, "")};
|
||||
var contentParts = [];
|
||||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||||
var result = renderToHtml(c, env);
|
||||
return (isSxTruthy(isSpread(result)) ? mergeSpreadAttrs(marshAttrs, spreadAttrs(result)) : append_b(contentParts, result));
|
||||
})(); } }
|
||||
return (String("<") + String(marshTag) + String(renderAttrs(marshAttrs)) + String(">") + String(join("", contentParts)) + String("</") + String(marshTag) + String(">"));
|
||||
providePush("element-attrs", NIL);
|
||||
return (function() {
|
||||
var content = join("", map(function(c) { return renderToHtml(c, env); }, children));
|
||||
{ var _c = sxEmitted("element-attrs"); for (var _i = 0; _i < _c.length; _i++) { var spreadDict = _c[_i]; mergeSpreadAttrs(marshAttrs, spreadDict); } }
|
||||
providePop("element-attrs");
|
||||
return (String("<") + String(marshTag) + String(renderAttrs(marshAttrs)) + String(">") + String(content) + String("</") + String(marshTag) + String(">"));
|
||||
})();
|
||||
})();
|
||||
})(); };
|
||||
|
||||
@@ -1710,14 +1692,7 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m =
|
||||
var islandName = componentName(island);
|
||||
{ var _c = componentParams(island); for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; envSet(local, p, (isSxTruthy(dictHas(kwargs, p)) ? dictGet(kwargs, p) : NIL)); } }
|
||||
if (isSxTruthy(componentHasChildren(island))) {
|
||||
(function() {
|
||||
var parts = [];
|
||||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||||
var r = renderToHtml(c, env);
|
||||
return (isSxTruthy(!isSxTruthy(isSpread(r))) ? append_b(parts, r) : NIL);
|
||||
})(); } }
|
||||
return envSet(local, "children", makeRawHtml(join("", parts)));
|
||||
})();
|
||||
envSet(local, "children", makeRawHtml(join("", map(function(c) { return renderToHtml(c, env); }, children))));
|
||||
}
|
||||
return (function() {
|
||||
var bodyHtml = renderToHtml(componentBody(island), local);
|
||||
@@ -1741,10 +1716,13 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m =
|
||||
|
||||
// aser
|
||||
var aser = function(expr, env) { setRenderActiveB(true);
|
||||
return (function() { var _m = typeOf(expr); if (_m == "number") return expr; if (_m == "string") return expr; if (_m == "boolean") return expr; if (_m == "nil") return NIL; if (_m == "symbol") return (function() {
|
||||
return (function() {
|
||||
var result = (function() { var _m = typeOf(expr); if (_m == "number") return expr; if (_m == "string") return expr; if (_m == "boolean") return expr; if (_m == "nil") return NIL; if (_m == "symbol") return (function() {
|
||||
var name = symbolName(expr);
|
||||
return (isSxTruthy(envHas(env, name)) ? envGet(env, name) : (isSxTruthy(isPrimitive(name)) ? getPrimitive(name) : (isSxTruthy((name == "true")) ? true : (isSxTruthy((name == "false")) ? false : (isSxTruthy((name == "nil")) ? NIL : error((String("Undefined symbol: ") + String(name))))))));
|
||||
})(); if (_m == "keyword") return keywordName(expr); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? [] : aserList(expr, env)); if (_m == "spread") return expr; return expr; })(); };
|
||||
})(); if (_m == "keyword") return keywordName(expr); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? [] : aserList(expr, env)); if (_m == "spread") return (sxEmit("element-attrs", spreadAttrs(expr)), NIL); return expr; })();
|
||||
return (isSxTruthy(isSpread(result)) ? (sxEmit("element-attrs", spreadAttrs(result)), NIL) : result);
|
||||
})(); };
|
||||
|
||||
// aser-list
|
||||
var aserList = function(expr, env) { return (function() {
|
||||
@@ -1772,29 +1750,36 @@ return (function() { var _m = typeOf(expr); if (_m == "number") return expr; if
|
||||
|
||||
// aser-call
|
||||
var aserCall = function(name, args, env) { return (function() {
|
||||
var parts = [name];
|
||||
var attrParts = [];
|
||||
var childParts = [];
|
||||
var skip = false;
|
||||
var i = 0;
|
||||
providePush("element-attrs", NIL);
|
||||
{ var _c = args; for (var _i = 0; _i < _c.length; _i++) { var arg = _c[_i]; (isSxTruthy(skip) ? ((skip = false), (i = (i + 1))) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((i + 1) < len(args)))) ? (function() {
|
||||
var val = aser(nth(args, (i + 1)), env);
|
||||
if (isSxTruthy(!isSxTruthy(isNil(val)))) {
|
||||
parts.push((String(":") + String(keywordName(arg))));
|
||||
parts.push(serialize(val));
|
||||
attrParts.push((String(":") + String(keywordName(arg))));
|
||||
attrParts.push(serialize(val));
|
||||
}
|
||||
skip = true;
|
||||
return (i = (i + 1));
|
||||
})() : (function() {
|
||||
var val = aser(arg, env);
|
||||
if (isSxTruthy(!isSxTruthy(isNil(val)))) {
|
||||
(isSxTruthy(isSpread(val)) ? forEach(function(k) { return (function() {
|
||||
var v = dictGet(spreadAttrs(val), k);
|
||||
parts.push((String(":") + String(k)));
|
||||
return append_b(parts, serialize(v));
|
||||
})(); }, keys(spreadAttrs(val))) : (isSxTruthy((typeOf(val) == "list")) ? forEach(function(item) { return (isSxTruthy(!isSxTruthy(isNil(item))) ? append_b(parts, serialize(item)) : NIL); }, val) : append_b(parts, serialize(val))));
|
||||
(isSxTruthy((typeOf(val) == "list")) ? forEach(function(item) { return (isSxTruthy(!isSxTruthy(isNil(item))) ? append_b(childParts, serialize(item)) : NIL); }, val) : append_b(childParts, serialize(val)));
|
||||
}
|
||||
return (i = (i + 1));
|
||||
})())); } }
|
||||
{ var _c = sxEmitted("element-attrs"); for (var _i = 0; _i < _c.length; _i++) { var spreadDict = _c[_i]; { var _c = keys(spreadDict); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; (function() {
|
||||
var v = dictGet(spreadDict, k);
|
||||
attrParts.push((String(":") + String(k)));
|
||||
return append_b(attrParts, serialize(v));
|
||||
})(); } } } }
|
||||
providePop("element-attrs");
|
||||
return (function() {
|
||||
var parts = concat([name], attrParts, childParts);
|
||||
return (String("(") + String(join(" ", parts)) + String(")"));
|
||||
})();
|
||||
})(); };
|
||||
|
||||
// SPECIAL_FORM_NAMES
|
||||
@@ -1898,7 +1883,7 @@ return result; }, args);
|
||||
|
||||
// render-to-dom
|
||||
var renderToDom = function(expr, env, ns) { setRenderActiveB(true);
|
||||
return (function() { var _m = typeOf(expr); if (_m == "nil") return createFragment(); if (_m == "boolean") return createFragment(); if (_m == "raw-html") return domParseHtml(rawHtmlContent(expr)); if (_m == "string") return createTextNode(expr); if (_m == "number") return createTextNode((String(expr))); if (_m == "symbol") return renderToDom(trampoline(evalExpr(expr, env)), env, ns); if (_m == "keyword") return createTextNode(keywordName(expr)); if (_m == "dom-node") return expr; if (_m == "spread") return expr; if (_m == "dict") return createFragment(); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? createFragment() : renderDomList(expr, env, ns)); return (isSxTruthy(isSignal(expr)) ? (isSxTruthy(_islandScope) ? reactiveText(expr) : createTextNode((String(deref(expr))))) : createTextNode((String(expr)))); })(); };
|
||||
return (function() { var _m = typeOf(expr); if (_m == "nil") return createFragment(); if (_m == "boolean") return createFragment(); if (_m == "raw-html") return domParseHtml(rawHtmlContent(expr)); if (_m == "string") return createTextNode(expr); if (_m == "number") return createTextNode((String(expr))); if (_m == "symbol") return renderToDom(trampoline(evalExpr(expr, env)), env, ns); if (_m == "keyword") return createTextNode(keywordName(expr)); if (_m == "dom-node") return expr; if (_m == "spread") return (sxEmit("element-attrs", spreadAttrs(expr)), expr); if (_m == "dict") return createFragment(); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? createFragment() : renderDomList(expr, env, ns)); return (isSxTruthy(isSignal(expr)) ? (isSxTruthy(_islandScope) ? reactiveText(expr) : createTextNode((String(deref(expr))))) : createTextNode((String(expr)))); })(); };
|
||||
|
||||
// render-dom-list
|
||||
var renderDomList = function(expr, env, ns) { return (function() {
|
||||
@@ -1927,6 +1912,7 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return createFragme
|
||||
var renderDomElement = function(tag, args, env, ns) { return (function() {
|
||||
var newNs = (isSxTruthy((tag == "svg")) ? SVG_NS : (isSxTruthy((tag == "math")) ? MATH_NS : ns));
|
||||
var el = domCreateElement(tag, newNs);
|
||||
providePush("element-attrs", NIL);
|
||||
reduce(function(state, arg) { return (function() {
|
||||
var skip = get(state, "skip");
|
||||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||||
@@ -1951,8 +1937,11 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return createFragme
|
||||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||||
})() : ((isSxTruthy(!isSxTruthy(contains(VOID_ELEMENTS, tag))) ? (function() {
|
||||
var child = renderToDom(arg, env, newNs);
|
||||
return (isSxTruthy((isSxTruthy(isSpread(child)) && _islandScope)) ? reactiveSpread(el, function() { return renderToDom(arg, env, newNs); }) : (isSxTruthy(isSpread(child)) ? forEach(function(key) { return (function() {
|
||||
var val = dictGet(spreadAttrs(child), key);
|
||||
return (isSxTruthy((isSxTruthy(isSpread(child)) && _islandScope)) ? reactiveSpread(el, function() { return renderToDom(arg, env, newNs); }) : (isSxTruthy(isSpread(child)) ? NIL : domAppend(el, child)));
|
||||
})() : NIL), assoc(state, "i", (get(state, "i") + 1)))));
|
||||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||||
{ var _c = sxEmitted("element-attrs"); for (var _i = 0; _i < _c.length; _i++) { var spreadDict = _c[_i]; { var _c = keys(spreadDict); for (var _i = 0; _i < _c.length; _i++) { var key = _c[_i]; (function() {
|
||||
var val = dictGet(spreadDict, key);
|
||||
return (isSxTruthy((key == "class")) ? (function() {
|
||||
var existing = domGetAttr(el, "class");
|
||||
return domSetAttr(el, "class", (isSxTruthy((isSxTruthy(existing) && !isSxTruthy((existing == "")))) ? (String(existing) + String(" ") + String(val)) : val));
|
||||
@@ -1960,9 +1949,8 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return createFragme
|
||||
var existing = domGetAttr(el, "style");
|
||||
return domSetAttr(el, "style", (isSxTruthy((isSxTruthy(existing) && !isSxTruthy((existing == "")))) ? (String(existing) + String(";") + String(val)) : val));
|
||||
})() : domSetAttr(el, key, (String(val)))));
|
||||
})(); }, keys(spreadAttrs(child))) : domAppend(el, child)));
|
||||
})() : NIL), assoc(state, "i", (get(state, "i") + 1)))));
|
||||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||||
})(); } } } }
|
||||
providePop("element-attrs");
|
||||
return el;
|
||||
})(); };
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"string" (escape-html expr)
|
||||
"number" (escape-html (str expr))
|
||||
"raw-html" (raw-html-content expr)
|
||||
"spread" expr
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs expr)) "")
|
||||
"symbol" (let ((val (async-eval expr env ctx)))
|
||||
(async-render val env ctx))
|
||||
"keyword" (escape-html (keyword-name expr))
|
||||
@@ -80,10 +80,9 @@
|
||||
(= name "raw!")
|
||||
(async-render-raw args env ctx)
|
||||
|
||||
;; Fragment (spreads filtered — no parent element)
|
||||
;; Fragment
|
||||
(= name "<>")
|
||||
(join "" (filter (fn (r) (not (spread? r)))
|
||||
(async-map-render args env ctx)))
|
||||
(join "" (async-map-render args env ctx))
|
||||
|
||||
;; html: prefix
|
||||
(starts-with? name "html:")
|
||||
@@ -171,18 +170,19 @@
|
||||
(css-class-collect! (str class-val))))
|
||||
(if (contains? VOID_ELEMENTS tag)
|
||||
(str "<" tag (render-attrs attrs) ">")
|
||||
;; Render children, collecting spreads and content separately
|
||||
;; Provide scope for spread emit!
|
||||
(let ((token (if (or (= tag "svg") (= tag "math"))
|
||||
(svg-context-set! true)
|
||||
nil))
|
||||
(content-parts (list)))
|
||||
(provide-push! "element-attrs" nil)
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((result (async-render c env ctx)))
|
||||
(if (spread? result)
|
||||
(merge-spread-attrs attrs (spread-attrs result))
|
||||
(append! content-parts result))))
|
||||
(fn (c) (append! content-parts (async-render c env ctx)))
|
||||
children)
|
||||
(for-each
|
||||
(fn (spread-dict) (merge-spread-attrs attrs spread-dict))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(when token (svg-context-reset! token))
|
||||
(str "<" tag (render-attrs attrs) ">"
|
||||
(join "" content-parts)
|
||||
@@ -231,14 +231,11 @@
|
||||
(for-each
|
||||
(fn (p) (env-set! local p (if (dict-has? kwargs p) (dict-get kwargs p) nil)))
|
||||
(component-params comp))
|
||||
;; Pre-render children to raw HTML (filter spreads — no parent element)
|
||||
;; Pre-render children to raw HTML
|
||||
(when (component-has-children? comp)
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((r (async-render c env ctx)))
|
||||
(when (not (spread? r))
|
||||
(append! parts r))))
|
||||
(fn (c) (append! parts (async-render c env ctx)))
|
||||
children)
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" parts)))))
|
||||
@@ -259,14 +256,11 @@
|
||||
(for-each
|
||||
(fn (p) (env-set! local p (if (dict-has? kwargs p) (dict-get kwargs p) nil)))
|
||||
(component-params island))
|
||||
;; Pre-render children (filter spreads — no parent element)
|
||||
;; Pre-render children
|
||||
(when (component-has-children? island)
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((r (async-render c env ctx)))
|
||||
(when (not (spread? r))
|
||||
(append! parts r))))
|
||||
(fn (c) (append! parts (async-render c env ctx)))
|
||||
children)
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" parts)))))
|
||||
@@ -367,14 +361,13 @@
|
||||
(async-render (nth expr 3) env ctx)
|
||||
"")))
|
||||
|
||||
;; when — single body: pass through (spread propagates). Multi: join strings.
|
||||
;; when — single body: pass through. Multi: join strings.
|
||||
(= name "when")
|
||||
(if (not (async-eval (nth expr 1) env ctx))
|
||||
""
|
||||
(if (= (len expr) 3)
|
||||
(async-render (nth expr 2) env ctx)
|
||||
(let ((results (async-map-render (slice expr 2) env ctx)))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results)))))
|
||||
(join "" (async-map-render (slice expr 2) env ctx))))
|
||||
|
||||
;; cond — uses cond-scheme? (every? check) from eval.sx
|
||||
(= name "cond")
|
||||
@@ -392,47 +385,39 @@
|
||||
(let ((local (async-process-bindings (nth expr 1) env ctx)))
|
||||
(if (= (len expr) 3)
|
||||
(async-render (nth expr 2) local ctx)
|
||||
(let ((results (async-map-render (slice expr 2) local ctx)))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results)))))
|
||||
(join "" (async-map-render (slice expr 2) local ctx))))
|
||||
|
||||
;; begin / do — single body: pass through. Multi: join strings.
|
||||
(or (= name "begin") (= name "do"))
|
||||
(if (= (len expr) 2)
|
||||
(async-render (nth expr 1) env ctx)
|
||||
(let ((results (async-map-render (rest expr) env ctx)))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results))))
|
||||
(join "" (async-map-render (rest expr) env ctx)))
|
||||
|
||||
;; Definition forms
|
||||
(definition-form? name)
|
||||
(do (async-eval expr env ctx) "")
|
||||
|
||||
;; map — spreads filtered
|
||||
;; map
|
||||
(= name "map")
|
||||
(let ((f (async-eval (nth expr 1) env ctx))
|
||||
(coll (async-eval (nth expr 2) env ctx)))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(async-map-fn-render f coll env ctx))))
|
||||
(join "" (async-map-fn-render f coll env ctx)))
|
||||
|
||||
;; map-indexed — spreads filtered
|
||||
;; map-indexed
|
||||
(= name "map-indexed")
|
||||
(let ((f (async-eval (nth expr 1) env ctx))
|
||||
(coll (async-eval (nth expr 2) env ctx)))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(async-map-indexed-fn-render f coll env ctx))))
|
||||
(join "" (async-map-indexed-fn-render f coll env ctx)))
|
||||
|
||||
;; filter — eval fully then render
|
||||
(= name "filter")
|
||||
(async-render (async-eval expr env ctx) env ctx)
|
||||
|
||||
;; for-each (render variant) — spreads filtered
|
||||
;; for-each (render variant)
|
||||
(= name "for-each")
|
||||
(let ((f (async-eval (nth expr 1) env ctx))
|
||||
(coll (async-eval (nth expr 2) env ctx)))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(async-map-fn-render f coll env ctx))))
|
||||
(join "" (async-map-fn-render f coll env ctx)))
|
||||
|
||||
;; provide — render-time dynamic scope
|
||||
(= name "provide")
|
||||
@@ -443,8 +428,7 @@
|
||||
(provide-push! prov-name prov-val)
|
||||
(let ((result (if (= body-count 1)
|
||||
(async-render (nth expr body-start) env ctx)
|
||||
(let ((results (async-map-render (slice expr body-start) env ctx)))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results))))))
|
||||
(join "" (async-map-render (slice expr body-start) env ctx)))))
|
||||
(provide-pop! prov-name)
|
||||
result))
|
||||
|
||||
@@ -595,35 +579,34 @@
|
||||
|
||||
(define-async async-aser :effects [render io]
|
||||
(fn (expr (env :as dict) ctx)
|
||||
(case (type-of expr)
|
||||
"number" expr
|
||||
"string" expr
|
||||
"boolean" expr
|
||||
"nil" nil
|
||||
|
||||
"symbol"
|
||||
(let ((name (symbol-name expr)))
|
||||
(cond
|
||||
(env-has? env name) (env-get env name)
|
||||
(primitive? name) (get-primitive name)
|
||||
(= name "true") true
|
||||
(= name "false") false
|
||||
(= name "nil") nil
|
||||
:else (error (str "Undefined symbol: " name))))
|
||||
|
||||
"keyword" (keyword-name expr)
|
||||
|
||||
"dict" (async-aser-dict expr env ctx)
|
||||
|
||||
;; Spread — pass through for client rendering
|
||||
"spread" expr
|
||||
|
||||
"list"
|
||||
(if (empty? expr)
|
||||
(list)
|
||||
(async-aser-list expr env ctx))
|
||||
|
||||
:else expr)))
|
||||
(let ((t (type-of expr))
|
||||
(result nil))
|
||||
(cond
|
||||
(= t "number") (set! result expr)
|
||||
(= t "string") (set! result expr)
|
||||
(= t "boolean") (set! result expr)
|
||||
(= t "nil") (set! result nil)
|
||||
(= t "symbol")
|
||||
(let ((name (symbol-name expr)))
|
||||
(set! result
|
||||
(cond
|
||||
(env-has? env name) (env-get env name)
|
||||
(primitive? name) (get-primitive name)
|
||||
(= name "true") true
|
||||
(= name "false") false
|
||||
(= name "nil") nil
|
||||
:else (error (str "Undefined symbol: " name)))))
|
||||
(= t "keyword") (set! result (keyword-name expr))
|
||||
(= t "dict") (set! result (async-aser-dict expr env ctx))
|
||||
;; Spread — emit attrs to nearest element provider
|
||||
(= t "spread") (do (emit! "element-attrs" (spread-attrs expr))
|
||||
(set! result nil))
|
||||
(= t "list") (set! result (if (empty? expr) (list) (async-aser-list expr env ctx)))
|
||||
:else (set! result expr))
|
||||
;; Catch spread values from function calls and symbol lookups
|
||||
(if (spread? result)
|
||||
(do (emit! "element-attrs" (spread-attrs result)) nil)
|
||||
result))))
|
||||
|
||||
|
||||
(define-async async-aser-dict :effects [render io]
|
||||
@@ -775,7 +758,6 @@
|
||||
|
||||
(define-async async-aser-fragment :effects [render io]
|
||||
(fn ((children :as list) (env :as dict) ctx)
|
||||
;; Spreads are filtered — fragments have no parent element to merge into
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
@@ -783,10 +765,10 @@
|
||||
(if (= (type-of result) "list")
|
||||
(for-each
|
||||
(fn (item)
|
||||
(when (and (not (nil? item)) (not (spread? item)))
|
||||
(when (not (nil? item))
|
||||
(append! parts (serialize item))))
|
||||
result)
|
||||
(when (and (not (nil? result)) (not (spread? result)))
|
||||
(when (not (nil? result))
|
||||
(append! parts (serialize result))))))
|
||||
children)
|
||||
(if (empty? parts)
|
||||
@@ -860,9 +842,12 @@
|
||||
(let ((token (if (or (= name "svg") (= name "math"))
|
||||
(svg-context-set! true)
|
||||
nil))
|
||||
(parts (list name))
|
||||
(attr-parts (list))
|
||||
(child-parts (list))
|
||||
(skip false)
|
||||
(i 0))
|
||||
;; Provide scope for spread emit!
|
||||
(provide-push! "element-attrs" nil)
|
||||
(for-each
|
||||
(fn (arg)
|
||||
(if skip
|
||||
@@ -872,39 +857,43 @@
|
||||
(< (inc i) (len args)))
|
||||
(let ((val (async-aser (nth args (inc i)) env ctx)))
|
||||
(when (not (nil? val))
|
||||
(append! parts (str ":" (keyword-name arg)))
|
||||
(append! attr-parts (str ":" (keyword-name arg)))
|
||||
(if (= (type-of val) "list")
|
||||
(let ((live (filter (fn (v) (not (nil? v))) val)))
|
||||
(if (empty? live)
|
||||
(append! parts "nil")
|
||||
(append! attr-parts "nil")
|
||||
(let ((items (map serialize live)))
|
||||
(if (some (fn (v) (sx-expr? v)) live)
|
||||
(append! parts (str "(<> " (join " " items) ")"))
|
||||
(append! parts (str "(list " (join " " items) ")"))))))
|
||||
(append! parts (serialize val))))
|
||||
(append! attr-parts (str "(<> " (join " " items) ")"))
|
||||
(append! attr-parts (str "(list " (join " " items) ")"))))))
|
||||
(append! attr-parts (serialize val))))
|
||||
(set! skip true)
|
||||
(set! i (inc i)))
|
||||
(let ((result (async-aser arg env ctx)))
|
||||
(when (not (nil? result))
|
||||
(if (spread? result)
|
||||
;; Spread child — merge attrs as keyword args into parent element
|
||||
(if (= (type-of result) "list")
|
||||
(for-each
|
||||
(fn (k)
|
||||
(let ((v (dict-get (spread-attrs result) k)))
|
||||
(append! parts (str ":" k))
|
||||
(append! parts (serialize v))))
|
||||
(keys (spread-attrs result)))
|
||||
(if (= (type-of result) "list")
|
||||
(for-each
|
||||
(fn (item)
|
||||
(when (not (nil? item))
|
||||
(append! parts (serialize item))))
|
||||
result)
|
||||
(append! parts (serialize result)))))
|
||||
(fn (item)
|
||||
(when (not (nil? item))
|
||||
(append! child-parts (serialize item))))
|
||||
result)
|
||||
(append! child-parts (serialize result))))
|
||||
(set! i (inc i))))))
|
||||
args)
|
||||
;; Collect emitted spread attrs — after explicit attrs, before children
|
||||
(for-each
|
||||
(fn (spread-dict)
|
||||
(for-each
|
||||
(fn (k)
|
||||
(let ((v (dict-get spread-dict k)))
|
||||
(append! attr-parts (str ":" k))
|
||||
(append! attr-parts (serialize v))))
|
||||
(keys spread-dict)))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(when token (svg-context-reset! token))
|
||||
(make-sx-expr (str "(" (join " " parts) ")")))))
|
||||
(let ((parts (concat (list name) attr-parts child-parts)))
|
||||
(make-sx-expr (str "(" (join " " parts) ")"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
;; Pre-rendered DOM node → pass through
|
||||
"dom-node" expr
|
||||
|
||||
;; Spread → pass through (parent element handles it)
|
||||
"spread" expr
|
||||
;; Spread → emit attrs to nearest element provider, pass through for reactive-spread
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs expr)) expr)
|
||||
|
||||
;; Dict → empty
|
||||
"dict" (create-fragment)
|
||||
@@ -180,6 +180,9 @@
|
||||
:else ns))
|
||||
(el (dom-create-element tag new-ns)))
|
||||
|
||||
;; Provide scope for spread emit! — deeply nested spreads emit here
|
||||
(provide-push! "element-attrs" nil)
|
||||
|
||||
;; Process args: keywords → attrs, others → children
|
||||
(reduce
|
||||
(fn (state arg)
|
||||
@@ -236,28 +239,8 @@
|
||||
;; Reactive spread: track signal deps, update attrs on change
|
||||
(and (spread? child) *island-scope*)
|
||||
(reactive-spread el (fn () (render-to-dom arg env new-ns)))
|
||||
;; Static spread: one-shot merge attrs onto parent element
|
||||
(spread? child)
|
||||
(for-each
|
||||
(fn ((key :as string))
|
||||
(let ((val (dict-get (spread-attrs child) key)))
|
||||
(if (= key "class")
|
||||
;; Class: append to existing
|
||||
(let ((existing (dom-get-attr el "class")))
|
||||
(dom-set-attr el "class"
|
||||
(if (and existing (not (= existing "")))
|
||||
(str existing " " val)
|
||||
val)))
|
||||
(if (= key "style")
|
||||
;; Style: append with semicolon
|
||||
(let ((existing (dom-get-attr el "style")))
|
||||
(dom-set-attr el "style"
|
||||
(if (and existing (not (= existing "")))
|
||||
(str existing ";" val)
|
||||
val)))
|
||||
;; Other attrs: overwrite
|
||||
(dom-set-attr el key (str val))))))
|
||||
(keys (spread-attrs child)))
|
||||
;; Static spread: already emitted via provide, skip
|
||||
(spread? child) nil
|
||||
;; Normal child: append to element
|
||||
:else
|
||||
(dom-append el child))))
|
||||
@@ -265,6 +248,29 @@
|
||||
(dict "i" 0 "skip" false)
|
||||
args)
|
||||
|
||||
;; Collect emitted spread attrs and merge onto DOM element
|
||||
(for-each
|
||||
(fn (spread-dict)
|
||||
(for-each
|
||||
(fn ((key :as string))
|
||||
(let ((val (dict-get spread-dict key)))
|
||||
(if (= key "class")
|
||||
(let ((existing (dom-get-attr el "class")))
|
||||
(dom-set-attr el "class"
|
||||
(if (and existing (not (= existing "")))
|
||||
(str existing " " val)
|
||||
val)))
|
||||
(if (= key "style")
|
||||
(let ((existing (dom-get-attr el "style")))
|
||||
(dom-set-attr el "style"
|
||||
(if (and existing (not (= existing "")))
|
||||
(str existing ";" val)
|
||||
val)))
|
||||
(dom-set-attr el key (str val))))))
|
||||
(keys spread-dict)))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
|
||||
el)))
|
||||
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
"keyword" (escape-html (keyword-name expr))
|
||||
;; Raw HTML passthrough
|
||||
"raw-html" (raw-html-content expr)
|
||||
;; Spread — pass through as-is (parent element will merge attrs)
|
||||
"spread" expr
|
||||
;; Spread — emit attrs to nearest element provider
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs expr)) "")
|
||||
;; Everything else — evaluate first
|
||||
:else (render-value-to-html (trampoline (eval-expr expr env)) env))))
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"boolean" (if val "true" "false")
|
||||
"list" (render-list-to-html val env)
|
||||
"raw-html" (raw-html-content val)
|
||||
"spread" val
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs val)) "")
|
||||
:else (escape-html (str val)))))
|
||||
|
||||
|
||||
@@ -73,16 +73,14 @@
|
||||
""
|
||||
(let ((head (first expr)))
|
||||
(if (not (= (type-of head) "symbol"))
|
||||
;; Data list — render each item (spreads filtered — no parent element)
|
||||
(join "" (filter (fn (x) (not (spread? x)))
|
||||
(map (fn (x) (render-value-to-html x env)) expr)))
|
||||
;; Data list — render each item
|
||||
(join "" (map (fn (x) (render-value-to-html x env)) expr))
|
||||
(let ((name (symbol-name head))
|
||||
(args (rest expr)))
|
||||
(cond
|
||||
;; Fragment (spreads filtered — no parent element)
|
||||
;; Fragment
|
||||
(= name "<>")
|
||||
(join "" (filter (fn (x) (not (spread? x)))
|
||||
(map (fn (x) (render-to-html x env)) args)))
|
||||
(join "" (map (fn (x) (render-to-html x env)) args))
|
||||
|
||||
;; Raw HTML passthrough
|
||||
(= name "raw!")
|
||||
@@ -152,15 +150,14 @@
|
||||
(render-to-html (nth expr 3) env)
|
||||
"")))
|
||||
|
||||
;; when — single body: pass through (spread propagates). Multi: join strings.
|
||||
;; when — single body: pass through. Multi: join strings.
|
||||
(= name "when")
|
||||
(if (not (trampoline (eval-expr (nth expr 1) env)))
|
||||
""
|
||||
(if (= (len expr) 3)
|
||||
(render-to-html (nth expr 2) env)
|
||||
(let ((results (map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range 2 (len expr)))))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results)))))
|
||||
(join "" (map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range 2 (len expr))))))
|
||||
|
||||
;; cond
|
||||
(= name "cond")
|
||||
@@ -178,64 +175,59 @@
|
||||
(let ((local (process-bindings (nth expr 1) env)))
|
||||
(if (= (len expr) 3)
|
||||
(render-to-html (nth expr 2) local)
|
||||
(let ((results (map (fn (i) (render-to-html (nth expr i) local))
|
||||
(range 2 (len expr)))))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results)))))
|
||||
(join "" (map (fn (i) (render-to-html (nth expr i) local))
|
||||
(range 2 (len expr))))))
|
||||
|
||||
;; begin / do — single body: pass through. Multi: join strings.
|
||||
(or (= name "begin") (= name "do"))
|
||||
(if (= (len expr) 2)
|
||||
(render-to-html (nth expr 1) env)
|
||||
(let ((results (map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range 1 (len expr)))))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results))))
|
||||
(join "" (map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range 1 (len expr)))))
|
||||
|
||||
;; Definition forms — eval for side effects
|
||||
(definition-form? name)
|
||||
(do (trampoline (eval-expr expr env)) "")
|
||||
|
||||
;; map — spreads filtered (no parent element in list context)
|
||||
;; map
|
||||
(= name "map")
|
||||
(let ((f (trampoline (eval-expr (nth expr 1) env)))
|
||||
(coll (trampoline (eval-expr (nth expr 2) env))))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(map
|
||||
(fn (item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list item) env)
|
||||
(render-to-html (apply f (list item)) env)))
|
||||
coll))))
|
||||
(map
|
||||
(fn (item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list item) env)
|
||||
(render-to-html (apply f (list item)) env)))
|
||||
coll)))
|
||||
|
||||
;; map-indexed — spreads filtered
|
||||
;; map-indexed
|
||||
(= name "map-indexed")
|
||||
(let ((f (trampoline (eval-expr (nth expr 1) env)))
|
||||
(coll (trampoline (eval-expr (nth expr 2) env))))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(map-indexed
|
||||
(fn (i item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list i item) env)
|
||||
(render-to-html (apply f (list i item)) env)))
|
||||
coll))))
|
||||
(map-indexed
|
||||
(fn (i item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list i item) env)
|
||||
(render-to-html (apply f (list i item)) env)))
|
||||
coll)))
|
||||
|
||||
;; filter — evaluate fully then render
|
||||
(= name "filter")
|
||||
(render-to-html (trampoline (eval-expr expr env)) env)
|
||||
|
||||
;; for-each (render variant) — spreads filtered
|
||||
;; for-each (render variant)
|
||||
(= name "for-each")
|
||||
(let ((f (trampoline (eval-expr (nth expr 1) env)))
|
||||
(coll (trampoline (eval-expr (nth expr 2) env))))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(map
|
||||
(fn (item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list item) env)
|
||||
(render-to-html (apply f (list item)) env)))
|
||||
coll))))
|
||||
(map
|
||||
(fn (item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list item) env)
|
||||
(render-to-html (apply f (list item)) env)))
|
||||
coll)))
|
||||
|
||||
;; provide — render-time dynamic scope
|
||||
(= name "provide")
|
||||
@@ -246,9 +238,8 @@
|
||||
(provide-push! prov-name prov-val)
|
||||
(let ((result (if (= body-count 1)
|
||||
(render-to-html (nth expr body-start) env)
|
||||
(join "" (filter (fn (r) (not (spread? r)))
|
||||
(map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range body-start (+ body-start body-count))))))))
|
||||
(join "" (map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range body-start (+ body-start body-count)))))))
|
||||
(provide-pop! prov-name)
|
||||
result))
|
||||
|
||||
@@ -307,17 +298,9 @@
|
||||
(env-set! local p (if (dict-has? kwargs p) (dict-get kwargs p) nil)))
|
||||
(component-params comp))
|
||||
;; If component accepts children, pre-render them to raw HTML
|
||||
;; Spread values are filtered out (no parent element to merge onto)
|
||||
(when (component-has-children? comp)
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((r (render-to-html c env)))
|
||||
(when (not (spread? r))
|
||||
(append! parts r))))
|
||||
children)
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" parts)))))
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" (map (fn (c) (render-to-html c env)) children)))))
|
||||
(render-to-html (component-body comp) local)))))
|
||||
|
||||
|
||||
@@ -329,18 +312,17 @@
|
||||
(is-void (contains? VOID_ELEMENTS tag)))
|
||||
(if is-void
|
||||
(str "<" tag (render-attrs attrs) " />")
|
||||
;; Render children, collecting spreads and content separately
|
||||
(let ((content-parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((result (render-to-html c env)))
|
||||
(if (spread? result)
|
||||
(merge-spread-attrs attrs (spread-attrs result))
|
||||
(append! content-parts result))))
|
||||
children)
|
||||
(str "<" tag (render-attrs attrs) ">"
|
||||
(join "" content-parts)
|
||||
"</" tag ">"))))))
|
||||
;; Provide scope for spread emit!
|
||||
(do
|
||||
(provide-push! "element-attrs" nil)
|
||||
(let ((content (join "" (map (fn (c) (render-to-html c env)) children))))
|
||||
(for-each
|
||||
(fn (spread-dict) (merge-spread-attrs attrs spread-dict))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(str "<" tag (render-attrs attrs) ">"
|
||||
content
|
||||
"</" tag ">")))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -375,19 +357,17 @@
|
||||
(assoc state "i" (inc (get state "i"))))))))
|
||||
(dict "i" 0 "skip" false)
|
||||
args)
|
||||
;; Render children, handling spreads
|
||||
(let ((lake-attrs (dict "data-sx-lake" (or lake-id "")))
|
||||
(content-parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((result (render-to-html c env)))
|
||||
(if (spread? result)
|
||||
(merge-spread-attrs lake-attrs (spread-attrs result))
|
||||
(append! content-parts result))))
|
||||
children)
|
||||
(str "<" lake-tag (render-attrs lake-attrs) ">"
|
||||
(join "" content-parts)
|
||||
"</" lake-tag ">")))))
|
||||
;; Provide scope for spread emit!
|
||||
(let ((lake-attrs (dict "data-sx-lake" (or lake-id ""))))
|
||||
(provide-push! "element-attrs" nil)
|
||||
(let ((content (join "" (map (fn (c) (render-to-html c env)) children))))
|
||||
(for-each
|
||||
(fn (spread-dict) (merge-spread-attrs lake-attrs spread-dict))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(str "<" lake-tag (render-attrs lake-attrs) ">"
|
||||
content
|
||||
"</" lake-tag ">"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -425,19 +405,17 @@
|
||||
(assoc state "i" (inc (get state "i"))))))))
|
||||
(dict "i" 0 "skip" false)
|
||||
args)
|
||||
;; Render children, handling spreads
|
||||
(let ((marsh-attrs (dict "data-sx-marsh" (or marsh-id "")))
|
||||
(content-parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((result (render-to-html c env)))
|
||||
(if (spread? result)
|
||||
(merge-spread-attrs marsh-attrs (spread-attrs result))
|
||||
(append! content-parts result))))
|
||||
children)
|
||||
(str "<" marsh-tag (render-attrs marsh-attrs) ">"
|
||||
(join "" content-parts)
|
||||
"</" marsh-tag ">")))))
|
||||
;; Provide scope for spread emit!
|
||||
(let ((marsh-attrs (dict "data-sx-marsh" (or marsh-id ""))))
|
||||
(provide-push! "element-attrs" nil)
|
||||
(let ((content (join "" (map (fn (c) (render-to-html c env)) children))))
|
||||
(for-each
|
||||
(fn (spread-dict) (merge-spread-attrs marsh-attrs spread-dict))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(str "<" marsh-tag (render-attrs marsh-attrs) ">"
|
||||
content
|
||||
"</" marsh-tag ">"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -487,17 +465,9 @@
|
||||
(component-params island))
|
||||
|
||||
;; If island accepts children, pre-render them to raw HTML
|
||||
;; Spread values filtered out (no parent element)
|
||||
(when (component-has-children? island)
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((r (render-to-html c env)))
|
||||
(when (not (spread? r))
|
||||
(append! parts r))))
|
||||
children)
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" parts)))))
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" (map (fn (c) (render-to-html c env)) children)))))
|
||||
|
||||
;; Render the island body as HTML
|
||||
(let ((body-html (render-to-html (component-body island) local))
|
||||
|
||||
@@ -25,33 +25,38 @@
|
||||
;; Evaluate for SX wire format — serialize rendering forms,
|
||||
;; evaluate control flow and function calls.
|
||||
(set-render-active! true)
|
||||
(case (type-of expr)
|
||||
"number" expr
|
||||
"string" expr
|
||||
"boolean" expr
|
||||
"nil" nil
|
||||
(let ((result
|
||||
(case (type-of expr)
|
||||
"number" expr
|
||||
"string" expr
|
||||
"boolean" expr
|
||||
"nil" nil
|
||||
|
||||
"symbol"
|
||||
(let ((name (symbol-name expr)))
|
||||
(cond
|
||||
(env-has? env name) (env-get env name)
|
||||
(primitive? name) (get-primitive name)
|
||||
(= name "true") true
|
||||
(= name "false") false
|
||||
(= name "nil") nil
|
||||
:else (error (str "Undefined symbol: " name))))
|
||||
"symbol"
|
||||
(let ((name (symbol-name expr)))
|
||||
(cond
|
||||
(env-has? env name) (env-get env name)
|
||||
(primitive? name) (get-primitive name)
|
||||
(= name "true") true
|
||||
(= name "false") false
|
||||
(= name "nil") nil
|
||||
:else (error (str "Undefined symbol: " name))))
|
||||
|
||||
"keyword" (keyword-name expr)
|
||||
"keyword" (keyword-name expr)
|
||||
|
||||
"list"
|
||||
(if (empty? expr)
|
||||
(list)
|
||||
(aser-list expr env))
|
||||
"list"
|
||||
(if (empty? expr)
|
||||
(list)
|
||||
(aser-list expr env))
|
||||
|
||||
;; Spread — pass through for client rendering
|
||||
"spread" expr
|
||||
;; Spread — emit attrs to nearest element provider
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs expr)) nil)
|
||||
|
||||
:else expr)))
|
||||
:else expr)))
|
||||
;; Catch spread values from function calls and symbol lookups
|
||||
(if (spread? result)
|
||||
(do (emit! "element-attrs" (spread-attrs result)) nil)
|
||||
result))))
|
||||
|
||||
|
||||
(define aser-list :effects [render]
|
||||
@@ -110,7 +115,6 @@
|
||||
(fn ((children :as list) (env :as dict))
|
||||
;; Serialize (<> child1 child2 ...) to sx source string
|
||||
;; Must flatten list results (e.g. from map/filter) to avoid nested parens
|
||||
;; Spreads are filtered — fragments have no parent element to merge into
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
@@ -118,10 +122,10 @@
|
||||
(if (= (type-of result) "list")
|
||||
(for-each
|
||||
(fn (item)
|
||||
(when (and (not (nil? item)) (not (spread? item)))
|
||||
(when (not (nil? item))
|
||||
(append! parts (serialize item))))
|
||||
result)
|
||||
(when (and (not (nil? result)) (not (spread? result)))
|
||||
(when (not (nil? result))
|
||||
(append! parts (serialize result))))))
|
||||
children)
|
||||
(if (empty? parts)
|
||||
@@ -134,9 +138,13 @@
|
||||
;; Serialize (name :key val child ...) — evaluate args but keep as sx
|
||||
;; Uses for-each + mutable state (not reduce) so bootstrapper emits for-loops
|
||||
;; that can contain nested for-each for list flattening.
|
||||
(let ((parts (list name))
|
||||
;; Separate attrs and children so emitted spread attrs go before children.
|
||||
(let ((attr-parts (list))
|
||||
(child-parts (list))
|
||||
(skip false)
|
||||
(i 0))
|
||||
;; Provide scope for spread emit!
|
||||
(provide-push! "element-attrs" nil)
|
||||
(for-each
|
||||
(fn (arg)
|
||||
(if skip
|
||||
@@ -146,30 +154,34 @@
|
||||
(< (inc i) (len args)))
|
||||
(let ((val (aser (nth args (inc i)) env)))
|
||||
(when (not (nil? val))
|
||||
(append! parts (str ":" (keyword-name arg)))
|
||||
(append! parts (serialize val)))
|
||||
(append! attr-parts (str ":" (keyword-name arg)))
|
||||
(append! attr-parts (serialize val)))
|
||||
(set! skip true)
|
||||
(set! i (inc i)))
|
||||
(let ((val (aser arg env)))
|
||||
(when (not (nil? val))
|
||||
(if (spread? val)
|
||||
;; Spread child — merge attrs as keyword args into parent element
|
||||
(if (= (type-of val) "list")
|
||||
(for-each
|
||||
(fn (k)
|
||||
(let ((v (dict-get (spread-attrs val) k)))
|
||||
(append! parts (str ":" k))
|
||||
(append! parts (serialize v))))
|
||||
(keys (spread-attrs val)))
|
||||
(if (= (type-of val) "list")
|
||||
(for-each
|
||||
(fn (item)
|
||||
(when (not (nil? item))
|
||||
(append! parts (serialize item))))
|
||||
val)
|
||||
(append! parts (serialize val)))))
|
||||
(fn (item)
|
||||
(when (not (nil? item))
|
||||
(append! child-parts (serialize item))))
|
||||
val)
|
||||
(append! child-parts (serialize val))))
|
||||
(set! i (inc i))))))
|
||||
args)
|
||||
(str "(" (join " " parts) ")"))))
|
||||
;; Collect emitted spread attrs — goes after explicit attrs, before children
|
||||
(for-each
|
||||
(fn (spread-dict)
|
||||
(for-each
|
||||
(fn (k)
|
||||
(let ((v (dict-get spread-dict k)))
|
||||
(append! attr-parts (str ":" k))
|
||||
(append! attr-parts (serialize v))))
|
||||
(keys spread-dict)))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(let ((parts (concat (list name) attr-parts child-parts)))
|
||||
(str "(" (join " " parts) ")")))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
@@ -1203,8 +1203,6 @@ PLATFORM_JS_PRE = '''
|
||||
function sxEmit(name, value) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||||
_provideStacks[name][_provideStacks[name].length - 1].emitted.push(value);
|
||||
} else {
|
||||
throw new Error("No provider for emit!: " + name);
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
@@ -126,11 +126,9 @@ def sx_context(name, *default):
|
||||
|
||||
|
||||
def sx_emit(name, value):
|
||||
"""Append value to nearest enclosing provider's accumulator. Error if no provider."""
|
||||
"""Append value to nearest enclosing provider's accumulator. No-op if no provider."""
|
||||
if name in _provide_stacks and _provide_stacks[name]:
|
||||
_provide_stacks[name][-1]["emitted"].append(value)
|
||||
else:
|
||||
raise RuntimeError(f"No provider for emit!: {name}")
|
||||
return NIL
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# WARNING: special-forms.sx declares forms not in eval.sx: reset, shift
|
||||
# WARNING: eval.sx dispatches forms not in special-forms.sx: form?, provide
|
||||
"""
|
||||
sx_ref.py -- Generated from reference SX evaluator specification.
|
||||
|
||||
@@ -87,11 +85,9 @@ def sx_context(name, *default):
|
||||
|
||||
|
||||
def sx_emit(name, value):
|
||||
"""Append value to nearest enclosing provider's accumulator. Error if no provider."""
|
||||
"""Append value to nearest enclosing provider's accumulator. No-op if no provider."""
|
||||
if name in _provide_stacks and _provide_stacks[name]:
|
||||
_provide_stacks[name][-1]["emitted"].append(value)
|
||||
else:
|
||||
raise RuntimeError(f"No provider for emit!: {name}")
|
||||
return NIL
|
||||
|
||||
|
||||
@@ -2225,7 +2221,8 @@ def render_to_html(expr, env):
|
||||
elif _match == 'raw-html':
|
||||
return raw_html_content(expr)
|
||||
elif _match == 'spread':
|
||||
return expr
|
||||
sx_emit('element-attrs', spread_attrs(expr))
|
||||
return ''
|
||||
else:
|
||||
return render_value_to_html(trampoline(eval_expr(expr, env)), env)
|
||||
|
||||
@@ -2248,7 +2245,8 @@ def render_value_to_html(val, env):
|
||||
elif _match == 'raw-html':
|
||||
return raw_html_content(val)
|
||||
elif _match == 'spread':
|
||||
return val
|
||||
sx_emit('element-attrs', spread_attrs(val))
|
||||
return ''
|
||||
else:
|
||||
return escape_html(sx_str(val))
|
||||
|
||||
@@ -2266,12 +2264,12 @@ def render_list_to_html(expr, env):
|
||||
else:
|
||||
head = first(expr)
|
||||
if sx_truthy((not sx_truthy((type_of(head) == 'symbol')))):
|
||||
return join('', filter(lambda x: (not sx_truthy(is_spread(x))), map(lambda x: render_value_to_html(x, env), expr)))
|
||||
return join('', map(lambda x: render_value_to_html(x, env), expr))
|
||||
else:
|
||||
name = symbol_name(head)
|
||||
args = rest(expr)
|
||||
if sx_truthy((name == '<>')):
|
||||
return join('', filter(lambda x: (not sx_truthy(is_spread(x))), map(lambda x: render_to_html(x, env), args)))
|
||||
return join('', map(lambda x: render_to_html(x, env), args))
|
||||
elif sx_truthy((name == 'raw!')):
|
||||
return join('', map(lambda x: sx_str(trampoline(eval_expr(x, env))), args))
|
||||
elif sx_truthy((name == 'lake')):
|
||||
@@ -2315,8 +2313,7 @@ def dispatch_html_form(name, expr, env):
|
||||
if sx_truthy((len(expr) == 3)):
|
||||
return render_to_html(nth(expr, 2), env)
|
||||
else:
|
||||
results = map(lambda i: render_to_html(nth(expr, i), env), range(2, len(expr)))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', map(lambda i: render_to_html(nth(expr, i), env), range(2, len(expr))))
|
||||
elif sx_truthy((name == 'cond')):
|
||||
branch = eval_cond(rest(expr), env)
|
||||
if sx_truthy(branch):
|
||||
@@ -2330,38 +2327,36 @@ def dispatch_html_form(name, expr, env):
|
||||
if sx_truthy((len(expr) == 3)):
|
||||
return render_to_html(nth(expr, 2), local)
|
||||
else:
|
||||
results = map(lambda i: render_to_html(nth(expr, i), local), range(2, len(expr)))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', map(lambda i: render_to_html(nth(expr, i), local), range(2, len(expr))))
|
||||
elif sx_truthy(((name == 'begin') if sx_truthy((name == 'begin')) else (name == 'do'))):
|
||||
if sx_truthy((len(expr) == 2)):
|
||||
return render_to_html(nth(expr, 1), env)
|
||||
else:
|
||||
results = map(lambda i: render_to_html(nth(expr, i), env), range(1, len(expr)))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', map(lambda i: render_to_html(nth(expr, i), env), range(1, len(expr))))
|
||||
elif sx_truthy(is_definition_form(name)):
|
||||
trampoline(eval_expr(expr, env))
|
||||
return ''
|
||||
elif sx_truthy((name == 'map')):
|
||||
f = trampoline(eval_expr(nth(expr, 1), env))
|
||||
coll = trampoline(eval_expr(nth(expr, 2), env))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll)))
|
||||
return join('', map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll))
|
||||
elif sx_truthy((name == 'map-indexed')):
|
||||
f = trampoline(eval_expr(nth(expr, 1), env))
|
||||
coll = trampoline(eval_expr(nth(expr, 2), env))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), map_indexed(lambda i, item: (render_lambda_html(f, [i, item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [i, item]), env)), coll)))
|
||||
return join('', map_indexed(lambda i, item: (render_lambda_html(f, [i, item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [i, item]), env)), coll))
|
||||
elif sx_truthy((name == 'filter')):
|
||||
return render_to_html(trampoline(eval_expr(expr, env)), env)
|
||||
elif sx_truthy((name == 'for-each')):
|
||||
f = trampoline(eval_expr(nth(expr, 1), env))
|
||||
coll = trampoline(eval_expr(nth(expr, 2), env))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll)))
|
||||
return join('', map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll))
|
||||
elif sx_truthy((name == 'provide')):
|
||||
prov_name = trampoline(eval_expr(nth(expr, 1), env))
|
||||
prov_val = trampoline(eval_expr(nth(expr, 2), env))
|
||||
body_start = 3
|
||||
body_count = (len(expr) - 3)
|
||||
provide_push(prov_name, prov_val)
|
||||
result = (render_to_html(nth(expr, body_start), env) if sx_truthy((body_count == 1)) else join('', filter(lambda r: (not sx_truthy(is_spread(r))), map(lambda i: render_to_html(nth(expr, i), env), range(body_start, (body_start + body_count))))))
|
||||
result = (render_to_html(nth(expr, body_start), env) if sx_truthy((body_count == 1)) else join('', map(lambda i: render_to_html(nth(expr, i), env), range(body_start, (body_start + body_count)))))
|
||||
provide_pop(prov_name)
|
||||
return result
|
||||
else:
|
||||
@@ -2382,12 +2377,7 @@ def render_html_component(comp, args, env):
|
||||
for p in component_params(comp):
|
||||
local[p] = (dict_get(kwargs, p) if sx_truthy(dict_has(kwargs, p)) else NIL)
|
||||
if sx_truthy(component_has_children(comp)):
|
||||
parts = []
|
||||
for c in children:
|
||||
r = render_to_html(c, env)
|
||||
if sx_truthy((not sx_truthy(is_spread(r)))):
|
||||
parts.append(r)
|
||||
local['children'] = make_raw_html(join('', parts))
|
||||
local['children'] = make_raw_html(join('', map(lambda c: render_to_html(c, env), children)))
|
||||
return render_to_html(component_body(comp), local)
|
||||
|
||||
# render-html-element
|
||||
@@ -2399,14 +2389,12 @@ def render_html_element(tag, args, env):
|
||||
if sx_truthy(is_void):
|
||||
return sx_str('<', tag, render_attrs(attrs), ' />')
|
||||
else:
|
||||
content_parts = []
|
||||
for c in children:
|
||||
result = render_to_html(c, env)
|
||||
if sx_truthy(is_spread(result)):
|
||||
merge_spread_attrs(attrs, spread_attrs(result))
|
||||
else:
|
||||
content_parts.append(result)
|
||||
return sx_str('<', tag, render_attrs(attrs), '>', join('', content_parts), '</', tag, '>')
|
||||
provide_push('element-attrs', NIL)
|
||||
content = join('', map(lambda c: render_to_html(c, env), children))
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
merge_spread_attrs(attrs, spread_dict)
|
||||
provide_pop('element-attrs')
|
||||
return sx_str('<', tag, render_attrs(attrs), '>', content, '</', tag, '>')
|
||||
|
||||
# render-html-lake
|
||||
def render_html_lake(args, env):
|
||||
@@ -2416,14 +2404,12 @@ def render_html_lake(args, env):
|
||||
children = []
|
||||
reduce(lambda state, arg: (lambda skip: (assoc(state, 'skip', False, 'i', (get(state, 'i') + 1)) if sx_truthy(skip) else ((lambda kname: (lambda kval: _sx_begin((_sx_cell_set(_cells, 'lake_id', kval) if sx_truthy((kname == 'id')) else (_sx_cell_set(_cells, 'lake_tag', kval) if sx_truthy((kname == 'tag')) else NIL)), assoc(state, 'skip', True, 'i', (get(state, 'i') + 1))))(trampoline(eval_expr(nth(args, (get(state, 'i') + 1)), env))))(keyword_name(arg)) if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((get(state, 'i') + 1) < len(args)))) else _sx_begin(_sx_append(children, arg), assoc(state, 'i', (get(state, 'i') + 1))))))(get(state, 'skip')), {'i': 0, 'skip': False}, args)
|
||||
lake_attrs = {'data-sx-lake': (_cells['lake_id'] if sx_truthy(_cells['lake_id']) else '')}
|
||||
content_parts = []
|
||||
for c in children:
|
||||
result = render_to_html(c, env)
|
||||
if sx_truthy(is_spread(result)):
|
||||
merge_spread_attrs(lake_attrs, spread_attrs(result))
|
||||
else:
|
||||
content_parts.append(result)
|
||||
return sx_str('<', _cells['lake_tag'], render_attrs(lake_attrs), '>', join('', content_parts), '</', _cells['lake_tag'], '>')
|
||||
provide_push('element-attrs', NIL)
|
||||
content = join('', map(lambda c: render_to_html(c, env), children))
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
merge_spread_attrs(lake_attrs, spread_dict)
|
||||
provide_pop('element-attrs')
|
||||
return sx_str('<', _cells['lake_tag'], render_attrs(lake_attrs), '>', content, '</', _cells['lake_tag'], '>')
|
||||
|
||||
# render-html-marsh
|
||||
def render_html_marsh(args, env):
|
||||
@@ -2433,14 +2419,12 @@ def render_html_marsh(args, env):
|
||||
children = []
|
||||
reduce(lambda state, arg: (lambda skip: (assoc(state, 'skip', False, 'i', (get(state, 'i') + 1)) if sx_truthy(skip) else ((lambda kname: (lambda kval: _sx_begin((_sx_cell_set(_cells, 'marsh_id', kval) if sx_truthy((kname == 'id')) else (_sx_cell_set(_cells, 'marsh_tag', kval) if sx_truthy((kname == 'tag')) else (NIL if sx_truthy((kname == 'transform')) else NIL))), assoc(state, 'skip', True, 'i', (get(state, 'i') + 1))))(trampoline(eval_expr(nth(args, (get(state, 'i') + 1)), env))))(keyword_name(arg)) if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((get(state, 'i') + 1) < len(args)))) else _sx_begin(_sx_append(children, arg), assoc(state, 'i', (get(state, 'i') + 1))))))(get(state, 'skip')), {'i': 0, 'skip': False}, args)
|
||||
marsh_attrs = {'data-sx-marsh': (_cells['marsh_id'] if sx_truthy(_cells['marsh_id']) else '')}
|
||||
content_parts = []
|
||||
for c in children:
|
||||
result = render_to_html(c, env)
|
||||
if sx_truthy(is_spread(result)):
|
||||
merge_spread_attrs(marsh_attrs, spread_attrs(result))
|
||||
else:
|
||||
content_parts.append(result)
|
||||
return sx_str('<', _cells['marsh_tag'], render_attrs(marsh_attrs), '>', join('', content_parts), '</', _cells['marsh_tag'], '>')
|
||||
provide_push('element-attrs', NIL)
|
||||
content = join('', map(lambda c: render_to_html(c, env), children))
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
merge_spread_attrs(marsh_attrs, spread_dict)
|
||||
provide_pop('element-attrs')
|
||||
return sx_str('<', _cells['marsh_tag'], render_attrs(marsh_attrs), '>', content, '</', _cells['marsh_tag'], '>')
|
||||
|
||||
# render-html-island
|
||||
def render_html_island(island, args, env):
|
||||
@@ -2452,12 +2436,7 @@ def render_html_island(island, args, env):
|
||||
for p in component_params(island):
|
||||
local[p] = (dict_get(kwargs, p) if sx_truthy(dict_has(kwargs, p)) else NIL)
|
||||
if sx_truthy(component_has_children(island)):
|
||||
parts = []
|
||||
for c in children:
|
||||
r = render_to_html(c, env)
|
||||
if sx_truthy((not sx_truthy(is_spread(r)))):
|
||||
parts.append(r)
|
||||
local['children'] = make_raw_html(join('', parts))
|
||||
local['children'] = make_raw_html(join('', map(lambda c: render_to_html(c, env), children)))
|
||||
body_html = render_to_html(component_body(island), local)
|
||||
state_sx = serialize_island_state(kwargs)
|
||||
return sx_str('<span data-sx-island="', escape_attr(island_name), '"', (sx_str(' data-sx-state="', escape_attr(state_sx), '"') if sx_truthy(state_sx) else ''), '>', body_html, '</span>')
|
||||
@@ -2483,40 +2462,12 @@ def render_to_sx(expr, env):
|
||||
# aser
|
||||
def aser(expr, env):
|
||||
set_render_active_b(True)
|
||||
_match = type_of(expr)
|
||||
if _match == 'number':
|
||||
return expr
|
||||
elif _match == 'string':
|
||||
return expr
|
||||
elif _match == 'boolean':
|
||||
return expr
|
||||
elif _match == 'nil':
|
||||
result = _sx_case(type_of(expr), [('number', lambda: expr), ('string', lambda: expr), ('boolean', lambda: expr), ('nil', lambda: NIL), ('symbol', lambda: (lambda name: (env_get(env, name) if sx_truthy(env_has(env, name)) else (get_primitive(name) if sx_truthy(is_primitive(name)) else (True if sx_truthy((name == 'true')) else (False if sx_truthy((name == 'false')) else (NIL if sx_truthy((name == 'nil')) else error(sx_str('Undefined symbol: ', name))))))))(symbol_name(expr))), ('keyword', lambda: keyword_name(expr)), ('list', lambda: ([] if sx_truthy(empty_p(expr)) else aser_list(expr, env))), ('spread', lambda: _sx_begin(sx_emit('element-attrs', spread_attrs(expr)), NIL)), (None, lambda: expr)])
|
||||
if sx_truthy(is_spread(result)):
|
||||
sx_emit('element-attrs', spread_attrs(result))
|
||||
return NIL
|
||||
elif _match == 'symbol':
|
||||
name = symbol_name(expr)
|
||||
if sx_truthy(env_has(env, name)):
|
||||
return env_get(env, name)
|
||||
elif sx_truthy(is_primitive(name)):
|
||||
return get_primitive(name)
|
||||
elif sx_truthy((name == 'true')):
|
||||
return True
|
||||
elif sx_truthy((name == 'false')):
|
||||
return False
|
||||
elif sx_truthy((name == 'nil')):
|
||||
return NIL
|
||||
else:
|
||||
return error(sx_str('Undefined symbol: ', name))
|
||||
elif _match == 'keyword':
|
||||
return keyword_name(expr)
|
||||
elif _match == 'list':
|
||||
if sx_truthy(empty_p(expr)):
|
||||
return []
|
||||
else:
|
||||
return aser_list(expr, env)
|
||||
elif _match == 'spread':
|
||||
return expr
|
||||
else:
|
||||
return expr
|
||||
return result
|
||||
|
||||
# aser-list
|
||||
def aser_list(expr, env):
|
||||
@@ -2561,10 +2512,10 @@ def aser_fragment(children, env):
|
||||
result = aser(c, env)
|
||||
if sx_truthy((type_of(result) == 'list')):
|
||||
for item in result:
|
||||
if sx_truthy(((not sx_truthy(is_nil(item))) if not sx_truthy((not sx_truthy(is_nil(item)))) else (not sx_truthy(is_spread(item))))):
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
parts.append(serialize(item))
|
||||
else:
|
||||
if sx_truthy(((not sx_truthy(is_nil(result))) if not sx_truthy((not sx_truthy(is_nil(result)))) else (not sx_truthy(is_spread(result))))):
|
||||
if sx_truthy((not sx_truthy(is_nil(result)))):
|
||||
parts.append(serialize(result))
|
||||
if sx_truthy(empty_p(parts)):
|
||||
return ''
|
||||
@@ -2574,9 +2525,11 @@ def aser_fragment(children, env):
|
||||
# aser-call
|
||||
def aser_call(name, args, env):
|
||||
_cells = {}
|
||||
parts = [name]
|
||||
attr_parts = []
|
||||
child_parts = []
|
||||
_cells['skip'] = False
|
||||
_cells['i'] = 0
|
||||
provide_push('element-attrs', NIL)
|
||||
for arg in args:
|
||||
if sx_truthy(_cells['skip']):
|
||||
_cells['skip'] = False
|
||||
@@ -2585,26 +2538,27 @@ def aser_call(name, args, env):
|
||||
if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((_cells['i'] + 1) < len(args)))):
|
||||
val = aser(nth(args, (_cells['i'] + 1)), env)
|
||||
if sx_truthy((not sx_truthy(is_nil(val)))):
|
||||
parts.append(sx_str(':', keyword_name(arg)))
|
||||
parts.append(serialize(val))
|
||||
attr_parts.append(sx_str(':', keyword_name(arg)))
|
||||
attr_parts.append(serialize(val))
|
||||
_cells['skip'] = True
|
||||
_cells['i'] = (_cells['i'] + 1)
|
||||
else:
|
||||
val = aser(arg, env)
|
||||
if sx_truthy((not sx_truthy(is_nil(val)))):
|
||||
if sx_truthy(is_spread(val)):
|
||||
for k in keys(spread_attrs(val)):
|
||||
v = dict_get(spread_attrs(val), k)
|
||||
parts.append(sx_str(':', k))
|
||||
parts.append(serialize(v))
|
||||
if sx_truthy((type_of(val) == 'list')):
|
||||
for item in val:
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
child_parts.append(serialize(item))
|
||||
else:
|
||||
if sx_truthy((type_of(val) == 'list')):
|
||||
for item in val:
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
parts.append(serialize(item))
|
||||
else:
|
||||
parts.append(serialize(val))
|
||||
child_parts.append(serialize(val))
|
||||
_cells['i'] = (_cells['i'] + 1)
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
for k in keys(spread_dict):
|
||||
v = dict_get(spread_dict, k)
|
||||
attr_parts.append(sx_str(':', k))
|
||||
attr_parts.append(serialize(v))
|
||||
provide_pop('element-attrs')
|
||||
parts = concat([name], attr_parts, child_parts)
|
||||
return sx_str('(', join(' ', parts), ')')
|
||||
|
||||
# SPECIAL_FORM_NAMES
|
||||
@@ -3659,7 +3613,8 @@ async def async_render(expr, env, ctx):
|
||||
elif _match == 'raw-html':
|
||||
return raw_html_content(expr)
|
||||
elif _match == 'spread':
|
||||
return expr
|
||||
sx_emit('element-attrs', spread_attrs(expr))
|
||||
return ''
|
||||
elif _match == 'symbol':
|
||||
val = (await async_eval(expr, env, ctx))
|
||||
return (await async_render(val, env, ctx))
|
||||
@@ -3691,7 +3646,7 @@ async def async_render_list(expr, env, ctx):
|
||||
elif sx_truthy((name == 'raw!')):
|
||||
return (await async_render_raw(args, env, ctx))
|
||||
elif sx_truthy((name == '<>')):
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_render(args, env, ctx))))
|
||||
return join('', (await async_map_render(args, env, ctx)))
|
||||
elif sx_truthy(starts_with_p(name, 'html:')):
|
||||
return (await async_render_element(slice(name, 5), args, env, ctx))
|
||||
elif sx_truthy(async_render_form_p(name)):
|
||||
@@ -3746,12 +3701,12 @@ async def async_render_element(tag, args, env, ctx):
|
||||
else:
|
||||
token = (svg_context_set(True) if sx_truthy(((tag == 'svg') if sx_truthy((tag == 'svg')) else (tag == 'math'))) else NIL)
|
||||
content_parts = []
|
||||
provide_push('element-attrs', NIL)
|
||||
for c in children:
|
||||
result = (await async_render(c, env, ctx))
|
||||
if sx_truthy(is_spread(result)):
|
||||
merge_spread_attrs(attrs, spread_attrs(result))
|
||||
else:
|
||||
content_parts.append(result)
|
||||
content_parts.append((await async_render(c, env, ctx)))
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
merge_spread_attrs(attrs, spread_dict)
|
||||
provide_pop('element-attrs')
|
||||
if sx_truthy(token):
|
||||
svg_context_reset(token)
|
||||
return sx_str('<', tag, render_attrs(attrs), '>', join('', content_parts), '</', tag, '>')
|
||||
@@ -3787,9 +3742,7 @@ async def async_render_component(comp, args, env, ctx):
|
||||
if sx_truthy(component_has_children(comp)):
|
||||
parts = []
|
||||
for c in children:
|
||||
r = (await async_render(c, env, ctx))
|
||||
if sx_truthy((not sx_truthy(is_spread(r)))):
|
||||
parts.append(r)
|
||||
parts.append((await async_render(c, env, ctx)))
|
||||
local['children'] = make_raw_html(join('', parts))
|
||||
return (await async_render(component_body(comp), local, ctx))
|
||||
|
||||
@@ -3805,9 +3758,7 @@ async def async_render_island(island, args, env, ctx):
|
||||
if sx_truthy(component_has_children(island)):
|
||||
parts = []
|
||||
for c in children:
|
||||
r = (await async_render(c, env, ctx))
|
||||
if sx_truthy((not sx_truthy(is_spread(r)))):
|
||||
parts.append(r)
|
||||
parts.append((await async_render(c, env, ctx)))
|
||||
local['children'] = make_raw_html(join('', parts))
|
||||
body_html = (await async_render(component_body(island), local, ctx))
|
||||
state_json = serialize_island_state(kwargs)
|
||||
@@ -3871,8 +3822,7 @@ async def dispatch_async_render_form(name, expr, env, ctx):
|
||||
if sx_truthy((len(expr) == 3)):
|
||||
return (await async_render(nth(expr, 2), env, ctx))
|
||||
else:
|
||||
results = (await async_map_render(slice(expr, 2), env, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', (await async_map_render(slice(expr, 2), env, ctx)))
|
||||
elif sx_truthy((name == 'cond')):
|
||||
clauses = rest(expr)
|
||||
if sx_truthy(cond_scheme_p(clauses)):
|
||||
@@ -3886,38 +3836,36 @@ async def dispatch_async_render_form(name, expr, env, ctx):
|
||||
if sx_truthy((len(expr) == 3)):
|
||||
return (await async_render(nth(expr, 2), local, ctx))
|
||||
else:
|
||||
results = (await async_map_render(slice(expr, 2), local, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', (await async_map_render(slice(expr, 2), local, ctx)))
|
||||
elif sx_truthy(((name == 'begin') if sx_truthy((name == 'begin')) else (name == 'do'))):
|
||||
if sx_truthy((len(expr) == 2)):
|
||||
return (await async_render(nth(expr, 1), env, ctx))
|
||||
else:
|
||||
results = (await async_map_render(rest(expr), env, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', (await async_map_render(rest(expr), env, ctx)))
|
||||
elif sx_truthy(is_definition_form(name)):
|
||||
(await async_eval(expr, env, ctx))
|
||||
return ''
|
||||
elif sx_truthy((name == 'map')):
|
||||
f = (await async_eval(nth(expr, 1), env, ctx))
|
||||
coll = (await async_eval(nth(expr, 2), env, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_fn_render(f, coll, env, ctx))))
|
||||
return join('', (await async_map_fn_render(f, coll, env, ctx)))
|
||||
elif sx_truthy((name == 'map-indexed')):
|
||||
f = (await async_eval(nth(expr, 1), env, ctx))
|
||||
coll = (await async_eval(nth(expr, 2), env, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_indexed_fn_render(f, coll, env, ctx))))
|
||||
return join('', (await async_map_indexed_fn_render(f, coll, env, ctx)))
|
||||
elif sx_truthy((name == 'filter')):
|
||||
return (await async_render((await async_eval(expr, env, ctx)), env, ctx))
|
||||
elif sx_truthy((name == 'for-each')):
|
||||
f = (await async_eval(nth(expr, 1), env, ctx))
|
||||
coll = (await async_eval(nth(expr, 2), env, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_fn_render(f, coll, env, ctx))))
|
||||
return join('', (await async_map_fn_render(f, coll, env, ctx)))
|
||||
elif sx_truthy((name == 'provide')):
|
||||
prov_name = (await async_eval(nth(expr, 1), env, ctx))
|
||||
prov_val = (await async_eval(nth(expr, 2), env, ctx))
|
||||
body_start = 3
|
||||
body_count = (len(expr) - 3)
|
||||
provide_push(prov_name, prov_val)
|
||||
result = ((await async_render(nth(expr, body_start), env, ctx)) if sx_truthy((body_count == 1)) else (lambda results: join('', filter(lambda r: (not sx_truthy(is_spread(r))), results)))((await async_map_render(slice(expr, body_start), env, ctx))))
|
||||
result = ((await async_render(nth(expr, body_start), env, ctx)) if sx_truthy((body_count == 1)) else join('', (await async_map_render(slice(expr, body_start), env, ctx))))
|
||||
provide_pop(prov_name)
|
||||
return result
|
||||
else:
|
||||
@@ -4019,42 +3967,35 @@ async def async_invoke(f, *args):
|
||||
|
||||
# async-aser
|
||||
async def async_aser(expr, env, ctx):
|
||||
_match = type_of(expr)
|
||||
if _match == 'number':
|
||||
return expr
|
||||
elif _match == 'string':
|
||||
return expr
|
||||
elif _match == 'boolean':
|
||||
return expr
|
||||
elif _match == 'nil':
|
||||
return NIL
|
||||
elif _match == 'symbol':
|
||||
t = type_of(expr)
|
||||
result = NIL
|
||||
if sx_truthy((t == 'number')):
|
||||
result = expr
|
||||
elif sx_truthy((t == 'string')):
|
||||
result = expr
|
||||
elif sx_truthy((t == 'boolean')):
|
||||
result = expr
|
||||
elif sx_truthy((t == 'nil')):
|
||||
result = NIL
|
||||
elif sx_truthy((t == 'symbol')):
|
||||
name = symbol_name(expr)
|
||||
if sx_truthy(env_has(env, name)):
|
||||
return env_get(env, name)
|
||||
elif sx_truthy(is_primitive(name)):
|
||||
return get_primitive(name)
|
||||
elif sx_truthy((name == 'true')):
|
||||
return True
|
||||
elif sx_truthy((name == 'false')):
|
||||
return False
|
||||
elif sx_truthy((name == 'nil')):
|
||||
return NIL
|
||||
else:
|
||||
return error(sx_str('Undefined symbol: ', name))
|
||||
elif _match == 'keyword':
|
||||
return keyword_name(expr)
|
||||
elif _match == 'dict':
|
||||
return (await async_aser_dict(expr, env, ctx))
|
||||
elif _match == 'spread':
|
||||
return expr
|
||||
elif _match == 'list':
|
||||
if sx_truthy(empty_p(expr)):
|
||||
return []
|
||||
else:
|
||||
return (await async_aser_list(expr, env, ctx))
|
||||
result = (env_get(env, name) if sx_truthy(env_has(env, name)) else (get_primitive(name) if sx_truthy(is_primitive(name)) else (True if sx_truthy((name == 'true')) else (False if sx_truthy((name == 'false')) else (NIL if sx_truthy((name == 'nil')) else error(sx_str('Undefined symbol: ', name)))))))
|
||||
elif sx_truthy((t == 'keyword')):
|
||||
result = keyword_name(expr)
|
||||
elif sx_truthy((t == 'dict')):
|
||||
result = (await async_aser_dict(expr, env, ctx))
|
||||
elif sx_truthy((t == 'spread')):
|
||||
sx_emit('element-attrs', spread_attrs(expr))
|
||||
result = NIL
|
||||
elif sx_truthy((t == 'list')):
|
||||
result = ([] if sx_truthy(empty_p(expr)) else (await async_aser_list(expr, env, ctx)))
|
||||
else:
|
||||
return expr
|
||||
result = expr
|
||||
if sx_truthy(is_spread(result)):
|
||||
sx_emit('element-attrs', spread_attrs(result))
|
||||
return NIL
|
||||
else:
|
||||
return result
|
||||
|
||||
# async-aser-dict
|
||||
async def async_aser_dict(expr, env, ctx):
|
||||
@@ -4148,10 +4089,10 @@ async def async_aser_fragment(children, env, ctx):
|
||||
result = (await async_aser(c, env, ctx))
|
||||
if sx_truthy((type_of(result) == 'list')):
|
||||
for item in result:
|
||||
if sx_truthy(((not sx_truthy(is_nil(item))) if not sx_truthy((not sx_truthy(is_nil(item)))) else (not sx_truthy(is_spread(item))))):
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
parts.append(serialize(item))
|
||||
else:
|
||||
if sx_truthy(((not sx_truthy(is_nil(result))) if not sx_truthy((not sx_truthy(is_nil(result)))) else (not sx_truthy(is_spread(result))))):
|
||||
if sx_truthy((not sx_truthy(is_nil(result)))):
|
||||
parts.append(serialize(result))
|
||||
if sx_truthy(empty_p(parts)):
|
||||
return make_sx_expr('')
|
||||
@@ -4204,9 +4145,11 @@ async def async_parse_aser_kw_args(args, kwargs, children, env, ctx):
|
||||
async def async_aser_call(name, args, env, ctx):
|
||||
_cells = {}
|
||||
token = (svg_context_set(True) if sx_truthy(((name == 'svg') if sx_truthy((name == 'svg')) else (name == 'math'))) else NIL)
|
||||
parts = [name]
|
||||
attr_parts = []
|
||||
child_parts = []
|
||||
_cells['skip'] = False
|
||||
_cells['i'] = 0
|
||||
provide_push('element-attrs', NIL)
|
||||
for arg in args:
|
||||
if sx_truthy(_cells['skip']):
|
||||
_cells['skip'] = False
|
||||
@@ -4215,39 +4158,40 @@ async def async_aser_call(name, args, env, ctx):
|
||||
if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((_cells['i'] + 1) < len(args)))):
|
||||
val = (await async_aser(nth(args, (_cells['i'] + 1)), env, ctx))
|
||||
if sx_truthy((not sx_truthy(is_nil(val)))):
|
||||
parts.append(sx_str(':', keyword_name(arg)))
|
||||
attr_parts.append(sx_str(':', keyword_name(arg)))
|
||||
if sx_truthy((type_of(val) == 'list')):
|
||||
live = filter(lambda v: (not sx_truthy(is_nil(v))), val)
|
||||
if sx_truthy(empty_p(live)):
|
||||
parts.append('nil')
|
||||
attr_parts.append('nil')
|
||||
else:
|
||||
items = map(serialize, live)
|
||||
if sx_truthy(some(lambda v: is_sx_expr(v), live)):
|
||||
parts.append(sx_str('(<> ', join(' ', items), ')'))
|
||||
attr_parts.append(sx_str('(<> ', join(' ', items), ')'))
|
||||
else:
|
||||
parts.append(sx_str('(list ', join(' ', items), ')'))
|
||||
attr_parts.append(sx_str('(list ', join(' ', items), ')'))
|
||||
else:
|
||||
parts.append(serialize(val))
|
||||
attr_parts.append(serialize(val))
|
||||
_cells['skip'] = True
|
||||
_cells['i'] = (_cells['i'] + 1)
|
||||
else:
|
||||
result = (await async_aser(arg, env, ctx))
|
||||
if sx_truthy((not sx_truthy(is_nil(result)))):
|
||||
if sx_truthy(is_spread(result)):
|
||||
for k in keys(spread_attrs(result)):
|
||||
v = dict_get(spread_attrs(result), k)
|
||||
parts.append(sx_str(':', k))
|
||||
parts.append(serialize(v))
|
||||
if sx_truthy((type_of(result) == 'list')):
|
||||
for item in result:
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
child_parts.append(serialize(item))
|
||||
else:
|
||||
if sx_truthy((type_of(result) == 'list')):
|
||||
for item in result:
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
parts.append(serialize(item))
|
||||
else:
|
||||
parts.append(serialize(result))
|
||||
child_parts.append(serialize(result))
|
||||
_cells['i'] = (_cells['i'] + 1)
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
for k in keys(spread_dict):
|
||||
v = dict_get(spread_dict, k)
|
||||
attr_parts.append(sx_str(':', k))
|
||||
attr_parts.append(serialize(v))
|
||||
provide_pop('element-attrs')
|
||||
if sx_truthy(token):
|
||||
svg_context_reset(token)
|
||||
parts = concat([name], attr_parts, child_parts)
|
||||
return make_sx_expr(sx_str('(', join(' ', parts), ')'))
|
||||
|
||||
# ASYNC_ASER_FORM_NAMES
|
||||
|
||||
@@ -285,6 +285,19 @@
|
||||
(assert-equal "(div :class \"card\" :style \"color:red\" \"hello\")"
|
||||
(render-sx "(div (make-spread {:class \"card\"}) (make-spread {:style \"color:red\"}) \"hello\")")))
|
||||
|
||||
(deftest "spread in fragment is filtered"
|
||||
(deftest "spread in fragment is silently dropped"
|
||||
(assert-equal "(<> \"hello\")"
|
||||
(render-sx "(<> (make-spread {:class \"card\"}) \"hello\")"))))
|
||||
(render-sx "(<> (make-spread {:class \"card\"}) \"hello\")")))
|
||||
|
||||
(deftest "stored spread in let binding"
|
||||
(assert-equal "(div :class \"card\" \"hello\")"
|
||||
(render-sx "(let ((card (make-spread {:class \"card\"})))
|
||||
(div card \"hello\"))")))
|
||||
|
||||
(deftest "spread in nested element"
|
||||
(assert-equal "(div (span :class \"inner\" \"hi\"))"
|
||||
(render-sx "(div (span (make-spread {:class \"inner\"}) \"hi\"))")))
|
||||
|
||||
(deftest "spread in non-element context silently drops"
|
||||
(assert-equal "hello"
|
||||
(render-sx "(do (make-spread {:class \"card\"}) \"hello\")"))))
|
||||
|
||||
Reference in New Issue
Block a user