diff options
| author | Mattias EngdegÄrd | 2019-05-15 22:44:00 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2019-05-20 17:56:40 +0200 |
| commit | afdc20d73c8588e5a744ecf7bffaf4401a557d20 (patch) | |
| tree | fa09854d24edb81160a2d709bd450ea7284d83f1 | |
| parent | c2cda3ff4025e8c27bdfc2a5279f3b635c8df260 (diff) | |
| download | emacs-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/NEWS | 6 | ||||
| -rw-r--r-- | lisp/emacs-lisp/rx.el | 14 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/rx-tests.el | 8 |
3 files changed, 22 insertions, 6 deletions
| @@ -1321,6 +1321,12 @@ when given in a string. Previously, '(any "\x80-\xff")' would match | |||
| 1321 | characters U+0080...U+00FF. Now the expression matches raw bytes in | 1321 | characters U+0080...U+00FF. Now the expression matches raw bytes in |
| 1322 | the 128...255 range, as expected. | 1322 | the 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) | ||
| 1326 | matches the empty string, each being an identity for the operation. | ||
| 1327 | This 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. |