diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2021-12-27 13:26:01 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2021-12-27 13:26:01 -0800 |
commit | 724187e4d22b26cc81e1d7b0d9b95306cbddc9e2 (patch) | |
tree | b13d13aab6176e6a8f004b7fdd1272cbdd3e2d72 | |
parent | 3f6a55831805e755812aef6ddd4197384dbc822d (diff) | |
download | txr-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.tl | 11 | ||||
-rw-r--r-- | tests/011/patmatch.tl | 6 | ||||
-rw-r--r-- | txr.1 | 21 |
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" @@ -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 |