WIP: pre-existing changes from WASM browser work + test infrastructure

Accumulated changes from WASM browser development sessions:
- sx_runtime.ml: signal subscription + notify, env unwrap tolerance
- sx_browser.bc.js: rebuilt js_of_ocaml browser kernel
- sx_browser.bc.wasm.js + assets: WASM browser kernel build
- sx-platform.js browser tests (test_js, test_platform, test_wasm)
- Playwright sx-inspect.js: interactive page inspector tool
- harness-web.sx: DOM assertion updates
- deploy.sh, Dockerfile, dune-project: build config updates
- test-stepper.sx: stepper unit tests
- reader-macro-demo plan update

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-26 16:40:38 +00:00
parent 10576f86d1
commit c72a5af04d
47 changed files with 5485 additions and 1728 deletions

View File

@@ -14,7 +14,7 @@
// =========================================================================
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
var SX_VERSION = "2026-03-26T11:30:03Z";
var SX_VERSION = "2026-03-26T16:13:53Z";
function isNil(x) { return x === NIL || x === null || x === undefined; }
function isSxTruthy(x) { return x !== false && !isNil(x); }
@@ -6583,6 +6583,400 @@ PRIMITIVES["bridge-event"] = bridgeEvent;
PRIMITIVES["resource"] = resource;
// === Transpiled from types (gradual type system) ===
// base-types
var baseTypes = ["number", "string", "boolean", "nil", "symbol", "keyword", "element", "any", "never", "list", "dict", "lambda", "component", "island", "macro", "signal"];
PRIMITIVES["base-types"] = baseTypes;
// type-any?
var typeAny_p = function(t) { return (t == "any"); };
PRIMITIVES["type-any?"] = typeAny_p;
// type-never?
var typeNever_p = function(t) { return (t == "never"); };
PRIMITIVES["type-never?"] = typeNever_p;
// type-nullable?
var typeNullable_p = function(t) { return (isSxTruthy((t == "any")) ? true : (isSxTruthy((t == "nil")) ? true : (isSxTruthy((isSxTruthy((typeOf(t) == "string")) && endsWith(t, "?"))) ? true : (isSxTruthy((isSxTruthy((typeOf(t) == "list")) && isSxTruthy(!isSxTruthy(isEmpty(t))) && (first(t) == "or"))) ? contains(rest(t), "nil") : false)))); };
PRIMITIVES["type-nullable?"] = typeNullable_p;
// nullable-base
var nullableBase = function(t) { return (isSxTruthy((isSxTruthy((typeOf(t) == "string")) && isSxTruthy(endsWith(t, "?")) && !isSxTruthy((t == "?")))) ? slice(t, 0, (stringLength(t) - 1)) : t); };
PRIMITIVES["nullable-base"] = nullableBase;
// subtype?
var subtype_p = function(a, b) { return (isSxTruthy(typeAny_p(b)) ? true : (isSxTruthy(typeNever_p(a)) ? true : (isSxTruthy(typeAny_p(a)) ? false : (isSxTruthy((a == b)) ? true : (isSxTruthy((a == "nil")) ? typeNullable_p(b) : (isSxTruthy((isSxTruthy((typeOf(b) == "string")) && endsWith(b, "?"))) ? (function() {
var base = nullableBase(b);
return sxOr((a == base), (a == "nil"));
})() : (isSxTruthy((isSxTruthy((typeOf(a) == "list")) && isSxTruthy(!isSxTruthy(isEmpty(a))) && (first(a) == "or"))) ? isEvery(function(member) { return subtype_p(member, b); }, rest(a)) : (isSxTruthy((isSxTruthy((typeOf(b) == "list")) && isSxTruthy(!isSxTruthy(isEmpty(b))) && (first(b) == "or"))) ? some(function(member) { return subtype_p(a, member); }, rest(b)) : (isSxTruthy((isSxTruthy((typeOf(a) == "list")) && isSxTruthy((typeOf(b) == "list")) && isSxTruthy((len(a) == 2)) && isSxTruthy((len(b) == 2)) && isSxTruthy((first(a) == "list-of")) && (first(b) == "list-of"))) ? subtype_p(nth(a, 1), nth(b, 1)) : (isSxTruthy((isSxTruthy((a == "list")) && isSxTruthy((typeOf(b) == "list")) && isSxTruthy((len(b) == 2)) && (first(b) == "list-of"))) ? typeAny_p(nth(b, 1)) : (isSxTruthy((isSxTruthy((typeOf(a) == "list")) && isSxTruthy((len(a) == 2)) && isSxTruthy((first(a) == "list-of")) && (b == "list"))) ? true : false))))))))))); };
PRIMITIVES["subtype?"] = subtype_p;
// type-union
var typeUnion = function(a, b) { return (isSxTruthy((a == b)) ? a : (isSxTruthy(typeAny_p(a)) ? "any" : (isSxTruthy(typeAny_p(b)) ? "any" : (isSxTruthy(typeNever_p(a)) ? b : (isSxTruthy(typeNever_p(b)) ? a : (isSxTruthy(subtype_p(a, b)) ? b : (isSxTruthy(subtype_p(b, a)) ? a : (isSxTruthy((a == "nil")) ? (isSxTruthy((isSxTruthy((typeOf(b) == "string")) && !isSxTruthy(endsWith(b, "?")))) ? (String(b) + String("?")) : ["or", a, b]) : (isSxTruthy((b == "nil")) ? (isSxTruthy((isSxTruthy((typeOf(a) == "string")) && !isSxTruthy(endsWith(a, "?")))) ? (String(a) + String("?")) : ["or", a, b]) : ["or", a, b]))))))))); };
PRIMITIVES["type-union"] = typeUnion;
// narrow-type
var narrowType = function(t, predicateName) { return (isSxTruthy((predicateName == "nil?")) ? ["nil", narrowExcludeNil(t)] : (isSxTruthy((predicateName == "string?")) ? ["string", narrowExclude(t, "string")] : (isSxTruthy((predicateName == "number?")) ? ["number", narrowExclude(t, "number")] : (isSxTruthy((predicateName == "list?")) ? ["list", narrowExclude(t, "list")] : (isSxTruthy((predicateName == "dict?")) ? ["dict", narrowExclude(t, "dict")] : (isSxTruthy((predicateName == "boolean?")) ? ["boolean", narrowExclude(t, "boolean")] : [t, t])))))); };
PRIMITIVES["narrow-type"] = narrowType;
// narrow-exclude-nil
var narrowExcludeNil = function(t) { return (isSxTruthy((t == "nil")) ? "never" : (isSxTruthy((t == "any")) ? "any" : (isSxTruthy((isSxTruthy((typeOf(t) == "string")) && endsWith(t, "?"))) ? nullableBase(t) : (isSxTruthy((isSxTruthy((typeOf(t) == "list")) && isSxTruthy(!isSxTruthy(isEmpty(t))) && (first(t) == "or"))) ? (function() {
var members = filter(function(m) { return !isSxTruthy((m == "nil")); }, rest(t));
return (isSxTruthy((len(members) == 1)) ? first(members) : (isSxTruthy(isEmpty(members)) ? "never" : cons("or", members)));
})() : t)))); };
PRIMITIVES["narrow-exclude-nil"] = narrowExcludeNil;
// narrow-exclude
var narrowExclude = function(t, excluded) { return (isSxTruthy((t == excluded)) ? "never" : (isSxTruthy((t == "any")) ? "any" : (isSxTruthy((isSxTruthy((typeOf(t) == "list")) && isSxTruthy(!isSxTruthy(isEmpty(t))) && (first(t) == "or"))) ? (function() {
var members = filter(function(m) { return !isSxTruthy((m == excluded)); }, rest(t));
return (isSxTruthy((len(members) == 1)) ? first(members) : (isSxTruthy(isEmpty(members)) ? "never" : cons("or", members)));
})() : t))); };
PRIMITIVES["narrow-exclude"] = narrowExclude;
// infer-type
var inferType = function(node, typeEnv, primTypes, typeRegistry) { return (function() {
var kind = typeOf(node);
return (isSxTruthy((kind == "number")) ? "number" : (isSxTruthy((kind == "string")) ? "string" : (isSxTruthy((kind == "boolean")) ? "boolean" : (isSxTruthy(isNil(node)) ? "nil" : (isSxTruthy((kind == "keyword")) ? "keyword" : (isSxTruthy((kind == "symbol")) ? (function() {
var name = symbolName(node);
return (isSxTruthy(dictHas(typeEnv, name)) ? get(typeEnv, name) : (isSxTruthy((name == "true")) ? "boolean" : (isSxTruthy((name == "false")) ? "boolean" : (isSxTruthy((name == "nil")) ? "nil" : (isSxTruthy(dictHas(primTypes, name)) ? get(primTypes, name) : "any")))));
})() : (isSxTruthy((kind == "dict")) ? "dict" : (isSxTruthy((kind == "list")) ? inferListType(node, typeEnv, primTypes, typeRegistry) : "any"))))))));
})(); };
PRIMITIVES["infer-type"] = inferType;
// infer-list-type
var inferListType = function(node, typeEnv, primTypes, typeRegistry) { return (isSxTruthy(isEmpty(node)) ? "list" : (function() {
var head = first(node);
var args = rest(node);
return (isSxTruthy(!isSxTruthy((typeOf(head) == "symbol"))) ? "any" : (function() {
var name = symbolName(head);
return (isSxTruthy((name == "if")) ? inferIfType(args, typeEnv, primTypes, typeRegistry) : (isSxTruthy((name == "when")) ? (isSxTruthy((len(args) >= 2)) ? typeUnion(inferType(last(args), typeEnv, primTypes, typeRegistry), "nil") : "nil") : (isSxTruthy(sxOr((name == "cond"), (name == "case"))) ? "any" : (isSxTruthy((name == "let")) ? inferLetType(args, typeEnv, primTypes, typeRegistry) : (isSxTruthy(sxOr((name == "do"), (name == "begin"))) ? (isSxTruthy(isEmpty(args)) ? "nil" : inferType(last(args), typeEnv, primTypes, typeRegistry)) : (isSxTruthy(sxOr((name == "lambda"), (name == "fn"))) ? "lambda" : (isSxTruthy((name == "and")) ? (isSxTruthy(isEmpty(args)) ? "boolean" : inferType(last(args), typeEnv, primTypes, typeRegistry)) : (isSxTruthy((name == "or")) ? (isSxTruthy(isEmpty(args)) ? "boolean" : reduce(typeUnion, "never", map(function(a) { return inferType(a, typeEnv, primTypes, typeRegistry); }, args))) : (isSxTruthy((name == "map")) ? (isSxTruthy((len(args) >= 2)) ? (function() {
var fnType = inferType(first(args), typeEnv, primTypes, typeRegistry);
return (isSxTruthy((isSxTruthy((typeOf(fnType) == "list")) && (first(fnType) == "->"))) ? ["list-of", last(fnType)] : "list");
})() : "list") : (isSxTruthy((name == "filter")) ? (isSxTruthy((len(args) >= 2)) ? inferType(nth(args, 1), typeEnv, primTypes, typeRegistry) : "list") : (isSxTruthy((name == "reduce")) ? "any" : (isSxTruthy((name == "list")) ? "list" : (isSxTruthy((name == "dict")) ? "dict" : (isSxTruthy((name == "quote")) ? "any" : (isSxTruthy((name == "str")) ? "string" : (isSxTruthy((name == "not")) ? "boolean" : (isSxTruthy((name == "get")) ? (isSxTruthy((isSxTruthy((len(args) >= 2)) && !isSxTruthy(isNil(typeRegistry)))) ? (function() {
var dictType = inferType(first(args), typeEnv, primTypes, typeRegistry);
var keyArg = nth(args, 1);
var keyName = (isSxTruthy((typeOf(keyArg) == "keyword")) ? keywordName(keyArg) : (isSxTruthy((typeOf(keyArg) == "string")) ? keyArg : NIL));
return (isSxTruthy((isSxTruthy(keyName) && isSxTruthy((typeOf(dictType) == "string")) && dictHas(typeRegistry, dictType))) ? (function() {
var resolved = resolveType(dictType, typeRegistry);
return (isSxTruthy((isSxTruthy((typeOf(resolved) == "dict")) && dictHas(resolved, keyName))) ? get(resolved, keyName) : "any");
})() : "any");
})() : "any") : (isSxTruthy(startsWith(name, "~")) ? "element" : (isSxTruthy(dictHas(primTypes, name)) ? get(primTypes, name) : "any")))))))))))))))))));
})());
})()); };
PRIMITIVES["infer-list-type"] = inferListType;
// infer-if-type
var inferIfType = function(args, typeEnv, primTypes, typeRegistry) { return (isSxTruthy((len(args) < 2)) ? "nil" : (function() {
var thenType = inferType(nth(args, 1), typeEnv, primTypes, typeRegistry);
return (isSxTruthy((len(args) >= 3)) ? typeUnion(thenType, inferType(nth(args, 2), typeEnv, primTypes, typeRegistry)) : typeUnion(thenType, "nil"));
})()); };
PRIMITIVES["infer-if-type"] = inferIfType;
// infer-let-type
var inferLetType = function(args, typeEnv, primTypes, typeRegistry) { return (isSxTruthy((len(args) < 2)) ? "nil" : (function() {
var bindings = first(args);
var body = last(args);
var extended = merge(typeEnv, {});
{ var _c = bindings; for (var _i = 0; _i < _c.length; _i++) { var binding = _c[_i]; if (isSxTruthy((isSxTruthy((typeOf(binding) == "list")) && (len(binding) >= 2)))) {
(function() {
var name = (isSxTruthy((typeOf(first(binding)) == "symbol")) ? symbolName(first(binding)) : (String(first(binding))));
var valType = inferType(nth(binding, 1), extended, primTypes, typeRegistry);
return dictSet(extended, name, valType);
})();
} } }
return inferType(body, extended, primTypes, typeRegistry);
})()); };
PRIMITIVES["infer-let-type"] = inferLetType;
// make-diagnostic
var makeDiagnostic = function(level, message, component, expr) { return {"level": level, "component": component, "expr": expr, "message": message}; };
PRIMITIVES["make-diagnostic"] = makeDiagnostic;
// check-primitive-call
var checkPrimitiveCall = function(name, args, typeEnv, primTypes, primParamTypes, compName, typeRegistry) { return (function() {
var diagnostics = [];
if (isSxTruthy((isSxTruthy(!isSxTruthy(isNil(primParamTypes))) && dictHas(primParamTypes, name)))) {
(function() {
var sig = get(primParamTypes, name);
var positional = get(sig, "positional");
var restType = get(sig, "rest-type");
return forEach(function(idx) { return (isSxTruthy((idx < len(args))) ? (isSxTruthy((idx < len(positional))) ? (function() {
var paramInfo = nth(positional, idx);
var argExpr = nth(args, idx);
return (function() {
var expectedType = nth(paramInfo, 1);
return (isSxTruthy(!isSxTruthy(isNil(expectedType))) ? (function() {
var actual = inferType(argExpr, typeEnv, primTypes, typeRegistry);
return (isSxTruthy((isSxTruthy(!isSxTruthy(typeAny_p(expectedType))) && isSxTruthy(!isSxTruthy(typeAny_p(actual))) && !isSxTruthy(subtypeResolved_p(actual, expectedType, typeRegistry)))) ? append_b(diagnostics, makeDiagnostic("error", (String("Argument ") + String((idx + 1)) + String(" of `") + String(name) + String("` expects ") + String(expectedType) + String(", got ") + String(actual)), compName, argExpr)) : NIL);
})() : NIL);
})();
})() : (isSxTruthy(!isSxTruthy(isNil(restType))) ? (function() {
var argExpr = nth(args, idx);
var actual = inferType(argExpr, typeEnv, primTypes, typeRegistry);
return (isSxTruthy((isSxTruthy(!isSxTruthy(typeAny_p(restType))) && isSxTruthy(!isSxTruthy(typeAny_p(actual))) && !isSxTruthy(subtypeResolved_p(actual, restType, typeRegistry)))) ? append_b(diagnostics, makeDiagnostic("error", (String("Argument ") + String((idx + 1)) + String(" of `") + String(name) + String("` expects ") + String(restType) + String(", got ") + String(actual)), compName, argExpr)) : NIL);
})() : NIL)) : NIL); }, range(0, len(args), 1));
})();
}
return diagnostics;
})(); };
PRIMITIVES["check-primitive-call"] = checkPrimitiveCall;
// check-component-call
var checkComponentCall = function(compName, comp, callArgs, typeEnv, primTypes, typeRegistry) { return (function() {
var diagnostics = [];
var paramTypes = componentParamTypes(comp);
var params = componentParams(comp);
if (isSxTruthy((isSxTruthy(!isSxTruthy(isNil(paramTypes))) && !isSxTruthy(isEmpty(keys(paramTypes)))))) {
(function() {
var i = 0;
var providedKeys = [];
{ var _c = range(0, len(callArgs), 1); for (var _i = 0; _i < _c.length; _i++) { var idx = _c[_i]; if (isSxTruthy((idx < len(callArgs)))) {
(function() {
var arg = nth(callArgs, idx);
return (isSxTruthy((typeOf(arg) == "keyword")) ? (function() {
var keyName = keywordName(arg);
providedKeys.push(keyName);
return (isSxTruthy(((idx + 1) < len(callArgs))) ? (function() {
var valExpr = nth(callArgs, (idx + 1));
return (isSxTruthy(dictHas(paramTypes, keyName)) ? (function() {
var expected = get(paramTypes, keyName);
var actual = inferType(valExpr, typeEnv, primTypes, typeRegistry);
return (isSxTruthy((isSxTruthy(!isSxTruthy(typeAny_p(expected))) && isSxTruthy(!isSxTruthy(typeAny_p(actual))) && !isSxTruthy(subtypeResolved_p(actual, expected, typeRegistry)))) ? append_b(diagnostics, makeDiagnostic("error", (String("Keyword :") + String(keyName) + String(" of ") + String(compName) + String(" expects ") + String(expected) + String(", got ") + String(actual)), compName, valExpr)) : NIL);
})() : NIL);
})() : NIL);
})() : NIL);
})();
} } }
{ var _c = params; for (var _i = 0; _i < _c.length; _i++) { var paramName = _c[_i]; if (isSxTruthy((isSxTruthy(dictHas(paramTypes, paramName)) && isSxTruthy(!isSxTruthy(contains(providedKeys, paramName))) && !isSxTruthy(typeNullable_p(get(paramTypes, paramName)))))) {
diagnostics.push(makeDiagnostic("warning", (String("Required param :") + String(paramName) + String(" of ") + String(compName) + String(" not provided")), compName, NIL));
} } }
return forEach(function(key) { return (isSxTruthy(!isSxTruthy(contains(params, key))) ? append_b(diagnostics, makeDiagnostic("warning", (String("Unknown keyword :") + String(key) + String(" passed to ") + String(compName)), compName, NIL)) : NIL); }, providedKeys);
})();
}
return diagnostics;
})(); };
PRIMITIVES["check-component-call"] = checkComponentCall;
// check-body-walk
var checkBodyWalk = function(node, compName, typeEnv, primTypes, primParamTypes, env, diagnostics, typeRegistry, effectAnnotations) { return (function() {
var kind = typeOf(node);
return (isSxTruthy((kind == "list")) ? (isSxTruthy(!isSxTruthy(isEmpty(node))) ? (function() {
var head = first(node);
var args = rest(node);
if (isSxTruthy((typeOf(head) == "symbol"))) {
(function() {
var name = symbolName(head);
if (isSxTruthy(startsWith(name, "~"))) {
(function() {
var compVal = envGet(env, name);
return (isSxTruthy((typeOf(compVal) == "component")) ? forEach(function(d) { return append_b(diagnostics, d); }, checkComponentCall(name, compVal, args, typeEnv, primTypes, typeRegistry)) : NIL);
})();
if (isSxTruthy(!isSxTruthy(isNil(effectAnnotations)))) {
(function() {
var callerEffects = getEffects(compName, effectAnnotations);
return forEach(function(d) { return append_b(diagnostics, d); }, checkEffectCall(name, callerEffects, effectAnnotations, compName));
})();
}
}
if (isSxTruthy((isSxTruthy(!isSxTruthy(startsWith(name, "~"))) && isSxTruthy(!isSxTruthy(isNil(primParamTypes))) && dictHas(primParamTypes, name)))) {
{ var _c = checkPrimitiveCall(name, args, typeEnv, primTypes, primParamTypes, compName, typeRegistry); for (var _i = 0; _i < _c.length; _i++) { var d = _c[_i]; diagnostics.push(d); } }
}
if (isSxTruthy((isSxTruthy(!isSxTruthy(startsWith(name, "~"))) && !isSxTruthy(isNil(effectAnnotations))))) {
(function() {
var callerEffects = getEffects(compName, effectAnnotations);
return forEach(function(d) { return append_b(diagnostics, d); }, checkEffectCall(name, callerEffects, effectAnnotations, compName));
})();
}
if (isSxTruthy(sxOr((name == "let"), (name == "let*")))) {
if (isSxTruthy((len(args) >= 2))) {
(function() {
var bindings = first(args);
var bodyExprs = rest(args);
var extended = merge(typeEnv, {});
{ var _c = bindings; for (var _i = 0; _i < _c.length; _i++) { var binding = _c[_i]; if (isSxTruthy((isSxTruthy((typeOf(binding) == "list")) && (len(binding) >= 2)))) {
(function() {
var bname = (isSxTruthy((typeOf(first(binding)) == "symbol")) ? symbolName(first(binding)) : (String(first(binding))));
var valType = inferType(nth(binding, 1), extended, primTypes, typeRegistry);
return dictSet(extended, bname, valType);
})();
} } }
return forEach(function(body) { return checkBodyWalk(body, compName, extended, primTypes, primParamTypes, env, diagnostics, typeRegistry, effectAnnotations); }, bodyExprs);
})();
}
}
return (isSxTruthy((name == "define")) ? (isSxTruthy((len(args) >= 2)) ? (function() {
var defName = (isSxTruthy((typeOf(first(args)) == "symbol")) ? symbolName(first(args)) : NIL);
var defVal = nth(args, 1);
if (isSxTruthy(defName)) {
typeEnv[defName] = inferType(defVal, typeEnv, primTypes, typeRegistry);
}
return checkBodyWalk(defVal, compName, typeEnv, primTypes, primParamTypes, env, diagnostics, typeRegistry, effectAnnotations);
})() : NIL) : NIL);
})();
}
return forEach(function(child) { return checkBodyWalk(child, compName, typeEnv, primTypes, primParamTypes, env, diagnostics, typeRegistry, effectAnnotations); }, args);
})() : NIL) : NIL);
})(); };
PRIMITIVES["check-body-walk"] = checkBodyWalk;
// check-component
var checkComponent = function(compName, env, primTypes, primParamTypes, typeRegistry, effectAnnotations) { return (function() {
var comp = envGet(env, compName);
var diagnostics = [];
if (isSxTruthy((typeOf(comp) == "component"))) {
(function() {
var body = componentBody(comp);
var params = componentParams(comp);
var paramTypes = componentParamTypes(comp);
var typeEnv = {};
{ var _c = params; for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; typeEnv[p] = (isSxTruthy((isSxTruthy(!isSxTruthy(isNil(paramTypes))) && dictHas(paramTypes, p))) ? get(paramTypes, p) : "any"); } }
if (isSxTruthy(componentHasChildren(comp))) {
typeEnv["children"] = ["list-of", "element"];
}
return checkBodyWalk(body, compName, typeEnv, primTypes, primParamTypes, env, diagnostics, typeRegistry, effectAnnotations);
})();
}
return diagnostics;
})(); };
PRIMITIVES["check-component"] = checkComponent;
// check-all
var checkAll = function(env, primTypes, primParamTypes, typeRegistry, effectAnnotations) { return (function() {
var allDiagnostics = [];
{ var _c = keys(env); for (var _i = 0; _i < _c.length; _i++) { var name = _c[_i]; (function() {
var val = envGet(env, name);
return (isSxTruthy((typeOf(val) == "component")) ? forEach(function(d) { return append_b(allDiagnostics, d); }, checkComponent(name, env, primTypes, primParamTypes, typeRegistry, effectAnnotations)) : NIL);
})(); } }
return allDiagnostics;
})(); };
PRIMITIVES["check-all"] = checkAll;
// build-type-registry
var buildTypeRegistry = function(primDeclarations, ioDeclarations) { return (function() {
var registry = {};
{ var _c = primDeclarations; for (var _i = 0; _i < _c.length; _i++) { var decl = _c[_i]; (function() {
var name = get(decl, "name");
var returns = get(decl, "returns");
return (isSxTruthy((isSxTruthy(!isSxTruthy(isNil(name))) && !isSxTruthy(isNil(returns)))) ? dictSet(registry, name, returns) : NIL);
})(); } }
{ var _c = ioDeclarations; for (var _i = 0; _i < _c.length; _i++) { var decl = _c[_i]; (function() {
var name = get(decl, "name");
var returns = get(decl, "returns");
return (isSxTruthy((isSxTruthy(!isSxTruthy(isNil(name))) && !isSxTruthy(isNil(returns)))) ? dictSet(registry, name, returns) : NIL);
})(); } }
return registry;
})(); };
PRIMITIVES["build-type-registry"] = buildTypeRegistry;
// type-def-name
var typeDefName = function(td) { return get(td, "name"); };
PRIMITIVES["type-def-name"] = typeDefName;
// type-def-params
var typeDefParams = function(td) { return get(td, "params"); };
PRIMITIVES["type-def-params"] = typeDefParams;
// type-def-body
var typeDefBody = function(td) { return get(td, "body"); };
PRIMITIVES["type-def-body"] = typeDefBody;
// resolve-type
var resolveType = function(t, registry) { return (isSxTruthy(isNil(registry)) ? t : (isSxTruthy((typeOf(t) == "string")) ? (isSxTruthy(dictHas(registry, t)) ? (function() {
var td = get(registry, t);
return (function() {
var params = typeDefParams(td);
var body = typeDefBody(td);
return (isSxTruthy(isEmpty(params)) ? resolveType(body, registry) : t);
})();
})() : t) : (isSxTruthy((typeOf(t) == "list")) ? (isSxTruthy(isEmpty(t)) ? t : (function() {
var head = first(t);
return (isSxTruthy(sxOr((head == "or"), (head == "list-of"), (head == "->"), (head == "dict-of"))) ? cons(head, map(function(m) { return resolveType(m, registry); }, rest(t))) : (isSxTruthy((isSxTruthy((typeOf(head) == "string")) && dictHas(registry, head))) ? (function() {
var td = get(registry, head);
var params = typeDefParams(td);
var body = typeDefBody(td);
var args = rest(t);
return (isSxTruthy((len(params) == len(args))) ? resolveType(substituteTypeVars(body, params, args), registry) : t);
})() : t));
})()) : (isSxTruthy((typeOf(t) == "dict")) ? mapDict(function(k, v) { return resolveType(v, registry); }, t) : t)))); };
PRIMITIVES["resolve-type"] = resolveType;
// substitute-type-vars
var substituteTypeVars = function(body, params, args) { return (function() {
var subst = {};
{ var _c = range(0, len(params), 1); for (var _i = 0; _i < _c.length; _i++) { var i = _c[_i]; subst[nth(params, i)] = nth(args, i); } }
return substituteInType(body, subst);
})(); };
PRIMITIVES["substitute-type-vars"] = substituteTypeVars;
// substitute-in-type
var substituteInType = function(t, subst) { return (isSxTruthy((typeOf(t) == "string")) ? (isSxTruthy(dictHas(subst, t)) ? get(subst, t) : t) : (isSxTruthy((typeOf(t) == "list")) ? map(function(m) { return substituteInType(m, subst); }, t) : (isSxTruthy((typeOf(t) == "dict")) ? mapDict(function(k, v) { return substituteInType(v, subst); }, t) : t))); };
PRIMITIVES["substitute-in-type"] = substituteInType;
// subtype-resolved?
var subtypeResolved_p = function(a, b, registry) { return (isSxTruthy(isNil(registry)) ? subtype_p(a, b) : (function() {
var ra = resolveType(a, registry);
var rb = resolveType(b, registry);
return (isSxTruthy((isSxTruthy((typeOf(ra) == "dict")) && (typeOf(rb) == "dict"))) ? isEvery(function(key) { return (isSxTruthy(dictHas(ra, key)) && subtypeResolved_p(get(ra, key), get(rb, key), registry)); }, keys(rb)) : subtype_p(ra, rb));
})()); };
PRIMITIVES["subtype-resolved?"] = subtypeResolved_p;
// get-effects
var getEffects = function(name, effectAnnotations) { return (isSxTruthy(isNil(effectAnnotations)) ? NIL : (isSxTruthy(dictHas(effectAnnotations, name)) ? get(effectAnnotations, name) : NIL)); };
PRIMITIVES["get-effects"] = getEffects;
// effects-subset?
var effectsSubset_p = function(calleeEffects, callerEffects) { return (isSxTruthy(isNil(callerEffects)) ? true : (isSxTruthy(isNil(calleeEffects)) ? true : isEvery(function(e) { return contains(callerEffects, e); }, calleeEffects))); };
PRIMITIVES["effects-subset?"] = effectsSubset_p;
// check-effect-call
var checkEffectCall = function(calleeName, callerEffects, effectAnnotations, compName) { return (function() {
var diagnostics = [];
var calleeEffects = getEffects(calleeName, effectAnnotations);
if (isSxTruthy((isSxTruthy(!isSxTruthy(isNil(callerEffects))) && isSxTruthy(!isSxTruthy(isNil(calleeEffects))) && !isSxTruthy(effectsSubset_p(calleeEffects, callerEffects))))) {
diagnostics.push(makeDiagnostic("error", (String("`") + String(calleeName) + String("` has effects ") + String(join(", ", calleeEffects)) + String(" but `") + String(compName) + String("` only allows ") + String((isSxTruthy(isEmpty(callerEffects)) ? "[pure]" : join(", ", callerEffects)))), compName, NIL));
}
return diagnostics;
})(); };
PRIMITIVES["check-effect-call"] = checkEffectCall;
// build-effect-annotations
var buildEffectAnnotations = function(ioDeclarations) { return (function() {
var annotations = {};
{ var _c = ioDeclarations; for (var _i = 0; _i < _c.length; _i++) { var decl = _c[_i]; (function() {
var name = get(decl, "name");
return (isSxTruthy(!isSxTruthy(isNil(name))) ? dictSet(annotations, name, ["io"]) : NIL);
})(); } }
return annotations;
})(); };
PRIMITIVES["build-effect-annotations"] = buildEffectAnnotations;
// check-component-effects
var checkComponentEffects = function(compName, env, effectAnnotations) { return (function() {
var comp = envGet(env, compName);
var diagnostics = [];
if (isSxTruthy((typeOf(comp) == "component"))) {
(function() {
var body = componentBody(comp);
return checkBodyWalk(body, compName, {}, {}, NIL, env, diagnostics, NIL, effectAnnotations);
})();
}
return diagnostics;
})(); };
PRIMITIVES["check-component-effects"] = checkComponentEffects;
// check-all-effects
var checkAllEffects = function(env, effectAnnotations) { return (function() {
var allDiagnostics = [];
{ var _c = keys(env); for (var _i = 0; _i < _c.length; _i++) { var name = _c[_i]; (function() {
var val = envGet(env, name);
return (isSxTruthy((typeOf(val) == "component")) ? forEach(function(d) { return append_b(allDiagnostics, d); }, checkComponentEffects(name, env, effectAnnotations)) : NIL);
})(); } }
return allDiagnostics;
})(); };
PRIMITIVES["check-all-effects"] = checkAllEffects;
// =========================================================================
// Post-transpilation fixups
// =========================================================================