Add (name :as type) annotation syntax for defcomp params

parse-comp-params now recognizes (name :as type) — a 3-element list
with :as keyword separator. Type annotations are stored on the
Component via component-param-types and used by types.sx for call-site
checking. Unannotated params default to any. 428/428 tests pass (50
types tests including 6 annotation tests).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 17:12:54 +00:00
parent b82fd7822d
commit 8a530569a2
5 changed files with 147 additions and 31 deletions

View File

@@ -14,7 +14,7 @@
// =========================================================================
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
var SX_VERSION = "2026-03-11T16:56:11Z";
var SX_VERSION = "2026-03-11T17:12:38Z";
function isNil(x) { return x === NIL || x === null || x === undefined; }
function isSxTruthy(x) { return x !== false && !isNil(x); }
@@ -904,9 +904,13 @@ return append_b(inits, nth(binding, 1)); }, bindings) : reduce(function(acc, pai
var parsed = parseCompParams(paramsRaw);
var params = first(parsed);
var hasChildren = nth(parsed, 1);
var paramTypes = nth(parsed, 2);
var affinity = defcompKwarg(args, "affinity", "auto");
return (function() {
var comp = makeComponent(compName, params, hasChildren, body, env, affinity);
if (isSxTruthy((isSxTruthy(!isSxTruthy(isNil(paramTypes))) && !isSxTruthy(isEmpty(keys(paramTypes)))))) {
componentSetParamTypes_b(comp, paramTypes);
}
envSet(env, symbolName(nameSym), comp);
return comp;
})();
@@ -928,15 +932,21 @@ return append_b(inits, nth(binding, 1)); }, bindings) : reduce(function(acc, pai
// parse-comp-params
var parseCompParams = function(paramsExpr) { return (function() {
var params = [];
var paramTypes = {};
var hasChildren = false;
var inKey = false;
{ var _c = paramsExpr; for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; if (isSxTruthy((typeOf(p) == "symbol"))) {
(function() {
{ var _c = paramsExpr; for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; (isSxTruthy((isSxTruthy((typeOf(p) == "list")) && isSxTruthy((len(p) == 3)) && isSxTruthy((typeOf(first(p)) == "symbol")) && isSxTruthy((typeOf(nth(p, 1)) == "keyword")) && (keywordName(nth(p, 1)) == "as"))) ? (function() {
var name = symbolName(first(p));
var ptype = nth(p, 2);
return (function() {
var typeVal = (isSxTruthy((typeOf(ptype) == "symbol")) ? symbolName(ptype) : ptype);
return (isSxTruthy(!isSxTruthy(hasChildren)) ? (append_b(params, name), dictSet(paramTypes, name, typeVal)) : NIL);
})();
})() : (isSxTruthy((typeOf(p) == "symbol")) ? (function() {
var name = symbolName(p);
return (isSxTruthy((name == "&key")) ? (inKey = true) : (isSxTruthy((name == "&rest")) ? (hasChildren = true) : (isSxTruthy((name == "&children")) ? (hasChildren = true) : (isSxTruthy(hasChildren) ? NIL : (isSxTruthy(inKey) ? append_b(params, name) : append_b(params, name))))));
})();
} } }
return [params, hasChildren];
})() : NIL)); } }
return [params, hasChildren, paramTypes];
})(); };
// sf-defisland