aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2019-05-15 22:44:00 +0200
committerMattias EngdegÄrd2019-05-20 17:56:40 +0200
commitafdc20d73c8588e5a744ecf7bffaf4401a557d20 (patch)
treefa09854d24edb81160a2d709bd450ea7284d83f1
parentc2cda3ff4025e8c27bdfc2a5279f3b635c8df260 (diff)
downloademacs-afdc20d73c8588e5a744ecf7bffaf4401a557d20.tar.gz
emacs-afdc20d73c8588e5a744ecf7bffaf4401a557d20.zip
Allow zero-argument rx `or' and `seq' forms
Make the rx `or' and `seq' forms accept zero arguments to produce a never-matching regexp and an empty string, respectively. * lisp/emacs-lisp/rx.el: Require cl-extra. (rx-constituents, rx-or): Permit zero args. (rx): Amend doc string for `or' and `seq'. * test/lisp/emacs-lisp/rx-tests.el (rx-or, rx-seq): Test the change. * etc/NEWS (Changes in Specialized Modes and Packages): Mention the change.
-rw-r--r--etc/NEWS6
-rw-r--r--lisp/emacs-lisp/rx.el14
-rw-r--r--test/lisp/emacs-lisp/rx-tests.el8
3 files changed, 22 insertions, 6 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 9ca98c370e6..72702a9aaac 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1321,6 +1321,12 @@ when given in a string. Previously, '(any "\x80-\xff")' would match
1321characters U+0080...U+00FF. Now the expression matches raw bytes in 1321characters U+0080...U+00FF. Now the expression matches raw bytes in
1322the 128...255 range, as expected. 1322the 128...255 range, as expected.
1323 1323
1324*** The rx 'or' and 'seq' forms no longer require any arguments.
1325(or) produces a regexp that never matches anything, while (seq)
1326matches the empty string, each being an identity for the operation.
1327This also works for their aliases: '|' for 'or'; ':', 'and' and
1328'sequence' for 'seq'.
1329
1324** Frames 1330** Frames
1325 1331
1326+++ 1332+++
diff --git a/lisp/emacs-lisp/rx.el b/lisp/emacs-lisp/rx.el
index 9d9028d87d5..ed32490ceee 100644
--- a/lisp/emacs-lisp/rx.el
+++ b/lisp/emacs-lisp/rx.el
@@ -106,15 +106,16 @@
106;;; Code: 106;;; Code:
107 107
108(require 'cl-lib) 108(require 'cl-lib)
109(require 'cl-extra)
109 110
110;; FIXME: support macros. 111;; FIXME: support macros.
111 112
112(defvar rx-constituents ;Not `const' because some modes extend it. 113(defvar rx-constituents ;Not `const' because some modes extend it.
113 '((and . (rx-and 1 nil)) 114 '((and . (rx-and 0 nil))
114 (seq . and) ; SRE 115 (seq . and) ; SRE
115 (: . and) ; SRE 116 (: . and) ; SRE
116 (sequence . and) ; sregex 117 (sequence . and) ; sregex
117 (or . (rx-or 1 nil)) 118 (or . (rx-or 0 nil))
118 (| . or) ; SRE 119 (| . or) ; SRE
119 (not-newline . ".") 120 (not-newline . ".")
120 (nonl . not-newline) ; SRE 121 (nonl . not-newline) ; SRE
@@ -390,9 +391,11 @@ FORM is of the form `(and FORM1 ...)'."
390 "Parse and produce code from FORM, which is `(or FORM1 ...)'." 391 "Parse and produce code from FORM, which is `(or FORM1 ...)'."
391 (rx-check form) 392 (rx-check form)
392 (rx-group-if 393 (rx-group-if
393 (if (memq nil (mapcar 'stringp (cdr form))) 394 (cond
394 (mapconcat (lambda (x) (rx-form x '|)) (cdr form) "\\|") 395 ((null (cdr form)) regexp-unmatchable)
396 ((cl-every #'stringp (cdr form))
395 (regexp-opt (cdr form) nil t)) 397 (regexp-opt (cdr form) nil t))
398 (t (mapconcat (lambda (x) (rx-form x '|)) (cdr form) "\\|")))
396 (and (memq rx-parent '(: * t)) rx-parent))) 399 (and (memq rx-parent '(: * t)) rx-parent)))
397 400
398 401
@@ -1121,6 +1124,7 @@ CHAR
1121`(seq SEXP1 SEXP2 ...)' 1124`(seq SEXP1 SEXP2 ...)'
1122`(sequence SEXP1 SEXP2 ...)' 1125`(sequence SEXP1 SEXP2 ...)'
1123 matches what SEXP1 matches, followed by what SEXP2 matches, etc. 1126 matches what SEXP1 matches, followed by what SEXP2 matches, etc.
1127 Without arguments, matches the empty string.
1124 1128
1125`(submatch SEXP1 SEXP2 ...)' 1129`(submatch SEXP1 SEXP2 ...)'
1126`(group SEXP1 SEXP2 ...)' 1130`(group SEXP1 SEXP2 ...)'
@@ -1136,7 +1140,7 @@ CHAR
1136`(| SEXP1 SEXP2 ...)' 1140`(| SEXP1 SEXP2 ...)'
1137 matches anything that matches SEXP1 or SEXP2, etc. If all 1141 matches anything that matches SEXP1 or SEXP2, etc. If all
1138 args are strings, use `regexp-opt' to optimize the resulting 1142 args are strings, use `regexp-opt' to optimize the resulting
1139 regular expression. 1143 regular expression. Without arguments, never matches anything.
1140 1144
1141`(minimal-match SEXP)' 1145`(minimal-match SEXP)'
1142 produce a non-greedy regexp for SEXP. Normally, regexps matching 1146 produce a non-greedy regexp for SEXP. Normally, regexps matching
diff --git a/test/lisp/emacs-lisp/rx-tests.el b/test/lisp/emacs-lisp/rx-tests.el
index 4a5919edf02..6f392d616d1 100644
--- a/test/lisp/emacs-lisp/rx-tests.el
+++ b/test/lisp/emacs-lisp/rx-tests.el
@@ -107,7 +107,13 @@
107 "ab")) 107 "ab"))
108 (should (equal (and (string-match (rx (or "a" "ab" "abc")) s) 108 (should (equal (and (string-match (rx (or "a" "ab" "abc")) s)
109 (match-string 0 s)) 109 (match-string 0 s))
110 "a")))) 110 "a")))
111 ;; Test zero-argument `or'.
112 (should (equal (rx (or)) regexp-unmatchable)))
113
114(ert-deftest rx-seq ()
115 ;; Test zero-argument `seq'.
116 (should (equal (rx (seq)) "")))
111 117
112(provide 'rx-tests) 118(provide 'rx-tests)
113;; rx-tests.el ends here. 119;; rx-tests.el ends here.