summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-12-27 13:26:01 -0800
committerKaz Kylheku <kaz@kylheku.com>2021-12-27 13:26:01 -0800
commit724187e4d22b26cc81e1d7b0d9b95306cbddc9e2 (patch)
treeb13d13aab6176e6a8f004b7fdd1272cbdd3e2d72
parent3f6a55831805e755812aef6ddd4197384dbc822d (diff)
downloadtxr-724187e4d22b26cc81e1d7b0d9b95306cbddc9e2.tar.gz
txr-724187e4d22b26cc81e1d7b0d9b95306cbddc9e2.tar.bz2
txr-724187e4d22b26cc81e1d7b0d9b95306cbddc9e2.zip
match: allow bound variables with regex modifier.
* stdlib/match.tl (expand-quasi-match): Add regex cases with bound variable. * tests/011/patmatch.tl: Test cases for this. * txr.1: Documented.
-rw-r--r--stdlib/match.tl11
-rw-r--r--tests/011/patmatch.tl6
-rw-r--r--txr.121
3 files changed, 37 insertions, 1 deletions
diff --git a/stdlib/match.tl b/stdlib/match.tl
index 4a326fdb..30bf1cab 100644
--- a/stdlib/match.tl
+++ b/stdlib/match.tl
@@ -926,6 +926,17 @@
(cons ^@(require @(with ,npos (+ ,pos (len ,txt)))
(match-str ,str ,txt ,pos))
(quasi-match vlist rest vars str npos))))
+ ;; `@{var #/rx/}` (existing binding)
+ (((@(eq 'sys:var) @(bound-p vlist vars @sym) (@(regexp @reg))))
+ (list ^@(require @nil (equal ,sym (m^$ ,reg (sub-str ,str ,pos t))))))
+ ;; `@{var #/rx/}@...` (existing binding)
+ (((@(eq 'sys:var) @(bound-p vlist vars @sym) (@(regexp @reg))) . @rest)
+ (with-gensyms (len npos)
+ (list* ^@(require @(with ,len (match-regex ,str ,reg ,pos))
+ ,len)
+ ^@(with ,npos (+ ,pos ,len))
+ ^@(require @nil (equal ,sym (sub-str ,str ,pos ,npos)))
+ (quasi-match vlist rest vars str npos))))
;; `@var` (existing binding)
(((@(eq 'sys:var) @(bound-p vlist vars @sym) . @nil))
(list ^@(require @nil (match-str ,str (sys:quasi ,(car args))
diff --git a/tests/011/patmatch.tl b/tests/011/patmatch.tl
index fbdd3da0..4b44eca9 100644
--- a/tests/011/patmatch.tl
+++ b/tests/011/patmatch.tl
@@ -417,6 +417,12 @@
(let ((a "$"))
(test (when-match `@a-@b` "$-@" b) "@"))
+(mtest
+ (when-match `@{a #/\d+/}-@{a #/\d+/}` "123-123" a) "123"
+ (when-match `@{a #/\d+/}-@{a #/\d+/}-` "123-123-" a) "123"
+ (when-match `@{a #/\d+/}-@{a #/\d+/}` "123-1234" a) nil
+ (when-match `@{a #/\d+/}-@{a #/\d+/}-` "123-1234-" a) nil)
+
(test
(build
(each-match (`(@a) @b-@c` '("x"
diff --git a/txr.1 b/txr.1
index dd87f46d..90f6cbdd 100644
--- a/txr.1
+++ b/txr.1
@@ -43157,7 +43157,7 @@ A quasiliteral pattern matches in a linear fashion, from left to right.
Variables bound earlier in the pattern can be referenced later in the pattern
as bound variables.
-Bound variables denote character strings in accordance with the usual
+With one exception, bound variables denote character strings in accordance with the usual
quasiliteral conversion and formatting rules. All of the modifier notations may
be used. For instance, if
.code x
@@ -43167,6 +43167,11 @@ denotes the value of
.code x
converted to a string, and right-aligned in a forty-character-wide field.
Consequently, the notation matches exactly such a forty-character text.
+The exception is that if a bound variable has a regular expression modifier,
+as in
+.code "@{x #/re/}"
+then it has a special meaning as a pattern. Moreover, this syntax has no
+meaning in a quasiliteral.
In the following description of the quasiliteral pattern-matching rules, the
symbols
@@ -43259,6 +43264,20 @@ then the match is successful and
captures that prefix. The rest of the pattern
.code {P}
is then matched against the rest of the string after the prefix.
+.meIP >> `@{ bv <> #/ regex /}{P}`
+A bound variable
+.meta bv
+which carries a regular expression modifier specifies a regular expression
+match exactly like an unbound variable. This syntax produces a successful
+match if two conditions are met: a prefix of the input string matches
+.metn regex ,
+and the matched prefix is
+.meta equal
+to the value of
+.metn bv .
+The rest of the pattern
+.code {P}
+is then matched against the rest of the string after the prefix.
.meIP <> `@ bv {P}`
The bound variable
.meta bv