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:
2026-04-26 18:16:16 +00:00
parent 6c87210728
commit 0dc7e1599c
4 changed files with 153 additions and 7 deletions

View File

@@ -2736,6 +2736,17 @@
(= value (nth pattern 1))
(symbol? pattern)
(do (env-bind! env (symbol-name pattern) value) true)
(and (list? pattern) (not (empty? pattern)) (symbol? (first pattern)) (dict? value) (get value :_adt))
(let
((ctor-name (symbol-name (first pattern)))
(field-patterns (rest pattern))
(fields (get value :_fields)))
(and
(= (get value :_ctor) ctor-name)
(= (len field-patterns) (len fields))
(every?
(fn (pair) (match-pattern (first pair) (nth pair 1) env))
(zip field-patterns fields))))
(and (dict? pattern) (dict? value))
(every?
(fn (k) (match-pattern (get pattern k) (get value k) env))
@@ -2780,7 +2791,7 @@
((result (match-find-clause val clauses env)))
(if
(nil? result)
(error (str "match: no clause matched " (inspect val)))
(make-cek-value (str "match: no clause matched " (inspect val)) env (kont-push (make-raise-eval-frame env false) kont))
(make-cek-state (nth result 1) (first result) kont))))))
(define