From cbd439e785cd1e72c3eae39ed987fda357014bf8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mattias=20Engdeg=C3=A5rd?= Date: Sun, 27 Oct 2019 09:54:54 +0100 Subject: [PATCH] Expand rx definitions inside (not ...) * lisp/emacs-lisp/rx.el (rx--translate-not): * test/lisp/emacs-lisp/rx-tests.el (rx-not, rx-def-in-not): * doc/lispref/searching.texi (Rx Constructs, Extending Rx): Allow user-defined rx constructs to be expanded inside (not ...) forms, for better composability (bug#37849). --- doc/lispref/searching.texi | 4 ++-- lisp/emacs-lisp/rx.el | 3 +++ test/lisp/emacs-lisp/rx-tests.el | 17 ++++++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi index 5178575a3bb..74b15cfc7fd 100644 --- a/doc/lispref/searching.texi +++ b/doc/lispref/searching.texi @@ -1214,7 +1214,7 @@ Corresponding string regexp: @samp{[@dots{}]} @item @code{(not @var{charspec})} @cindex @code{not} in rx Match a character not included in @var{charspec}. @var{charspec} can -be an @code{any}, @code{syntax} or @code{category} form, or a +be an @code{any}, @code{not}, @code{syntax} or @code{category} form, or a character class.@* Corresponding string regexp: @samp{[^@dots{}]}, @samp{\S@var{code}}, @samp{\C@var{code}} @@ -1581,7 +1581,7 @@ when they are used, not when they are defined. User-defined forms are allowed wherever arbitrary @code{rx} expressions are expected; for example, in the body of a @code{zero-or-one} form, but not inside @code{any} or @code{category} -forms. +forms. They are also allowed inside @code{not} forms. @end itemize @defmac rx-define name [arglist] rx-form diff --git a/lisp/emacs-lisp/rx.el b/lisp/emacs-lisp/rx.el index d7677f14443..52a35ffa2a7 100644 --- a/lisp/emacs-lisp/rx.el +++ b/lisp/emacs-lisp/rx.el @@ -477,6 +477,9 @@ If NEGATED, negate the sense (thus making it positive)." ((eq arg 'word-boundary) (rx--translate-symbol (if negated 'word-boundary 'not-word-boundary))) + ((let ((expanded (rx--expand-def arg))) + (and expanded + (rx--translate-not negated (list expanded))))) (t (error "Illegal argument to rx `not': %S" arg))))) (defun rx--atomic-regexp (item) diff --git a/test/lisp/emacs-lisp/rx-tests.el b/test/lisp/emacs-lisp/rx-tests.el index ef2541d83af..4ecc805aead 100644 --- a/test/lisp/emacs-lisp/rx-tests.el +++ b/test/lisp/emacs-lisp/rx-tests.el @@ -268,7 +268,9 @@ (should (equal (rx (not (syntax punctuation)) (not (syntax escape))) "\\S.\\S\\")) (should (equal (rx (not (category tone-mark)) (not (category lao))) - "\\C4\\Co"))) + "\\C4\\Co")) + (should (equal (rx (not (not ascii)) (not (not (not (any "a-z"))))) + "[[:ascii:]][^a-z]"))) (ert-deftest rx-group () (should (equal (rx (group nonl) (submatch "x") @@ -404,6 +406,19 @@ (should-error (rx-let-eval '((not-char () "x")) nil)) (should-error (rx-let-eval '((not-char "x")) nil))) +(ert-deftest rx-def-in-not () + "Test definition expansion inside (not ...)." + (rx-let ((a alpha) + (b (not hex)) + (c (not (category base))) + (d (x) (any ?a x ?z)) + (e (x) (syntax x)) + (f (not b))) + (should (equal (rx (not a) (not b) (not c) (not f)) + "[^[:alpha:]][[:xdigit:]]\\c.[^[:xdigit:]]")) + (should (equal (rx (not (d ?m)) (not (e symbol))) + "[^amz]\\S_")))) + (ert-deftest rx-constituents () (let ((rx-constituents (append '((beta . gamma) -- 2.39.2