spec: define-type special form — constructors, predicates, accessors (20 tests)
Adds sf-define-type via register-special-form! in spec/evaluator.sx.
ADT values are dicts {:_adt true :_type "T" :_ctor "C" :_fields (list ...)}.
Each define-type call registers: ctor functions with arity checking, Name?
type predicate, Ctor? constructor predicates, Ctor-field positional accessors,
and populates *adt-registry* dict with type→[ctor-names] mapping.
20/20 JS tests pass in spec/tests/test-adt.sx.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
// =========================================================================
|
||||
|
||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||
var SX_VERSION = "2026-04-26T17:04:43Z";
|
||||
var SX_VERSION = "2026-04-26T17:41:33Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -2155,6 +2155,34 @@ PRIMITIVES["step-sf-let-match"] = stepSfLetMatch;
|
||||
})(); };
|
||||
PRIMITIVES["step-eval-list"] = stepEvalList;
|
||||
|
||||
// sf-define-type
|
||||
var sfDefineType = function(args, env) { return (function() {
|
||||
var typeSym = first(args);
|
||||
var ctorSpecs = rest(args);
|
||||
return (function() {
|
||||
var typeName = symbolName(typeSym);
|
||||
var ctorNames = map(function(spec) { return symbolName(first(spec)); }, ctorSpecs);
|
||||
if (isSxTruthy(!isSxTruthy(envHas(env, "*adt-registry*")))) {
|
||||
envBind(env, "*adt-registry*", {});
|
||||
}
|
||||
envGet(env, "*adt-registry*")[typeName] = ctorNames;
|
||||
envBind(env, (String(typeName) + String("?")), function(v) { return (isSxTruthy(isDict(v)) && isSxTruthy(get(v, "_adt")) && sxEq(get(v, "_type"), typeName)); });
|
||||
{ var _c = ctorSpecs; for (var _i = 0; _i < _c.length; _i++) { var spec = _c[_i]; (function() {
|
||||
var cn = symbolName(first(spec));
|
||||
var fieldNames = map(function(f) { return symbolName(f); }, rest(spec));
|
||||
var arity = len(rest(spec));
|
||||
envBind(env, cn, function() { var ctorArgs = Array.prototype.slice.call(arguments, 0); return (isSxTruthy(!isSxTruthy(sxEq(len(ctorArgs), arity))) ? error((String(cn) + String(": expected ") + String(arity) + String(" args, got ") + String(len(ctorArgs)))) : {"_ctor": cn, "_type": typeName, "_adt": true, "_fields": ctorArgs}); });
|
||||
envBind(env, (String(cn) + String("?")), function(v) { return (isSxTruthy(isDict(v)) && isSxTruthy(get(v, "_adt")) && sxEq(get(v, "_ctor"), cn)); });
|
||||
return forEachIndexed(function(idx, fieldName) { return envBind(env, (String(cn) + String("-") + String(fieldName)), function(v) { return nth(get(v, "_fields"), idx); }); }, fieldNames);
|
||||
})(); } }
|
||||
return NIL;
|
||||
})();
|
||||
})(); };
|
||||
PRIMITIVES["sf-define-type"] = sfDefineType;
|
||||
|
||||
// (register-special-form! ...)
|
||||
registerSpecialForm("define-type", sfDefineType);
|
||||
|
||||
// kont-extract-provides
|
||||
var kontExtractProvides = function(kont) { return (isSxTruthy(isEmpty(kont)) ? [] : (function() {
|
||||
var frame = first(kont);
|
||||
|
||||
Reference in New Issue
Block a user