diff options
| author | Philipp Stephani | 2017-07-20 21:36:18 +0200 |
|---|---|---|
| committer | Philipp Stephani | 2017-07-23 22:32:23 +0200 |
| commit | ad4eff3b905dbc32e2d38bfec1e4f93eceec288d (patch) | |
| tree | 9645505457f716c9aab23e1417bfbdf6a7380710 | |
| parent | f57c7107727a615e217f1c245c400722c1422870 (diff) | |
| download | emacs-ad4eff3b905dbc32e2d38bfec1e4f93eceec288d.tar.gz emacs-ad4eff3b905dbc32e2d38bfec1e4f93eceec288d.zip | |
Add 'rx' pattern for pcase.
* lisp/emacs-lisp/rx.el (rx): New pcase macro.
* test/lisp/emacs-lisp/rx-tests.el (rx-pcase): Add unit test.
| -rw-r--r-- | etc/NEWS | 3 | ||||
| -rw-r--r-- | lisp/emacs-lisp/pcase.el | 1 | ||||
| -rw-r--r-- | lisp/emacs-lisp/rx.el | 56 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/rx-tests.el | 10 |
4 files changed, 69 insertions, 1 deletions
| @@ -1555,6 +1555,9 @@ manual. | |||
| 1555 | ** 'tcl-auto-fill-mode' is now declared obsolete. Its functionality | 1555 | ** 'tcl-auto-fill-mode' is now declared obsolete. Its functionality |
| 1556 | can be replicated simply by setting 'comment-auto-fill-only-comments'. | 1556 | can be replicated simply by setting 'comment-auto-fill-only-comments'. |
| 1557 | 1557 | ||
| 1558 | ** New pcase pattern 'rx' to match against a rx-style regular | ||
| 1559 | expression. | ||
| 1560 | |||
| 1558 | 1561 | ||
| 1559 | * Changes in Emacs 26.1 on Non-Free Operating Systems | 1562 | * Changes in Emacs 26.1 on Non-Free Operating Systems |
| 1560 | 1563 | ||
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index 4a06ab25d3e..b40161104d2 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el | |||
| @@ -930,6 +930,5 @@ QPAT can take the following forms: | |||
| 930 | ((or (stringp qpat) (integerp qpat) (symbolp qpat)) `',qpat) | 930 | ((or (stringp qpat) (integerp qpat) (symbolp qpat)) `',qpat) |
| 931 | (t (error "Unknown QPAT: %S" qpat)))) | 931 | (t (error "Unknown QPAT: %S" qpat)))) |
| 932 | 932 | ||
| 933 | |||
| 934 | (provide 'pcase) | 933 | (provide 'pcase) |
| 935 | ;;; pcase.el ends here | 934 | ;;; pcase.el ends here |
diff --git a/lisp/emacs-lisp/rx.el b/lisp/emacs-lisp/rx.el index 386232c6eef..b66f2c6d512 100644 --- a/lisp/emacs-lisp/rx.el +++ b/lisp/emacs-lisp/rx.el | |||
| @@ -1169,6 +1169,62 @@ enclosed in `(and ...)'. | |||
| 1169 | (rx-to-string `(and ,@regexps) t)) | 1169 | (rx-to-string `(and ,@regexps) t)) |
| 1170 | (t | 1170 | (t |
| 1171 | (rx-to-string (car regexps) t)))) | 1171 | (rx-to-string (car regexps) t)))) |
| 1172 | |||
| 1173 | |||
| 1174 | (pcase-defmacro rx (&rest regexps) | ||
| 1175 | "Build a `pcase' pattern matching `rx' regexps. | ||
| 1176 | The REGEXPS are interpreted as by `rx'. The pattern matches if | ||
| 1177 | the regular expression so constructed matches the object, as if | ||
| 1178 | by `string-match'. | ||
| 1179 | |||
| 1180 | In addition to the usual `rx' constructs, REGEXPS can contain the | ||
| 1181 | following constructs: | ||
| 1182 | |||
| 1183 | (let VAR FORM...) creates a new explicitly numbered submatch | ||
| 1184 | that matches FORM and binds the match to | ||
| 1185 | VAR. | ||
| 1186 | (backref VAR) creates a backreference to the submatch | ||
| 1187 | introduced by a previous (let VAR ...) | ||
| 1188 | construct. | ||
| 1189 | |||
| 1190 | The VARs are associated with explicitly numbered submatches | ||
| 1191 | starting from 1. Multiple occurrences of the same VAR refer to | ||
| 1192 | the same submatch. | ||
| 1193 | |||
| 1194 | If a case matches, the match data is modified as usual so you can | ||
| 1195 | use it in the case body, but you still have to pass the correct | ||
| 1196 | string as argument to `match-string'." | ||
| 1197 | (let* ((vars ()) | ||
| 1198 | (rx-constituents | ||
| 1199 | `((let | ||
| 1200 | ,(lambda (form) | ||
| 1201 | (rx-check form) | ||
| 1202 | (let ((var (cadr form))) | ||
| 1203 | (cl-check-type var symbol) | ||
| 1204 | (let ((i (or (cl-position var vars :test #'eq) | ||
| 1205 | (prog1 (length vars) | ||
| 1206 | (setq vars `(,@vars ,var)))))) | ||
| 1207 | (rx-form `(submatch-n ,(1+ i) ,@(cddr form)))))) | ||
| 1208 | 1 nil) | ||
| 1209 | (backref | ||
| 1210 | ,(lambda (form) | ||
| 1211 | (rx-check form) | ||
| 1212 | (rx-backref | ||
| 1213 | `(backref ,(let ((var (cadr form))) | ||
| 1214 | (if (integerp var) var | ||
| 1215 | (1+ (cl-position var vars :test #'eq))))))) | ||
| 1216 | 1 1 | ||
| 1217 | ,(lambda (var) | ||
| 1218 | (cond ((integerp var) (rx-check-backref var)) | ||
| 1219 | ((memq var vars) t) | ||
| 1220 | (t (error "rx `backref' variable must be one of %s: %s" | ||
| 1221 | vars var))))) | ||
| 1222 | ,@rx-constituents)) | ||
| 1223 | (regexp (rx-to-string `(seq ,@regexps) :no-group))) | ||
| 1224 | `(and (pred (string-match ,regexp)) | ||
| 1225 | ,@(cl-loop for i from 1 | ||
| 1226 | for var in vars | ||
| 1227 | collect `(app (match-string ,i) ,var))))) | ||
| 1172 | 1228 | ||
| 1173 | ;; ;; sregex.el replacement | 1229 | ;; ;; sregex.el replacement |
| 1174 | 1230 | ||
diff --git a/test/lisp/emacs-lisp/rx-tests.el b/test/lisp/emacs-lisp/rx-tests.el index 8b7945c9d27..8f353b7e863 100644 --- a/test/lisp/emacs-lisp/rx-tests.el +++ b/test/lisp/emacs-lisp/rx-tests.el | |||
| @@ -33,5 +33,15 @@ | |||
| 33 | (number-sequence ?< ?\]) | 33 | (number-sequence ?< ?\]) |
| 34 | (number-sequence ?- ?:)))))) | 34 | (number-sequence ?- ?:)))))) |
| 35 | 35 | ||
| 36 | (ert-deftest rx-pcase () | ||
| 37 | (should (equal (pcase "a 1 2 3 1 1 b" | ||
| 38 | ((rx (let u (+ digit)) space | ||
| 39 | (let v (+ digit)) space | ||
| 40 | (let v (+ digit)) space | ||
| 41 | (backref u) space | ||
| 42 | (backref 1)) | ||
| 43 | (list u v))) | ||
| 44 | '("1" "3")))) | ||
| 45 | |||
| 36 | (provide 'rx-tests) | 46 | (provide 'rx-tests) |
| 37 | ;; rx-tests.el ends here. | 47 | ;; rx-tests.el ends here. |