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

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

[elpa] externals/relint 60d5627 21/23: Lazy evaluation of global variabl


From: Mattias Engdegård
Subject: [elpa] externals/relint 60d5627 21/23: Lazy evaluation of global variables
Date: Sun, 29 Sep 2019 15:34:54 -0400 (EDT)

branch: externals/relint
commit 60d5627e06e31c15864b4e38d7d48282981b9e32
Author: Mattias Engdegård <address@hidden>
Commit: Mattias Engdegård <address@hidden>

    Lazy evaluation of global variables
    
    This improves performance by over 5 %.
    Previously, global variables were evaluated at every reference.
    
    When redefined, the new expression is evaluated eagerly in case it
    relies on the old value.
---
 relint.el       | 39 +++++++++++++++++++++++++++++++--------
 test/4.elisp    | 14 ++++++++++++++
 test/4.expected |  9 +++++++++
 3 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/relint.el b/relint.el
index 53acede..c2113be 100644
--- a/relint.el
+++ b/relint.el
@@ -298,8 +298,9 @@ list of list indices to follow to target)."
     (nreverse errs)))
 
 (defvar relint--variables nil
-  "Alist of global variable definitions seen so far.
- The variable names map to unevaluated forms.")
+  "Alist of global variable definitions.
+Each element is either (NAME expr EXPR), for unevaluated expressions,
+or (NAME val VAL), for values.")
 
 ;; List of variables that have been checked, so that we can avoid
 ;; checking direct uses of it.
@@ -528,8 +529,12 @@ not be evaluated safely."
                 (throw 'relint-eval 'no-value))
             (let ((binding (assq form relint--variables)))
               (if binding
-                  (relint--eval (cdr binding))
-                (throw 'relint-eval 'no-value))))))
+                  (if (eq (cadr binding) 'val)
+                      (caddr binding)
+                    (let ((val (relint--eval (caddr binding))))
+                      (setcdr binding (list 'val val))
+                      val))
+                  (throw 'relint-eval 'no-value))))))
        (t form))
     (let ((head (car form))
           (body (cdr form)))
@@ -889,8 +894,13 @@ evaluated are nil."
          (let ((local (assq form relint--locals)))
            (if local
                (and (cdr local) (cadr local))
-             (let ((val (cdr (assq form relint--variables))))
-               (and val (relint--eval-list val)))))))
+             (let ((binding (assq form relint--variables)))
+               (and binding
+                    (if (eq (cadr binding) 'val)
+                        (caddr binding)
+                      ;; Since we are only doing a list evaluation, don't
+                      ;; update the variable here.
+                      (relint--eval-list (caddr binding)))))))))
    ((atom form)
     form)
    ((memq (car form) '(progn ignore-errors eval-when-compile eval-and-compile))
@@ -1012,7 +1022,8 @@ EXPANDED is a list of expanded functions, to prevent 
recursion."
          ;; Check both variable contents and name.
          (or (let ((def (assq expr relint--variables)))
                (and def
-                    (relint--regexp-generators (cdr def) expanded)))
+                    (eq (cadr def) 'expr)
+                    (relint--regexp-generators (caddr def) expanded)))
              (and (or (memq expr '(page-delimiter paragraph-separate
                                    paragraph-start sentence-end
                                    comment-start-skip comment-end-skip))
@@ -1496,7 +1507,19 @@ directly."
                 (relint--check-defcustom-re form name file pos path))
               (push name relint--checked-variables))
              )
-            (push (cons name re-arg) relint--variables))))
+
+            (let* ((old (assq name relint--variables))
+                   (new
+                    (or (and old
+                             ;; Redefinition of the same variable: eagerly
+                             ;; evaluate the new expression in case it uses
+                             ;; the old value.
+                             (let ((val (catch 'relint-eval
+                                          (list (relint--eval re-arg)))))
+                               (and (consp val)
+                                    (cons 'val val))))
+                        (list 'expr re-arg))))
+              (push (cons name new) relint--variables)))))
        (`(define-generic-mode ,name ,_ ,_ ,font-lock-list ,auto-mode-list . ,_)
         (let ((origin (format "define-generic-mode %s" name)))
           (relint--check-font-lock-keywords font-lock-list origin
diff --git a/test/4.elisp b/test/4.elisp
index 4dc8a94..b9ae44a 100644
--- a/test/4.elisp
+++ b/test/4.elisp
@@ -45,3 +45,17 @@
   (looking-at (unless nil "c++"))
   (looking-at (string-join `("a" ,@(list "$") ,"b")))
   (looking-at (pcase 'a ((pred symbolp) "d++"))))
+
+;; Test repeated use of global variable
+(defconst my-var-a "*")
+(defconst my-var-b (concat my-var-a "b"))
+
+(defun test-var-ref ()
+  (looking-at my-var-b)
+  (looking-at (concat my-var-b "c")))
+
+;; Test global variable redefinition
+(defconst my-var-a (concat my-var-a "a"))
+
+(defun test-var-redef ()
+  (looking-at my-var-a))
diff --git a/test/4.expected b/test/4.expected
index d051130..d1897ed 100644
--- a/test/4.expected
+++ b/test/4.expected
@@ -49,3 +49,12 @@
 4.elisp:47:15: In call to looking-at: Repetition of repetition (pos 2)
   "d++"
    ..^
+4.elisp:54:15: In call to looking-at: Unescaped literal `*' (pos 0)
+  "*b"
+   ^
+4.elisp:55:15: In call to looking-at: Unescaped literal `*' (pos 0)
+  "*bc"
+   ^
+4.elisp:61:15: In call to looking-at: Unescaped literal `*' (pos 0)
+  "*a"
+   ^



reply via email to

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