summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-03-23 07:37:57 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-03-23 07:37:57 -0700
commitbf82e9cfa8fc2b627af6e2fcfcbc1bbfc61e63d9 (patch)
tree1fb96bf438be30420dcc50f376b9e5d4996a8aae
parent5861192436b31f7377bd82cacb7acc8cc8baf4f9 (diff)
downloadtxr-bf82e9cfa8fc2b627af6e2fcfcbc1bbfc61e63d9.tar.gz
txr-bf82e9cfa8fc2b627af6e2fcfcbc1bbfc61e63d9.tar.bz2
txr-bf82e9cfa8fc2b627af6e2fcfcbc1bbfc61e63d9.zip
match: support @nil in predicates.
For instance @(<= 10 @nil 20) is a pattern which matches a number between 10 and 20, without binding a variable. * stdlib/match.tl (compile-predicate-match): Looks like this code was already halfway expressing the intent that the avar could be nil, because arg-var takes the value of avar if that is non-nil, otherwise a gensym is substituted. What was missing was that the gensym that replaces nil must also be substituted into the predicate. * tests/011/patmatch.tl: New tests. * txr.1: Document that the variable embedded in a predicate may be null.
-rw-r--r--stdlib/match.tl12
-rw-r--r--tests/011/patmatch.tl8
-rw-r--r--txr.120
3 files changed, 35 insertions, 5 deletions
diff --git a/stdlib/match.tl b/stdlib/match.tl
index 3adbba27..c59179f3 100644
--- a/stdlib/match.tl
+++ b/stdlib/match.tl
@@ -275,21 +275,27 @@
(if (and (consp head) (eq (car head) 'sys:var))
(tree-case exp
(((t rvar) (op . args))
- (let* ((avar
+ (let* ((arg-var (gensym "obj-"))
+ (avar
(condlet
(((vm (member-if [andf consp (op eq (car @1) 'sys:var)]
args)))
(let ((sym (cadar vm)))
+ (if (null sym)
+ (set sym arg-var)
+ (set arg-var sym))
(set args (append (ldiff args vm)
(list sym)
(cdr vm)))
sym))
(((vm (memq 'sys:var args)))
(let ((sym (cadr vm)))
+ (if (null sym)
+ (set sym arg-var)
+ (set arg-var sym))
(set args (append (ldiff args vm) sym))
sym))))
- (res-var (gensym "res-"))
- (arg-var (if avar avar (gensym "obj-"))))
+ (res-var (gensym "res-")))
(unless avar
(set args (append args (list arg-var))))
(let* ((guard (new match-guard
diff --git a/tests/011/patmatch.tl b/tests/011/patmatch.tl
index 5e8d3f7f..bace28ce 100644
--- a/tests/011/patmatch.tl
+++ b/tests/011/patmatch.tl
@@ -560,3 +560,11 @@
(match @`foo-@a` "foo-abc" a) "abc"
(match ^(,`foo-@a`) '("foo-abc") a) "abc"
(match ^#J[~`foo-@a`] #("foo-abc") a) "abc")
+
+(mtest
+ (match @(< @nil 0) -1 42) 42
+ (match @(> 0 @nil) -1 42) 42
+ (if-match @(< @nil 0) 1 :y :n) :n
+ (if-match @(< @nil 2) 1 :y :n) :y
+ (match @(@nil (< @x 0)) -1 x) -1
+ (match @(@nil (< @nil 0)) -1 t) t)
diff --git a/txr.1 b/txr.1
index 159c958d..1d1046d3 100644
--- a/txr.1
+++ b/txr.1
@@ -46207,8 +46207,10 @@ The first form of the predicate pattern consists of a compound form consisting
of an operator and arguments. Exactly one of the arguments may be a pattern
variable
.meta avar
-("argument variable") which must be a bindable symbol. The pattern variable
-may also appear in the dot position, rather than as an argument. The role of
+("argument variable") which must be a bindable symbol or else
+.codn nil .
+The pattern variable may also appear in the dot position, rather than as an
+argument. The role of
.meta avar
and the consequences of omitting it are described below.
@@ -46297,6 +46299,14 @@ The form
is a standard \*(TL notation with the same meaning as
.codn "(apply (fun f) x)" .
+If
+.meta avar
+is the
+.code nil
+symbol, then no variable is bound. The matched object is substituted
+into the predicate expression at the position indicated by
+.codn @nil .
+
.TP* Examples:
.verb
@@ -46321,6 +46331,12 @@ is a standard \*(TL notation with the same meaning as
;; apply (1 2 3) to < using dot position
(when-match @(@x (< . @sym)) '(1 2 3) (list x sym))
-> (t (1 2 3))
+
+ ;; Match three-element list whose middle element
+ ;; is a number in the range 10 20, without
+ ;; binding any variables:
+ (when-match (@nil @(<= 10 @nil 20) @nil) obj
+ (prinl "obj matches"))
.brev
.coNP Pattern macro @ sme