Fix pcase rx pattern bugs

Two unrelated bugs: A missing type check caused an error in rx
patterns for non-string match targets, and rx patterns did not work at
all in pcase-let or pcase-let*.

Second bug reported by Basil Contovounesios and Ag Ibragimov; fixes
proposed by Stefan Monnier.  Discussion and explanation in thread at
https://lists.gnu.org/archive/html/emacs-devel/2021-02/msg01924.html

* lisp/emacs-lisp/rx.el (rx): Add (pred stringp) to avoid type errors,
and replace the `pred` clause for the actual match with something that
works with pcase-let(*) without being optimised away.
* test/lisp/emacs-lisp/rx-tests.el (rx-pcase): Add test cases.
This commit is contained in:
Mattias Engdegård 2021-02-26 09:52:16 +01:00
parent 6bf56a3614
commit 70f2d658e4
2 changed files with 16 additions and 2 deletions

View file

@ -1437,7 +1437,11 @@ following constructs:
construct."
(let* ((rx--pcase-vars nil)
(regexp (rx--to-expr (rx--pcase-transform (cons 'seq regexps)))))
`(and (pred (string-match ,regexp))
`(and (pred stringp)
;; `pcase-let' takes a match for granted and discards all unnecessary
;; conditions, which means that a `pred' clause cannot be used for
;; the match condition. The following construct seems to survive.
(app (lambda (s) (string-match ,regexp s)) (pred identity))
,@(let ((i 0))
(mapcar (lambda (name)
(setq i (1+ i))

View file

@ -171,7 +171,17 @@
(should (equal (pcase "abc"
((rx (? (let x alpha)) (?? (let y alnum)) ?c)
(list x y)))
'("a" "b"))))
'("a" "b")))
(should (equal (pcase 'not-a-string
((rx nonl) 'wrong)
(_ 'correct))
'correct))
(should (equal (pcase-let (((rx ?B (let z nonl)) "ABC"))
(list 'ok z))
'(ok "C")))
(should (equal (pcase-let* (((rx ?E (let z nonl)) "DEF"))
(list 'ok z))
'(ok "F"))))
(ert-deftest rx-kleene ()
"Test greedy and non-greedy repetition operators."