summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--stdlib/match.tl63
-rw-r--r--txr.171
2 files changed, 102 insertions, 32 deletions
diff --git a/stdlib/match.tl b/stdlib/match.tl
index 333596b2..9fb62b39 100644
--- a/stdlib/match.tl
+++ b/stdlib/match.tl
@@ -674,26 +674,53 @@
,cm.(wrap-guards ^(progn ,*body t)))))
())))
+(defun non-triv-pat-p (syntax)
+ (ignore syntax)
+ t)
+
+(defun match-case-to-casequal (obj clauses)
+ (let ((dfl-cnt 0))
+ (if (and [all clauses
+ [chain car [orf [chain non-triv-pat-p not]
+ [iff (op equal '@nil)
+ (do inc dfl-cnt)]
+ (do if-match (@(eq 'sys:var) @nil) @1
+ (inc dfl-cnt))]]]
+ (< dfl-cnt 2)
+ (or (zerop dfl-cnt)
+ (non-triv-pat-p (car (first (last clauses))))))
+ (with-gensyms (otmp)
+ ^(let ((,otmp ,obj))
+ (casequal ,otmp ,*(mapcar (tb ((f . r))
+ (or (if-match (@(eq 'sys:var) nil) f
+ ^(t ,*r))
+ (if-match (@(eq 'sys:var) @sym) f
+ ^(t (let ((,sym ,otmp)) ,*r)))
+ ^((,f) ,*r)))
+ clauses)))))))
+
(defmacro match-case (:form *match-form* :env e obj . clauses)
(unless [all clauses [andf proper-listp [chain len plusp]]]
(compile-error *match-form* "bad clause syntax"))
- (let* ((result-temp (gensym "result-"))
- (objvar (gensym "obj-"))
- (var-list (get-var-list e))
- (clause-matches [mapcar (op compile-match (car @1)
+ (iflet ((cq (match-case-to-casequal obj clauses)))
+ cq
+ (let* ((result-temp (gensym "result-"))
+ (objvar (gensym "obj-"))
+ (var-list (get-var-list e))
+ (clause-matches [mapcar (op compile-match (car @1)
objvar (copy var-list))
- clauses])
- (clause-code (collect-each ((cl clauses)
- (cm clause-matches))
- (mac-param-bind *match-form* (t . forms) cl
- ^(let (,*cm.(get-vars))
- ,cm.(wrap-guards ^(set ,result-temp
- (progn ,*forms))
- t))))))
- ^(alet ((,objvar ,obj))
- (let (,result-temp)
- (or ,*clause-code)
- ,result-temp))))
+ clauses])
+ (clause-code (collect-each ((cl clauses)
+ (cm clause-matches))
+ (mac-param-bind *match-form* (t . forms) cl
+ ^(let (,*cm.(get-vars))
+ ,cm.(wrap-guards ^(set ,result-temp
+ (progn ,*forms))
+ t))))))
+ ^(alet ((,objvar ,obj))
+ (let (,result-temp)
+ (or ,*clause-code)
+ ,result-temp)))))
(defmacro match-cond (:form *match-form* :env e . clauses)
(unless [all clauses [andf proper-listp [chain len (op < 1)]]]
@@ -916,10 +943,6 @@
(nthlast ,lend ,obj)))))
(defun non-triv-pat-p (syntax)
- (ignore syntax)
- t)
-
-(defun non-triv-pat-p (syntax)
(match-case syntax
((@(eq 'sys:expr) (@(bindable) . @nil)) t)
((@(eq 'sys:var) @(or @(bindable) nil) . @nil) t)
diff --git a/txr.1 b/txr.1
index ecc15ca2..31b2644f 100644
--- a/txr.1
+++ b/txr.1
@@ -16681,18 +16681,15 @@ yields
These three macros arrange for the evaluation of
.metn test-form ,
whose value is then compared against the key or keys in each
-.meta normal-clause
-in turn.
+.metn normal-clause .
When the value matches a key, then the remaining forms of
.meta normal-clause
are evaluated, and the value of the last form is returned; subsequent
-clauses are not evaluated. When the value doesn't match any of the keys
-of a
-.meta normal-clause
-then the next
+clauses are not evaluated.
+
+If no
.meta normal-clause
-is tested.
-If all these clauses are exhausted, and there is no
+matches, and there is no
.metn else-clause ,
then the value nil is returned. Otherwise, the forms in the
.meta else-clause
@@ -16701,6 +16698,12 @@ If there are no forms, then
.code nil
is returned.
+If duplicates keys are present in such a way that the value of the
+.meta test-form
+matches multiple
+.metn normal-clause s,
+it is unspecified which of those clauses is evaluated.
+
The syntax of a
.meta normal-clause
takes on these two forms:
@@ -45552,9 +45555,8 @@ in the scope of the bindings established by the pattern.
The
.code match-case
macro evaluates the same object against multiple clauses, each consisting of a
-pattern and zero or more forms. The first case whose pattern matches the object
-is selected. The forms associated with a matching clause are evaluated in
-the scope the variables bound by that clause's pattern.
+pattern and zero or more forms. At most one matching clause is identified
+and evaluated.
The
.code match-ecase
@@ -47524,10 +47526,27 @@ if it is not specified.
.desc
The
.code match-case
-macro successively matches the value of
+macro matches the value of
.meta expr
against zero or more patterns.
+Normally, the patterns are considered in left-to-right order.
+If the value
+.meta expr
+matches more than one
+.metn pattern ,
+the leftmost
+.meta pattern
+is selected and that clause is evaluated. Under certain conditions,
+detailed below, it is possible for
+.code match-case
+and
+.code match-ecase
+to be transformed into a
+.code casequal
+form. In that case, if there are multiple clauses with equivalent
+patterns, it is not specified which one is evaluated.
+
The syntax of
.code match-case
consists of an expression
@@ -47576,6 +47595,34 @@ In the same situation, the
form throws an exception of type
.codn match-error .
+An
+.code match-ecase
+form may be transformed to a
+.code casequal
+form if all the
+.mets pattern s
+are trivial. A trivial pattern is either an atom, or else a vector or list
+expression containing no variables.
+
+A
+.code match-case
+form may be transformed to a
+.code casequal
+form under the same conditions as
+.codn match-case .
+Additionally,
+.code match-case
+may also be transformed if it contains exactly one
+clause which matches any object by means of the key
+.code @nil
+or else a variable match such as
+.codn @abc ,
+if that clause appears last. That clause is transformed into an
+.meta else-clause
+of the
+.code casequal
+form.
+
.TP* Examples:
.verb