spec: match special form — ADT constructor pattern matching (20 tests)
Extends match-pattern in spec/evaluator.sx with an ADT case: when the pattern is (CtorName var...) and the value is an ADT dict (:_adt true), check :_ctor matches, arity matches, then recursively bind field patterns. Supports nested patterns, wildcard _, variable binding, and zero-arg ctors. Changes step-sf-match to route no-clause errors through raise-eval-frame instead of direct error, allowing guard to catch non-exhaustive matches. 40/40 ADT tests pass (20 define-type + 20 match). Zero regressions. 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:41:33Z";
|
||||
var SX_VERSION = "2026-04-26T18:15:33Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -2558,7 +2558,12 @@ PRIMITIVES["match-find-clause"] = matchFindClause;
|
||||
var matchPattern = function(pattern, value, env) { return (isSxTruthy(sxEq(pattern, new Symbol("_"))) ? true : (isSxTruthy((isSxTruthy(isList(pattern)) && isSxTruthy(sxEq(len(pattern), 2)) && sxEq(first(pattern), new Symbol("?")))) ? (function() {
|
||||
var pred = evalExpr(nth(pattern, 1), env);
|
||||
return cekCall(pred, [value]);
|
||||
})() : (isSxTruthy((isSxTruthy(isList(pattern)) && isSxTruthy(!isSxTruthy(isEmpty(pattern))) && sxEq(first(pattern), new Symbol("quote")))) ? sxEq(value, nth(pattern, 1)) : (isSxTruthy(symbol_p(pattern)) ? (envBind(env, symbolName(pattern), value), true) : (isSxTruthy((isSxTruthy(isDict(pattern)) && isDict(value))) ? isEvery(function(k) { return matchPattern(get(pattern, k), get(value, k), env); }, keys(pattern)) : (isSxTruthy((isSxTruthy(isList(pattern)) && isSxTruthy(isList(value)) && contains(pattern, new Symbol("&rest")))) ? (function() {
|
||||
})() : (isSxTruthy((isSxTruthy(isList(pattern)) && isSxTruthy(!isSxTruthy(isEmpty(pattern))) && sxEq(first(pattern), new Symbol("quote")))) ? sxEq(value, nth(pattern, 1)) : (isSxTruthy(symbol_p(pattern)) ? (envBind(env, symbolName(pattern), value), true) : (isSxTruthy((isSxTruthy(isList(pattern)) && isSxTruthy(!isSxTruthy(isEmpty(pattern))) && isSxTruthy(symbol_p(first(pattern))) && isSxTruthy(isDict(value)) && get(value, "_adt"))) ? (function() {
|
||||
var ctorName = symbolName(first(pattern));
|
||||
var fieldPatterns = rest(pattern);
|
||||
var fields = get(value, "_fields");
|
||||
return (isSxTruthy(sxEq(get(value, "_ctor"), ctorName)) && isSxTruthy(sxEq(len(fieldPatterns), len(fields))) && isEvery(function(pair) { return matchPattern(first(pair), nth(pair, 1), env); }, zip(fieldPatterns, fields)));
|
||||
})() : (isSxTruthy((isSxTruthy(isDict(pattern)) && isDict(value))) ? isEvery(function(k) { return matchPattern(get(pattern, k), get(value, k), env); }, keys(pattern)) : (isSxTruthy((isSxTruthy(isList(pattern)) && isSxTruthy(isList(value)) && contains(pattern, new Symbol("&rest")))) ? (function() {
|
||||
var restIdx = indexOf_(pattern, new Symbol("&rest"));
|
||||
return (isSxTruthy((len(value) >= restIdx)) && isSxTruthy(isEvery(function(pair) { return matchPattern(first(pair), nth(pair, 1), env); }, zip(slice(pattern, 0, restIdx), slice(value, 0, restIdx)))) && (function() {
|
||||
var restName = nth(pattern, (restIdx + 1));
|
||||
@@ -2568,7 +2573,7 @@ PRIMITIVES["match-find-clause"] = matchFindClause;
|
||||
})() : (isSxTruthy((isSxTruthy(isList(pattern)) && isList(value))) ? (isSxTruthy(!isSxTruthy(sxEq(len(pattern), len(value)))) ? false : (function() {
|
||||
var pairs = zip(pattern, value);
|
||||
return isEvery(function(pair) { return matchPattern(first(pair), nth(pair, 1), env); }, pairs);
|
||||
})()) : sxEq(pattern, value)))))))); };
|
||||
})()) : sxEq(pattern, value))))))))); };
|
||||
PRIMITIVES["match-pattern"] = matchPattern;
|
||||
|
||||
// step-sf-match
|
||||
@@ -2577,7 +2582,7 @@ PRIMITIVES["match-pattern"] = matchPattern;
|
||||
var clauses = rest(args);
|
||||
return (function() {
|
||||
var result = matchFindClause(val, clauses, env);
|
||||
return (isSxTruthy(isNil(result)) ? error((String("match: no clause matched ") + String(inspect(val)))) : makeCekState(nth(result, 1), first(result), kont));
|
||||
return (isSxTruthy(isNil(result)) ? makeCekValue((String("match: no clause matched ") + String(inspect(val))), env, kontPush(makeRaiseEvalFrame(env, false), kont)) : makeCekState(nth(result, 1), first(result), kont));
|
||||
})();
|
||||
})(); };
|
||||
PRIMITIVES["step-sf-match"] = stepSfMatch;
|
||||
|
||||
Reference in New Issue
Block a user