Optimize evaluator hot path: prototype-chain envs, imperative kwarg parsing
Three key optimizations to the JS evaluator platform layer: 1. envMerge uses Object.create() instead of copying all keys — O(own) vs O(all) 2. renderDomComponent/renderDomElement override: imperative kwarg/attr parsing replaces reduce+assoc pattern (no per-arg dict allocation) 3. callComponent/parseKeywordArgs override: same imperative pattern for the eval path (not just DOM rendering) Wire format and spec semantics unchanged — these are host-level performance overrides in the platform JS. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
// =========================================================================
|
||||
|
||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||
var SX_VERSION = "2026-03-07T01:23:32Z";
|
||||
var SX_VERSION = "2026-03-07T01:41:53Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -174,8 +174,12 @@
|
||||
function envHas(env, name) { return name in env; }
|
||||
function envGet(env, name) { return env[name]; }
|
||||
function envSet(env, name, val) { env[name] = val; }
|
||||
function envExtend(env) { return merge(env); }
|
||||
function envMerge(base, overlay) { return merge(base, overlay); }
|
||||
function envExtend(env) { return Object.create(env); }
|
||||
function envMerge(base, overlay) {
|
||||
var child = Object.create(base);
|
||||
if (overlay) for (var k in overlay) if (overlay.hasOwnProperty(k)) child[k] = overlay[k];
|
||||
return child;
|
||||
}
|
||||
|
||||
function dictSet(d, k, v) { d[k] = v; return v; }
|
||||
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
||||
@@ -515,6 +519,52 @@
|
||||
return NIL;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Performance overrides — evaluator hot path
|
||||
// =========================================================================
|
||||
|
||||
// Override parseKeywordArgs: imperative loop instead of reduce+assoc
|
||||
parseKeywordArgs = function(rawArgs, env) {
|
||||
var kwargs = {};
|
||||
var children = [];
|
||||
for (var i = 0; i < rawArgs.length; i++) {
|
||||
var arg = rawArgs[i];
|
||||
if (arg && arg._kw && (i + 1) < rawArgs.length) {
|
||||
kwargs[arg.name] = trampoline(evalExpr(rawArgs[i + 1], env));
|
||||
i++;
|
||||
} else {
|
||||
children.push(trampoline(evalExpr(arg, env)));
|
||||
}
|
||||
}
|
||||
return [kwargs, children];
|
||||
};
|
||||
|
||||
// Override callComponent: use prototype chain env, imperative kwarg binding
|
||||
callComponent = function(comp, rawArgs, env) {
|
||||
var kwargs = {};
|
||||
var children = [];
|
||||
for (var i = 0; i < rawArgs.length; i++) {
|
||||
var arg = rawArgs[i];
|
||||
if (arg && arg._kw && (i + 1) < rawArgs.length) {
|
||||
kwargs[arg.name] = trampoline(evalExpr(rawArgs[i + 1], env));
|
||||
i++;
|
||||
} else {
|
||||
children.push(trampoline(evalExpr(arg, env)));
|
||||
}
|
||||
}
|
||||
var local = Object.create(componentClosure(comp));
|
||||
for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k];
|
||||
var params = componentParams(comp);
|
||||
for (var j = 0; j < params.length; j++) {
|
||||
var p = params[j];
|
||||
local[p] = p in kwargs ? kwargs[p] : NIL;
|
||||
}
|
||||
if (componentHasChildren(comp)) {
|
||||
local["children"] = children;
|
||||
}
|
||||
return makeThunk(componentBody(comp), local);
|
||||
};
|
||||
|
||||
// =========================================================================
|
||||
// Platform: deps module — component dependency analysis
|
||||
// =========================================================================
|
||||
@@ -2849,6 +2899,84 @@ callExpr.push(dictGet(kwargs, k)); } }
|
||||
|
||||
function domTagName(el) { return el && el.tagName ? el.tagName : ""; }
|
||||
|
||||
// =========================================================================
|
||||
// Performance overrides — replace transpiled spec with imperative JS
|
||||
// =========================================================================
|
||||
|
||||
// Override renderDomComponent: imperative kwarg parsing, no reduce/assoc
|
||||
renderDomComponent = function(comp, args, env, ns) {
|
||||
// Parse keyword args imperatively
|
||||
var kwargs = {};
|
||||
var children = [];
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
if (arg && arg._kw && (i + 1) < args.length) {
|
||||
kwargs[arg.name] = trampoline(evalExpr(args[i + 1], env));
|
||||
i++; // skip value
|
||||
} else {
|
||||
children.push(arg);
|
||||
}
|
||||
}
|
||||
// Build local env via prototype chain
|
||||
var local = Object.create(componentClosure(comp));
|
||||
// Copy caller env own properties
|
||||
for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k];
|
||||
// Bind params
|
||||
var params = componentParams(comp);
|
||||
for (var j = 0; j < params.length; j++) {
|
||||
var p = params[j];
|
||||
local[p] = p in kwargs ? kwargs[p] : NIL;
|
||||
}
|
||||
// Bind children
|
||||
if (componentHasChildren(comp)) {
|
||||
var childFrag = document.createDocumentFragment();
|
||||
for (var c = 0; c < children.length; c++) {
|
||||
var rendered = renderToDom(children[c], env, ns);
|
||||
if (rendered) childFrag.appendChild(rendered);
|
||||
}
|
||||
local["children"] = childFrag;
|
||||
}
|
||||
return renderToDom(componentBody(comp), local, ns);
|
||||
};
|
||||
|
||||
// Override renderDomElement: imperative attr parsing, no reduce/assoc
|
||||
renderDomElement = function(tag, args, env, ns) {
|
||||
var newNs = tag === "svg" ? SVG_NS : tag === "math" ? MATH_NS : ns;
|
||||
var el = domCreateElement(tag, newNs);
|
||||
var extraClasses = [];
|
||||
var isVoid = contains(VOID_ELEMENTS, tag);
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
if (arg && arg._kw && (i + 1) < args.length) {
|
||||
var attrName = arg.name;
|
||||
var attrVal = trampoline(evalExpr(args[i + 1], env));
|
||||
i++; // skip value
|
||||
if (isNil(attrVal) || attrVal === false) continue;
|
||||
if (attrName === "class" && attrVal && attrVal._styleValue) {
|
||||
extraClasses.push(attrVal.className);
|
||||
} else if (attrName === "style" && attrVal && attrVal._styleValue) {
|
||||
extraClasses.push(attrVal.className);
|
||||
} else if (contains(BOOLEAN_ATTRS, attrName)) {
|
||||
if (isSxTruthy(attrVal)) el.setAttribute(attrName, "");
|
||||
} else if (attrVal === true) {
|
||||
el.setAttribute(attrName, "");
|
||||
} else {
|
||||
el.setAttribute(attrName, String(attrVal));
|
||||
}
|
||||
} else {
|
||||
if (!isVoid) {
|
||||
var child = renderToDom(arg, env, newNs);
|
||||
if (child) el.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (extraClasses.length) {
|
||||
var existing = el.getAttribute("class") || "";
|
||||
el.setAttribute("class", (existing ? existing + " " : "") + extraClasses.join(" "));
|
||||
}
|
||||
return el;
|
||||
};
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Platform interface — Engine pure logic (browser + node compatible)
|
||||
|
||||
@@ -1710,8 +1710,12 @@ PLATFORM_JS_PRE = '''
|
||||
function envHas(env, name) { return name in env; }
|
||||
function envGet(env, name) { return env[name]; }
|
||||
function envSet(env, name, val) { env[name] = val; }
|
||||
function envExtend(env) { return merge(env); }
|
||||
function envMerge(base, overlay) { return merge(base, overlay); }
|
||||
function envExtend(env) { return Object.create(env); }
|
||||
function envMerge(base, overlay) {
|
||||
var child = Object.create(base);
|
||||
if (overlay) for (var k in overlay) if (overlay.hasOwnProperty(k)) child[k] = overlay[k];
|
||||
return child;
|
||||
}
|
||||
|
||||
function dictSet(d, k, v) { d[k] = v; return v; }
|
||||
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
||||
@@ -1852,7 +1856,53 @@ PLATFORM_JS_POST = '''
|
||||
function forEachIndexed(fn, coll) {
|
||||
for (var i = 0; i < coll.length; i++) fn(i, coll[i]);
|
||||
return NIL;
|
||||
}'''
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Performance overrides — evaluator hot path
|
||||
// =========================================================================
|
||||
|
||||
// Override parseKeywordArgs: imperative loop instead of reduce+assoc
|
||||
parseKeywordArgs = function(rawArgs, env) {
|
||||
var kwargs = {};
|
||||
var children = [];
|
||||
for (var i = 0; i < rawArgs.length; i++) {
|
||||
var arg = rawArgs[i];
|
||||
if (arg && arg._kw && (i + 1) < rawArgs.length) {
|
||||
kwargs[arg.name] = trampoline(evalExpr(rawArgs[i + 1], env));
|
||||
i++;
|
||||
} else {
|
||||
children.push(trampoline(evalExpr(arg, env)));
|
||||
}
|
||||
}
|
||||
return [kwargs, children];
|
||||
};
|
||||
|
||||
// Override callComponent: use prototype chain env, imperative kwarg binding
|
||||
callComponent = function(comp, rawArgs, env) {
|
||||
var kwargs = {};
|
||||
var children = [];
|
||||
for (var i = 0; i < rawArgs.length; i++) {
|
||||
var arg = rawArgs[i];
|
||||
if (arg && arg._kw && (i + 1) < rawArgs.length) {
|
||||
kwargs[arg.name] = trampoline(evalExpr(rawArgs[i + 1], env));
|
||||
i++;
|
||||
} else {
|
||||
children.push(trampoline(evalExpr(arg, env)));
|
||||
}
|
||||
}
|
||||
var local = Object.create(componentClosure(comp));
|
||||
for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k];
|
||||
var params = componentParams(comp);
|
||||
for (var j = 0; j < params.length; j++) {
|
||||
var p = params[j];
|
||||
local[p] = p in kwargs ? kwargs[p] : NIL;
|
||||
}
|
||||
if (componentHasChildren(comp)) {
|
||||
local["children"] = children;
|
||||
}
|
||||
return makeThunk(componentBody(comp), local);
|
||||
};'''
|
||||
|
||||
PLATFORM_DEPS_JS = '''
|
||||
// =========================================================================
|
||||
@@ -2117,6 +2167,84 @@ PLATFORM_DOM_JS = """
|
||||
}
|
||||
|
||||
function domTagName(el) { return el && el.tagName ? el.tagName : ""; }
|
||||
|
||||
// =========================================================================
|
||||
// Performance overrides — replace transpiled spec with imperative JS
|
||||
// =========================================================================
|
||||
|
||||
// Override renderDomComponent: imperative kwarg parsing, no reduce/assoc
|
||||
renderDomComponent = function(comp, args, env, ns) {
|
||||
// Parse keyword args imperatively
|
||||
var kwargs = {};
|
||||
var children = [];
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
if (arg && arg._kw && (i + 1) < args.length) {
|
||||
kwargs[arg.name] = trampoline(evalExpr(args[i + 1], env));
|
||||
i++; // skip value
|
||||
} else {
|
||||
children.push(arg);
|
||||
}
|
||||
}
|
||||
// Build local env via prototype chain
|
||||
var local = Object.create(componentClosure(comp));
|
||||
// Copy caller env own properties
|
||||
for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k];
|
||||
// Bind params
|
||||
var params = componentParams(comp);
|
||||
for (var j = 0; j < params.length; j++) {
|
||||
var p = params[j];
|
||||
local[p] = p in kwargs ? kwargs[p] : NIL;
|
||||
}
|
||||
// Bind children
|
||||
if (componentHasChildren(comp)) {
|
||||
var childFrag = document.createDocumentFragment();
|
||||
for (var c = 0; c < children.length; c++) {
|
||||
var rendered = renderToDom(children[c], env, ns);
|
||||
if (rendered) childFrag.appendChild(rendered);
|
||||
}
|
||||
local["children"] = childFrag;
|
||||
}
|
||||
return renderToDom(componentBody(comp), local, ns);
|
||||
};
|
||||
|
||||
// Override renderDomElement: imperative attr parsing, no reduce/assoc
|
||||
renderDomElement = function(tag, args, env, ns) {
|
||||
var newNs = tag === "svg" ? SVG_NS : tag === "math" ? MATH_NS : ns;
|
||||
var el = domCreateElement(tag, newNs);
|
||||
var extraClasses = [];
|
||||
var isVoid = contains(VOID_ELEMENTS, tag);
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
if (arg && arg._kw && (i + 1) < args.length) {
|
||||
var attrName = arg.name;
|
||||
var attrVal = trampoline(evalExpr(args[i + 1], env));
|
||||
i++; // skip value
|
||||
if (isNil(attrVal) || attrVal === false) continue;
|
||||
if (attrName === "class" && attrVal && attrVal._styleValue) {
|
||||
extraClasses.push(attrVal.className);
|
||||
} else if (attrName === "style" && attrVal && attrVal._styleValue) {
|
||||
extraClasses.push(attrVal.className);
|
||||
} else if (contains(BOOLEAN_ATTRS, attrName)) {
|
||||
if (isSxTruthy(attrVal)) el.setAttribute(attrName, "");
|
||||
} else if (attrVal === true) {
|
||||
el.setAttribute(attrName, "");
|
||||
} else {
|
||||
el.setAttribute(attrName, String(attrVal));
|
||||
}
|
||||
} else {
|
||||
if (!isVoid) {
|
||||
var child = renderToDom(arg, env, newNs);
|
||||
if (child) el.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (extraClasses.length) {
|
||||
var existing = el.getAttribute("class") || "";
|
||||
el.setAttribute("class", (existing ? existing + " " : "") + extraClasses.join(" "));
|
||||
}
|
||||
return el;
|
||||
};
|
||||
"""
|
||||
|
||||
PLATFORM_ENGINE_PURE_JS = """
|
||||
|
||||
Reference in New Issue
Block a user