emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/relint c857c98c4b 1/2: Improved backquote expansion in


From: ELPA Syncer
Subject: [elpa] externals/relint c857c98c4b 1/2: Improved backquote expansion in rx forms
Date: Mon, 31 Jul 2023 12:58:47 -0400 (EDT)

branch: externals/relint
commit c857c98c4b9ed07818f3371f5ddc9459cac4565b
Author: Mattias Engdegård <mattiase@acm.org>
Commit: Mattias Engdegård <mattiase@acm.org>

    Improved backquote expansion in rx forms
    
    This comes at the cost of some reduced warning location accuracy, but
    should be worth it.
---
 relint.el        | 79 ++++++++++++++++++++++++++++++++++++++++----------------
 test/11.elisp    |  4 ++-
 test/11.expected | 32 ++++++++++++-----------
 3 files changed, 77 insertions(+), 38 deletions(-)

diff --git a/relint.el b/relint.el
index 0555930c3c..ef00882282 100644
--- a/relint.el
+++ b/relint.el
@@ -1551,12 +1551,63 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
     (setq ranges (cdr ranges)))
   (car ranges))
 
+(defun relint--expand-rx-args (items)
+  "Expand unquotes and `eval' and `literal' forms in ITEMS recursively."
+  (if (atom items)
+      items
+    (let ((acc nil)
+          (tail items))
+      (while (consp tail)
+        (let* ((item (car tail))
+               (head (car-safe item)))
+          ;; Evaluate unquote and unquote-splicing forms as if inside a
+          ;; (single) backquote.
+          (cond ((memq head '(eval \,))
+                 (let ((val (relint--eval-or-nil (cadr item))))
+                   (pop tail)
+                   (if val
+                       (push val tail)
+                     (push item acc))))
+                ((eq head 'literal)
+                 (let ((val (relint--eval-or-nil (cadr item))))
+                   (pop tail)
+                   (push (if (stringp val)
+                             (regexp-quote val)
+                           item)
+                         acc)))
+                ((eq head '\,@)
+                 (let ((vals (relint--eval-or-nil (cadr item))))
+                   (pop tail)
+                   (if vals
+                       (setq tail (append vals tail))
+                     (push item acc))))
+                ((eq item '\,)            ; (... . ,TAIL) = (... , TAIL)
+                 (let ((vals (relint--eval-or-nil (cadr tail))))
+                   (pop tail)
+                   (if vals
+                       (setq tail vals)
+                     (push item acc))))
+                ((and (consp item) (listp (cdr item)))
+                 (push (relint--expand-rx-args item) acc)
+                 (pop tail))
+                (t (push item acc)
+                   (pop tail)))))
+      (setq acc (nreverse acc))
+      (if (equal acc items)
+          items
+        acc))))
+
 (defun relint--check-rx (item pos path exact-path)
   "Check the `rx' expression ITEM.
 EXACT-PATH indicates whether PATH leads to ITEM exactly, rather
 than just to a surrounding or producing expression."
+  (let ((expanded (relint--expand-rx-args item)))
+    (relint--check-rx-1 expanded pos path
+                        (and exact-path (eq expanded item)))))
+
+(defun relint--check-rx-1 (item pos path exact-path)
   (pcase item
-    (`(,(or ': 'seq 'sequence 'and 'or '|
+    (`(,(or 'rx ': 'seq 'sequence 'and 'or '|   ; pretend that `rx' is `seq'
             'not 'intersection 'repeat '= '>= '**
             'zero-or-more '0+ '* '*?
             'one-or-more '1+ '+ '+?
@@ -1585,8 +1636,8 @@ than just to a surrounding or producing expression."
      ;; Form with subforms: recurse.
      (let ((i 1))
        (dolist (arg args)
-         (relint--check-rx arg pos (if exact-path (cons i path) path)
-                           exact-path)
+         (relint--check-rx-1 arg pos (if exact-path (cons i path) path)
+                             exact-path)
          (setq i (1+ i)))))
 
     (`(,(or 'any 'in 'char 'not-char) . ,args)
@@ -1721,19 +1772,7 @@ than just to a surrounding or producing expression."
 
     (`(,(or 'regexp 'regex) ,expr)
      (relint--check-re expr (format-message "rx `%s' form" (car item))
-                       pos (if exact-path (cons 1 path) path)))
-
-    ;; Evaluate unquote and unquote-splicing forms as if inside a
-    ;; (single) backquote.
-    (`(,(or 'eval '\,) ,expr)
-     (let ((val (relint--eval-or-nil expr)))
-       (when val
-         (relint--check-rx val pos (if exact-path (cons 1 path) path) nil))))
-
-    (`(\,@ ,expr)
-     (let ((items (relint--eval-list expr)))
-       (dolist (form items)
-         (relint--check-rx form pos (if exact-path (cons 1 path) path) 
nil))))))
+                       pos (if exact-path (cons 1 path) path)))))
 
 (defun relint--regexp-args-from-doc (doc-string)
   "Extract regexp arguments (as a list of symbols) from DOC-STRING."
@@ -2240,12 +2279,8 @@ directly."
                                     (cons 'val val))))
                         (list 'expr re-arg))))
               (push (cons name new) relint--variables)))))
-       (`(rx . ,items)
-        (let ((i 1))
-          (while (consp items)
-            (relint--check-rx (car items) pos (cons i path) t)
-            (setq items (cdr items))
-            (setq i (1+ i)))))
+       (`(rx . ,_)
+        (relint--check-rx form pos path t))
        (`(rx-to-string (,(or 'quote '\`) ,arg) . ,_)
         (relint--check-rx arg pos (cons 1 (cons 1 path)) t))
        (`(font-lock-add-keywords ,_ ,keywords . ,_)
diff --git a/test/11.elisp b/test/11.elisp
index 3f4527b23a..c0af6a1792 100644
--- a/test/11.elisp
+++ b/test/11.elisp
@@ -21,7 +21,9 @@
    (rx-to-string `(: bol
                      ,(list 'in "BB")))
    `(rx ,(list 'char "CC"))
-   `(rx ,@(list nonl (list 'any "DD"))))
+   `(rx ,@(list 'nonl (list 'any "DD")))
+   (let ((things '(?x ?y ?z ?y)))
+     `(rx (any ?z . ,things))))
 
   ;; No error here.
   (rx (any "\000-\377" ?å) (any "\377" 255))
diff --git a/test/11.expected b/test/11.expected
index 9b8c9b1b19..c48a42b73e 100644
--- a/test/11.expected
+++ b/test/11.expected
@@ -25,41 +25,43 @@
 11.elisp:15:20: Literal `-' not first or last (pos 3)
   "A-F-K-T"
    ...^
-11.elisp:16:19: In rx `regexp' form: Duplicated `1' inside character 
alternative (pos 2)
+11.elisp:16:4: In rx `regexp' form: Duplicated `1' inside character 
alternative (pos 2)
   "[11]"
    ..^
-11.elisp:17:18: In rx `regex' form: Duplicated `2' inside character 
alternative (pos 2)
+11.elisp:16:4: In rx `regex' form: Duplicated `2' inside character alternative 
(pos 2)
   "[22]"
    ..^
-11.elisp:18:14: Duplicated character `3' (pos 1)
+11.elisp:16:4: Duplicated character `3' (pos 1)
   "33"
    .^
 11.elisp:20:29: Duplicated character `A' (pos 1)
   "AA"
    .^
-11.elisp:22:23: Duplicated character `B' (pos 1)
+11.elisp:21:19: Duplicated character `B' (pos 1)
   "BB"
    .^
-11.elisp:23:10: Duplicated character `C' (pos 1)
+11.elisp:23:5: Duplicated character `C' (pos 1)
   "CC"
    .^
-11.elisp:24:11: Duplicated character `D' (pos 1)
+11.elisp:24:5: Duplicated character `D' (pos 1)
   "DD"
    .^
-11.elisp:29:25: Character `\177' included in range `\000-\177' (pos 0)
+11.elisp:26:7: Duplicated character `z'
+11.elisp:26:7: Duplicated character `y'
+11.elisp:31:25: Character `\177' included in range `\000-\177' (pos 0)
   "\177"
    ^
-11.elisp:29:32: Character `\240' included in range `\200-\377' (pos 0)
+11.elisp:31:32: Character `\240' included in range `\200-\377' (pos 0)
   "\240"
    ^
-11.elisp:31:18: Character `m' included in range `a-z'
-11.elisp:32:19: Range `\000-\377' overlaps previous `a-f' (pos 0)
+11.elisp:33:18: Character `m' included in range `a-z'
+11.elisp:34:19: Range `\000-\377' overlaps previous `a-f' (pos 0)
   "\000-\377"
    ^
-11.elisp:33:25: Range `\000-\377' overlaps previous `\240-\277' (pos 0)
+11.elisp:35:25: Range `\000-\377' overlaps previous `\240-\277' (pos 0)
   "\000-\377"
    ^
-11.elisp:35:17: Duplicated rx form in or-pattern: ?A
-11.elisp:35:20: Duplicated rx form in or-pattern: "def"
-11.elisp:36:10: Duplicated rx form in or-pattern: "abc"
-11.elisp:36:16: Duplicated rx form in or-pattern: (= 3 ?*)
+11.elisp:37:17: Duplicated rx form in or-pattern: ?A
+11.elisp:37:20: Duplicated rx form in or-pattern: "def"
+11.elisp:38:10: Duplicated rx form in or-pattern: "abc"
+11.elisp:38:16: Duplicated rx form in or-pattern: (= 3 ?*)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]