diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2023-03-23 07:37:57 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2023-03-23 07:37:57 -0700 |
commit | bf82e9cfa8fc2b627af6e2fcfcbc1bbfc61e63d9 (patch) | |
tree | 1fb96bf438be30420dcc50f376b9e5d4996a8aae | |
parent | 5861192436b31f7377bd82cacb7acc8cc8baf4f9 (diff) | |
download | txr-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.tl | 12 | ||||
-rw-r--r-- | tests/011/patmatch.tl | 8 | ||||
-rw-r--r-- | txr.1 | 20 |
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) @@ -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 |