[elpa] externals/relint ee70350 44/44: FSF copyright, URL, and increment version to 1.5

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit ee70350bf5d9416990194b43ae0ef89b09260366
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

FSF copyright, URL, and increment version to 1.5
---
 relint.el | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 39a1db8..e6753ce 100644
--- a/relint.el
+++ b/relint.el
@@ -1,8 +1,11 @@
 ;;; relint.el --- Elisp regexp mistake finder   -*- lexical-binding: t -*-
 
+;; Copyright (C) 2019 Free Software Foundation, Inc.
+
 ;; Author: Mattias Engdegård 
-;; Version: 1.4
+;; Version: 1.5
 ;; Package-Requires: ((xr "1.7"))
+;; URL: https://github.com/mattiase/relint
 ;; Keywords: lisp, maint, regexps
 
 ;; This program is free software; you can redistribute it and/or modify



[elpa] externals/relint c1b92cc 36/44: Wrap and evaluate defined functions passed as parameters

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit c1b92cc2d103b077ec62d6d4b74a32e773d18bc4
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Wrap and evaluate defined functions passed as parameters

The much more general way of handling functions passed as parameters to
primitives allows most pure code to be used, and removes a lot of
special-purpose code.
---
 relint.el | 297 ++
 1 file changed, 125 insertions(+), 172 deletions(-)

diff --git a/relint.el b/relint.el
index af46b1d..8ef0e4b 100644
--- a/relint.el
+++ b/relint.el
@@ -199,6 +199,7 @@
 string-match split-string replace-regexp-in-string
 wildcard-to-regexp
 combine-and-quote-strings split-string-and-unquote
+string-to-multibyte string-as-multibyte string-to-unibyte string-as-unibyte
 string-join string-trim-left string-trim-right string-trim
 string-prefix-p string-suffix-p
 string-blank-p string-remove-prefix string-remove-suffix
@@ -224,60 +225,7 @@
 (nreverse . reverse)
 (nbutlast . butlast)))
 
-;; Transform FORM into an expression that is safe to evaluate with the
-;; bindings in relint--variables and parameters in PARAMS.
-;; Return the transformed expression with known variables substituted away,
-;; or 'no-value if safe evaluation could not be guaranteed.
-(defun relint--safe-expr (form params)
-  (cond
-   ((symbolp form)
-(if (or (memq form '(t nil))
-(memq form params))
-form
-  (let ((binding (assq form relint--variables)))
-(if binding
-(list 'quote (relint--eval (cdr binding)))
-  'no-value
-   ((atom form) form)   ; Other atoms considered OK.
-   ((eq (car form) 'quote) form)
-   (t
-(let* ((fun (relint--safe-function (car form) params))
-   (args (mapcar (lambda (x) (relint--safe-expr x params))
- (cdr form
-  (if (and fun (not (memq 'no-value args)))
-  (cons fun args)
-'no-value)
-
-;; Transform F into a function that is safe to pass as a higher-order function
-;; in a call. Return the transformed function or nil if safe evaluation
-;; could not be guaranteed.
-;; PARAMS is a list of parameters that can be assumed to be in scope.
-(defun relint--safe-function (f params)
-  (cond
-   ;; Functions (and some special forms/macros) considered safe.
-   ((symbolp f)
-(cond ((or (memq f relint--safe-functions)
-   (memq f '(if when unless and or)))
-   f)
-  ((cdr (assq f relint--safe-alternatives)
-   ((atom f) nil)
-   ((eq (car f) 'function)
-(relint--safe-function (cadr f) params))
-
-   ;; Only permit one-argument one-expression lambdas (for purity),
-   ;; where the body only refers to arguments and known variables,
-   ;; and calls safe functions.
-   ((eq (car f) 'lambda)
-(let ((vars (cadr f))
-  (body (cddr f)))
-  (and (= (length vars) 1)
-   (= (length body) 1)
-   (let ((expr (relint--safe-expr (car body) (cons (car vars) 
params
- (and (not (eq expr 'no-value))
-  `(lambda (,(car vars)) ,expr
-
-;; Whether an `rx' form is safe to translate.
-;; Will mutate (eval ...) subforms with their results when possible.
+;; Make an `rx' form safe to translate, by mutating (eval ...) subforms.
 (defun relint--rx-safe (form)
   (cond
((atom form) t)
@@ -297,7 +245,7 @@
   (condition-case err
   (apply #'rx-to-string args)
 (error (signal 'relint--eval-error (format "rx error: %s" (cadr 
err)
-'no-value))
+(throw 'relint-eval 'no-value)))
 
 ;; Bind FORMALS to ACTUALS and evaluate EXPR.
 (defun relint--apply (formals actuals expr)
@@ -318,8 +266,38 @@
 (let ((relint--variables (append bindings relint--variables)))
   (relint--eval expr
 
-;; Evaluate a form as far as possible. Substructures that cannot be evaluated
-;; become `no-value'.
+;; A function that fails when called.
+(defun relint--no-value ( _)
+  (throw 'relint-eval 'no-value))
+
+;; Transform an evaluated function (typically a symbol or lambda expr)
+;; into something that can be called safely.
+(defun relint--wrap-function (form)
+  (cond
+   ((symbolp form)
+(if (memq form relint--safe-functions)
+form
+  (let ((alt (cdr (assq form relint--safe-alternatives
+(if alt
+alt
+  (let ((def (cdr (assq form relint--function-defs
+(if def
+(let ((formals (car def))
+  (expr (cadr def)))
+  (lambda ( args)
+(relint--apply formals args expr)))
+  'relint--no-value))
+   ((and (consp form) (eq (car form) 'lambda))
+(let ((formals (cadr form))
+  (body (cddr form)))
+  (if (= (length body) 1)
+  (lambda ( args)
+(relint--apply formals args (car body)))
+'relint--no-value)))
+   (t 

[elpa] externals/relint e1b1ef9 22/44: Run in two phases on each file

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit e1b1ef92b4427dcb964de93b6b7334ad1e30b7de
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Run in two phases on each file

In the first phase, only scan function signatures for regexp arguments.
In the second, do everything else.
This way, the order of function definitions in a file don't matter.
---
 trawl.el | 132 ---
 1 file changed, 75 insertions(+), 57 deletions(-)

diff --git a/trawl.el b/trawl.el
index 809ca72..a5d84da 100644
--- a/trawl.el
+++ b/trawl.el
@@ -532,7 +532,43 @@
  re (format "%s (%s)" name rule-name) file pos path)
 (trawl--get-list form file pos path)))
 
-(defun trawl--check-form-recursively (form file pos path)
+(defun trawl--check-form-recursively-1 (form file pos path)
+  (pcase form
+(`(,(or `defun `defmacro `defsubst)
+   ,name ,args . ,_)
+ ;; If any argument looks like a regexp, remember it so that it can be
+ ;; checked in calls.
+ (when (consp args)
+   (let ((indices nil)
+ (index 0))
+ (while args
+   (let ((arg (car args)))
+ (when (symbolp arg)
+   (cond
+((eq arg '))   ; Treat optional args as regular.
+((eq arg ')
+ (setq args nil))   ; Ignore  args.
+(t
+ (when (string-match-p (rx (or (or "regexp" "regex" "-re"
+   "pattern")
+   (seq bos "re"))
+   eos)
+(symbol-name arg))
+   (push index indices))
+ (setq index (1+ index)
+ (setq args (cdr args
+ (when indices
+   (push (cons name (reverse indices)) trawl--regexp-functions)
+(_
+ (let ((index 0))
+   (while (consp form)
+ (when (consp (car form))
+   (trawl--check-form-recursively-1
+(car form) file pos (cons index path)))
+ (setq form (cdr form))
+ (setq index (1+ index)))
+
+(defun trawl--check-form-recursively-2 (form file pos path)
   (pcase form
 (`(,(or `looking-at `re-search-forward `re-search-backward
 `string-match `string-match-p `looking-back `looking-at-p
@@ -613,30 +649,6 @@
(trawl--check-font-lock-keywords font-lock-list origin
 file pos (cons 4 path))
(trawl--check-list auto-mode-list origin file pos (cons 5 path
-(`(,(or `defun `defmacro `defsubst)
-   ,name ,args . ,_)
- ;; If any argument looks like a regexp, remember it so that it can be
- ;; checked in calls.
- (when (consp args)
-   (let ((indices nil)
- (index 0))
- (while args
-   (let ((arg (car args)))
- (when (symbolp arg)
-   (cond
-((eq arg '))
-((eq arg ')
- (setq args nil))
-(t
- (when (or (string-suffix-p "regexp" (symbol-name arg))
-   (string-suffix-p "regex" (symbol-name arg))
-   (eq arg 're)
-   (string-suffix-p "-re" (symbol-name arg)))
-   (push index indices))
- (setq index (1+ index)
- (setq args (cdr args
- (when indices
-   (push (cons name (reverse indices)) trawl--regexp-functions)
 )
 
   ;; Check calls to remembered functions with regexp arguments.
@@ -658,55 +670,61 @@
   (let ((index 0))
 (while (consp form)
   (when (consp (car form))
-(trawl--check-form-recursively (car form) file pos (cons index path)))
+(trawl--check-form-recursively-2 (car form) file pos (cons index 
path)))
   (setq form (cdr form))
   (setq index (1+ index)
 
-(defun trawl--check-toplevel-form (form file pos)
-  (when (consp form)
-(trawl--check-form-recursively form file pos nil)))
-  
 (defun trawl--show-errors ()
   (unless noninteractive
 (let ((pop-up-windows t))
   (display-buffer (trawl--error-buffer))
   (sit-for 0
 
+(defun trawl--check-buffer (file forms function)
+  (dolist (form forms)
+(funcall function (car form) file (cdr form) nil)))
+
+;; Read top-level forms from the current buffer.
+;; Return a list of (FORM . STARTING-POSITION).
+(defun trawl--read-buffer (file)
+  (goto-char (point-min))
+  (let ((pos nil)
+(keep-going t)
+(read-circle nil)
+(forms nil))
+(while keep-going
+  (setq pos (point))
+  (let ((form nil))
+(condition-case err
+(setq form (read (current-buffer)))
+  (end-of-file
+   (setq keep-going nil))
+  (invalid-read-syntax
+   (cond
+((equal (cadr err) "#")
+ 

[elpa] master 2915039: * externals-list: Add relint

2019-03-26 Thread Mattias Engdegrd
branch: master
commit 29150392e4d5192228c963bfc0fb91cd1c2c3e54
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

* externals-list: Add relint
---
 externals-list | 1 +
 1 file changed, 1 insertion(+)

diff --git a/externals-list b/externals-list
index f5e5a83..b43c39d 100644
--- a/externals-list
+++ b/externals-list
@@ -114,6 +114,7 @@
  ("psgml"   :external "https://github.com/lenst/psgml.git;)
  ("python" :core "lisp/progmodes/python.el")
  ;;FIXME:("org":external ??) ;; Need to introduce snapshots!!
+ ("relint" :external "https://github.com/mattiase/relint;)
  ("rich-minority"  :subtree "https://github.com/Malabarba/rich-minority;)
  ("rudel"  :external nil) ;; Was 
bzr::bzr://rudel.bzr.sourceforge.net/bzrroot/rudel/trunk
  ("soap-client":core ("lisp/net/soap-client.el" 
"lisp/net/soap-inspect.el"))



[elpa] externals/relint 6ab713e 07/44: Reinstate erroneously removed line

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 6ab713e2791654943b25ed061016be7ba8345a39
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Reinstate erroneously removed line
---
 trawl.el | 1 +
 1 file changed, 1 insertion(+)

diff --git a/trawl.el b/trawl.el
index 0f97633..d365a5a 100644
--- a/trawl.el
+++ b/trawl.el
@@ -372,6 +372,7 @@
   (let ((inhibit-read-only t))
 (erase-buffer)
 (insert (format ";; Trawling %s  -*- compilation -*-\n" file-or-dir)))
+  (setq trawl--error-count 0)
   (cd dir
 
 (defun trawl--finish ()



[elpa] externals/relint 4dbcad9 24/44: Increment version to 1.2

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 4dbcad9d3000b105dd1da44d0c203103ff68a303
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.2
---
 trawl.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/trawl.el b/trawl.el
index 5149a20..89e61a1 100644
--- a/trawl.el
+++ b/trawl.el
@@ -1,7 +1,7 @@
 ;;; trawl.el --- Scan elisp files for regexp errors -*- lexical-binding: t -*-
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.1
+;; Version: 1.2
 ;; Package-Requires: ((xr "1.4"))
 ;; Keywords: lisp, maint, regexps
 



[elpa] externals/relint 7d0e177 20/44: Rewrite the higher-order function handling

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 7d0e17725eab654cd4c2958e9b3967fa20cff92c
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Rewrite the higher-order function handling

Now variable references from lambda-expressions are handled correctly.
Free variables are substituted before use in order to isolate the
pseudo-evaluation from the runtime environment.
---
 trawl.el | 153 +++
 1 file changed, 94 insertions(+), 59 deletions(-)

diff --git a/trawl.el b/trawl.el
index 5dd3f46..12f5c36 100644
--- a/trawl.el
+++ b/trawl.el
@@ -152,43 +152,62 @@
 ;; The names map to a list of the regexp argument indices.
 (defvar trawl--regexp-functions)
 
-;; Whether form is a safe expression to evaluate.
-(defun trawl--safe-expr (form)
+;; Transform FORM into an expression that is safe to evaluate with the
+;; bindings in trawl--variables and parameters in PARAMS.
+;; Return the transformed expression with known variables substituted away,
+;; or 'no-value if safe evaluation could not be guaranteed.
+(defun trawl--safe-expr (form params)
   (cond
((symbolp form)
-(or (memq form '(t nil))
-(assq form trawl--variables)))
-   ((consp form)
-(or (eq (car form) 'quote)
-(and (trawl--safe-function (car form))
- (not (memq nil (mapcar #'trawl--safe-expr (cdr form)))
-   (t t)))  ; Other atoms assumed OK.
-
-;; Whether f is safe to pass as a higher-order function in a call.
-(defun trawl--safe-function (f)
-  (when (and (consp f) (memq (car f) '(quote function)))
-(setq f (cadr f)))
+(if (or (memq form '(t nil))
+(memq form params))
+form
+  (let ((binding (assq form trawl--variables)))
+(if binding
+(list 'quote (trawl--eval (cdr binding)))
+  'no-value
+   ((atom form) form)   ; Other atoms considered OK.
+   ((eq (car form) 'quote) form)
+   (t
+(let* ((fun (trawl--safe-function (car form) params))
+   (args (mapcar (lambda (x) (trawl--safe-expr x params))
+ (cdr form
+  (if (and fun (not (memq 'no-value args)))
+  (cons fun args)
+'no-value)
+
+;; Transform F into a function that is safe to pass as a higher-order function
+;; in a call. Return the transformed function or nil if safe evaluation
+;; could not be guaranteed.
+;; PARAMS is a list of parameters that can be assumed to be in scope.
+(defun trawl--safe-function (f params)
   (cond
;; Functions (and some special forms/macros) considered safe.
((symbolp f)
-(or (get f 'side-effect-free)
-(memq f '(caar cadr cdar cddr purecopy remove remq
-  if unless when and or
-  regexp-opt regexp-opt-charset
+(and (or (and (get f 'side-effect-free)
+  (not (eq f 'symbol-value)))
+ (memq f '(caar cadr cdar cddr purecopy remove remq
+   if unless when and or
+   regexp-opt regexp-opt-charset)))
+ f))
+   ((atom f) nil)
+   ((eq (car f) 'function)
+(trawl--safe-function (cadr f) params))
 
;; Only permit one-argument one-expression lambdas (for purity),
;; where the body only refers to arguments and known variables,
;; and calls safe functions.
-   ((and (consp f) (eq (car f) 'lambda))
+   ((eq (car f) 'lambda)
 (let ((vars (cadr f))
   (body (cddr f)))
   (and (= (length vars) 1)
(= (length body) 1)
-   (let ((trawl--variables
-  (cons (cons (car vars) nil) trawl--variables)))
- (trawl--safe-expr (car body
+   (let ((expr (trawl--safe-expr (car body) (cons (car vars) params
+ (and (not (eq expr 'no-value))
+  `(lambda (,(car vars)) ,expr
 
 ;; Whether an `rx' form is safe to translate.
+;; Will mutate (eval ...) subforms with their results when possible.
 (defun trawl--rx-safe (form)
   (cond
((atom form) t)
@@ -226,6 +245,11 @@
 (trawl--add-to-error-buffer (format "eval error: %S" form))
 'no-value)
((eq (car form) 'quote)
+(if (and (consp (cadr form))
+ (eq (caadr form) '\,)) ; In case we are inside a backquote.
+'no-value
+  (cadr form)))
+   ((eq (car form) 'function)
 (cadr form))
((eq (car form) 'eval-when-compile)
 (trawl--eval (car (last form
@@ -233,7 +257,11 @@
 form)
 
;; Reasonably pure functions: only call if all args can be fully evaluated.
-   ((or (get (car form) 'side-effect-free)
+   ((or (and (get (car form) 'side-effect-free)
+ ;; Exceptions: there should probably be more.
+ ;; Maybe we should just list the ones we believe are safe,
+ ;; and not use side-effect-free?
+ (not (eq (car form) 'symbol-value)))
 ;; Common functions that aren't marked as side-effect-free.
 (memq (car 

[elpa] externals/relint 365dc91 41/44: Check bad skip-set provenance

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 365dc91b8f59142a4fa50c3de085b90bc9e92242
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check bad skip-set provenance

Check whether known regexp-returning functions such as regexp-quote
are used in the generation of arguments to skip-chars-{forward,backward}.
The check is purely textual; no interpretation is performed, but definitions
of variables and functions are scanned.
---
 relint.el | 35 ++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 7018857..844373f 100644
--- a/relint.el
+++ b/relint.el
@@ -648,6 +648,36 @@
  re (format "%s (%s)" name rule-name) file pos path)
 (relint--get-list form file pos path)))
 
+;; List of known regexp-generating functions used in EXPR.
+;; EXPANDED is a list of expanded functions, to prevent recursion.
+(defun relint--regexp-generators (expr expanded)
+  (cond
+   ((symbolp expr)
+(let ((def (assq expr relint--variables)))
+  (and def (relint--regexp-generators (cdr def) expanded
+   ((atom expr) nil)
+   ((memq (car expr) '(regexp-quote regexp-opt regexp-opt-charset
+   rx rx-to-string wildcard-to-regexp))
+(list (car expr)))
+   ((memq (car expr) '(looking-at re-search-forward re-search-backward
+   string-match string-match-p looking-back looking-at-p))
+nil)
+   ((listp (cdr (last expr)))
+(let ((head (car expr)))
+  (append (mapcan (lambda (x) (relint--regexp-generators x expanded))
+  (cdr expr))
+  (let ((fun (assq head relint--function-defs)))
+(and fun (not (memq head expanded))
+ (relint--regexp-generators
+  (caddr fun) (cons head expanded)
+
+(defun relint--check-skip-set-provenance (skip-function form file pos path)
+  (let ((reg-gen (relint--regexp-generators form nil)))
+(when reg-gen
+  (relint--report file pos path
+  (format "`%s' cannot be used for arguments to `%s'"
+  (car reg-gen) skip-function)
+
 (defun relint--check-form-recursively-1 (form file pos path)
   (pcase form
 (`(,(or `defun `defmacro `defsubst)
@@ -743,7 +773,10 @@
  (let ((str (relint--get-string skip-arg file pos path)))
(when str
  (relint--check-skip-set str (format "call to %s" (car form))
- file pos (cons 1 path)
+ file pos (cons 1 path
+ (relint--check-skip-set-provenance
+  (car form) skip-arg file pos (cons 1 path))
+ )
 (`(,(or `defvar `defconst `defcustom)
,name ,re-arg . ,rest)
  (when (symbolp name)



[elpa] externals/relint 02bf0ba 21/44: Use explicit list of pure functions

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 02bf0ba01743a45b9a7d3a993d66c43fa62b6c4e
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Use explicit list of pure functions

Instead of relying on the `side-effect-free' property, which is set
by the byte-compiler and not necessarily available in batch mode,
use our own list. We had to add some functions anyway.
---
 trawl.el | 55 ---
 1 file changed, 36 insertions(+), 19 deletions(-)

diff --git a/trawl.el b/trawl.el
index 12f5c36..809ca72 100644
--- a/trawl.el
+++ b/trawl.el
@@ -152,6 +152,39 @@
 ;; The names map to a list of the regexp argument indices.
 (defvar trawl--regexp-functions)
 
+;; Functions that are safe to call during evaluation.
+;; With some exceptions (noted), these are pure.
+;; More functions could be added if there is evidence that it would
+;; help in evaluating more regexp strings.
+(defconst trawl--safe-functions
+  '(cons list append
+concat
+car cdr caar cadr cdar cddr car-safe cdr-safe nth nthcdr
+format format-message
+regexp-quote regexp-opt regexp-opt-charset
+reverse
+member memq remove remq
+assoc assq rassoc rassq
+identity
+string make-string make-list
+substring
+length safe-length
+symbol-name
+null not
+eq eql equal
+string-equal string= string< string-lessp char-equal string-match-p
+string-match; Alters the match state.
+vector aref elt vconcat
+char-to-string string-to-char
+number-to-string string-to-number int-to-string
+upcase downcase capitalize
+purecopy copy-sequence copy-alist
+plist-get plist-member
+consp atom stringp symbolp listp nlisp
+integerp numberp natnump fixnump bignump characterp
+sequencep vectorp arrayp
++ - * / % mod 1+ 1- max min < <= = > >= /= abs))
+
 ;; Transform FORM into an expression that is safe to evaluate with the
 ;; bindings in trawl--variables and parameters in PARAMS.
 ;; Return the transformed expression with known variables substituted away,
@@ -184,11 +217,8 @@
   (cond
;; Functions (and some special forms/macros) considered safe.
((symbolp f)
-(and (or (and (get f 'side-effect-free)
-  (not (eq f 'symbol-value)))
- (memq f '(caar cadr cdar cddr purecopy remove remq
-   if unless when and or
-   regexp-opt regexp-opt-charset)))
+(and (or (memq f trawl--safe-functions)
+ (memq f '(if when unless and or)))
  f))
((atom f) nil)
((eq (car f) 'function)
@@ -257,20 +287,7 @@
 form)
 
;; Reasonably pure functions: only call if all args can be fully evaluated.
-   ((or (and (get (car form) 'side-effect-free)
- ;; Exceptions: there should probably be more.
- ;; Maybe we should just list the ones we believe are safe,
- ;; and not use side-effect-free?
- (not (eq (car form) 'symbol-value)))
-;; Common functions that aren't marked as side-effect-free.
-(memq (car form) '(caar cadr cdar cddr
-   regexp-opt regexp-opt-charset
-   ;; alters last-coding-system-used
-   decode-coding-string
-   format-message format-spec
-   purecopy remove remq
-   ;; alters match state
-   string-match string-match-p)))
+   ((memq (car form) trawl--safe-functions)
 (let ((args (mapcar #'trawl--eval (cdr form
   (if (memq 'no-value args)
   'no-value



[elpa] externals/relint 0fd1d46 29/44: Rename trawl to relint

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 0fd1d46d2eadd359ec31284ff11c817096ae80dc
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Rename trawl to relint

It's slightly more descriptive ('regexp linter').
---
 trawl.el => relint.el | 456 +-
 1 file changed, 228 insertions(+), 228 deletions(-)

diff --git a/trawl.el b/relint.el
similarity index 63%
rename from trawl.el
rename to relint.el
index b4b9147..97454e1 100644
--- a/trawl.el
+++ b/relint.el
@@ -1,4 +1,4 @@
-;;; trawl.el --- Scan elisp files for regexp errors -*- lexical-binding: t -*-
+;;; relint.el --- Scan elisp files for regexp errors -*- lexical-binding: t -*-
 
 ;; Author: Mattias Engdegård 
 ;; Version: 1.3
@@ -24,14 +24,14 @@
 ;; reports potential errors in them, using `xr-lint' from the `xr'
 ;; package.
 ;;
-;; To use:  M-x trawl-file   (check a single elisp file)
-;;  or  M-x trawl-directory  (check all .el files in a directory tree)
+;; To use:  M-x relint-file   (check a single elisp file)
+;;  or  M-x relint-directory  (check all .el files in a directory tree)
 ;;
-;; It can also be used from batch mode by calling `trawl-batch' with
+;; It can also be used from batch mode by calling `relint-batch' with
 ;; files and/or directories as command-line arguments, errors going
 ;; to stderr:
 ;;
-;;  emacs -batch -l trawl.el -f trawl-batch FILES-AND-DIRS...
+;;  emacs -batch -l relint.el -f relint-batch FILES-AND-DIRS...
 ;;
 ;; Since there is no sure way to know whether a particular string is a
 ;; regexp, the code has to guess a lot, and will likely miss quite a
@@ -44,27 +44,27 @@
 
 (require 'xr)
 
-(defconst trawl--error-buffer-name "*trawl-catch*")
+(defconst relint--error-buffer-name "*relint-catch*")
 
-(defun trawl--error-buffer ()
-  (let ((buf (get-buffer trawl--error-buffer-name)))
+(defun relint--error-buffer ()
+  (let ((buf (get-buffer relint--error-buffer-name)))
 (or buf
-(let ((buf (get-buffer-create trawl--error-buffer-name)))
+(let ((buf (get-buffer-create relint--error-buffer-name)))
   (with-current-buffer buf
 (compilation-mode))
   buf
 
-(defvar trawl--error-count)
+(defvar relint--error-count)
 
-(defun trawl--add-to-error-buffer (string)
-  (with-current-buffer (trawl--error-buffer)
+(defun relint--add-to-error-buffer (string)
+  (with-current-buffer (relint--error-buffer)
 (goto-char (point-max))
 (let ((inhibit-read-only t))
   (insert string
 
 ;; Compute (LINE . COLUMN) from POS (toplevel position)
 ;; and PATH (reversed list of list indices to follow to target).
-(defun trawl--line-col-from-pos-path (pos path)
+(defun relint--line-col-from-pos-path (pos path)
   (save-excursion
 (goto-char pos)
 (let ((p (reverse path)))
@@ -87,18 +87,18 @@
   (cons (line-number-at-pos (point) t)
 (1+ (current-column))
 
-(defun trawl--output-error (string)
+(defun relint--output-error (string)
   (if noninteractive
   (message "%s" string)
-(trawl--add-to-error-buffer (concat string "\n"
+(relint--add-to-error-buffer (concat string "\n"
 
-(defun trawl--report (file pos path message)
-  (let ((line-col (trawl--line-col-from-pos-path pos path)))
-(trawl--output-error
+(defun relint--report (file pos path message)
+  (let ((line-col (relint--line-col-from-pos-path pos path)))
+(relint--output-error
  (format "%s:%d:%d: %s" file (car line-col) (cdr line-col) message)))
-  (setq trawl--error-count (1+ trawl--error-count)))
+  (setq relint--error-count (1+ relint--error-count)))
 
-(defun trawl--quote-string (str)
+(defun relint--quote-string (str)
   (concat "\""
   (replace-regexp-in-string
(rx (any cntrl "\177-\377" ?\\ ?\"))
@@ -118,61 +118,61 @@
str t t)
   "\""))
 
-(defun trawl--caret-string (string pos)
+(defun relint--caret-string (string pos)
   (let ((quoted-pos
- (- (length (trawl--quote-string (substring string 0 pos)))
+ (- (length (relint--quote-string (substring string 0 pos)))
 2))); Lop off quotes
 (concat (make-string quoted-pos ?.) "^")))
 
-(defun trawl--check-skip-set (skip-set-string name file pos path)
+(defun relint--check-skip-set (skip-set-string name file pos path)
   (let ((complaints
  (condition-case err
  (mapcar (lambda (warning)
(let ((ofs (car warning)))
  (format "In %s: %s (pos %d)\n  %s\n   %s"
  name (cdr warning) ofs
- (trawl--quote-string skip-set-string)
- (trawl--caret-string skip-set-string ofs
+ (relint--quote-string skip-set-string)
+ (relint--caret-string skip-set-string ofs
  (xr-skip-set-lint skip-set-string))
(error (list 

[elpa] externals/relint 7a1b632 33/44: Add wildcard-to-regexp as 'pure' function

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 7a1b632f65baff84ed862decef2383ed63f3bd7b
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add wildcard-to-regexp as 'pure' function
---
 relint.el | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/relint.el b/relint.el
index e1d9c27..0147bf0 100644
--- a/relint.el
+++ b/relint.el
@@ -171,7 +171,7 @@
 (defvar relint--regexp-functions)
 
 ;; Functions that are safe to call during evaluation.
-;; With some exceptions (noted), these are pure.
+;; Except for altering the match state, these are pure.
 ;; More functions could be added if there is evidence that it would
 ;; help in evaluating more regexp strings.
 (defconst relint--safe-functions
@@ -191,10 +191,8 @@
 null not
 eq eql equal
 string-equal string= string< string-lessp char-equal string-match-p
-
-; These alter the match state.
 string-match split-string replace-regexp-in-string
-
+wildcard-to-regexp
 combine-and-quote-strings split-string-and-unquote
 string-join string-trim-left string-trim-right string-trim
 string-prefix-p string-suffix-p



[elpa] externals/relint 0f76132 40/44: Add README.org

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 0f7613211ccdd6340caed1fe0ba5aa8789f2b75b
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add README.org
---
 README.org | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/README.org b/README.org
new file mode 100644
index 000..2ce02db
--- /dev/null
+++ b/README.org
@@ -0,0 +1,39 @@
+#+TITLE: relint.el
+
+Relint (regular expression lint) scans elisp files for mistakes in
+regexps, including deprecated syntax and bad practice. It also checks
+the regexp-like arguments to ~skip-chars-forward~ and
+~skip-chars-backward~.
+
+* Usage
+
+Check a single file:
+
+: M-x relint-file
+
+Check all .el files in a directory tree:
+
+: M-x relint-directory
+
+From batch mode:
+
+: emacs -batch -l relint.el -f relint-batch FILES-AND-DIRS...
+
+where directories are scanned recursively.
+
+* Installation
+
+Download the source file =relint.el= and set ~load-path~:
+
+: (add-to-list 'load-path "RELINT-DIRECTORY")
+
+Relint requires the package [[https://elpa.gnu.org/packages/xr.html][xr]]; 
install it from GNU ELPA.
+
+* Bugs
+
+The recognition of regexps is done by ad-hoc rules; the simplistic
+method employed means that many errors will go undetected.
+
+Still, if you believe that a flawed regexp could have been discovered
+but wasn't, please report it as a bug. Reports of false positives and
+crashes are of course equally welcome.



[elpa] externals/relint 0604fad 43/44: Use a custom mode for the *relint* buffer

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 0604faded0efb16f1e6688b851b90335108706b9
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Use a custom mode for the *relint* buffer

Using our own mode, a sub-mode to compilation-mode, is mainly so that
we can bind the "g" key to "run the same thing again".
---
 relint.el | 53 +
 1 file changed, 41 insertions(+), 12 deletions(-)

diff --git a/relint.el b/relint.el
index 65af095..39a1db8 100644
--- a/relint.el
+++ b/relint.el
@@ -45,6 +45,7 @@
 ;;; Code:
 
 (require 'xr)
+(require 'compile)
 
 (defconst relint--error-buffer-name "*relint*")
 
@@ -53,7 +54,7 @@
 (or buf
 (let ((buf (get-buffer-create relint--error-buffer-name)))
   (with-current-buffer buf
-(compilation-mode))
+(relint-mode))
   buf
 
 (defvar relint--error-count)
@@ -975,24 +976,52 @@
 (when (> relint--error-count errors-before)
   (relint--show-errors
 
-(defun relint--init (dir)
+(defvar relint-last-target nil
+  "The last file or directory on which relint was run.  Buffer-local.")
+
+(defun relint--init (target)
   (if noninteractive
   (setq relint--error-count 0)
 (with-current-buffer (relint--error-buffer)
   (let ((inhibit-read-only t))
 (erase-buffer)
-(insert ";; -*- compilation -*-\n"))
-  (setq default-directory dir)
+(insert (format "Relint results for %s\n" target)))
+  (setq relint-last-target target)
+  (setq default-directory
+(if (file-directory-p target)
+target
+  (file-name-directory target)))
   (setq relint--error-count 0
 
 (defun relint--finish ()
-  (unless noninteractive
-(relint--add-to-error-buffer "Finished.\n")
-(let ((errors relint--error-count))
-  (message "relint: %d error%s found." errors (if (= errors 1) "" "s")
-
-(defun relint--scan-files (files cwd)
-  (relint--init cwd)
+  (let* ((errors relint--error-count)
+ (msg (format "%d error%s" errors (if (= errors 1) "" "s"
+(unless noninteractive
+  (relint--add-to-error-buffer (format "\nFinished -- %s found.\n" msg)))
+(message "relint: %s found." msg)))
+
+(defun relint-again ()
+  "Re-run relint on the same file or directory as last time."
+  (interactive)
+  (if (file-directory-p relint-last-target)
+  (relint-directory relint-last-target)
+(relint-file relint-last-target)))
+
+(defvar relint-mode-map
+  (let ((map (make-sparse-keymap)))
+(set-keymap-parent map compilation-minor-mode-map)
+(define-key map "n" 'next-error-no-select)
+(define-key map "p" 'previous-error-no-select)
+(define-key map "g" 'relint-again)
+map)
+  "Keymap for relint buffers.")
+
+(define-compilation-mode relint-mode "Relint"
+  "Mode for relint output."
+  (setq-local relint-last-target nil))
+
+(defun relint--scan-files (files target)
+  (relint--init target)
   (dolist (file files)
 ;;(relint--add-to-error-buffer (format "Scanning %s\n" file))
 (relint--single-file file))
@@ -1007,7 +1036,7 @@
 (defun relint-file (file)
   "Scan FILE, an elisp file, for errors in regexp strings."
   (interactive "fRelint elisp file: ")
-  (relint--scan-files (list file) (file-name-directory file)))
+  (relint--scan-files (list file) file))
 
 
 ;;;###autoload



[elpa] externals/relint d4a6d46 37/44: Evaluate some more functions, macros and special forms

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit d4a6d46e6cbf8510a11ff59aa0a58a62bbb2e0d5
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Evaluate some more functions, macros and special forms

Including sort, pcase and cond.
---
 relint.el | 68 +++
 1 file changed, 51 insertions(+), 17 deletions(-)

diff --git a/relint.el b/relint.el
index 8ef0e4b..7e85bb3 100644
--- a/relint.el
+++ b/relint.el
@@ -195,7 +195,8 @@
 symbol-name
 null not
 eq eql equal
-string-equal string= string< string-lessp char-equal string-match-p
+string-equal string= string< string-lessp string> string-greaterp
+char-equal string-match-p
 string-match split-string replace-regexp-in-string
 wildcard-to-regexp
 combine-and-quote-strings split-string-and-unquote
@@ -206,12 +207,13 @@
 vector aref elt vconcat
 char-to-string string-to-char
 number-to-string string-to-number int-to-string
+string-to-list string-to-vector string-or-null-p
 upcase downcase capitalize
 purecopy copy-sequence copy-alist copy-tree
 assoc-default member-ignore-case alist-get
 last butlast number-sequence
 plist-get plist-member
-consp atom stringp symbolp listp nlistp
+consp atom stringp symbolp listp nlistp booleanp
 integerp numberp natnump fixnump bignump characterp zerop
 sequencep vectorp arrayp
 + - * / % mod 1+ 1- max min < <= = > >= /= abs))
@@ -355,7 +357,6 @@
 (apply (car form) args)
   (error (throw 'relint-eval 'no-value))
 
-   ;; if: evaluate condition and the right branch.
((eq (car form) 'if)
 (let ((condition (relint--eval (cadr form
   (let ((then-part (nth 2 form))
@@ -363,11 +364,11 @@
 (cond (condition
(relint--eval then-part))
   ((and else-tail (cdr else-tail))
-   (throw 'relint-eval 'no-value)) ; Ignore multi-value else bodies
+   ;; Ignore multi-expression else bodies
+   (throw 'relint-eval 'no-value))
   (else-tail
(relint--eval (car else-tail)))
 
-   ;; and: keep evaluating until false or empty.
((eq (car form) 'and)
 (if (cdr form)
 (let ((val (relint--eval (cadr form
@@ -376,7 +377,6 @@
 val))
   t))
 
-   ;; or: keep evaluating until true or empty.
((eq (car form) 'or)
 (if (cdr form)
 (let ((val (relint--eval (cadr form
@@ -385,9 +385,23 @@
 val))
   nil))

-   ;; FIXME: cond
+   ((eq (car form) 'cond)
+(and (cdr form)
+ (let ((clause (cadr form)))
+   (if (consp clause)
+   (let ((val (relint--eval (car clause
+ (if val
+ (if (cdr clause)
+ (if (= (length (cdr clause)) 1)
+ (relint--eval (cadr clause))
+   ;; Ignore multi-expression clauses
+   (throw 'relint-eval 'no-value))
+   val)
+   (relint--eval (cons 'cond (cddr form)
+ ;; Syntax error
+ (throw 'relint-eval 'no-value)
 
-   ((eq (car form) 'progn)
+   ((memq (car form) '(progn ignore-errors))
 (cond ((null (cdr form)) nil)
   ((null (cddr form)) (relint--eval (cadr form)))
   (t (throw 'relint-eval 'no-value
@@ -401,9 +415,9 @@
 (let ((arg (relint--eval (cadr form
   (delete-dups (copy-sequence arg
 
-   ;; FIXME: more macros: pcase, pcase-let...
-   ;; Maybe ones from cl?
-   ((memq (car form) '(when unless \` backquote-list*))
+   ;; FIXME: more macros. Maybe ones from cl?
+   ;; If they are useful but expand to impure code, we need to emulate them.
+   ((memq (car form) '(when unless \` backquote-list* pcase pcase-let))
 (relint--eval (macroexpand form)))
 
;; apply: Call only if the function is safe and all args evaluated.
@@ -431,7 +445,7 @@
 (let* ((fun (relint--wrap-function (relint--eval (cadr form
(arg (relint--eval-list (caddr form)))
(seq (if (listp arg)
-(delq nil arg)
+(remq nil arg)
   arg)))
   (condition-case err
   (funcall (car form) fun seq)
@@ -447,7 +461,17 @@
 (error (signal 'relint--eval-error (format "eval error: %S: %s"
form err))
   
-   ;; FIXME: sort
+   ;; sort: accept missing items in a list argument.
+   ((eq (car form) 'sort)
+(let* ((arg (relint--eval-list (cadr form)))
+   (seq (cond ((listp arg) (remq nil arg))
+  ((sequencep arg) (copy-sequence arg))
+  (arg)))
+   (pred (relint--wrap-function (relint--eval (caddr form)
+  (condition-case err
+  (sort seq pred)
+(error (signal 'relint--eval-error (format "eval error: %S: %s"
+  

[elpa] externals/relint a1829d7 39/44: Refactor the file scanning and linting code

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit a1829d76099f34678c1653ece502d4beb2b8fdf5
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Refactor the file scanning and linting code
---
 relint.el | 97 ---
 1 file changed, 43 insertions(+), 54 deletions(-)

diff --git a/relint.el b/relint.el
index 4847fac..7018857 100644
--- a/relint.el
+++ b/relint.el
@@ -126,37 +126,27 @@
 2))); Lop off quotes
 (concat (make-string quoted-pos ?.) "^")))
 
-(defun relint--check-skip-set (skip-set-string name file pos path)
+(defun relint--check-string (string checker name file pos path)
   (let ((complaints
  (condition-case err
  (mapcar (lambda (warning)
(let ((ofs (car warning)))
  (format "In %s: %s (pos %d)\n  %s\n   %s"
  name (cdr warning) ofs
- (relint--quote-string skip-set-string)
- (relint--caret-string skip-set-string ofs
- (xr-skip-set-lint skip-set-string))
+ (relint--quote-string string)
+ (relint--caret-string string ofs
+ (funcall checker string))
(error (list (format "In %s: Error: %s: %s"
 name  (cadr err)
-(relint--quote-string skip-set-string)))
+(relint--quote-string string)))
 (mapc (lambda (msg) (relint--report file pos path msg))
   complaints)))
 
+(defun relint--check-skip-set (skip-set-string name file pos path)
+  (relint--check-string skip-set-string #'xr-skip-set-lint name file pos path))
+
 (defun relint--check-re-string (re name file pos path)
-  (let ((complaints
- (condition-case err
- (mapcar (lambda (warning)
-   (let ((ofs (car warning)))
- (format "In %s: %s (pos %d)\n  %s\n   %s"
- name (cdr warning) ofs
- (relint--quote-string re)
- (relint--caret-string re ofs
- (xr-lint re))
-   (error (list (format "In %s: Error: %s: %s"
-name  (cadr err)
-(relint--quote-string re)))
-(mapc (lambda (msg) (relint--report file pos path msg))
-  complaints)))
+  (relint--check-string re #'xr-lint name file pos path))
   
 ;; Alist of variable definitions seen so far.
 ;; The variable names map to unevaluated forms.
@@ -563,9 +553,6 @@
(and val (relint--eval-list val)
((atom form)
 form)
-   ((not (symbolp (car form)))
-(relint--add-to-error-buffer (format "eval error: %S\n" form))
-nil)
((eq (car form) 'eval-when-compile)
 (relint--eval-list (car (last form
 
@@ -838,10 +825,6 @@
   (display-buffer (relint--error-buffer))
   (sit-for 0
 
-(defun relint--check-buffer (file forms function)
-  (dolist (form forms)
-(funcall function (car form) file (cdr form) nil)))
-
 ;; Read top-level forms from the current buffer.
 ;; Return a list of (FORM . STARTING-POSITION).
 (defun relint--read-buffer (file)
@@ -885,48 +868,53 @@
 (relint--function-defs nil)
 (relint--macro-defs nil)
 )
-(relint--check-buffer file forms #'relint--check-form-recursively-1)
-(relint--check-buffer file forms #'relint--check-form-recursively-2)))
+(dolist (form forms)
+  (relint--check-form-recursively-1 (car form) file (cdr form) nil))
+(dolist (form forms)
+  (relint--check-form-recursively-2 (car form) file (cdr form) nil
 (when (> relint--error-count errors-before)
   (relint--show-errors
 
-(defun relint--tree (dir)
-  (dolist (file (directory-files-recursively
- dir (rx bos (not (any ".")) (* anything) ".el" eos)))
-;;(relint--add-to-error-buffer (format "Scanning %s\n" file))
-(relint--single-file file)))
-
-(defun relint--init (file-or-dir dir)
-  (unless noninteractive
+(defun relint--init (dir)
+  (if noninteractive
+  (setq relint--error-count 0)
 (with-current-buffer (relint--error-buffer)
   (let ((inhibit-read-only t))
 (erase-buffer)
-(insert (format ";; relint %s  -*- compilation -*-\n" file-or-dir)))
-  (setq relint--error-count 0)
-  (cd dir
+(insert ";; -*- compilation -*-\n"))
+  (setq default-directory dir)
+  (setq relint--error-count 0
 
 (defun relint--finish ()
-  (relint--add-to-error-buffer "Finished.\n")
-  (let ((errors relint--error-count))
-(message "relint: %d error%s found." errors (if (= errors 1) "" "s"
+  (unless noninteractive
+(relint--add-to-error-buffer "Finished.\n")
+

[elpa] externals/relint 15c799e 35/44: Evaluate calls to functions defined in the same file.

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 15c799e1c163b23ec54dd6dea8fc90a969ede51a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Evaluate calls to functions defined in the same file.

As before, only a subset of purely-functional code is considered.
Yet this change expands the set of analysed regexps in interesting ways.
---
 relint.el | 47 +--
 1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index e13af44..af46b1d 100644
--- a/relint.el
+++ b/relint.el
@@ -170,6 +170,11 @@
 ;; The names map to a list of the regexp argument indices.
 (defvar relint--regexp-functions)
 
+;; List of possibly safe functions defined in the current file, each
+;; element on the form (FUNCTION ARGS BODY), where ARGS is the lambda list
+;; and BODY its single body expression.
+(defvar relint--function-defs)
+
 ;; Functions that are safe to call during evaluation.
 ;; Except for altering the match state, these are pure.
 ;; More functions could be added if there is evidence that it would
@@ -294,6 +299,25 @@
 (error (signal 'relint--eval-error (format "rx error: %s" (cadr 
err)
 'no-value))
 
+;; Bind FORMALS to ACTUALS and evaluate EXPR.
+(defun relint--apply (formals actuals expr)
+  (let ((bindings nil))
+(while formals
+  (cond
+   ((eq (car formals) ')
+(push (cons (cadr formals) (list 'quote actuals)) bindings)
+(setq formals nil))
+   ((eq (car formals) ')
+(setq formals (cdr formals)))
+   (t
+(push (cons (car formals) (list 'quote (car actuals))) bindings)
+(setq formals (cdr formals))
+(setq actuals (cdr actuals)
+;; This results in dynamic binding, but that doesn't matter for our
+;; purposes.
+(let ((relint--variables (append bindings relint--variables)))
+  (relint--eval expr
+
 ;; Evaluate a form as far as possible. Substructures that cannot be evaluated
 ;; become `no-value'.
 (defun relint--eval (form)
@@ -334,6 +358,16 @@
 (apply (car form) args)
   (error 'no-value)
 
+   ;; Locally defined functions: try evaluating.
+   ((assq (car form) relint--function-defs)
+(let ((args (mapcar #'relint--eval (cdr form
+  (if (memq 'no-value args)
+  'no-value
+(let* ((fn (cdr (assq (car form) relint--function-defs)))
+   (formals (car fn))
+   (expr (cadr fn)))
+  (relint--apply formals args expr)
+
;; replace-regexp-in-string: Only safe if no function given.
((eq (car form) 'replace-regexp-in-string)
 (let ((args (mapcar #'relint--eval (cdr form
@@ -632,7 +666,14 @@
 (defun relint--check-form-recursively-1 (form file pos path)
   (pcase form
 (`(,(or `defun `defmacro `defsubst)
-   ,name ,args . ,_)
+   ,name ,args . ,body)
+ ;; Save the function for possible use.
+ (unless (eq (car form) 'defmacro)
+   (when (stringp (car body))
+ (setq body (cdr body)))  ; Skip doc string.
+   ;; Only consider functions with single-expression bodies.
+   (when (= (length body) 1)
+ (push (list name args (car body)) relint--function-defs)))
  ;; If any argument looks like a regexp, remember it so that it can be
  ;; checked in calls.
  (when (consp args)
@@ -835,7 +876,9 @@
 (case-fold-search nil)
 (relint--variables nil)
 (relint--checked-variables nil)
-(relint--regexp-functions nil))
+(relint--regexp-functions nil)
+(relint--function-defs nil)
+)
 (relint--check-buffer file forms #'relint--check-form-recursively-1)
 (relint--check-buffer file forms #'relint--check-form-recursively-2)))
 (when (> relint--error-count errors-before)



[elpa] externals/relint ac5d0cf 25/44: Add more safe functions

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit ac5d0cf79b72cf012d88f79affae7d703702d7ea
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add more safe functions
---
 trawl.el | 17 +
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/trawl.el b/trawl.el
index 89e61a1..2a71f65 100644
--- a/trawl.el
+++ b/trawl.el
@@ -173,15 +173,24 @@
 null not
 eq eql equal
 string-equal string= string< string-lessp char-equal string-match-p
-string-match; Alters the match state.
+
+; These alter the match state.
+string-match split-string replace-regexp-in-string
+
+combine-and-quote-strings split-string-and-unquote
+string-join string-trim-left string-trim-right string-trim
+string-prefix-p string-suffix-p
+string-blank-p string-remove-prefix string-remove-suffix
 vector aref elt vconcat
 char-to-string string-to-char
 number-to-string string-to-number int-to-string
 upcase downcase capitalize
-purecopy copy-sequence copy-alist
+purecopy copy-sequence copy-alist copy-tree
+assoc-default member-ignore-case alist-get
+last butlast number-sequence
 plist-get plist-member
-consp atom stringp symbolp listp nlisp
-integerp numberp natnump fixnump bignump characterp
+consp atom stringp symbolp listp nlistp
+integerp numberp natnump fixnump bignump characterp zerop
 sequencep vectorp arrayp
 + - * / % mod 1+ 1- max min < <= = > >= /= abs))
 



[elpa] externals/relint 019f4cf 10/44: Rewrite the partial evaluator and extend coverage

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 019f4cf6c6ca4776a32af7bf0fe121080f656ff5
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Rewrite the partial evaluator and extend coverage

Complete rewrite making the partial evaluator slightly less ad-hoc,
evaluate more complex expressions, and extend coverage to more
functions and variables.
---
 trawl.el | 368 ++-
 1 file changed, 295 insertions(+), 73 deletions(-)

diff --git a/trawl.el b/trawl.el
index 7067155..3193f26 100644
--- a/trawl.el
+++ b/trawl.el
@@ -141,105 +141,310 @@
   complaints)))
   
 ;; Alist of variable definitions seen so far.
+;; The variable names map to unevaluated forms.
 (defvar trawl--variables)
 
 ;; List of variables that have been checked, so that we can avoid
 ;; checking direct uses of it.
 (defvar trawl--checked-variables)
 
-(defun trawl--remove-comma (form)
+;; Whether form is a safe expression to evaluate.
+(defun trawl--safe-expr (form)
   (cond
-   ((not (consp form)) form)
-   ((eq (car form) '\,) (trawl--remove-comma (cadr form)))
+   ((symbolp form)
+(or (memq form '(t nil))
+(assq form trawl--variables)))
+   ((consp form)
+(or (eq (car form) 'quote)
+(and (trawl--safe-function (car form))
+ (not (memq nil (mapcar #'trawl--safe-expr (cdr form)))
+   (t t)))  ; Other atoms assumed OK.
+
+;; Whether f is safe to pass as a higher-order function in a call.
+(defun trawl--safe-function (f)
+  (when (and (consp f) (memq (car f) '(quote function)))
+(setq f (cadr f)))
+  (cond
+   ;; Functions (and some special forms/macros) considered safe.
+   ((symbolp f)
+(or (get f 'side-effect-free)
+(memq f '(caar cadr cdar cddr purecopy remove remq
+  if unless when and or
+  regexp-opt regexp-opt-charset
+
+   ;; Only permit one-argument one-expression lambdas (for purity),
+   ;; where the body only refers to arguments and known variables,
+   ;; and calls safe functions.
+   ((and (consp f) (eq (car f) 'lambda))
+(let ((vars (cadr f))
+  (body (cddr f)))
+  (and (= (length vars) 1)
+   (= (length body) 1)
+   (let ((trawl--variables
+  (cons (cons (car vars) nil) trawl--variables)))
+ (trawl--safe-expr (car body
+
+;; Whether an `rx' form is safe to translate.
+(defun trawl--rx-safe (form)
+  (cond
+   ((atom form) t)
+   ((eq (car form) 'eval)
+(let ((arg (trawl--eval (cadr form
+  (and (stringp arg)
+   (setcar (cdr form) arg; Avoid double work.
+   ;; Avoid traversing impure lists like (?A . ?Z).
+   ((memq (car form) '(any in char not-char)) t)
+   (t (not (memq nil (mapcar #'trawl--rx-safe (cdr form)))
+
+;; Evaluate a form as far as possible. Substructures that cannot be evaluated
+;; become `no-value'.
+(defun trawl--eval (form)
+  (cond
+   ((symbolp form)
+(and form
+ (let ((binding (assq form trawl--variables)))
+   (if binding
+   (trawl--eval (cdr binding))
+ 'no-value
+   ((atom form)
+form)
+   ((not (symbolp (car form)))
+(trawl--add-to-error-buffer (format "eval error: %S" form))
+'no-value)
+   ((eq (car form) 'quote)
+(cadr form))
+   ((eq (car form) 'eval-when-compile)
+(trawl--eval (car (last form
+   ((eq (car form) 'lambda)
+form)
+
+   ;; Reasonably pure functions: only call if all args can be fully evaluated.
+   ((or (get (car form) 'side-effect-free)
+;; Common functions that aren't marked as side-effect-free.
+(memq (car form) '(caar cadr cdar cddr
+   regexp-opt regexp-opt-charset
+   decode-coding-string
+   format-message format-spec
+   purecopy remove remq
+   ;; We don't mind them changing the match state.
+   string-match string-match-p)))
+(let ((args (mapcar #'trawl--eval (cdr form
+  (if (memq 'no-value args)
+  'no-value
+;; Catching all errors isn't wonderful, but sometimes a global
+;; variable argument has an unsuitable default value which is supposed
+;; to have been changed at the expression point.
+(condition-case nil
+(apply (car form) args)
+  (error 'no-value)
+
+   ;; replace-regexp-in-string: Only safe if no function given.
+   ((eq (car form) 'replace-regexp-in-string)
+(let ((args (mapcar #'trawl--eval (cdr form
+  (if (and (not (memq 'no-value args))
+   (stringp (cadr args)))
+  (condition-case nil
+  (apply (car form) args)
+(error 'no-value))
+'no-value)))
+
+   ;; if, when, unless, and, or: Treat these as functions and eval all args.
+   ((memq (car form) '(if when unless and or))
+(let ((args (mapcar 

[elpa] externals/relint 0214845 01/44: Move to github

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 0214845aea0086ba72ab7e3cbd91cc8a269f68aa
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Move to github
---
 trawl.el | 380 +++
 1 file changed, 380 insertions(+)

diff --git a/trawl.el b/trawl.el
new file mode 100644
index 000..2882df8
--- /dev/null
+++ b/trawl.el
@@ -0,0 +1,380 @@
+;;; trawl.el --- Scan elisp files for regexp errors -*- lexical-binding: t -*-
+
+;; Author: Mattias Engdegård 
+;; Version: 1.0
+;; Package-Requires: ((xr "1.4"))
+;; Keywords: lisp, maint, regexps
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see .
+
+;;; Commentary:
+
+;; Scan one or more elisp files for potential regexp strings and
+;; reports potential errors in them, using `xr-lint' from the `xr'
+;; package.
+;;
+;; To use:  M-x trawl-file   (check a single elisp file)
+;;  or  M-x trawl-directory  (check all .el files in a directory tree)
+;;
+;; Since there is no sure way to know whether a particular string is a
+;; regexp, the code has to guess a lot, and will likely miss quite a
+;; few. It looks at calls to known functions with regexp arguments,
+;; and at variables with regexp-sounding names.
+;;
+;; In other words, it is a nothing but a hack.
+
+;;; Code:
+
+(require 'xr)
+
+(defconst trawl--error-buffer-name "*trawl-catch*")
+
+(defun trawl--error-buffer ()
+  (let ((buf (get-buffer trawl--error-buffer-name)))
+(or buf
+(let ((buf (get-buffer-create trawl--error-buffer-name)))
+  (with-current-buffer buf
+(compilation-mode))
+  buf
+
+(defvar trawl--error-count)
+
+(defun trawl--add-to-error-buffer (string)
+  (with-current-buffer (trawl--error-buffer)
+(goto-char (point-max))
+(let ((inhibit-read-only t))
+  (insert string
+
+;; Compute (LINE . COLUMN) from POS (toplevel position)
+;; and PATH (reversed list of list indices to follow to target).
+(defun trawl--line-col-from-pos-path (pos path)
+  (save-excursion
+(goto-char pos)
+(let ((p (reverse path)))
+  (while p
+(when (looking-at (rx (1+ (or blank "\n" "\f"
+  (seq ";" (0+ nonl))
+  (goto-char (match-end 0)))
+(let ((skip (car p)))
+  (cond
+   ((looking-at (rx (any "'`,")))
+(forward-char 1)
+(setq skip (1- skip)))
+   ((looking-at (rx "("))
+(forward-char 1)))
+  (forward-sexp skip)
+  (setq p (cdr p
+  (when (looking-at (rx (1+ (or blank "\n" "\f"
+(seq ";" (0+ nonl))
+(goto-char (match-end 0)))
+  (cons (line-number-at-pos (point) t)
+(1+ (current-column))
+
+(defun trawl--report (file pos path message)
+  (let ((line-col (trawl--line-col-from-pos-path pos path)))
+(trawl--add-to-error-buffer
+ (format "%s:%d:%d: %s\n" file (car line-col) (cdr line-col) message)))
+  (setq trawl--error-count (1+ trawl--error-count)))
+
+(defun trawl--quote-string (str)
+  (concat "\""
+  (replace-regexp-in-string
+   (rx (any cntrl "\177-\377" ?\\ ?\"))
+   (lambda (s)
+ (let ((c (logand (string-to-char s) #xff)))
+   (or (cdr (assq c
+  '((?\" . "\\\"")
+(?\\ . "")
+(?\b . "\\b")
+(?\t . "\\t")
+(?\n . "\\n")
+(?\v . "\\v")
+(?\f . "\\f")
+(?\r . "\\r")
+(?\e . "\\e"
+   (format "\\%03o" c
+   str t t)
+  "\""))
+
+(defun trawl--check-re-string (re name file pos path)
+  (let ((complaints
+ (condition-case err
+(mapcar (lambda (warning)
+   (format "In %s: %s (pos %d): %s"
+   name (cdr warning) (car warning)
+  (trawl--quote-string re)))
+(xr-lint re))
+  (error (list (format "In %s: Error: %s: %s"
+   name  (cadr err)
+(trawl--quote-string re)))
+(mapc (lambda (msg) (trawl--report file pos path msg))
+  

[elpa] externals/relint f6fb8e6 31/44: Sundry cosmetic fixes

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit f6fb8e6af22de04eec967519cb5189d97a5f97b9
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Sundry cosmetic fixes

Run with case-fold-search set to nil.
The error buffer is now named "*relint*".
---
 relint.el | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/relint.el b/relint.el
index 24e8eec..3d67093 100644
--- a/relint.el
+++ b/relint.el
@@ -1,4 +1,4 @@
-;;; relint.el --- Scan elisp files for regexp errors -*- lexical-binding: t -*-
+;;; relint.el --- Elisp regexp mistake finder   -*- lexical-binding: t -*-
 
 ;; Author: Mattias Engdegård 
 ;; Version: 1.4
@@ -46,7 +46,7 @@
 
 (require 'xr)
 
-(defconst relint--error-buffer-name "*relint-catch*")
+(defconst relint--error-buffer-name "*relint*")
 
 (defun relint--error-buffer ()
   (let ((buf (get-buffer relint--error-buffer-name)))
@@ -310,7 +310,7 @@
((atom form)
 form)
((not (symbolp (car form)))
-(relint--add-to-error-buffer (format "eval error: %S" form))
+(relint--add-to-error-buffer (format "eval error: %S\n" form))
 'no-value)
((eq (car form) 'quote)
 (if (and (consp (cadr form))
@@ -743,7 +743,8 @@
   (let ((index 0))
 (while (consp form)
   (when (consp (car form))
-(relint--check-form-recursively-2 (car form) file pos (cons index 
path)))
+(relint--check-form-recursively-2
+ (car form) file pos (cons index path)))
   (setq form (cdr form))
   (setq index (1+ index)
 
@@ -793,6 +794,7 @@
   (emacs-lisp-mode)
   (insert-file-contents file)
   (let ((forms (relint--read-buffer file))
+(case-fold-search nil)
 (relint--variables nil)
 (relint--checked-variables nil)
 (relint--regexp-functions nil))
@@ -846,7 +848,7 @@ Call this function in batch mode with files and directories 
as
 command-line arguments.  Files are scanned; directories are
 searched recursively for *.el files to scan."
   (unless noninteractive
-(error "`relint-batch' is to be used only with -batch"))
+(error "`relint-batch' is only for use with -batch"))
   (setq relint--error-count 0)
   (while command-line-args-left
 (let ((arg (pop command-line-args-left)))



[elpa] externals/relint 187d586 27/44: Scan arguments to `skip-chars-{forward, backward}'

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 187d586847f4545e6ba276098ca37d294ca6109f
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Scan arguments to `skip-chars-{forward,backward}'

Make use of the new skip set parser in xr.
---
 trawl.el | 30 ++
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/trawl.el b/trawl.el
index 254fdbf..613e800 100644
--- a/trawl.el
+++ b/trawl.el
@@ -2,7 +2,7 @@
 
 ;; Author: Mattias Engdegård 
 ;; Version: 1.2
-;; Package-Requires: ((xr "1.4"))
+;; Package-Requires: ((xr "1.7"))
 ;; Keywords: lisp, maint, regexps
 
 ;; This program is free software; you can redistribute it and/or modify
@@ -124,15 +124,31 @@
 2))); Lop off quotes
 (concat (make-string quoted-pos ?.) "^")))
 
+(defun trawl--check-skip-set (skip-set-string name file pos path)
+  (let ((complaints
+ (condition-case err
+ (mapcar (lambda (warning)
+   (let ((ofs (car warning)))
+ (format "In %s: %s (pos %d)\n  %s\n   %s"
+ name (cdr warning) ofs
+ (trawl--quote-string skip-set-string)
+ (trawl--caret-string skip-set-string ofs
+ (xr-skip-set-lint skip-set-string))
+   (error (list (format "In %s: Error: %s: %s"
+name  (cadr err)
+(trawl--quote-string skip-set-string)))
+(mapc (lambda (msg) (trawl--report file pos path msg))
+  complaints)))
+
 (defun trawl--check-re-string (re name file pos path)
   (let ((complaints
  (condition-case err
  (mapcar (lambda (warning)
-   (let ((pos (car warning)))
+   (let ((ofs (car warning)))
  (format "In %s: %s (pos %d)\n  %s\n   %s"
- name (cdr warning) pos
+ name (cdr warning) ofs
  (trawl--quote-string re)
- (trawl--caret-string re pos
+ (trawl--caret-string re ofs
  (xr-lint re))
(error (list (format "In %s: Error: %s: %s"
 name  (cadr err)
@@ -649,6 +665,12 @@
   (memq trim trawl--checked-variables))
(trawl--check-re trim (format "call to %s" (car form))
 file pos (cons 4 path))
+(`(,(or `skip-chars-forward `skip-chars-backward)
+   ,skip-arg . ,_)
+ (let ((str (trawl--get-string skip-arg file pos path)))
+   (when str
+ (trawl--check-skip-set str (format "call to %s" (car form))
+file pos (cons 1 path)
 (`(,(or `defvar `defconst `defcustom)
,name ,re-arg . ,rest)
  (when (symbolp name)



[elpa] externals/relint 151dbb8 23/44: Handle some destructive list functions

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 151dbb841f5afd913642db4294340352ba62aac0
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Handle some destructive list functions

Safely evaluate nconc, delete, delq, nreverse, nbutlast and delete-dups.
---
 trawl.el | 46 +++---
 1 file changed, 39 insertions(+), 7 deletions(-)

diff --git a/trawl.el b/trawl.el
index a5d84da..5149a20 100644
--- a/trawl.el
+++ b/trawl.el
@@ -163,7 +163,7 @@
 format format-message
 regexp-quote regexp-opt regexp-opt-charset
 reverse
-member memq remove remq
+member memq remove remq member-ignore-case
 assoc assq rassoc rassq
 identity
 string make-string make-list
@@ -185,6 +185,15 @@
 sequencep vectorp arrayp
 + - * / % mod 1+ 1- max min < <= = > >= /= abs))
 
+;; Alist mapping non-safe functions to semantically equivalent safe
+;; alternatives.
+(defconst trawl--safe-alternatives
+  '((nconc . append)
+(delete . remove)
+(delq . remq)
+(nreverse . reverse)
+(nbutlast . butlast)))
+
 ;; Transform FORM into an expression that is safe to evaluate with the
 ;; bindings in trawl--variables and parameters in PARAMS.
 ;; Return the transformed expression with known variables substituted away,
@@ -217,9 +226,10 @@
   (cond
;; Functions (and some special forms/macros) considered safe.
((symbolp f)
-(and (or (memq f trawl--safe-functions)
- (memq f '(if when unless and or)))
- f))
+(cond ((or (memq f trawl--safe-functions)
+   (memq f '(if when unless and or)))
+   f)
+  ((cdr (assq f trawl--safe-alternatives)
((atom f) nil)
((eq (car f) 'function)
 (trawl--safe-function (cadr f) params))
@@ -263,6 +273,7 @@
 ;; become `no-value'.
 (defun trawl--eval (form)
   (cond
+   ((memq form '(nil t)) form)
((symbolp form)
 (and form
  (let ((binding (assq form trawl--variables)))
@@ -317,6 +328,17 @@
 (eval (cons (car form)
 (mapcar (lambda (x) (list 'quote x)) args))
 
+   ((assq (car form) trawl--safe-alternatives)
+(trawl--eval (cons (cdr (assq (car form) trawl--safe-alternatives))
+   (cdr form
+
+   ;; delete-dups: Work on a copy of the argument.
+   ((eq (car form) 'delete-dups)
+(let ((arg (trawl--eval (cadr form
+  (if (eq arg 'no-value)
+  'no-value
+(delete-dups (copy-sequence arg)
+
((memq (car form) '(\` backquote-list*))
 (trawl--eval (macroexpand form)))
 
@@ -351,7 +373,7 @@
;; evaluate.
((memq (car form) '(mapcar mapcan))
 (let ((fun (trawl--safe-function (trawl--eval (cadr form)) nil))
-  (seq (delq nil (trawl--eval-list (caddr form)
+  (seq (remq nil (trawl--eval-list (caddr form)
   (if fun
   (condition-case err
   (funcall (car form) fun seq)
@@ -450,10 +472,20 @@
;; Pure structure-generating functions: Apply even if we cannot evaluate
;; all arguments (they will be nil), because we want a reasonable
;; approximation of the structure.
-   ((memq (car form) '(list append cons))
+   ((memq (car form) '(list append cons reverse remove remq))
 (apply (car form) (mapcar #'trawl--eval-list (cdr form
 
-   ((eq (car form) 'purecopy)
+   ((assq (car form) trawl--safe-alternatives)
+(trawl--eval-list (cons (cdr (assq (car form) trawl--safe-alternatives))
+(cdr form
+
+   ((eq (car form) 'delete-dups)
+(let ((arg (trawl--eval (cadr form
+  (if (eq arg 'no-value)
+  'no-value
+(delete-dups (copy-sequence arg)
+
+   ((memq (car form) '(purecopy copy-sequence copy-alist))
 (trawl--eval-list (cadr form)))
 
((memq (car form) '(\` backquote-list*))



[elpa] externals/relint 830f4bf 03/44: Allow use from batch mode

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 830f4bf3ce7a1c73f6e05b04d03a681af2e920a2
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Allow use from batch mode

Add trawl--batch for use from the command line:

emacs --batch -l trawl.el -f trawl--batch FILES-AND-DIRECTORIES...

Errors go to stderr.
---
 trawl.el | 56 ++--
 1 file changed, 42 insertions(+), 14 deletions(-)

diff --git a/trawl.el b/trawl.el
index ce26dfb..11e09a9 100644
--- a/trawl.el
+++ b/trawl.el
@@ -27,6 +27,10 @@
 ;; To use:  M-x trawl-file   (check a single elisp file)
 ;;  or  M-x trawl-directory  (check all .el files in a directory tree)
 ;;
+;; It can also be used from batch mode by calling `trawl--batch' with
+;; files and/or directories as command-line arguments, errors going
+;; to stderr.
+;;
 ;; Since there is no sure way to know whether a particular string is a
 ;; regexp, the code has to guess a lot, and will likely miss quite a
 ;; few. It looks at calls to known functions with regexp arguments,
@@ -81,10 +85,15 @@
   (cons (line-number-at-pos (point) t)
 (1+ (current-column))
 
+(defun trawl--output-error (string)
+  (if noninteractive
+  (message "%s" string)
+(trawl--add-to-error-buffer (concat string "\n"
+
 (defun trawl--report (file pos path message)
   (let ((line-col (trawl--line-col-from-pos-path pos path)))
-(trawl--add-to-error-buffer
- (format "%s:%d:%d: %s\n" file (car line-col) (cdr line-col) message)))
+(trawl--output-error
+ (format "%s:%d:%d: %s" file (car line-col) (cdr line-col) message)))
   (setq trawl--error-count (1+ trawl--error-count)))
 
 (defun trawl--quote-string (str)
@@ -322,9 +331,10 @@
   (trawl--check-form-recursively form file pos nil))
   
 (defun trawl--show-errors ()
-  (let ((pop-up-windows t))
-(display-buffer (trawl--error-buffer))
-(sit-for 0)))
+  (unless noninteractive
+(let ((pop-up-windows t))
+  (display-buffer (trawl--error-buffer))
+  (sit-for 0
 
 (defun trawl--single-file (file)
   (let ((errors-before trawl--error-count))
@@ -362,13 +372,18 @@
 (when (> trawl--error-count errors-before)
   (trawl--show-errors
 
+(defun trawl--tree (dir)
+  (dolist (file (directory-files-recursively
+ dir (rx bos (not (any ".")) (* anything) ".el" eos)))
+(trawl--single-file file)))
+
 (defun trawl--init (file-or-dir dir)
-  (with-current-buffer (trawl--error-buffer)
-(let ((inhibit-read-only t))
-  (erase-buffer)
-  (insert (format ";; Trawling %s  -*- compilation -*-\n" file-or-dir)))
-(setq trawl--error-count 0)
-(cd dir)))
+  (unless noninteractive
+(with-current-buffer (trawl--error-buffer)
+  (let ((inhibit-read-only t))
+(erase-buffer)
+(insert (format ";; Trawling %s  -*- compilation -*-\n" file-or-dir)))
+  (cd dir
 
 (defun trawl--finish ()
   (trawl--add-to-error-buffer "Finished.\n")
@@ -390,7 +405,20 @@
   "Scan all *.el files in DIR for errors in regexp strings."
   (interactive "DTrawl directory: ")
   (trawl--init dir dir)
-  (dolist (file (directory-files-recursively
- dir (rx bos (not (any ".")) (* anything) ".el" eos)))
-(trawl--single-file file))
+  (trawl--tree dir)
   (trawl--finish))
+
+
+(defun trawl--batch ()
+  "Scan elisp source files for errors in regex strings.
+Call this function in batch mode with files and directories as
+command-line arguments.  Files are scanned; directories are
+searched recursively for *.el files to scan."
+  (unless noninteractive
+(error "`trawl--batch' is to be used only with -batch"))
+  (setq trawl--error-count 0)
+  (while command-line-args-left
+(let ((arg (pop command-line-args-left)))
+  (if (file-directory-p arg)
+  (trawl--tree arg)
+(trawl--single-file arg)



[elpa] externals/relint b4fc385 04/44: Rename trawl--batch to trawl-batch

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit b4fc385078265c15ef8367c99cf37b08ba55a531
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Rename trawl--batch to trawl-batch
---
 trawl.el | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/trawl.el b/trawl.el
index 11e09a9..ab4295b 100644
--- a/trawl.el
+++ b/trawl.el
@@ -27,9 +27,11 @@
 ;; To use:  M-x trawl-file   (check a single elisp file)
 ;;  or  M-x trawl-directory  (check all .el files in a directory tree)
 ;;
-;; It can also be used from batch mode by calling `trawl--batch' with
+;; It can also be used from batch mode by calling `trawl-batch' with
 ;; files and/or directories as command-line arguments, errors going
-;; to stderr.
+;; to stderr:
+;;
+;;  emacs -batch -l trawl.el -f trawl-batch FILES-AND-DIRS...
 ;;
 ;; Since there is no sure way to know whether a particular string is a
 ;; regexp, the code has to guess a lot, and will likely miss quite a
@@ -409,7 +411,7 @@
   (trawl--finish))
 
 
-(defun trawl--batch ()
+(defun trawl-batch ()
   "Scan elisp source files for errors in regex strings.
 Call this function in batch mode with files and directories as
 command-line arguments.  Files are scanned; directories are



[elpa] externals/relint 3f8509a 13/44: Add more functions to check for regexp arguments

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 3f8509a41078c346e50b7b57339436568c0b41e6
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add more functions to check for regexp arguments
---
 trawl.el | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/trawl.el b/trawl.el
index 6f51bf0..e2d5501 100644
--- a/trawl.el
+++ b/trawl.el
@@ -471,13 +471,15 @@
 `posix-looking-at `posix-search-backward `posix-search-forward
 `posix-string-match
 `load-history-filename-element
-`kill-matching-buffers)
+`kill-matching-buffers
+`keep-lines `flush-lines `how-many)
,re-arg . ,_)
  (unless (and (symbolp re-arg)
   (memq re-arg trawl--checked-variables))
(trawl--check-re re-arg (format "call to %s" (car form))
 file pos (cons 1 path
 (`(,(or `split-string `split-string-and-unquote
+`string-trim-left `string-trim-right
 `directory-files-recursively)
,_ ,re-arg . ,_)
  (unless (and (symbolp re-arg)



[elpa] externals/relint 125b869 02/44: Try harder recovering from read errors

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 125b8693d6c986be888b01c7757c675d5ebbd064
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Try harder recovering from read errors

In particular, don't abandon the whole file because of a circular sexp.
---
 trawl.el | 28 ++--
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/trawl.el b/trawl.el
index 2882df8..ce26dfb 100644
--- a/trawl.el
+++ b/trawl.el
@@ -333,16 +333,32 @@
   (insert-file-contents file)
   (goto-char (point-min))
   (let ((pos nil)
+(keep-going t)
 (read-circle nil)
 (trawl--variables nil)
 (trawl--checked-variables nil))
-(condition-case err
-(while t
+(while keep-going
   (setq pos (point))
-  (let ((form (read (current-buffer
-(trawl--check-toplevel-form form file pos)))
-  (end-of-file nil)
-  (error (trawl--report file pos nil (prin1-to-string err))
+  (let ((form nil))
+(condition-case err
+(setq form (read (current-buffer)))
+  (end-of-file
+   (setq keep-going nil))
+  (invalid-read-syntax
+   (cond
+((equal (cadr err) "#")
+ (goto-char pos)
+ (forward-sexp 1))
+(t
+ (trawl--report file (point) nil
+(prin1-to-string err))
+ (setq keep-going nil
+  (error
+   (trawl--report file (point) nil
+  (prin1-to-string err))
+   (setq keep-going nil)))
+(when form
+  (trawl--check-toplevel-form form file pos))
 (when (> trawl--error-count errors-before)
   (trawl--show-errors
 



[elpa] externals/relint 34304b4 08/44: Add (provides) line to make file importable

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 34304b4f08df99a0c6396e14c19d1584dbed091e
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add (provides) line to make file importable

Suggested by Pierre Téchoueyres.
---
 trawl.el | 4 
 1 file changed, 4 insertions(+)

diff --git a/trawl.el b/trawl.el
index d365a5a..abf0223 100644
--- a/trawl.el
+++ b/trawl.el
@@ -412,3 +412,7 @@ searched recursively for *.el files to scan."
   (if (file-directory-p arg)
   (trawl--tree arg)
 (trawl--single-file arg)
+
+(provide 'trawl)
+
+;;; trawl.el ends here



[elpa] externals/relint be3979a 19/44: Check TRIM argument of `split-string' as well

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit be3979af7f49b770e0548a9c249c5bcc08d5e97a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check TRIM argument of `split-string' as well
---
 trawl.el | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/trawl.el b/trawl.el
index 35923b0..5dd3f46 100644
--- a/trawl.el
+++ b/trawl.el
@@ -499,11 +499,19 @@
 (`(,(or `split-string `split-string-and-unquote
 `string-trim-left `string-trim-right
 `directory-files-recursively)
-   ,_ ,re-arg . ,_)
+   ,_ ,re-arg . ,rest)
  (unless (and (symbolp re-arg)
   (memq re-arg trawl--checked-variables))
(trawl--check-re re-arg (format "call to %s" (car form))
-file pos (cons 2 path
+file pos (cons 2 path)))
+ ;; split-string has another regexp argument (trim, arg 4)
+ (when (and (eq (car form) 'split-string)
+(cadr rest))
+   (let ((trim (cadr rest)))
+ (unless (and (symbolp trim)
+  (memq trim trawl--checked-variables))
+   (trawl--check-re trim (format "call to %s" (car form))
+file pos (cons 4 path))
 (`(,(or `defvar `defconst `defcustom)
,name ,re-arg . ,rest)
  (when (symbolp name)



[elpa] externals/relint 2d1f488 32/44: mapcar on non-list sequence

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 2d1f488de40c027f4b5a20caaba5b559cb413970
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

mapcar on non-list sequence

Allow mapcar and mapcan to be run on any sequence that we can evaluate
statically, not just lists. In particular, mapcar on strings to
produce a regexp has been observed in the wild, and relint crashed
without this change.
---
 relint.el | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index 3d67093..e1d9c27 100644
--- a/relint.el
+++ b/relint.el
@@ -399,8 +399,11 @@
;; The sequence argument may be missing a few arguments that we cannot
;; evaluate.
((memq (car form) '(mapcar mapcan))
-(let ((fun (relint--safe-function (relint--eval (cadr form)) nil))
-  (seq (remq nil (relint--eval-list (caddr form)
+(let* ((fun (relint--safe-function (relint--eval (cadr form)) nil))
+   (arg (relint--eval-list (caddr form)))
+   (seq (if (listp arg)
+(delq nil arg)
+  arg)))
   (if fun
   (condition-case err
   (funcall (car form) fun seq)



[elpa] externals/relint 5af5466 26/44: Scan string-trim arguments

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 5af546669c44d72e54df4938ab37cee6267f00c4
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Scan string-trim arguments
---
 trawl.el | 10 +-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/trawl.el b/trawl.el
index 2a71f65..254fdbf 100644
--- a/trawl.el
+++ b/trawl.el
@@ -626,13 +626,21 @@
(trawl--check-re re-arg (format "call to %s" (car form))
 file pos (cons 1 path
 (`(,(or `split-string `split-string-and-unquote
-`string-trim-left `string-trim-right
+`string-trim-left `string-trim-right `string-trim
 `directory-files-recursively)
,_ ,re-arg . ,rest)
  (unless (and (symbolp re-arg)
   (memq re-arg trawl--checked-variables))
(trawl--check-re re-arg (format "call to %s" (car form))
 file pos (cons 2 path)))
+ ;; string-trim has another regexp argument (trim, arg 3)
+ (when (and (eq (car form) 'string-trim)
+(car rest))
+   (let ((right (car rest)))
+ (unless (and (symbolp right)
+  (memq right trawl--checked-variables))
+   (trawl--check-re right (format "call to %s" (car form))
+file pos (cons 3 path)
  ;; split-string has another regexp argument (trim, arg 4)
  (when (and (eq (car form) 'split-string)
 (cadr rest))



[elpa] externals/relint 5143edf 17/44: Fix indentation accidents

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 5143edfbbe5de97797c48129b852882dfc8ddb2d
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Fix indentation accidents
---
 trawl.el | 64 
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/trawl.el b/trawl.el
index 51dbb55..13b9040 100644
--- a/trawl.el
+++ b/trawl.el
@@ -127,15 +127,15 @@
 (defun trawl--check-re-string (re name file pos path)
   (let ((complaints
  (condition-case err
-(mapcar (lambda (warning)
+ (mapcar (lambda (warning)
(let ((pos (car warning)))
  (format "In %s: %s (pos %d)\n  %s\n   %s"
  name (cdr warning) pos
  (trawl--quote-string re)
  (trawl--caret-string re pos
-(xr-lint re))
-  (error (list (format "In %s: Error: %s: %s"
-   name  (cadr err)
+ (xr-lint re))
+   (error (list (format "In %s: Error: %s: %s"
+name  (cadr err)
 (trawl--quote-string re)))
 (mapc (lambda (msg) (trawl--report file pos path msg))
   complaints)))
@@ -509,14 +509,14 @@
  (when (symbolp name)
(cond
 ((string-match-p (rx (or "-regexp" "-re" "-regex" "-pattern") eos)
-(symbol-name name))
-(trawl--check-re re-arg name file pos (cons 2 path))
+ (symbol-name name))
+ (trawl--check-re re-arg name file pos (cons 2 path))
  (push name trawl--checked-variables))
 ((string-match-p (rx (or (or "-regexps" "-regexes" "-patterns")
  (seq (or "-regexp" "-re" "-regex" "-pattern")
   "-list"))
  eos)
-(symbol-name name))
+ (symbol-name name))
  (trawl--check-list re-arg name file pos (cons 2 path))
  (push name trawl--checked-variables))
 ((string-match-p (rx "-font-lock-keywords" eos)
@@ -544,7 +544,7 @@
 ((and (stringp (car rest))
   (let ((case-fold-search t))
 (string-match-p (rx bos "regexp") (car rest
-(trawl--check-re re-arg name file pos (cons 2 path))
+ (trawl--check-re re-arg name file pos (cons 2 path))
  (push name trawl--checked-variables))
 )
(push (cons name re-arg) trawl--variables)))
@@ -624,36 +624,36 @@
 (trawl--variables nil)
 (trawl--checked-variables nil)
 (trawl--regexp-functions nil))
-(while keep-going
-  (setq pos (point))
-;  (trawl--report file (point) nil "reading")
-  (let ((form nil))
-(condition-case err
-(setq form (read (current-buffer)))
-  (end-of-file
-   (setq keep-going nil))
-  (invalid-read-syntax
-   (cond
-((equal (cadr err) "#")
- (goto-char pos)
- (forward-sexp 1))
-(t
- (trawl--report file (point) nil
-(prin1-to-string err))
- (setq keep-going nil
-  (error
-   (trawl--report file (point) nil
-  (prin1-to-string err))
-   (setq keep-going nil)))
-(when form
-  (trawl--check-toplevel-form form file pos))
+(while keep-going
+  (setq pos (point))
+  ;;(trawl--report file (point) nil "reading")
+  (let ((form nil))
+(condition-case err
+(setq form (read (current-buffer)))
+  (end-of-file
+   (setq keep-going nil))
+  (invalid-read-syntax
+   (cond
+((equal (cadr err) "#")
+ (goto-char pos)
+ (forward-sexp 1))
+(t
+ (trawl--report file (point) nil
+(prin1-to-string err))
+ (setq keep-going nil
+  (error
+   (trawl--report file (point) nil
+  (prin1-to-string err))
+   (setq keep-going nil)))
+(when form
+  (trawl--check-toplevel-form form file pos))
 (when (> trawl--error-count errors-before)
   (trawl--show-errors
 
 (defun trawl--tree (dir)
   (dolist (file (directory-files-recursively
  dir (rx bos (not (any ".")) (* anything) ".el" eos)))
-;(trawl--add-to-error-buffer (format "trawling %s\n" file))
+;;(trawl--add-to-error-buffer (format "trawling %s\n" file))
   

[elpa] externals/relint e882b71 42/44: Detect regexps spliced into [...]

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit e882b71ed3ce20fb4088cb5fd7d7726555b330d8
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Detect regexps spliced into [...]

Look for attempts to splice the product of regexp-generating functions
such as regexp-quote into an [...] construct, using concat or format.
---
 relint.el | 67 +++
 1 file changed, 67 insertions(+)

diff --git a/relint.el b/relint.el
index 844373f..65af095 100644
--- a/relint.el
+++ b/relint.el
@@ -678,6 +678,67 @@
   (format "`%s' cannot be used for arguments to `%s'"
   (car reg-gen) skip-function)
 
+;; Look for a format expression that suggests insertion of a regexp
+;; into a character alternative: "[%s]" where the corresponding format
+;; parameter is regexp-generating.
+(defun relint--check-format-mixup (template args file pos path)
+  (let ((nargs (length args))
+(index 0)
+(start 0))
+(while (and (< index nargs)
+(string-match (rx
+;; An unescaped [, and some leading chars
+   (opt (or bos (not (any "\\")))
+(0+ "")
+(group "[")
+(0+ (not (any "]"
+   ;; Any %-sequence
+   "%"
+   (opt (1+ digit) "$")
+   (0+ digit)
+   (opt "." (0+ digit))
+   (group (any "%sdioxXefgcS")))
+  template start))
+  (let ((bracket (match-beginning 1))
+(type (string-to-char (match-string 2 template)))
+(next (match-end 0)))
+(when (and bracket (eq type ?s))
+  (let ((reg-gen (relint--regexp-generators (nth index args) nil)))
+(when reg-gen
+  (relint--report
+   file pos (cons (+ index 2) path)
+   (format
+"Value from `%s' cannot be spliced into `[...]'"
+(car reg-gen))
+(unless (eq type ?%)
+  (setq index (1+ index)))
+(setq start next)
+
+;; Look for concat args that suggest insertion of a regexp into a
+;; character alternative: "[" followed by a regexp-generating
+;; expression.
+(defun relint--check-concat-mixup (args file pos path)
+  (let ((index 1))
+(while (consp args)
+  (let ((arg (car args)))
+(when (and (stringp arg)
+   (cdr args)
+   (string-match-p (rx (or bos (not (any "\\")))
+   (0+ "")
+   "["
+   (0+ (not (any "]")))
+   eos)
+   arg))
+  (let ((reg-gen (relint--regexp-generators (cadr args) nil)))
+(when reg-gen
+  (relint--report
+   file pos (cons (1+ index) path)
+   (format
+"Value from `%s' cannot be spliced into `[...]'"
+(car reg-gen)))
+  (setq index (1+ index))
+  (setq args (cdr args)
+
 (defun relint--check-form-recursively-1 (form file pos path)
   (pcase form
 (`(,(or `defun `defmacro `defsubst)
@@ -777,6 +838,12 @@
  (relint--check-skip-set-provenance
   (car form) skip-arg file pos (cons 1 path))
  )
+(`(concat . ,args)
+ (relint--check-concat-mixup args file pos path))
+(`(format ,template-arg . ,args)
+ (let ((template (relint--get-string template-arg file pos path)))
+   (when template
+ (relint--check-format-mixup template args file pos path
 (`(,(or `defvar `defconst `defcustom)
,name ,re-arg . ,rest)
  (when (symbolp name)



[elpa] externals/relint 683f31b 28/44: Increment version to 1.3

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 683f31b6badb0c13817e3edfe28adc4092c36dc1
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.3
---
 trawl.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/trawl.el b/trawl.el
index 613e800..b4b9147 100644
--- a/trawl.el
+++ b/trawl.el
@@ -1,7 +1,7 @@
 ;;; trawl.el --- Scan elisp files for regexp errors -*- lexical-binding: t -*-
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.2
+;; Version: 1.3
 ;; Package-Requires: ((xr "1.7"))
 ;; Keywords: lisp, maint, regexps
 



[elpa] externals/relint e824db0 38/44: Expand locally defined macros

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit e824db0ab49f0208cbfbfe56670c0bfd1821d5f0
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Expand locally defined macros
---
 relint.el | 39 +--
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/relint.el b/relint.el
index 7e85bb3..4847fac 100644
--- a/relint.el
+++ b/relint.el
@@ -175,6 +175,11 @@
 ;; and BODY its single body expression.
 (defvar relint--function-defs)
 
+;; List of possibly safe macros defined in the current file, each
+;; element on the form (MACRO ARGS BODY), where ARGS is the lambda list
+;; and BODY its single body expression.
+(defvar relint--macro-defs)
+
 ;; Functions that are safe to call during evaluation.
 ;; Except for altering the match state, these are pure.
 ;; More functions could be added if there is evidence that it would
@@ -213,6 +218,7 @@
 assoc-default member-ignore-case alist-get
 last butlast number-sequence
 plist-get plist-member
+1value
 consp atom stringp symbolp listp nlistp booleanp
 integerp numberp natnump fixnump bignump characterp zerop
 sequencep vectorp arrayp
@@ -311,9 +317,6 @@
  (throw 'relint-eval 'no-value)
((atom form)
 form)
-   ((not (symbolp (car form)))
-(relint--add-to-error-buffer (format "eval error: %S\n" form))
-(throw 'relint-eval 'no-value))
 
((eq (car form) 'quote)
 (if (and (consp (cadr form))
@@ -345,6 +348,14 @@
  (expr (cadr fn)))
 (relint--apply formals args expr
 
+   ;; Locally defined macros: try expanding.
+   ((assq (car form) relint--macro-defs)
+(let ((args (cdr form)))
+  (let* ((macro (cdr (assq (car form) relint--macro-defs)))
+ (formals (car macro))
+ (expr (cadr macro)))
+(relint--eval (relint--apply formals args expr)
+
;; replace-regexp-in-string: wrap the rep argument if it's a function.
((eq (car form) 'replace-regexp-in-string)
 (let ((all-args (mapcar #'relint--eval (cdr form
@@ -654,13 +665,20 @@
   (pcase form
 (`(,(or `defun `defmacro `defsubst)
,name ,args . ,body)
- ;; Save the function for possible use.
- (unless (eq (car form) 'defmacro)
-   (when (stringp (car body))
- (setq body (cdr body)))  ; Skip doc string.
-   ;; Only consider functions with single-expression bodies.
-   (when (= (length body) 1)
- (push (list name args (car body)) relint--function-defs)))
+
+ ;; Save the function or macro for possible use.
+ (while (or (stringp (car body))
+(and (consp (car body))
+ (memq (caar body) '(interactive declare
+   (setq body (cdr body)))  ; Skip doc and declarations.
+ ;; Only consider functions/macros with single-expression bodies.
+ (when (= (length body) 1)
+   (let ((entry (list name args (car body
+ (if (eq (car form) 'defmacro)
+ (push entry relint--macro-defs)
+   (push entry relint--function-defs))
+ ))
+
  ;; If any argument looks like a regexp, remember it so that it can be
  ;; checked in calls.
  (when (consp args)
@@ -865,6 +883,7 @@
 (relint--checked-variables nil)
 (relint--regexp-functions nil)
 (relint--function-defs nil)
+(relint--macro-defs nil)
 )
 (relint--check-buffer file forms #'relint--check-form-recursively-1)
 (relint--check-buffer file forms #'relint--check-form-recursively-2)))



[elpa] externals/relint c215d54 34/44: More careful evaluation of if, when, unless, and, or

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit c215d54fa2bde02bb9508ff316078d97120fec7a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

More careful evaluation of if, when, unless, and, or
---
 relint.el | 53 +
 1 file changed, 45 insertions(+), 8 deletions(-)

diff --git a/relint.el b/relint.el
index 0147bf0..e13af44 100644
--- a/relint.el
+++ b/relint.el
@@ -344,15 +344,52 @@
 (error 'no-value))
 'no-value)))
 
-   ;; if, when, unless, and, or: Treat these as functions and eval all args.
-   ((memq (car form) '(if when unless and or))
-(let ((args (mapcar #'relint--eval (cdr form
-  (if (memq 'no-value args)
+   ;; if: evaluate condition and the right branch.
+   ((eq (car form) 'if)
+(let ((condition (relint--eval (cadr form
+  (if (eq condition 'no-value)
   'no-value
-;; eval is safe here: all args are quoted constants.
-(eval (cons (car form)
-(mapcar (lambda (x) (list 'quote x)) args))
-
+(let ((then-part (nth 2 form))
+  (else-tail (nthcdr 3 form)))
+  (cond (condition
+ (relint--eval then-part))
+((and else-tail (cdr else-tail))
+ 'no-value) ; Ignore multi-value else bodies.
+(else-tail
+ (relint--eval (car else-tail
+
+   ;; when, unless: evaluate condition and maybe consequent.
+   ((memq (car form) '(when unless))
+(let ((condition (relint--eval (cadr form)))
+  (body (cddr form)))
+  (cond ((or (eq condition 'no-value)
+ (not (= (length body) 1)))
+ 'no-value)
+((eq (not condition) (eq (car form) 'unless))
+ (relint--eval (car body))
+
+   ;; and: keep evaluating until false or empty.
+   ((eq (car form) 'and)
+(if (cdr form)
+(let ((val (relint--eval (cadr form
+  (if (eq val 'no-value)
+  'no-value
+(if (and val (cddr form))
+(relint--eval (cons 'and (cddr form)))
+  val)))
+  t))
+
+   ;; and: keep evaluating until true or empty.
+   ((eq (car form) 'or)
+(if (cdr form)
+(let ((val (relint--eval (cadr form
+  (if (eq val 'no-value)
+  'no-value
+(if (and (not val) (cddr form))
+(relint--eval (cons 'or (cddr form)))
+  val)))
+  nil))
+   
((assq (car form) relint--safe-alternatives)
 (relint--eval (cons (cdr (assq (car form) relint--safe-alternatives))
 (cdr form



[elpa] externals/relint f8878ca 16/44: Report rx errors in the result buffer

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit f8878ca325cd093374c176f8dc671df8cdd07dbe
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Report rx errors in the result buffer

Previously, rx errors aborted the entire run; now they are reported
like any other.
---
 trawl.el | 60 +---
 1 file changed, 37 insertions(+), 23 deletions(-)

diff --git a/trawl.el b/trawl.el
index 0ae230c..51dbb55 100644
--- a/trawl.el
+++ b/trawl.el
@@ -200,6 +200,16 @@
((memq (car form) '(any in char not-char)) t)
(t (not (memq nil (mapcar #'trawl--rx-safe (cdr form)))
 
+(define-error 'trawl--eval-error "trawl expression evaluation error")
+
+;; Evaluate an `rx-to-string' expression if safe.
+(defun trawl--eval-rx (args)
+  (if (trawl--rx-safe (car args))
+  (condition-case err
+  (apply #'rx-to-string args)
+(error (signal 'trawl--eval-error (format "rx error: %s" (cadr err)
+'no-value))
+
 ;; Evaluate a form as far as possible. Substructures that cannot be evaluated
 ;; become `no-value'.
 (defun trawl--eval (form)
@@ -227,10 +237,11 @@
 ;; Common functions that aren't marked as side-effect-free.
 (memq (car form) '(caar cadr cdar cddr
regexp-opt regexp-opt-charset
+   ;; alters last-coding-system-used
decode-coding-string
format-message format-spec
purecopy remove remq
-   ;; We don't mind them changing the match state.
+   ;; alters match state
string-match string-match-p)))
 (let ((args (mapcar #'trawl--eval (cdr form
   (if (memq 'no-value args)
@@ -311,17 +322,13 @@
   
;; rx, rx-to-string: check for (eval ...) constructs first, then apply.
((eq (car form) 'rx)
-(if (trawl--rx-safe (cons 'seq (cdr form)))
-(trawl--eval (macroexpand form))
-  'no-value))
+(trawl--eval-rx (list (cons 'seq (cdr form)) t)))
 
((eq (car form) 'rx-to-string)
-(let ((arg (trawl--eval (cadr form
-  (if (trawl--rx-safe arg)
-  (if (eq arg 'no-value)
-  'no-value
-(apply 'rx-to-string (list arg
-  'no-value))
+(let ((args (mapcar #'trawl--eval (cdr form
+  (if (memq 'no-value args)
+  'no-value
+(trawl--eval-rx args
 
;; setq: Ignore its side-effect and just pass on the value.
((eq (car form) 'setq)
@@ -405,24 +412,31 @@
   (if (eq val 'no-value) nil val)
 
 ;; Convert something to a list, or nil.
-(defun trawl--get-list (form)
-  (let ((val (trawl--eval-list form)))
-(and (consp val) val)))
+(defun trawl--get-list (form file pos path)
+  (condition-case err
+  (let ((val (trawl--eval-list form)))
+(and (consp val) val))
+(trawl--eval-error (trawl--report file pos path (cdr err))
+   nil)))
+  
 
 ;; Convert something to a string, or nil.
-(defun trawl--get-string (form)
-  (let ((val (trawl--eval form)))
-(and (stringp val) val)))
+(defun trawl--get-string (form file pos path)
+  (condition-case err
+  (let ((val (trawl--eval form)))
+(and (stringp val) val))
+(trawl--eval-error (trawl--report file pos path (cdr err))
+   nil)))
 
 (defun trawl--check-re (form name file pos path)
-  (let ((re (trawl--get-string form)))
+  (let ((re (trawl--get-string form file pos path)))
 (when re
   (trawl--check-re-string re name file pos path
 
 ;; Check a list of regexps.
 (defun trawl--check-list (form name file pos path)
   ;; Don't use mapc -- mustn't crash on improper lists.
-  (let ((l (trawl--get-list form)))
+  (let ((l (trawl--get-list form file pos path)))
 (while (consp l)
   (when (stringp (car l))
 (trawl--check-re-string (car l) name file pos path))
@@ -437,7 +451,7 @@
((and (consp elem)
  (stringp (car elem)))
 (trawl--check-re-string (car elem) name file pos path
-(trawl--get-list form)))
+(trawl--get-list form file pos path)))
 
 (defun trawl--check-font-lock-keywords (form name file pos path)
   (trawl--check-list-any form name file pos path))
@@ -447,11 +461,11 @@
 (form name file pos path)
   (mapc (lambda (elem)
   (if (cadr elem)
- (trawl--check-re-string
+  (trawl--check-re-string
(cadr elem)
(format "%s (%s)" name (car elem))
file pos path)))
-(trawl--get-list form)))
+(trawl--get-list form file pos path)))
 
 ;; Check a variable on `align-mode-rules-list' format
 (defun trawl--check-rules-list (form name file pos path)
@@ -460,11 +474,11 @@
  (symbolp (car rule)))
 (let* ((rule-name (car rule))
(re-form (cdr (assq 'regexp (cdr rule
-   

[elpa] externals/relint af745bb 30/44: Update the package description. Increment version to 1.4

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit af745bbe253de40e858cfd8cc608cddac9c25ba9
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Update the package description. Increment version to 1.4
---
 relint.el | 26 ++
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/relint.el b/relint.el
index 97454e1..24e8eec 100644
--- a/relint.el
+++ b/relint.el
@@ -1,7 +1,7 @@
 ;;; relint.el --- Scan elisp files for regexp errors -*- lexical-binding: t -*-
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.3
+;; Version: 1.4
 ;; Package-Requires: ((xr "1.7"))
 ;; Keywords: lisp, maint, regexps
 
@@ -20,23 +20,25 @@
 
 ;;; Commentary:
 
-;; Scan one or more elisp files for potential regexp strings and
-;; reports potential errors in them, using `xr-lint' from the `xr'
-;; package.
+;; Scan elisp files for regexp strings and reports potential errors,
+;; including deprecated syntax and bad practice.
+;; Also check the regexp-like-but-not-quite skip-set arguments to
+;; `skip-chars-forward' and `skip-chars-backward'.
 ;;
-;; To use:  M-x relint-file   (check a single elisp file)
-;;  or  M-x relint-directory  (check all .el files in a directory tree)
+;; How to use:
 ;;
-;; It can also be used from batch mode by calling `relint-batch' with
-;; files and/or directories as command-line arguments, errors going
-;; to stderr:
+;; * Inside Emacs:
 ;;
-;;  emacs -batch -l relint.el -f relint-batch FILES-AND-DIRS...
+;;   M-x relint-file   (check a single elisp file)
+;;   M-x relint-directory  (check all .el files in a directory tree)
+;;
+;; * From batch mode:
+;;
+;;   emacs -batch -l relint.el -f relint-batch FILES-AND-DIRS...
 ;;
 ;; Since there is no sure way to know whether a particular string is a
 ;; regexp, the code has to guess a lot, and will likely miss quite a
-;; few. It looks at calls to known functions with regexp arguments,
-;; and at variables with regexp-sounding names.
+;; few. It tries to minimise the amount of false positives.
 ;;
 ;; In other words, it is a nothing but a hack.
 



[elpa] externals/relint 104e66c 15/44: Fix bugs in evaluation of `rx' and `rx-to-strings'

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 104e66c28923bafcf9dbef1d1c0fa6f7b9a0c14a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Fix bugs in evaluation of `rx' and `rx-to-strings'

Found by trawling ntcmd.el, on a suggestion by Pierre Téchoueyres.
---
 trawl.el | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/trawl.el b/trawl.el
index 4298210..0ae230c 100644
--- a/trawl.el
+++ b/trawl.el
@@ -311,13 +311,13 @@
   
;; rx, rx-to-string: check for (eval ...) constructs first, then apply.
((eq (car form) 'rx)
-(if (trawl--rx-safe (cdr form))
+(if (trawl--rx-safe (cons 'seq (cdr form)))
 (trawl--eval (macroexpand form))
   'no-value))
 
((eq (car form) 'rx-to-string)
-(if (trawl--rx-safe (cdr form))
-(let ((arg (trawl--eval (cadr form
+(let ((arg (trawl--eval (cadr form
+  (if (trawl--rx-safe arg)
   (if (eq arg 'no-value)
   'no-value
 (apply 'rx-to-string (list arg



[elpa] externals/relint d6320f9 14/44: Detect functions with regexp arguments

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit d6320f9227509b5d4e0de23fb7660d1e13f990d0
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Detect functions with regexp arguments

Spot functions with argument names like `regexp', and check corresponding
arguments in calls to them. Right now, this is only done in the same file,
and only if the definition precedes the call.
---
 trawl.el | 48 +++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/trawl.el b/trawl.el
index e2d5501..4298210 100644
--- a/trawl.el
+++ b/trawl.el
@@ -148,6 +148,10 @@
 ;; checking direct uses of it.
 (defvar trawl--checked-variables)
 
+;; Alist of functions taking regexp argument(s).
+;; The names map to a list of the regexp argument indices.
+(defvar trawl--regexp-functions)
+
 ;; Whether form is a safe expression to evaluate.
 (defun trawl--safe-expr (form)
   (cond
@@ -535,7 +539,48 @@
(trawl--check-font-lock-keywords font-lock-list origin
 file pos (cons 4 path))
(trawl--check-list auto-mode-list origin file pos (cons 5 path
+(`(,(or `defun `defmacro `defsubst)
+   ,name ,args . ,_)
+ ;; If any argument looks like a regexp, remember it so that it can be
+ ;; checked in calls.
+ (when (consp args)
+   (let ((indices nil)
+ (index 0))
+ (while args
+   (let ((arg (car args)))
+ (when (symbolp arg)
+   (cond
+((eq arg '))
+((eq arg ')
+ (setq args nil))
+(t
+ (when (or (string-suffix-p "regexp" (symbol-name arg))
+   (string-suffix-p "regex" (symbol-name arg))
+   (eq arg 're)
+   (string-suffix-p "-re" (symbol-name arg)))
+   (push index indices))
+ (setq index (1+ index)
+ (setq args (cdr args
+ (when indices
+   (push (cons name (reverse indices)) trawl--regexp-functions)
 )
+
+  ;; Check calls to remembered functions with regexp arguments.
+  (when (consp form)
+(let ((indices (cdr (assq (car form) trawl--regexp-functions
+  (when indices
+(let ((index 0)
+  (args (cdr form)))
+  (while (and indices args)
+(when (= index (car indices))
+  (unless (and (symbolp (car args))
+   (memq (car args) trawl--checked-variables))
+(trawl--check-re (car args) (format "call to %s" (car form))
+ file pos (cons (1+ index) path)))
+  (setq indices (cdr indices)))
+(setq args (cdr args))
+(setq index (1+ index)))
+
   (let ((index 0))
 (while (consp form)
   (when (consp (car form))
@@ -563,7 +608,8 @@
 (keep-going t)
 (read-circle nil)
 (trawl--variables nil)
-(trawl--checked-variables nil))
+(trawl--checked-variables nil)
+(trawl--regexp-functions nil))
 (while keep-going
   (setq pos (point))
 ;  (trawl--report file (point) nil "reading")



[elpa] externals/relint 8e37762 18/44: Protect against improper lists in function calls

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 8e377623e7023e565c8b67133750104c30229a34
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Protect against improper lists in function calls

In case we come across the constant '((looking-at . something)), for
instance.
---
 trawl.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/trawl.el b/trawl.el
index 13b9040..35923b0 100644
--- a/trawl.el
+++ b/trawl.el
@@ -585,7 +585,7 @@
   (when indices
 (let ((index 0)
   (args (cdr form)))
-  (while (and indices args)
+  (while (and indices (consp args))
 (when (= index (car indices))
   (unless (and (symbolp (car args))
(memq (car args) trawl--checked-variables))



[elpa] externals/relint 66522ca 12/44: Increment version to 1.1

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 66522cac6798686bfff5cfd223c504c1ad80614c
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.1
---
 trawl.el | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/trawl.el b/trawl.el
index ed7b630..6f51bf0 100644
--- a/trawl.el
+++ b/trawl.el
@@ -1,7 +1,7 @@
 ;;; trawl.el --- Scan elisp files for regexp errors -*- lexical-binding: t -*-
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.0
+;; Version: 1.1
 ;; Package-Requires: ((xr "1.4"))
 ;; Keywords: lisp, maint, regexps
 
@@ -462,8 +462,6 @@
  re (format "%s (%s)" name rule-name) file pos path)
 (trawl--get-list form)))
 
-;; FIXME: handle let-when-compile
-
 (defun trawl--check-form-recursively (form file pos path)
   (pcase form
 (`(,(or `looking-at `re-search-forward `re-search-backward



[elpa] externals/relint 62ca3d4 05/44: Slight performance improvement

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit 62ca3d4dc94986de1cb948fc28582ea22a415ad0
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Slight performance improvement

Remove a function call in the inner loop in the common case.
---
 trawl.el | 158 ++-
 1 file changed, 74 insertions(+), 84 deletions(-)

diff --git a/trawl.el b/trawl.el
index ab4295b..48ef364 100644
--- a/trawl.el
+++ b/trawl.el
@@ -245,92 +245,82 @@
 (trawl--peel-list form)))
 
 (defun trawl--check-form-recursively (form file pos path)
-  (when (consp form)
-(pcase form
-;  (`(apply ,(or `nconc `(quote nconc) `(function nconc)) (mapcar . ,_))
-;   (trawl--report file pos path
-; "use mapcan instead of (apply nconc (mapcar...))"))
-;  (`(lambda (,var1) (,_ ,var2))
-;   (when (eq var1 var2)
-;(trawl--report file pos path
-;   "lambda expression can be η-reduced")))
-;  (`(lambda (,var1) ,var2)
-;   (when (eq var1 var2)
-;   (trawl--report file pos path
-;  "lambda expression is #'identity")))
-;  (`(defun ,name ,_ . ,body)
-;   (let ((f body))
-; (while (and f (consp (car f)) (eq (caar f) 'declare))
-;   (setq f (cdr f)))
-; (when (and f (consp (car f)))
-;   (setq f (cdr f))
-;   (while (cdr f)
-; (when (stringp (car f))
-;   (trawl--report file pos path
-;(format "defun %s: misplaced doc string" name)))
-; (setq f (cdr f))
-  (`(,(or `looking-at `re-search-forward `re-search-backward
-  `string-match `string-match-p `looking-back `looking-at-p
-  `replace-regexp-in-string 'replace-regexp
-  `query-replace-regexp
-  `posix-looking-at `posix-search-backward `posix-search-forward
-  `posix-string-match)
- ,re-arg . ,_)
-   (unless (and (symbolp re-arg)
-(memq re-arg trawl--checked-variables))
- (trawl--check-re re-arg (format "call to %s" (car form))
-  file pos (cons 1 path
-  (`(,(or `defvar `defconst 'defcustom)
-,name ,re-arg . ,rest)
-   (when (symbolp name)
- (cond
-  ((string-match-p (rx (or "-regexp" "-re" "-regex" "-pattern") eos)
-  (symbol-name name))
-  (trawl--check-re re-arg name file pos (cons 2 path))
-   (push name trawl--checked-variables))
-  ((string-match-p (rx (or "-regexps" "-regexes" "-patterns") eos)
-  (symbol-name name))
-   (trawl--check-list re-arg name file pos (cons 2 path))
-   (push name trawl--checked-variables))
-  ((string-match-p (rx "-font-lock-keywords" eos)
-   (symbol-name name))
-   (trawl--check-font-lock-keywords re-arg name file pos (cons 2 path))
-   (push name trawl--checked-variables))
-  ((eq name 'compilation-error-regexp-alist-alist)
-   (trawl--check-compilation-error-regexp-alist-alist
-re-arg name file pos (cons 2 path))
-   (push name trawl--checked-variables))
-  ((string-match-p (rx (or "-regexp" "-re" "-regex" "-pattern")
-   "-alist" eos)
-   (symbol-name name))
-   (trawl--check-list-car re-arg name file pos (cons 2 path))
-   (push name trawl--checked-variables))
-  ((string-match-p (rx "-rules-list" eos)
-   (symbol-name name))
-   (trawl--check-rules-list re-arg name file pos (cons 2 path))
-   (push name trawl--checked-variables))
-  ;; Doc string starting with "regexp"?
-  ((and (stringp (car rest))
-(let ((case-fold-search t))
-  (string-match-p (rx bos "regexp") (car rest
-  (trawl--check-re re-arg name file pos (cons 2 path))
-   (push name trawl--checked-variables))
-  )
- (push (cons name re-arg) trawl--variables)))
-  (`(define-generic-mode ,name ,_ ,_ ,font-lock-list ,auto-mode-list . ,_)
-   (let ((origin (format "define-generic-mode %s" name)))
- (trawl--check-font-lock-keywords font-lock-list origin
-  file pos (cons 4 path))
- (trawl--check-list auto-mode-list origin file pos (cons 5 path
-  )
-(let ((index 0))
-  (while (consp form)
-(trawl--check-form-recursively (car form) file pos (cons index path))
-(setq form (cdr form))
-(setq index (1+ index))
+  (pcase form
+;;;(`(defun ,name ,_ . ,body)
+;;; (let ((f body))
+;;;   (while (and f (consp (car f)) (eq (caar f) 'declare))
+;;; (setq f (cdr f)))
+;;;   (when (and f (consp (car f)))
+;;; (setq f (cdr f))
+;;; (while (cdr f)
+;;;   (when (stringp 

[elpa] branch externals/relint created (now ee70350)

2019-03-26 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/relint.

at  ee70350   FSF copyright, URL, and increment version to 1.5

This branch includes the following new commits:

   new  0214845   Move to github
   new  125b869   Try harder recovering from read errors
   new  830f4bf   Allow use from batch mode
   new  b4fc385   Rename trawl--batch to trawl-batch
   new  62ca3d4   Slight performance improvement
   new  cb1fdc5   Add caret pointing out the error in the quoted regexp
   new  6ab713e   Reinstate erroneously removed line
   new  34304b4   Add (provides) line to make file importable
   new  d19133e   Better variable name patterns
   new  019f4cf   Rewrite the partial evaluator and extend coverage
   new  d4d8f97   Eval mapcar and mapcan with partial-evaluated lists
   new  66522ca   Increment version to 1.1
   new  3f8509a   Add more functions to check for regexp arguments
   new  d6320f9   Detect functions with regexp arguments
   new  104e66c   Fix bugs in evaluation of `rx' and `rx-to-strings'
   new  f8878ca   Report rx errors in the result buffer
   new  5143edf   Fix indentation accidents
   new  8e37762   Protect against improper lists in function calls
   new  be3979a   Check TRIM argument of `split-string' as well
   new  7d0e177   Rewrite the higher-order function handling
   new  02bf0ba   Use explicit list of pure functions
   new  e1b1ef9   Run in two phases on each file
   new  151dbb8   Handle some destructive list functions
   new  4dbcad9   Increment version to 1.2
   new  ac5d0cf   Add more safe functions
   new  5af5466   Scan string-trim arguments
   new  187d586   Scan arguments to `skip-chars-{forward,backward}'
   new  683f31b   Increment version to 1.3
   new  0fd1d46   Rename trawl to relint
   new  af745bb   Update the package description. Increment version to 1.4
   new  f6fb8e6   Sundry cosmetic fixes
   new  2d1f488   mapcar on non-list sequence
   new  7a1b632   Add wildcard-to-regexp as 'pure' function
   new  c215d54   More careful evaluation of if, when, unless, and, or
   new  15c799e   Evaluate calls to functions defined in the same file.
   new  c1b92cc   Wrap and evaluate defined functions passed as parameters
   new  d4a6d46   Evaluate some more functions, macros and special forms
   new  e824db0   Expand locally defined macros
   new  a1829d7   Refactor the file scanning and linting code
   new  0f76132   Add README.org
   new  365dc91   Check bad skip-set provenance
   new  e882b71   Detect regexps spliced into [...]
   new  0604fad   Use a custom mode for the *relint* buffer
   new  ee70350   FSF copyright, URL, and increment version to 1.5




[elpa] externals/relint d4d8f97 11/44: Eval mapcar and mapcan with partial-evaluated lists

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit d4d8f97e0444bee4d98c45be8ae6a5b4e5263d35
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Eval mapcar and mapcan with partial-evaluated lists

Evaluate mapcar and mapcan even if their list argument isn't fully
evaluated, so a single missing element won't spoil analysis of a whole list.
This change allows auto-mode-alist to be analysed.
---
 trawl.el | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/trawl.el b/trawl.el
index 3193f26..ed7b630 100644
--- a/trawl.el
+++ b/trawl.el
@@ -290,7 +290,12 @@
((memq (car form) '(mapcar mapconcat mapcan))
 (let ((fun (cadr form)))
   (if (trawl--safe-function fun)
-  (let ((args (mapcar #'trawl--eval (cddr form
+  (let ((args
+ ;; Use trawl--eval-list when we believe that missing
+ ;; elements may be acceptable.
+ (if (eq (car form) 'mapconcat)
+ (mapcar #'trawl--eval (cddr form))
+   (delq nil (mapcar #'trawl--eval-list (cddr form))
 (if (memq 'no-value args)
 'no-value
   (condition-case nil



[elpa] externals/relint cb1fdc5 06/44: Add caret pointing out the error in the quoted regexp

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit cb1fdc5d10df9907df19afbe56e08165657684e9
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add caret pointing out the error in the quoted regexp

This helps when regexp strings are long and contain many backslashes,
which is frequently the case.
---
 trawl.el | 25 +++--
 1 file changed, 11 insertions(+), 14 deletions(-)

diff --git a/trawl.el b/trawl.el
index 48ef364..0f97633 100644
--- a/trawl.el
+++ b/trawl.el
@@ -118,13 +118,21 @@
str t t)
   "\""))
 
+(defun trawl--caret-string (string pos)
+  (let ((quoted-pos
+ (- (length (trawl--quote-string (substring string 0 pos)))
+2))); Lop off quotes
+(concat (make-string quoted-pos ?.) "^")))
+
 (defun trawl--check-re-string (re name file pos path)
   (let ((complaints
  (condition-case err
 (mapcar (lambda (warning)
-   (format "In %s: %s (pos %d): %s"
-   name (cdr warning) (car warning)
-  (trawl--quote-string re)))
+   (let ((pos (car warning)))
+ (format "In %s: %s (pos %d)\n  %s\n   %s"
+ name (cdr warning) pos
+ (trawl--quote-string re)
+ (trawl--caret-string re pos
 (xr-lint re))
   (error (list (format "In %s: Error: %s: %s"
name  (cadr err)
@@ -246,17 +254,6 @@
 
 (defun trawl--check-form-recursively (form file pos path)
   (pcase form
-;;;(`(defun ,name ,_ . ,body)
-;;; (let ((f body))
-;;;   (while (and f (consp (car f)) (eq (caar f) 'declare))
-;;; (setq f (cdr f)))
-;;;   (when (and f (consp (car f)))
-;;; (setq f (cdr f))
-;;; (while (cdr f)
-;;;   (when (stringp (car f))
-;;; (trawl--report file pos path
-;;;(format "defun %s: misplaced doc string" name)))
-;;;   (setq f (cdr f))
 (`(,(or `looking-at `re-search-forward `re-search-backward
 `string-match `string-match-p `looking-back `looking-at-p
 `replace-regexp-in-string `replace-regexp



[elpa] externals/relint d19133e 09/44: Better variable name patterns

2019-03-26 Thread Mattias Engdegrd
branch: externals/relint
commit d19133e33ea22f95b0313bfcd555901095d7027e
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Better variable name patterns

Now scan variables ending in -regexp-list (etc) as well.
---
 trawl.el | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/trawl.el b/trawl.el
index abf0223..7067155 100644
--- a/trawl.el
+++ b/trawl.el
@@ -273,7 +273,10 @@
 (symbol-name name))
 (trawl--check-re re-arg name file pos (cons 2 path))
  (push name trawl--checked-variables))
-((string-match-p (rx (or "-regexps" "-regexes" "-patterns") eos)
+((string-match-p (rx (or (or "-regexps" "-regexes" "-patterns")
+ (seq (or "-regexp" "-re" "-regex" "-pattern")
+  "-list"))
+ eos)
 (symbol-name name))
  (trawl--check-list re-arg name file pos (cons 2 path))
  (push name trawl--checked-variables))



[elpa] externals/relint 350a9e4 7/8: Extend regexp-generating heuristics

2019-04-01 Thread Mattias Engdegrd
branch: externals/relint
commit 350a9e4e90d4747ca8538a3332868b4b7a943ab6
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Extend regexp-generating heuristics

Recognise more standard regexp-returning functions, several
standard regexp variables, and look at variable names to determine
whether they are likely to contain regexps.
---
 relint.el | 21 +
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/relint.el b/relint.el
index e6d1586..343112a 100644
--- a/relint.el
+++ b/relint.el
@@ -706,16 +706,29 @@
  re (format "%s (%s)" name rule-name) file pos path)
 (relint--get-list form file pos path)))
 
-;; List of known regexp-generating functions used in EXPR.
+;; List of regexp-generating functions and variables used in EXPR.
 ;; EXPANDED is a list of expanded functions, to prevent recursion.
 (defun relint--regexp-generators (expr expanded)
   (cond
((symbolp expr)
-(let ((def (assq expr relint--variables)))
-  (and def (relint--regexp-generators (cdr def) expanded
+(and (not (memq expr '(nil t)))
+ (let ((def (assq expr relint--variables)))
+   (if def
+   (relint--regexp-generators (cdr def) expanded)
+ (and (or (memq expr '(page-delimiter paragraph-separate
+   paragraph-start sentence-end))
+  ;; This is guesswork, but effective.
+  (string-match-p
+   (rx (or (seq bos (or "regexp" "regex"))
+   (or "-regexp" "-regex" "-re"))
+   eos)
+   (symbol-name expr)))
+  (list expr))
((atom expr) nil)
((memq (car expr) '(regexp-quote regexp-opt regexp-opt-charset
-   rx rx-to-string wildcard-to-regexp))
+   rx rx-to-string wildcard-to-regexp read-regexp
+   char-fold-to-regexp find-tag-default-as-regexp
+   find-tag-default-as-symbol-regexp sentence-end))
 (list (car expr)))
((memq (car expr) '(looking-at re-search-forward re-search-backward
string-match string-match-p looking-back looking-at-p))



[elpa] externals/relint updated (ee70350 -> fdfb2d7)

2019-04-01 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/relint.

  from  ee70350   FSF copyright, URL, and increment version to 1.5
   new  41831f4   Add several cl-seq and other functions, and simplify.
   new  f9e4d20   More messages and updates when running interactively
   new  4145e3f   Drop -patterns and -pattern-list as variable suffixes
   new  98bbb44   Documentation updates
   new  eabac3b   Add memql as a safe function
   new  cff253a   Add relint-current-buffer
   new  350a9e4   Extend regexp-generating heuristics
   new  fdfb2d7   Increment version to 1.7; add News section


Summary of changes:
 README.org |  12 ++-
 relint.el  | 300 +
 2 files changed, 213 insertions(+), 99 deletions(-)



[elpa] externals/relint 98bbb44 4/8: Documentation updates

2019-04-01 Thread Mattias Engdegrd
branch: externals/relint
commit 98bbb445acc2f64ffa1e38e8e3e75b4ed04491f6
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Documentation updates

Update README.org and the package description in relint.el to account
for that installation is now made from ELPA.
---
 README.org |  8 ++--
 relint.el  | 14 ++
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/README.org b/README.org
index 2ce02db..9af54d7 100644
--- a/README.org
+++ b/README.org
@@ -20,12 +20,16 @@ From batch mode:
 : emacs -batch -l relint.el -f relint-batch FILES-AND-DIRS...
 
 where directories are scanned recursively.
+(Options for finding relint and xr need to be added after
+~-batch~, either ~-f package-initialize~ or ~-L DIR~.)
+
+In the ~*relint*~ buffer, pressing "g" will re-run the same check.
 
 * Installation
 
-Download the source file =relint.el= and set ~load-path~:
+From [[https://elpa.gnu.org/packages/relint.html][GNU ELPA]]:
 
-: (add-to-list 'load-path "RELINT-DIRECTORY")
+: M-x package-install RET relint RET
 
 Relint requires the package [[https://elpa.gnu.org/packages/xr.html][xr]]; 
install it from GNU ELPA.
 
diff --git a/relint.el b/relint.el
index 7f7e5c2..04081ca 100644
--- a/relint.el
+++ b/relint.el
@@ -39,11 +39,17 @@
 ;;
 ;;   emacs -batch -l relint.el -f relint-batch FILES-AND-DIRS...
 ;;
-;; Since there is no sure way to know whether a particular string is a
-;; regexp, the code has to guess a lot, and will likely miss quite a
-;; few. It tries to minimise the amount of false positives.
+;;   where options for finding relint and xr need to be added after
+;;   `-batch', either `-f package-initialize' or `-L DIR'.
 ;;
-;; In other words, it is a nothing but a hack.
+;; In the `*relint*' buffer, pressing "g" will re-run the same check.
+;;
+;; Bugs:
+;;
+;;   Since there is no sure way to know whether a particular string is a
+;;   regexp, the code has to guess a lot, and will likely miss quite a
+;;   few. It tries to minimise the amount of false positives.
+;;   In other words, it is a nothing but a hack.
 
 ;;; Code:
 



[elpa] externals/relint 4145e3f 3/8: Drop -patterns and -pattern-list as variable suffixes

2019-04-01 Thread Mattias Engdegrd
branch: externals/relint
commit 4145e3f91871694cf5b19a43e615a36e501ca657
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Drop -patterns and -pattern-list as variable suffixes

The -patterns and -pattern-list suffix rule found very few actual
regexp lists, and enough false positives.
---
 relint.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index b42e089..7f7e5c2 100644
--- a/relint.el
+++ b/relint.el
@@ -903,8 +903,8 @@
  (symbol-name name))
  (relint--check-re re-arg name file pos (cons 2 path))
  (push name relint--checked-variables))
-((string-match-p (rx (or (or "-regexps" "-regexes" "-patterns")
- (seq (or "-regexp" "-re" "-regex" "-pattern")
+((string-match-p (rx (or (or "-regexps" "-regexes")
+ (seq (or "-regexp" "-re" "-regex")
   "-list"))
  eos)
  (symbol-name name))



[elpa] externals/relint 41831f4 1/8: Add several cl-seq and other functions, and simplify.

2019-04-01 Thread Mattias Engdegrd
branch: externals/relint
commit 41831f4bc1fcbdcaa9326a1af08805b25253e004
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add several cl-seq and other functions, and simplify.

The cl-seq functions require special attention to the keyword
arguments, some of which must be wrapped.
---
 relint.el | 135 ++
 1 file changed, 91 insertions(+), 44 deletions(-)

diff --git a/relint.el b/relint.el
index e6753ce..10ffc88 100644
--- a/relint.el
+++ b/relint.el
@@ -49,6 +49,7 @@
 
 (require 'xr)
 (require 'compile)
+(require 'cl-seq)
 
 (defconst relint--error-buffer-name "*relint*")
 
@@ -221,12 +222,26 @@
 ;; Alist mapping non-safe functions to semantically equivalent safe
 ;; alternatives.
 (defconst relint--safe-alternatives
-  '((nconc . append)
-(delete . remove)
-(delq . remq)
+  '((nconc. append)
+(delete   . remove)
+(delq . remq)
 (nreverse . reverse)
 (nbutlast . butlast)))
 
+;; Alist mapping non-safe cl functions to semantically equivalent safe
+;; alternatives. They may still require wrapping their function arguments.
+(defconst relint--safe-cl-alternatives
+  '((cl-delete-duplicates . cl-remove-duplicates)
+(cl-delete. cl-remove)
+(cl-delete-if . cl-remove-if)
+(cl-delete-if-not . cl-remove-if-not)
+(cl-nsubstitute   . cl-substitute)
+(cl-nunion. cl-union)
+(cl-nintersection . cl-intersection)
+(cl-nset-difference   . cl-set-difference)
+(cl-nset-exclusive-or . cl-set-exclusive-or)
+(cl-nsublis   . cl-sublis)))
+
 ;; Make an `rx' form safe to translate, by mutating (eval ...) subforms.
 (defun relint--rx-safe (form)
   (cond
@@ -298,6 +313,20 @@
 'relint--no-value)))
(t 'relint--no-value)))
 
+;; Wrap the function arguments :test, :test-not, :key in ARGS.
+(defun relint--wrap-cl-keyword-args (args)
+  (let ((test (plist-get args :test))
+(test-not (plist-get args :test-not))
+(key  (plist-get args :key))
+(ret (copy-sequence args)))
+(when test
+  (plist-put ret :test (relint--wrap-function test)))
+(when test-not
+  (plist-put ret :test-not (relint--wrap-function test-not)))
+(when key
+  (plist-put ret :key  (relint--wrap-function key)))
+ret))
+
 ;; Evaluate a form. Throw 'relint-eval 'no-value if something could
 ;; not be evaluated safely.
 (defun relint--eval (form)
@@ -324,7 +353,7 @@
((eq (car form) 'eval-when-compile)
 (relint--eval (car (last form
 
-   ;; Reasonably pure functions: only call if all args can be fully evaluated.
+   ;; Functions considered safe.
((memq (car form) relint--safe-functions)
 (let ((args (mapcar #'relint--eval (cdr form
   ;; Catching all errors isn't wonderful, but sometimes a global
@@ -415,68 +444,80 @@
 (relint--eval (cons (cdr (assq (car form) relint--safe-alternatives))
 (cdr form
 
+   ((assq (car form) relint--safe-cl-alternatives)
+(relint--eval (cons (cdr (assq (car form) relint--safe-cl-alternatives))
+(cdr form
+   
;; delete-dups: Work on a copy of the argument.
((eq (car form) 'delete-dups)
 (let ((arg (relint--eval (cadr form
   (delete-dups (copy-sequence arg
 
-   ;; FIXME: more macros. Maybe ones from cl?
-   ;; If they are useful but expand to impure code, we need to emulate them.
-   ((memq (car form) '(when unless \` backquote-list* pcase pcase-let))
+   ;; Safe macros that expand to pure code, and their auxiliary macros.
+   ((memq (car form) '(when unless
+   \` backquote-list*
+   pcase pcase-let pcase-let* pcase--flip))
 (relint--eval (macroexpand form)))
 
-   ;; apply: Call only if the function is safe and all args evaluated.
-   ((eq (car form) 'apply)
-(let ((args (mapcar #'relint--eval (cdr form
-  (let ((fun (relint--wrap-function (car args
-(condition-case err
-(apply #'apply (cons fun (cdr args)))
-  (error (signal 'relint--eval-error (format "eval error: %S: %s"
- form err)))
-
-   ;; funcall: Call only if the function is safe and all args evaluated.
-   ((eq (car form) 'funcall)
-(let ((args (mapcar #'relint--eval (cdr form
-  (let ((fun (relint--wrap-function (car args
-(condition-case err
-(apply fun (cdr args))
-  (error (signal 'relint--eval-error (format "eval error: %S: %s"
- form err)))
+   ;; Functions taking a function as first argument.
+   ((memq (car form) '(apply funcall mapconcat
+   cl-some cl-every cl-notany cl-notevery))
+(let ((fun (relint--wrap-function (relint--eval (cadr form
+  (args (mapcar #'relint--eval (cddr form
+  (condition-case 

[elpa] externals/relint cff253a 6/8: Add relint-current-buffer

2019-04-01 Thread Mattias Engdegrd
branch: externals/relint
commit cff253a55d8e205d6a3dc52b58cb890cd1537dfc
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add relint-current-buffer

Suggested by Manuel Uberti (resolves #5).

File names in the error buffer are now relative, making them shorter
and more readable.

Use the undocumented but useful compilation-forget-errors between runs
to reset the state cached by compilation-mode; merely emptying the
buffer isn't enough.
---
 README.org |  4 +++
 relint.el  | 93 +-
 2 files changed, 59 insertions(+), 38 deletions(-)

diff --git a/README.org b/README.org
index 9af54d7..fb244c0 100644
--- a/README.org
+++ b/README.org
@@ -15,6 +15,10 @@ Check all .el files in a directory tree:
 
 : M-x relint-directory
 
+Check current buffer:
+
+: M-x relint-current-buffer
+
 From batch mode:
 
 : emacs -batch -l relint.el -f relint-batch FILES-AND-DIRS...
diff --git a/relint.el b/relint.el
index dd5faae..e6d1586 100644
--- a/relint.el
+++ b/relint.el
@@ -32,8 +32,9 @@
 ;;
 ;; * Inside Emacs:
 ;;
-;;   M-x relint-file   (check a single elisp file)
-;;   M-x relint-directory  (check all .el files in a directory tree)
+;;   M-x relint-file(check a single elisp file)
+;;   M-x relint-directory   (check all .el files in a directory tree)
+;;   M-x relint-current-buffer  (check current buffer)
 ;;
 ;; * From batch mode:
 ;;
@@ -1012,42 +1013,42 @@
   (push (cons form pos) forms
 (nreverse forms)))
 
-(defun relint--single-file (file)
+(defun relint--scan-current-buffer (file)
   (let ((errors-before relint--error-count))
-(with-temp-buffer
-  (emacs-lisp-mode)
-  (insert-file-contents file)
-  (let ((forms (relint--read-buffer file))
-(case-fold-search nil)
-(relint--variables nil)
-(relint--checked-variables nil)
-(relint--regexp-functions nil)
-(relint--function-defs nil)
-(relint--macro-defs nil)
-)
-(dolist (form forms)
-  (relint--check-form-recursively-1 (car form) file (cdr form) nil))
-(dolist (form forms)
-  (relint--check-form-recursively-2 (car form) file (cdr form) nil
+(let ((forms (relint--read-buffer file))
+  (relint--variables nil)
+  (relint--checked-variables nil)
+  (relint--regexp-functions nil)
+  (relint--function-defs nil)
+  (relint--macro-defs nil)
+  (case-fold-search nil))
+  (dolist (form forms)
+(relint--check-form-recursively-1 (car form) file (cdr form) nil))
+  (dolist (form forms)
+(relint--check-form-recursively-2 (car form) file (cdr form) nil)))
 (when (> relint--error-count errors-before)
   (relint--show-errors
+
+(defun relint--scan-file (file base-dir)
+  (with-temp-buffer
+(emacs-lisp-mode)
+(insert-file-contents file)
+(relint--scan-current-buffer (file-relative-name file base-dir
 
 (defvar relint-last-target nil
-  "The last file or directory on which relint was run.  Buffer-local.")
+  "The last file, directory or buffer on which relint was run.")
 
-(defun relint--init (target)
+(defun relint--init (target base-dir)
   (if noninteractive
   (setq relint--error-count 0)
 (with-current-buffer (relint--error-buffer)
   (let ((inhibit-read-only t))
+(compilation-forget-errors)
 (erase-buffer)
 (insert (format "Relint results for %s\n" target))
 (relint--show-errors))
   (setq relint-last-target target)
-  (setq default-directory
-(if (file-directory-p target)
-target
-  (file-name-directory target)))
+  (setq default-directory base-dir)
   (setq relint--error-count 0
 
 (defun relint--finish ()
@@ -1058,11 +1059,16 @@
 (message "relint: %s found." msg)))
 
 (defun relint-again ()
-  "Re-run relint on the same file or directory as last time."
+  "Re-run relint on the same file, directory or buffer as last time."
   (interactive)
-  (if (file-directory-p relint-last-target)
-  (relint-directory relint-last-target)
-(relint-file relint-last-target)))
+  (cond ((bufferp relint-last-target)
+ (with-current-buffer relint-last-target
+   (relint-current-buffer)))
+((file-directory-p relint-last-target)
+ (relint-directory relint-last-target))
+((file-readable-p relint-last-target)
+ (relint-file relint-last-target))
+(t (error "No target"
 
 (defvar relint-mode-map
   (let ((map (make-sparse-keymap)))
@@ -1077,11 +1083,11 @@
   "Mode for relint output."
   (setq-local relint-last-target nil))
 
-(defun relint--scan-files (files target)
-  (relint--init target)
+(defun relint--scan-files (files target base-dir)
+  (relint--init target base-dir)
   (dolist (file files)
 ;;(relint--add-to-error-buffer (format "Scanning 

[elpa] externals/xr 018a994 4/5: Warn about [[:class:]] in skip-sets

2019-04-01 Thread Mattias Engdegrd
branch: externals/xr
commit 018a994f9cb5d2fcd9dcfcabef40f492b7bb952b
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Warn about [[:class:]] in skip-sets

This check overlaps the general "[...]" check, but neither is a subset
of the other. It's possible to get both; no harm in that.
---
 xr-test.el | 2 ++
 xr.el  | 5 +
 2 files changed, 7 insertions(+)

diff --git a/xr-test.el b/xr-test.el
index 644eedf..dbcf84c 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -425,6 +425,8 @@
  '((2 . "Unnecessarily escaped `$'"
   (should (equal (xr-skip-set-lint "[^a-z]")
  '((0 . "Suspect skip set framed in `[...]'"
+  (should (equal (xr-skip-set-lint "[[:space:]].")
+ '((0 . "Suspect character class framed in `[...]'"
   (should (equal (xr-skip-set-lint "")
  '((0 . "Empty set matches nothing"
   (should (equal (xr-skip-set-lint "^")
diff --git a/xr.el b/xr.el
index d2a65d1..8b7c3b6 100644
--- a/xr.el
+++ b/xr.el
@@ -647,6 +647,11 @@
 lower multibyte nonascii print punct space
 unibyte upper word xdigit))
 (error "No character class `%s'" (match-string 0)))
+  ;; Another useful ad-hoc check.
+  (when (and (eq (char-before) ?\[)
+ (eq (char-after (match-end 0)) ?\]))
+(xr--report warnings (1- (point))
+"Suspect character class framed in `[...]'"))
   (when (memq sym classes)
 (xr--report warnings (point)
 (format "Duplicated character class `%s'"



[elpa] externals/xr updated (2136a7d -> 2aec9fd)

2019-04-01 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  2136a7d   Increment version to 1.9
   new  4525d39   Comment cosmetics, and add a README.
   new  7612347   URL to repository and to relint
   new  5b53cc9   Warn about two-character ranges like [*-+]
   new  018a994   Warn about [[:class:]] in skip-sets
   new  2aec9fd   Increment version to 1.10; add News section


Summary of changes:
 README.org | 54 ++
 xr-test.el |  7 +++
 xr.el  | 61 -
 3 files changed, 113 insertions(+), 9 deletions(-)
 create mode 100644 README.org



[elpa] externals/xr 2aec9fd 5/5: Increment version to 1.10; add News section

2019-04-01 Thread Mattias Engdegrd
branch: externals/xr
commit 2aec9fdd6bac987896c262bf8d8d19b6eefaa691
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.10; add News section
---
 xr.el | 28 +++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index 8b7c3b6..7540cef 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.9
+;; Version: 1.10
 ;; URL: https://github.com/mattiase/xr
 ;; Keywords: lisp, maint, regexps
 
@@ -78,6 +78,32 @@
 ;; Neither of these packages parse skip-set strings or provide
 ;; mistake-finding functions.
 
+;;; News:
+
+;; Version 1.10:
+;; - Warn about [[:class:]] in skip-sets
+;; - Warn about two-character ranges like [*-+] in regexps
+;; Version 1.9:
+;; - Don't complain about [z-a] and [^z-a] specifically
+;; - Improved skip set checks
+;; Version 1.8:
+;; - Improved skip set checks
+;; Version 1.7:
+;; - Parse skip-sets, adding `xr-skip-set', `xr-skip-set-pp' and
+;;   `xr-skip-set-lint'
+;; - Ad-hoc check for misplaced `]' in regexps
+;; Version 1.6:
+;; - Detect duplicated branches like A\|A
+;; Version 1.5:
+;; - Add dialect option to `xr' and `xr-pp'
+;; - Negative empty sets, [^z-a], now become `anything'
+;; Version 1.4:
+;; - Detect overlap in character alternatives
+;; Version 1.3:
+;; - Improved xr-lint warnings
+;; Version 1.2:
+;; - `xr-lint' added
+
 ;;; Code:
 
 (require 'rx)



[elpa] externals/xr 7612347 2/5: URL to repository and to relint

2019-04-01 Thread Mattias Engdegrd
branch: externals/xr
commit 761234723172e73de558d558c1e6336912f4e88f
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

URL to repository and to relint
---
 README.org | 2 +-
 xr.el  | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/README.org b/README.org
index 05551a8..98cb56a 100644
--- a/README.org
+++ b/README.org
@@ -51,4 +51,4 @@ Utility:
 
 * See also
 
-The [[https://github.com/mattiase/relint][relint]] package uses xr to find 
regexp mistakes in elisp code.
+The [[https://elpa.gnu.org/packages/relint.html][relint]] package uses xr to 
find regexp mistakes in elisp code.
diff --git a/xr.el b/xr.el
index 014b001..4828b45 100644
--- a/xr.el
+++ b/xr.el
@@ -4,6 +4,7 @@
 
 ;; Author: Mattias Engdegård 
 ;; Version: 1.9
+;; URL: https://github.com/mattiase/xr
 ;; Keywords: lisp, maint, regexps
 
 ;; This program is free software; you can redistribute it and/or modify



[elpa] externals/xr 5b53cc9 3/5: Warn about two-character ranges like [*-+]

2019-04-01 Thread Mattias Engdegrd
branch: externals/xr
commit 5b53cc9efe25b668ce0c7263c1b8cf50c999a6cb
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Warn about two-character ranges like [*-+]
---
 xr-test.el |  5 +
 xr.el  | 10 ++
 2 files changed, 15 insertions(+)

diff --git a/xr-test.el b/xr-test.el
index 8948c2a..644eedf 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -349,6 +349,7 @@
(10 . "Ranges `I-L' and `I-M' overlap")
(16 . "Ranges `a-e' and `b-d' overlap")
(22 . "Ranges `g-k' and `i-n' overlap")
+   (25 . "Two-character range `s-t'")
(29 . "Character `3' included in range `3-7'"
   (should (equal (xr-lint "[a[:digit:]b[:punct:]c[:digit:]]")
  '((22 . "Duplicated character class `[:digit:]'"
@@ -362,6 +363,10 @@
  '((4 . "Suspect `[' in char alternative"
   (should (equal (xr-lint "[^][-].]")
  nil))
+  (should (equal (xr-lint "[0-1]")
+ nil))
+  (should (equal (xr-lint "[^]-][]-^]")
+ '((6 . "Two-character range `]-^'"
   )
 
 (ert-deftest xr-skip-set ()
diff --git a/xr.el b/xr.el
index 4828b45..d2a65d1 100644
--- a/xr.el
+++ b/xr.el
@@ -98,6 +98,10 @@
 (push (vector ?\] end (point)) intervals)
   (xr--report warnings (point)
   (format "Reversed range `%s' matches nothing"
+  (xr--escape-string (match-string 0) nil
+(when (eq end ?^)
+  (xr--report warnings (point)
+  (format "Two-character range `%s'"
   (xr--escape-string (match-string 0) nil)
   (goto-char (match-end 0)))
  ;; Initial ]
@@ -133,6 +137,12 @@
 (xr--report warnings (point)
 (format "Reversed range `%s' matches nothing"
 (xr--escape-string (match-string 0) nil)
+  ;; Suppress warnings about ranges between adjacent digits,
+  ;; like [0-1], as they are common and harmless.
+  (when (and (= end (1+ start)) (not (<= ?0 start end ?9)))
+(xr--report warnings (point)
+(format "Two-character range `%s'"
+(xr--escape-string (match-string 0) nil
   (goto-char (match-end 0
((looking-at (rx eos))
 (error "Unterminated character alternative"))



[elpa] externals/relint f9e4d20 2/8: More messages and updates when running interactively

2019-04-01 Thread Mattias Engdegrd
branch: externals/relint
commit f9e4d20dae8544ecee426dcd43444b4ac08ef2ce
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

More messages and updates when running interactively
---
 relint.el | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index 10ffc88..b42e089 100644
--- a/relint.el
+++ b/relint.el
@@ -1035,7 +1035,8 @@
 (with-current-buffer (relint--error-buffer)
   (let ((inhibit-read-only t))
 (erase-buffer)
-(insert (format "Relint results for %s\n" target)))
+(insert (format "Relint results for %s\n" target))
+(relint--show-errors))
   (setq relint-last-target target)
   (setq default-directory
 (if (file-directory-p target)
@@ -1093,7 +1094,10 @@
 (defun relint-directory (dir)
   "Scan all *.el files in DIR for errors in regexp strings."
   (interactive "DRelint directory: ")
-  (relint--scan-files (relint--tree-files dir) dir))
+  (message "Finding .el files in %s..." dir)
+  (let ((files (relint--tree-files dir)))
+(message "Scanning files...")
+(relint--scan-files files dir)))
 
 
 (defun relint-batch ()



[elpa] externals/relint fdfb2d7 8/8: Increment version to 1.7; add News section

2019-04-01 Thread Mattias Engdegrd
branch: externals/relint
commit fdfb2d75c8a28808e7099635d9bfba651f9044cc
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.7; add News section

Also raise the xr requirement to version 1.10. Although older xr will
work technically, newer versions make relint more capable.
---
 relint.el | 31 +--
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/relint.el b/relint.el
index 343112a..445c7bb 100644
--- a/relint.el
+++ b/relint.el
@@ -3,8 +3,8 @@
 ;; Copyright (C) 2019 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.5
-;; Package-Requires: ((xr "1.7"))
+;; Version: 1.6
+;; Package-Requires: ((xr "1.10"))
 ;; URL: https://github.com/mattiase/relint
 ;; Keywords: lisp, maint, regexps
 
@@ -25,7 +25,7 @@
 
 ;; Scan elisp files for regexp strings and reports potential errors,
 ;; including deprecated syntax and bad practice.
-;; Also check the regexp-like-but-not-quite skip-set arguments to
+;; Also check the regexp-like skip-set arguments to
 ;; `skip-chars-forward' and `skip-chars-backward'.
 ;;
 ;; How to use:
@@ -36,15 +36,15 @@
 ;;   M-x relint-directory   (check all .el files in a directory tree)
 ;;   M-x relint-current-buffer  (check current buffer)
 ;;
+;;   In the `*relint*' buffer, pressing "g" will re-run the same check.
+;;
 ;; * From batch mode:
 ;;
 ;;   emacs -batch -l relint.el -f relint-batch FILES-AND-DIRS...
 ;;
 ;;   where options for finding relint and xr need to be added after
 ;;   `-batch', either `-f package-initialize' or `-L DIR'.
-;;
-;; In the `*relint*' buffer, pressing "g" will re-run the same check.
-;;
+
 ;; Bugs:
 ;;
 ;;   Since there is no sure way to know whether a particular string is a
@@ -52,6 +52,25 @@
 ;;   few. It tries to minimise the amount of false positives.
 ;;   In other words, it is a nothing but a hack.
 
+;;; News:
+
+;; Version 1.6:
+;; - Add `relint-current-buffer'
+;; - Show relative file names in *relint*
+;; - Extended regexp-generating heuristics, warning about suspiciously-named
+;;   variables used as skip-sets
+;; - "-patterns" and "-pattern-list" are no longer interesting variable
+;;   suffixes
+;; Version 1.5:
+;; - Substantially improved evaluator, able to evaluate some functions and
+;;   macros defined in the same file, even when passed as parameters
+;; - Detect regexps spliced into [...]
+;; - Check bad skip-set provenance
+;; - The *relint* buffer now uses a new relint-mode for better usability,
+;;   with "g" bound to `relint-again'
+;; Version 1.4:
+;; - First version after name change to `relint'
+
 ;;; Code:
 
 (require 'xr)



[elpa] externals/relint eabac3b 5/8: Add memql as a safe function

2019-04-01 Thread Mattias Engdegrd
branch: externals/relint
commit eabac3b9385c9c6e9f17cbecf66361e3b4b60410
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add memql as a safe function
---
 relint.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 04081ca..dd5faae 100644
--- a/relint.el
+++ b/relint.el
@@ -192,7 +192,7 @@
 format format-message
 regexp-quote regexp-opt regexp-opt-charset
 reverse
-member memq remove remq member-ignore-case
+member memq memql remove remq member-ignore-case
 assoc assq rassoc rassq
 identity
 string make-string make-list



[elpa] externals/xr 5b08350 2/2: Increment version to 1.3

2019-02-25 Thread Mattias Engdegrd
branch: externals/xr
commit 5b0835038ed43acf9cfc4201be1f012c633a019a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.3
---
 xr.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index 838db3e..853bfc6 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.2
+;; Version: 1.3
 ;; Keywords: lisp, maint, regexps
 
 ;; This program is free software; you can redistribute it and/or modify



[elpa] externals/xr updated (127d3fe -> 5b08350)

2019-02-25 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  127d3fe   Escape control characters in warnings and errors
   new  d08d400   Warn about reversed ranges in character alternatives
   new  5b08350   Increment version to 1.3


Summary of changes:
 xr-test.el |  3 +++
 xr.el  | 32 +---
 2 files changed, 24 insertions(+), 11 deletions(-)



[elpa] externals/xr d08d400 1/2: Warn about reversed ranges in character alternatives

2019-02-25 Thread Mattias Engdegrd
branch: externals/xr
commit d08d40097f4052874c6a526813bd23a7db3d6061
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Warn about reversed ranges in character alternatives

[z-a] does not match anything; remove such ranges from the output and
warn about them in xr-lint.

This can lead to output such as (any), which isn't legal rx,
but it's better than keeping the misleading ranges in the output.
---
 xr-test.el |  3 +++
 xr.el  | 30 --
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 0186fd2..b79c211 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -280,6 +280,9 @@
  '((2 . "Repetition of repetition")
(14 . "Repetition of repetition")
(25 . "Repetition of repetition"
+  (should (equal (xr-lint "[]-Qa-fz-t]")
+'((1 . "Reversed range `]-Q' matches nothing")
+  (7 . "Reversed range `z-t' matches nothing"
   )
 
 (provide 'xr-test)
diff --git a/xr.el b/xr.el
index 142a7ab..838db3e 100644
--- a/xr.el
+++ b/xr.el
@@ -80,8 +80,12 @@
   (let ((set nil))
 (cond
  ;; Initial ]-x range
- ((looking-at (rx "]-" (not (any "]"
-  (push (match-string 0) set)
+ ((looking-at (rx "]-" (group (not (any "]")
+  (if (>= (string-to-char (match-string 1)) ?\])
+ (push (match-string 0) set)
+(xr--report warnings (point)
+   (format "Reversed range `%s' matches nothing"
+   (match-string 0
   (goto-char (match-end 0)))
  ;; Initial ]
  ((looking-at "]")
@@ -107,14 +111,20 @@
   ;; become (97 . 122) when printed.
   ;; TODO: Possibly convert "[0-9]" to digit, and
   ;; "[0-9a-fA-F]" (and permutations) to hex-digit.
-  (goto-char (match-end 0))
-  (let ((prev (car set)))
-;; Merge with preceding range if any.
-(if (and (stringp prev)
- (>= (length prev) 3)
- (eq (aref prev 1) ?-))
-(setq set (cons (concat prev range) (cdr set)))
-  (push range set)
+ (cond
+  ((<= (aref range 0) (aref range 2))
+(let ((prev (car set)))
+  ;; Merge with preceding range if any.
+  (if (and (stringp prev)
+   (>= (length prev) 3)
+   (eq (aref prev 1) ?-))
+  (setq set (cons (concat prev range) (cdr set)))
+   (push range set
+  (t
+(xr--report warnings (point)
+   (format "Reversed range `%s' matches nothing"
+   range
+  (goto-char (match-end 0
((looking-at (rx eos))
 (error "Unterminated character alternative"))
;; plain character (including ^ or -)



[elpa] externals/xr 369800c: Fix doc string mistake

2019-03-01 Thread Mattias Engdegrd
branch: externals/xr
commit 369800c97d8b48b90be3477ad0ffe533bf49d306
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Fix doc string mistake
---
 xr.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/xr.el b/xr.el
index 98a306e..7f8d4e5 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.4
+;; Version: 1.5
 ;; Keywords: lisp, maint, regexps
 
 ;; This program is free software; you can redistribute it and/or modify
@@ -611,7 +611,7 @@ Passing the returned value to `rx' (or `rx-to-string') 
yields a regexp string
 equivalent to RE-STRING.  DIALECT controls the choice of keywords,
 and is one of:
 `verbose'   -- verbose keywords
-`short' -- short keywords
+`brief' -- short keywords
 `terse' -- very short keywords
 `medium' or nil -- a compromise (the default)"
   (let ((keywords (assq (or dialect 'medium) xr--keywords)))



[elpa] externals/xr updated (5b08350 -> 952276b)

2019-03-01 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  5b08350   Increment version to 1.3
   new  6085257   Detect overlap in character alternatives
   new  74b5287   Turn negative empty sets into anything
   new  952276b   Add dialect option and improve pretty-printing


Summary of changes:
 xr-test.el |  79 +---
 xr.el  | 304 ++---
 2 files changed, 277 insertions(+), 106 deletions(-)



[elpa] externals/xr 952276b 3/3: Add dialect option and improve pretty-printing

2019-03-01 Thread Mattias Engdegrd
branch: externals/xr
commit 952276b251a8bd667927d18f96995a22d582a115
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add dialect option and improve pretty-printing

`xr' and `xr-pp' now take an optional DIALECT argument that controls
the choice of keywords to some extent.

The pretty-printer now attempts to avoid line breaks after short
operators. Example:

  (seq
   (or
apple
banana)
   orange)

should now be rendered as

  (seq (or apple
   banana)
   orange)
---
 xr-test.el | 43 +
 xr.el  | 93 +-
 2 files changed, 117 insertions(+), 19 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 8dc2453..4a24ef3 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -258,6 +258,49 @@
  "(?? nonl)\n"))
   (should (equal (xr-pp-rx-to-str '(repeat 1 63 "a"))
  "(repeat 1 63 \"a\")\n"))
+  (let ((indent-tabs-mode nil))
+(should (equal (xr-pp-rx-to-str
+'(seq (1+ nonl
+  (or "a"
+  (not (any space
+  (* (? (not cntrl)
+blank
+(| nonascii "abcdef")
+   (concat
+"(seq (1+ nonl\n"
+" (or \"a\"\n"
+" (not (any space\n"
+" (* (? (not cntrl)\n"
+"   blank\n"
+"   (| nonascii \"abcdef\"\n"
+  )
+
+(ert-deftest xr-dialect ()
+  (should (equal (xr "a*b+c?d\\{2,5\\}\\(e\\|f\\)[gh][^ij]" 'medium)
+ '(seq (zero-or-more "a") (one-or-more "b") (opt "c")
+   (repeat 2 5 "d") (group (or "e" "f"))
+   (any "gh") (not (any "ij")
+  (should (equal (xr "a*b+c?d\\{2,5\\}\\(e\\|f\\)[gh][^ij]" 'verbose)
+ '(seq (zero-or-more "a") (one-or-more "b") (zero-or-one "c")
+   (repeat 2 5 "d") (group (or "e" "f"))
+   (any "gh") (not (any "ij")
+  (should (equal (xr "a*b+c?d\\{2,5\\}\\(e\\|f\\)[gh][^ij]" 'brief)
+ '(seq (0+ "a") (1+ "b") (opt "c")
+   (repeat 2 5 "d") (group (or "e" "f"))
+   (any "gh") (not (any "ij")
+  (should (equal (xr "a*b+c?d\\{2,5\\}\\(e\\|f\\)[gh][^ij]" 'terse)
+ '(: (* "a") (+ "b") (? "c")
+ (** 2 5 "d") (group (| "e" "f"))
+ (in "gh") (not (in "ij")
+  (should (equal (xr "^\\`\\<.\\>\\'$" 'medium)
+ '(seq bol bos bow nonl eow eos eol)))
+  (should (equal (xr "^\\`\\<.\\>\\'$" 'verbose)
+ '(seq line-start string-start word-start not-newline
+   word-end string-end line-end)))
+  (should (equal (xr "^\\`\\<.\\>\\'$" 'brief)
+ '(seq bol bos bow nonl eow eos eol)))
+  (should (equal (xr "^\\`\\<.\\>\\'$" 'terse)
+ '(: bol bos bow nonl eow eos eol)))
   )
 
 (ert-deftest xr-lint ()
diff --git a/xr.el b/xr.el
index 03b2110..98a306e 100644
--- a/xr.el
+++ b/xr.el
@@ -564,12 +564,63 @@
 (error "Unbalanced \\)"))
   rx)))
 
+;; Substitute keywords in RX using HEAD-ALIST and BODY-ALIST in the
+;; head and body positions, respectively.
+(defun xr--substitute-keywords (head-alist body-alist rx)
+  (cond
+   ((symbolp rx)
+(or (cdr (assq rx body-alist)) rx))
+   ((consp rx)
+(cons (or (cdr (assq (car rx) head-alist))
+  (car rx))
+  (mapcar (lambda (elem) (xr--substitute-keywords
+  head-alist body-alist elem))
+  (cdr rx
+   (t rx)))
+
+;; Alist mapping keyword dialect to (HEAD-ALIST . BODY-ALIST),
+;; or to nil if no translation should take place.
+;; The alists are mapping from the default choice.
+(defconst xr--keywords
+  '((medium . nil)
+(brief . (((zero-or-more . 0+)
+   (one-or-more  . 1+))
+  . nil))
+(terse . (((seq  . :)
+   (or   . |)
+   (any  . in)
+   (zero-or-more . *)
+   (one-or-more  . +)
+   (opt  . ? )
+   (repeat   . **))
+  . nil))
+(verbose . (((opt . zero-or-one))
+.
+((nonl . not-newline)
+ (bol  . line-start)
+ (eol  . line-end)
+ (bos  . string-start)
+ (eos  . string-end)
+ (bow  . word-start)
+ (eow  . word-end))
+
 ;;;###autoload
-(defun xr (re-string)
+(defun xr (re-string  dialect)
   "Convert a regexp string to rx notation; the inverse of `rx'.
 Passing the returned value to `rx' (or `rx-to-string') yields a regexp string

[elpa] externals/xr 6085257 1/3: Detect overlap in character alternatives

2019-03-01 Thread Mattias Engdegrd
branch: externals/xr
commit 608525744b4b354b166b4f1b9143734d44460d97
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Detect overlap in character alternatives

Detecting duplication and overlap in character alternatives turns
out to be a fruitful way of finding bugs.
Avoid escaping \ in messages where it applies to single characters.
Increment version to 1.4.
---
 xr-test.el |  34 +++
 xr.el  | 202 +++--
 2 files changed, 149 insertions(+), 87 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index b79c211..7beee0a 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -163,15 +163,17 @@
   (should (equal (xr "[^]-c]")
  '(not (any "]-c"
   (should (equal (xr "[-^]")
- '(any "-" "^")))
+ '(any "^-")))
   (should (equal (xr "[a-z-+/*%0-4[:xdigit:]]")
- '(any "a-z" "-" "+/*%" "0-4" xdigit)))
+ '(any "0-4a-z" "%*+/-" xdigit)))
   (should (equal (xr "[^]A-Za-z-]*")
- '(zero-or-more (not (any "]" "A-Za-z" "-")
+ '(zero-or-more (not (any "A-Za-z" "]-")
   (should (equal (xr "[+*%A-Ka-k0-3${-}]")
- '(any "+*%" "A-Ka-k0-3" "$" "{-}")))
+ '(any "0-3A-Ka-k{-}" "$%*+")))
   (should (equal (xr "[^o][A-][A--a]")
- '(seq (not (any "\\o")) (any "A-\\") (any "A--a"
+ '(seq (not (any "\\o")) (any "A-\\") (any "A-a"
+  (should (equal (xr "[^A-FFGI-LI-Mb-da-eg-ki-ns-tz-v]")
+ '(not (any "A-FI-Ma-eg-ns-t" "G"
   )
 
 (ert-deftest xr-empty ()
@@ -197,7 +199,7 @@
  '(seq bow (group (or "catch" "finally")) eow
(not (any "_")
   (should (equal (xr "[ \t\n]*:\\([^:]+\\|$\\)")
- '(seq (zero-or-more (any " \t\n")) ":"
+ '(seq (zero-or-more (any "\t\n ")) ":"
(group (or (one-or-more (not (any ":")))
   eol)
   )
@@ -265,11 +267,11 @@
   (should (equal (xr-lint "^**$")
  '((1 . "Unescaped literal `*'"
   (should (equal (xr-lint "a[[]")
- '((2 . "Escaped `\\' inside character alternative"
+ '((3 . "Duplicated `\\' inside character alternative"
   (should (equal (xr-lint "\\{\\(+\\|?\\)\\[\\]\\}\\\t")
- '((0 . "Escaped non-special character `{'")
-   (4 . "Unescaped literal `+'")
-   (7 . "Unescaped literal `?'")
+ '((0  . "Escaped non-special character `{'")
+   (4  . "Unescaped literal `+'")
+   (7  . "Unescaped literal `?'")
(14 . "Escaped non-special character `}'")
(16 . "Escaped non-special character `\\t'"
   (should (equal (xr-lint "\\}\\w\\a\\b\\%")
@@ -277,12 +279,18 @@
(4 . "Escaped non-special character `a'")
(8 . "Escaped non-special character `%'"
   (should (equal (xr-lint "a?+b+?\\(?:c?\\)*d\\{3\\}+e*?\\{2,5\\}")
- '((2 . "Repetition of repetition")
+ '((2  . "Repetition of repetition")
(14 . "Repetition of repetition")
(25 . "Repetition of repetition"
   (should (equal (xr-lint "[]-Qa-fz-t]")
-'((1 . "Reversed range `]-Q' matches nothing")
-  (7 . "Reversed range `z-t' matches nothing"
+ '((1 . "Reversed range `]-Q' matches nothing")
+   (7 . "Reversed range `z-t' matches nothing"
+  (should (equal (xr-lint "[^A-FFGI-LI-Mb-da-eg-ki-ns-t33-7]")
+ '((5  . "Character `F' included in range `A-F'")
+   (10 . "Ranges `I-L' and `I-M' overlap")
+   (16 . "Ranges `a-e' and `b-d' overlap")
+   (22 . "Ranges `g-k' and `i-n' overlap")
+   (29 . "Character `3' included in range `3-7'"
   )
 
 (provide 'xr-test)
diff --git a/xr.el b/xr.el
index 853bfc6..3b804ad 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.3
+;; Version: 1.4
 ;; Keywords: lisp, maint, regexps
 
 ;; This program is free software; you can redistribute it and/or modify
@@ -77,20 +77,23 @@
 (push (cons (1- position) message) (car warnings
 
 (defun xr--parse-char-alt (negated warnings)
-  (let ((set nil))
+  (let ((intervals nil)
+(classes nil))
 (cond
  ;; Initial ]-x range
- ((looking-at (rx "]-" (group (not (any "]")
-  (if (>= (string-to-char (match-string 1)) ?\])
- (push (match-string 0) set)
-(xr--report warnings (point)
-   (format "Reversed range `%s' matches nothing"
-   (match-string 0
+ ((looking-at (rx "]-" (not (any "]"
+  (let 

[elpa] externals/xr 74b5287 2/3: Turn negative empty sets into anything

2019-03-01 Thread Mattias Engdegrd
branch: externals/xr
commit 74b5287e3cf2f73f3fe34dffb91f3671e56b94a3
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Turn negative empty sets into anything

[^z-a] was found in the wild (auctex), apparently on purpose.
The correct rx translation should be `anything'.
---
 xr-test.el | 2 ++
 xr.el  | 9 +
 2 files changed, 11 insertions(+)

diff --git a/xr-test.el b/xr-test.el
index 7beee0a..8dc2453 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -174,6 +174,8 @@
  '(seq (not (any "\\o")) (any "A-\\") (any "A-a"
   (should (equal (xr "[^A-FFGI-LI-Mb-da-eg-ki-ns-tz-v]")
  '(not (any "A-FI-Ma-eg-ns-t" "G"
+  (should (equal (xr "[z-a][^z-a]")
+ '(seq (any) anything)))
   )
 
 (ert-deftest xr-empty ()
diff --git a/xr.el b/xr.el
index 3b804ad..03b2110 100644
--- a/xr.el
+++ b/xr.el
@@ -190,7 +190,16 @@
 ranges)))
   sorted)
 
+;; Note that we return (any) for non-negated empty sets,
+;; such as [z-a]. (any) is not accepted by rx but at least we
+;; are not hiding potential bugs from the user.
 (cond
+ ;; Negated empty set, like [^z-a]: anything.
+ ((and negated
+   (null chars)
+   (null ranges)
+   (null classes))
+  'anything)
  ;; Non-negated single-char set, like [$]: make a string.
  ((and (= (length chars) 1)
(not negated)



[elpa] externals/xr 5318a94 1/3: Eliminate duplicated \ in character alternatives

2019-02-21 Thread Mattias Engdegrd
branch: externals/xr
commit 5318a946ec06aae190203d59ec7adc5f8c12ace3
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Eliminate duplicated \ in character alternatives

Since we detect duplicated \ in character alternatives, we might just
as well remove them in the translation. The warning remains.
---
 xr-test.el |  2 ++
 xr.el  | 21 -
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 718471d..33c1e3e 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -170,6 +170,8 @@
  '(zero-or-more (not (any "]" "A-Za-z" "-")
   (should (equal (xr "[+*%A-Ka-k0-3${-}]")
  '(any "+*%" "A-Ka-k0-3" "$" "{-}")))
+  (should (equal (xr "[^o][A-][A--a]")
+ '(seq (not (any "\\o")) (any "A-\\") (any "A--a"
   )
 
 (ert-deftest xr-empty ()
diff --git a/xr.el b/xr.el
index f8b83c2..5a5fff4 100644
--- a/xr.el
+++ b/xr.el
@@ -121,17 +121,20 @@
(t
 (let* ((ch (following-char))
(ch-str (char-to-string ch)))
-  (when (and (eq ch ?\\)
- (stringp (car set))
- (string-match "\\'" (car set)))
+  (cond
+   ;; Duplicated \ are common enough for us to remove them (and warn).
+   ((and (eq ch ?\\)
+ (stringp (car set))
+ (eq (string-to-char (substring (car set) -1)) ?\\))
 (xr--report warnings (1- (point))
 "Escaped `\\' inside character alternative"))
-  ;; Merge with the previous string if neither contains "-".
-  (if (and (stringp (car set))
-   (not (eq ch ?-))
-   (not (string-match "-" (car set
-  (setq set (cons (concat (car set) ch-str) (cdr set)))
-(push ch-str set)))
+   ;; Merge with the previous string if neither contains "-".
+   ((and (stringp (car set))
+ (not (eq ch ?-))
+ (not (string-match "-" (car set
+(setq set (cons (concat (car set) ch-str) (cdr set
+   (t
+(push ch-str set
 (forward-char 1
 
 (forward-char 1); eat the ]



[elpa] externals/xr 3c1344b 2/3: Don't warn about repetition of counted repetition

2019-02-21 Thread Mattias Engdegrd
branch: externals/xr
commit 3c1344b10a2700a16359434a60c4b3eb6bb1de0c
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Don't warn about repetition of counted repetition

Repetition of counted repetition can actually be legitimate;
-- consider a\{3\}? -- so don't warn about it.
---
 xr-test.el | 5 ++---
 xr.el  | 6 ++
 2 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 33c1e3e..0c686c1 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -275,11 +275,10 @@
  '((0 . "Escaped non-special character `}'")
(4 . "Escaped non-special character `a'")
(8 . "Escaped non-special character `%'"
-  (should (equal (xr-lint "a?+b+?\\(?:c?\\)*d\\{3\\}+e*\\{2,5\\}")
+  (should (equal (xr-lint "a?+b+?\\(?:c?\\)*d\\{3\\}+e*?\\{2,5\\}")
  '((2 . "Repetition of repetition")
(14 . "Repetition of repetition")
-   (21 . "Repetition of repetition")
-   (24 . "Repetition of repetition"
+   (25 . "Repetition of repetition"
   )
 
 (provide 'xr-test)
diff --git a/xr.el b/xr.el
index 5a5fff4..95845dd 100644
--- a/xr.el
+++ b/xr.el
@@ -315,8 +315,7 @@
 (let ((operator (match-string 0)))
   (when (and (consp (car sequence))
  (memq (caar sequence)
-   '(opt zero-or-more one-or-more
- repeat = >=)))
+   '(opt zero-or-more one-or-more +? *? ??)))
 (xr--report warnings (match-beginning 0)
 "Repetition of repetition"))
   (goto-char (match-end 0))
@@ -335,8 +334,7 @@
 (forward-char 2)
 (when (and (consp (car sequence))
(memq (caar sequence)
- '(opt zero-or-more one-or-more
-   repeat = >=)))
+ '(opt zero-or-more one-or-more +? *? ??)))
   (xr--report warnings (match-beginning 0)
   "Repetition of repetition"))
 (if (looking-at (rx (opt (group (one-or-more digit)))



[elpa] externals/xr 127d3fe 3/3: Escape control characters in warnings and errors

2019-02-21 Thread Mattias Engdegrd
branch: externals/xr
commit 127d3fee727367294dcff86c695fb154a30358e1
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Escape control characters in warnings and errors
---
 xr-test.el |  5 +++--
 xr.el  | 65 --
 2 files changed, 37 insertions(+), 33 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 0c686c1..0186fd2 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -266,11 +266,12 @@
  '((1 . "Unescaped literal `*'"
   (should (equal (xr-lint "a[[]")
  '((2 . "Escaped `\\' inside character alternative"
-  (should (equal (xr-lint "\\{\\(+\\|?\\)\\[\\]\\}")
+  (should (equal (xr-lint "\\{\\(+\\|?\\)\\[\\]\\}\\\t")
  '((0 . "Escaped non-special character `{'")
(4 . "Unescaped literal `+'")
(7 . "Unescaped literal `?'")
-   (14 . "Escaped non-special character `}'"
+   (14 . "Escaped non-special character `}'")
+   (16 . "Escaped non-special character `\\t'"
   (should (equal (xr-lint "\\}\\w\\a\\b\\%")
  '((0 . "Escaped non-special character `}'")
(4 . "Escaped non-special character `a'")
diff --git a/xr.el b/xr.el
index 95845dd..142a7ab 100644
--- a/xr.el
+++ b/xr.el
@@ -244,7 +244,8 @@
  (?|  . string-delimiter)
  (?!  . comment-delimiter)
 (when (not sym)
-  (error "Unknown syntax code `%c'" syntax-code))
+  (error "Unknown syntax code `%s'"
+ (xr--escape-string (char-to-string syntax-code
 (let ((item (list 'syntax (cdr sym
   (if negated (list 'not item) item
 
@@ -455,7 +456,7 @@
   ;; makes it unlikely to be a serious error.
   (xr--report warnings (match-beginning 0)
   (format "Escaped non-special character `%s'"
-  (match-string 2)
+  (xr--escape-string (match-string 2))
 
(t (error "Backslash at end of regexp"
 
@@ -508,6 +509,36 @@ in RE-STRING."
 (xr--parse re-string warnings)
 (reverse (car warnings
 
+;; Escape non-printing characters in a string for maximum readability.
+(defun xr--escape-string (string)
+  ;; Translate control and raw chars to escape sequences for readability.
+  ;; We prefer hex escapes (\xHH) since that is usually what the user wants,
+  ;; but use octal (\OOO) if a legitimate hex digit follows, as
+  ;; hex escapes are not limited to two digits.
+  (replace-regexp-in-string
+   "[\x00-\x1f\"\\\x7f\x80-\xff][[:xdigit:]]?"
+   (lambda (s)
+ (let* ((c (logand (string-to-char s) #xff))
+(xdigit (substring s 1))
+(transl (assq c
+  '((?\" . "\\\"")
+(?\\ . "")
+(?\a . "\\a")
+(?\b . "\\b")
+(?\t . "\\t")
+(?\n . "\\n")
+(?\v . "\\v")
+(?\f . "\\f")
+(?\r . "\\r")
+(?\e . "\\e")
+   (concat
+(if transl
+(cdr transl)
+  (format (if (zerop (length xdigit)) "\\x%02x" "\\%03o")
+  c))
+xdigit)))
+   string 'fixedcase 'literal))
+
 ;; Print a rx expression to a string, unformatted.
 (defun xr--rx-to-string (rx)
   (cond
@@ -522,35 +553,7 @@ in RE-STRING."
   (rest (mapcar #'xr--rx-to-string (cdr rx
   (concat "(" (mapconcat #'identity (cons first rest) " ") ")")))
((stringp rx)
-;; Translate control and raw chars to escape sequences for readability.
-;; We prefer hex escapes (\xHH) since that is usually what the user wants,
-;; but use octal (\OOO) if a legitimate hex digit follows, as
-;; hex escapes are not limited to two digits.
-(concat "\""
-(replace-regexp-in-string
- "[\x00-\x1f\"\\\x7f\x80-\xff][[:xdigit:]]?"
- (lambda (s)
-   (let* ((c (logand (string-to-char s) #xff))
-  (xdigit (substring s 1))
-  (transl (assq c
-'((?\" . "\\\"")
-  (?\\ . "")
-  (?\a . "\\a")
-  (?\b . "\\b")
-  (?\t . "\\t")
-  (?\n . "\\n")
-  (?\v . "\\v")
-  (?\f . "\\f")
-  (?\r . "\\r")
-  (?\e . "\\e")
- (concat
-  (if transl
-  (cdr transl)
-(format (if (zerop (length xdigit)) "\\x%02x" "\\%03o")
- 

[elpa] externals/xr updated (dec9a2e -> 127d3fe)

2019-02-21 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  dec9a2e   Don't warn about \]
   new  5318a94   Eliminate duplicated \ in character alternatives
   new  3c1344b   Don't warn about repetition of counted repetition
   new  127d3fe   Escape control characters in warnings and errors


Summary of changes:
 xr-test.el | 12 
 xr.el  | 92 --
 2 files changed, 55 insertions(+), 49 deletions(-)



[elpa] externals/xr 1b26866 1/2: Warn about repetition of repetition

2019-02-21 Thread Mattias Engdegrd
branch: externals/xr
commit 1b26866aad4ceae17da416bd9328641a516c0d6a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Warn about repetition of repetition

Make xr-lint complain about constructs such as a?* as they are
usually mistakes.
---
 xr-test.el |  5 +
 xr.el  | 14 +-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/xr-test.el b/xr-test.el
index 7077283..c0a86a2 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -274,6 +274,11 @@
  '((0 . "Escaped non-special character `}'")
(4 . "Escaped non-special character `a'")
(8 . "Escaped non-special character `%'"
+  (should (equal (xr-lint "a?+b+?\\(?:c?\\)*d\\{3\\}+e*\\{2,5\\}")
+'((2 . "Repetition of repetition")
+  (14 . "Repetition of repetition")
+  (21 . "Repetition of repetition")
+  (24 . "Repetition of repetition"
   )
 
 (provide 'xr-test)
diff --git a/xr.el b/xr.el
index 60d84b9..6114ee7 100644
--- a/xr.el
+++ b/xr.el
@@ -26,7 +26,7 @@
 ;;
 ;; - Migrating existing code to rx form, for better readability and
 ;;   maintainability
-;; - Understanding complex regexp strings
+;; - Understanding complex regexp strings and finding errors in them
 ;;   
 ;; Please refer to `rx' for more information about the notation.
 ;;
@@ -310,6 +310,12 @@
 (if (and sequence
  (not (and (eq (car sequence) 'bol) (eq (preceding-char) ?^
 (let ((operator (match-string 0)))
+  (when (and (consp (car sequence))
+ (memq (caar sequence)
+   '(opt zero-or-more one-or-more
+ repeat = >=)))
+(xr--report warnings (match-beginning 0)
+"Repetition of repetition"))
   (goto-char (match-end 0))
   (setq sequence (cons (xr--postfix operator (car sequence))
(cdr sequence
@@ -324,6 +330,12 @@
  sequence
  (not (and (eq (car sequence) 'bol) (eq (preceding-char) ?^
 (forward-char 2)
+(when (and (consp (car sequence))
+   (memq (caar sequence)
+ '(opt zero-or-more one-or-more
+   repeat = >=)))
+  (xr--report warnings (match-beginning 0)
+  "Repetition of repetition"))
 (if (looking-at (rx (opt (group (one-or-more digit)))
 (opt (group ",")
  (opt (group (one-or-more digit



[elpa] externals/xr updated (8912612 -> dec9a2e)

2019-02-21 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  8912612   Fix xr-lint complaint about \[
   new  1b26866   Warn about repetition of repetition
   new  dec9a2e   Don't warn about \]


Summary of changes:
 xr-test.el |  6 +-
 xr.el  | 18 --
 2 files changed, 21 insertions(+), 3 deletions(-)



[elpa] externals/xr dec9a2e 2/2: Don't warn about \]

2019-02-21 Thread Mattias Engdegrd
branch: externals/xr
commit dec9a2ebc6bc79a1383e10b820e4934176f84b8b
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Don't warn about \]

Do not warn about an escaped ], since [ needs to be escaped and writing \]
is unlikely to be a hidden error.
---
 xr-test.el | 9 -
 xr.el  | 4 +++-
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index c0a86a2..718471d 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -268,17 +268,16 @@
  '((0 . "Escaped non-special character `{'")
(4 . "Unescaped literal `+'")
(7 . "Unescaped literal `?'")
-   (12 . "Escaped non-special character `]'")
(14 . "Escaped non-special character `}'"
   (should (equal (xr-lint "\\}\\w\\a\\b\\%")
  '((0 . "Escaped non-special character `}'")
(4 . "Escaped non-special character `a'")
(8 . "Escaped non-special character `%'"
   (should (equal (xr-lint "a?+b+?\\(?:c?\\)*d\\{3\\}+e*\\{2,5\\}")
-'((2 . "Repetition of repetition")
-  (14 . "Repetition of repetition")
-  (21 . "Repetition of repetition")
-  (24 . "Repetition of repetition"
+ '((2 . "Repetition of repetition")
+   (14 . "Repetition of repetition")
+   (21 . "Repetition of repetition")
+   (24 . "Repetition of repetition"
   )
 
 (provide 'xr-test)
diff --git a/xr.el b/xr.el
index 6114ee7..f8b83c2 100644
--- a/xr.el
+++ b/xr.el
@@ -445,11 +445,13 @@
;; Escaped character. Only \*+?.^$[ really need escaping, but we accept
;; any not otherwise handled character after the backslash since
;; such sequences are found in the wild.
-   ((looking-at (rx "\\" (group (or (any "\\*+?.^$[")
+   ((looking-at (rx "\\" (group (or (any "\\*+?.^$[]")
 (group anything)
 (forward-char 2)
 (push (match-string 1) sequence)
 (when (match-beginning 2)
+  ;; Note that we do not warn about \\], since the symmetry with \\[
+  ;; makes it unlikely to be a serious error.
   (xr--report warnings (match-beginning 0)
   (format "Escaped non-special character `%s'"
   (match-string 2)



[elpa] externals/xr 8912612: Fix xr-lint complaint about \[

2019-02-20 Thread Mattias Engdegrd
branch: externals/xr
commit 8912612803a734984f600b73d58c92ff40f7d480
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Fix xr-lint complaint about \[
---
 xr-test.el | 7 ---
 xr.el  | 2 +-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index f646c13..7077283 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -255,7 +255,7 @@
   )
 
 (ert-deftest xr-lint ()
-  (should (equal (xr-lint "^a*\\(b\\{3\\}\\|c\\)[^]\\a-d^-]$")
+  (should (equal (xr-lint "^a*\\[\\?\\$\\(b\\{3\\}\\|c\\)[^]\\a-d^-]$")
  nil))
   (should (equal (xr-lint "a^b$c")
  '((1 . "Unescaped literal `^'")
@@ -264,11 +264,12 @@
  '((1 . "Unescaped literal `*'"
   (should (equal (xr-lint "a[[]")
  '((2 . "Escaped `\\' inside character alternative"
-  (should (equal (xr-lint "\\{\\(+\\|?\\)\\}")
+  (should (equal (xr-lint "\\{\\(+\\|?\\)\\[\\]\\}")
  '((0 . "Escaped non-special character `{'")
(4 . "Unescaped literal `+'")
(7 . "Unescaped literal `?'")
-   (10 . "Escaped non-special character `}'"
+   (12 . "Escaped non-special character `]'")
+   (14 . "Escaped non-special character `}'"
   (should (equal (xr-lint "\\}\\w\\a\\b\\%")
  '((0 . "Escaped non-special character `}'")
(4 . "Escaped non-special character `a'")
diff --git a/xr.el b/xr.el
index a430cf2..60d84b9 100644
--- a/xr.el
+++ b/xr.el
@@ -433,7 +433,7 @@
;; Escaped character. Only \*+?.^$[ really need escaping, but we accept
;; any not otherwise handled character after the backslash since
;; such sequences are found in the wild.
-   ((looking-at (rx "\\" (group (or (any "\\*+?.^$")
+   ((looking-at (rx "\\" (group (or (any "\\*+?.^$[")
 (group anything)
 (forward-char 2)
 (push (match-string 1) sequence)



[elpa] externals/xr 513e815 3/3: Run with case-fold-search set to nil

2019-03-05 Thread Mattias Engdegrd
branch: externals/xr
commit 513e81551f01a1557f1f6a38c4cc0dcbadb14ffa
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Run with case-fold-search set to nil

Although none of the regexps matches in the code appear to have their
meaning altered by `case-fold-search' right now, it is a ticking bomb,
so better be safe.
---
 xr.el | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index 1fd9324..c9ce0f2 100644
--- a/xr.el
+++ b/xr.el
@@ -559,7 +559,8 @@
 (set-buffer-multibyte t)
 (insert re-string)
 (goto-char (point-min))
-(let ((rx (xr--parse-alt warnings)))
+(let* ((case-fold-search nil)
+   (rx (xr--parse-alt warnings)))
   (when (looking-at (rx "\\)"))
 (error "Unbalanced \\)"))
   rx)))



[elpa] externals/xr updated (369800c -> 513e815)

2019-03-05 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  369800c   Fix doc string mistake
   new  dc6d6e3   Escape control chars in all warnings but not double quote
   new  ccc76c8   More careful character class parsing
   new  513e815   Run with case-fold-search set to nil


Summary of changes:
 xr-test.el | 11 +++
 xr.el  | 30 +++---
 2 files changed, 26 insertions(+), 15 deletions(-)



[elpa] externals/xr ccc76c8 2/3: More careful character class parsing

2019-03-05 Thread Mattias Engdegrd
branch: externals/xr
commit ccc76c8c0b836bbf26b94edfd33d5bb3e8e2a021
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

More careful character class parsing

[[:random rubbish:]] is an error, not a valid regexp.
---
 xr-test.el | 11 +++
 xr.el  | 12 ++--
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 4a24ef3..d4e2d48 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -176,6 +176,17 @@
  '(not (any "A-FI-Ma-eg-ns-t" "G"
   (should (equal (xr "[z-a][^z-a]")
  '(seq (any) anything)))
+  (should (equal (xr "[[:alpha]]")
+ '(seq (any ":[ahlp") "]")))
+  (should (equal (xr "[:alpha:]")
+ '(any ":ahlp")))
+  (should (equal (xr "[[:digit:]-z]")
+ '(any "z-" digit)))
+  (should (equal (xr "[A-[:digit:]]")
+ '(seq (any "A-[" ":dgit") "]")))
+  (should-error (xr "[[::]]"))
+  (should-error (xr "[[:=:]]"))
+  (should-error (xr "[[:letter:]]"))
   )
 
 (ert-deftest xr-empty ()
diff --git a/xr.el b/xr.el
index 9db27b3..1fd9324 100644
--- a/xr.el
+++ b/xr.el
@@ -97,13 +97,13 @@
 (while (not (looking-at "]"))
   (cond
;; character class
-   ((looking-at (rx "[:" (group (one-or-more letter)) ":]"))
+   ((looking-at (rx "[:" (group (*? anything)) ":]"))
 (let ((sym (intern (match-string 1
-  (when (not (memq sym
-   '(ascii alnum alpha blank cntrl digit graph
- lower multibyte nonascii print punct space
- unibyte upper word xdigit)))
-(error "No character class `%s'" sym))
+  (unless (memq sym
+'(ascii alnum alpha blank cntrl digit graph
+  lower multibyte nonascii print punct space
+  unibyte upper word xdigit))
+(error "No character class `%s'" (match-string 0)))
   (if (memq sym classes)
   (xr--report warnings (point)
   (format "Duplicated character class `[:%s:]'" sym))



[elpa] externals/xr dc6d6e3 1/3: Escape control chars in all warnings but not double quote

2019-03-05 Thread Mattias Engdegrd
branch: externals/xr
commit dc6d6e3cab769ef85fb7a386769a499b6404c3de
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Escape control chars in all warnings but not double quote
---
 xr.el | 15 +++
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/xr.el b/xr.el
index 7f8d4e5..9db27b3 100644
--- a/xr.el
+++ b/xr.el
@@ -87,7 +87,7 @@
 (push (vector ?\] end (point)) intervals)
   (xr--report warnings (point)
   (format "Reversed range `%s' matches nothing"
-  (match-string 0)
+  (xr--escape-string (match-string 0) nil)
   (goto-char (match-end 0)))
  ;; Initial ]
  ((looking-at "]")
@@ -119,7 +119,7 @@
(t
 (xr--report warnings (point)
 (format "Reversed range `%s' matches nothing"
-(match-string 0)
+(xr--escape-string (match-string 0) nil)
   (goto-char (match-end 0
((looking-at (rx eos))
 (error "Unterminated character alternative"))
@@ -634,8 +634,8 @@ in RE-STRING."
 (sort (car warnings) #'car-less-than-car)))
 
 ;; Escape non-printing characters in a string for maximum readability.
-;; If ESCAPE-BACKSLASH, also escape \, otherwise don't.
-(defun xr--escape-string (string escape-backslash)
+;; If ESCAPE-PRINTABLE, also escape \ and ", otherwise don't.
+(defun xr--escape-string (string escape-printable)
   ;; Translate control and raw chars to escape sequences for readability.
   ;; We prefer hex escapes (\xHH) since that is usually what the user wants,
   ;; but use octal (\OOO) if a legitimate hex digit follows, as
@@ -646,8 +646,7 @@ in RE-STRING."
  (let* ((c (logand (string-to-char s) #xff))
 (xdigit (substring s 1))
 (transl (assq c
-  '((?\" . "\\\"")
-(?\b . "\\b")
+  '((?\b . "\\b")
 (?\t . "\\t")
 (?\n . "\\n")
 (?\v . "\\v")
@@ -656,8 +655,8 @@ in RE-STRING."
 (?\e . "\\e")
(concat
 (cond (transl (cdr transl))
-  ((eq c ?\\)
-   (if escape-backslash "" "\\"))
+  ((memq c '(?\\ ?\"))
+   (if escape-printable (string ?\\ c) (string c)))
   ((zerop (length xdigit)) (format "\\x%02x" c))
   (t (format (format "\\%03o" c
 xdigit)))



[elpa] externals/xr db5f17b 1/3: Check suspicious curly-bracket constructs

2019-03-17 Thread Mattias Engdegrd
branch: externals/xr
commit db5f17b29c96c9a1cfa50cbf831dec1d27cc9e80
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check suspicious curly-bracket constructs

Warn about \{\} and \{,\} (which really mean \{0\} and *),
and signal an error for \{N,M\} where N>M.
---
 xr-test.el | 5 +
 xr.el  | 7 +++
 2 files changed, 12 insertions(+)

diff --git a/xr-test.el b/xr-test.el
index c1c9b31..670a2f2 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -56,6 +56,7 @@
  '(repeat 0 1 "a")))
   (should (equal (xr "a\\{1,\\}")
  '(>= 1 "a")))
+  (should-error (xr "a\\{3,2\\}"))
   )
 
 (ert-deftest xr-backref ()
@@ -351,6 +352,10 @@
  '((22 . "Duplicated character class `[:digit:]'"
   (should (equal (xr-lint "a*\\|b+\\|\\(?:a\\)*")
  '((8 . "Duplicated alternative branch"
+  (should (equal (xr-lint "a\\{,\\}")
+ '((1 . "Uncounted repetition"
+  (should (equal (xr-lint "a\\{\\}")
+ '((1 . "Implicit zero repetition"
   )
 
 (provide 'xr-test)
diff --git a/xr.el b/xr.el
index 24249aa..db0adda 100644
--- a/xr.el
+++ b/xr.el
@@ -342,6 +342,8 @@
 ;; Apply a repetition of {LOWER,UPPER} to OPERAND.
 ;; UPPER may be nil, meaning infinity.
 (defun xr--repeat (lower upper operand)
+  (when (and upper (> lower upper))
+(error "Invalid repetition interval"))
   ;; rx does not accept (= 0 ...) or (>= 0 ...), so we use 
   ;; (repeat 0 0 ...) and (zero-or-more ...), respectively.
   ;; Note that we cannot just delete the operand if LOWER=UPPER=0,
@@ -420,6 +422,11 @@
   (comma (match-string 2))
   (upper (and (match-string 3)
   (string-to-number (match-string 3)
+  (unless (or (match-beginning 1) (match-string 3))
+(xr--report warnings (- (match-beginning 0) 2)
+(if comma
+"Uncounted repetition"
+"Implicit zero repetition")))
   (goto-char (match-end 0))
   (setq sequence (cons (xr--repeat
 lower



[elpa] externals/xr a248977 3/3: Parse and lint skip set strings

2019-03-17 Thread Mattias Engdegrd
branch: externals/xr
commit a24897795ed811ce58d593fb2472723268e27391
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Parse and lint skip set strings

Add functions to parse and lint skip set strings, which are
the arguments to `skip-chars-forward' and `skip-chars-backward':

  xr-skip-set
  xr-skip-set-pp
  xr-skip-set-lint

Increment the version to 1.7.
---
 xr-test.el |  53 +++
 xr.el  | 221 +
 2 files changed, 261 insertions(+), 13 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 4d197bf..860070c 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -362,6 +362,59 @@
  nil))
   )
 
+(ert-deftest xr-skip-set ()
+  (should (equal (xr-skip-set "0-9a-fA-F+*")
+ '(any "0-9a-fA-F" "+*")))
+  (should (equal (xr-skip-set "^ab-ex-")
+ '(not (any "b-e" "ax-"
+  (should (equal (xr-skip-set "-^][\\")
+ '(any "^][-")))
+  (should (equal (xr-skip-set "\\^a\\-bc-\\fg")
+ '(any "c-f" "^abg-")))
+  (should (equal (xr-skip-set "\\")
+ '(any)))
+  (should (equal (xr-skip-set "--3^Q-\\")
+ '(any "--3Q-\\" "^")))
+  (should (equal (xr-skip-set "^Q-\\c-\\n")
+ '(not (any "Q-c" "n-"
+  (should (equal (xr-skip-set "A-")
+ '(any "\\A-")))
+  (should (equal (xr-skip-set "[a-z]")
+ '(any "a-z" "[]")))
+  (should (equal (xr-skip-set "[:ascii:]-[:digit:]")
+ '(any "-" ascii digit)))
+  (should (equal (xr-skip-set "A-[:blank:]")
+ '(any "A-[" ":blank]")))
+  (should (equal (xr-skip-set "\\[:xdigit:]-b")
+ '(any "]-b" "[:xdigt")))
+  (should (equal (xr-skip-set "^a-z+" 'terse)
+ '(not (in "a-z" "+"
+  (should-error (xr-skip-set "[::]"))
+  (should-error (xr-skip-set "[:whitespace:]"))
+  (should (equal (xr-skip-set ".")
+ "\\."))
+  (should (equal (xr-skip-set "^")
+ 'anything))
+  (should (equal (xr-skip-set "^[:print:]")
+ '(not print)))
+  )
+
+(ert-deftest xr-skip-set-lint ()
+  (should (equal (xr-skip-set-lint "A[:ascii:]B[:space:][:ascii:]")
+ '((20 . "Duplicated character class `[:ascii:]'"
+  (should (equal (xr-skip-set-lint "a\\bF-AM-M\\")
+ '((1 . "Unnecessarily escaped `b'")
+   (3 . "Reversed range `F-A'")
+   (6 . "Single-element range `M-M'")
+   (9 . "Stray `\\' at end of string"
+  (should (equal (xr-skip-set-lint "A-Fa-z3D-K!3-7\\!b")
+ '((7 . "Ranges `A-F' and `D-K' overlap")
+   (11 . "Range `3-7' includes character `3'")
+   (14 . "Duplicated character `!'")
+   (14 . "Unnecessarily escaped `!'")
+   (16 . "Character `b' included in range `a-z'"
+  )
+
 (provide 'xr-test)
 
 ;;; xr-test.el ends here
diff --git a/xr.el b/xr.el
index eba3a10..2d1eff8 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.6
+;; Version: 1.7
 ;; Keywords: lisp, maint, regexps
 
 ;; This program is free software; you can redistribute it and/or modify
@@ -30,11 +30,24 @@
 ;;   
 ;; Please refer to `rx' for more information about the notation.
 ;;
-;; The exported functions are:
+;; In addition to Emacs regexps, this package can also parse and
+;; troubleshoot skip set strings, which are arguments to
+;; `skip-chars-forward' and `skip-chars-backward'.
+;;
+;; The exported functions for regexps are:
+;;
+;;  `xr'   - returns the converted rx expression
+;;  `xr-pp'- converts to rx and pretty-prints
+;;  `xr-lint'  - finds mistakes in a regexp string
+;;
+;; For skip sets we also have:
+;;
+;;  `xr-skip-set'  - return the converted rx expression
+;;  `xr-skip-set-pp'   - converts to rx and pretty-prints
+;;  `xr-skip-set-lint' - finds mistakes in a skip set string
+;;
+;; There is finally the generally useful:
 ;;
-;;  `xr'  - returns the converted rx expression
-;;  `xr-pp'   - pretty-prints the converted rx expression
-;;  `xr-lint' - finds deprecated syntax in a regexp string
 ;;  `xr-pp-rx-to-str' - pretty-prints an rx expression to a string
 ;;
 ;; Suggested use is from an interactive elisp buffer.
@@ -591,6 +604,153 @@
 (error "Unbalanced \\)"))
   rx)))
 
+;; Grammar for skip-set strings:
+;;
+;; skip-set ::= `^'? item*
+;; item ::= range | single
+;; range::= single `-' end
+;; single   ::= (any char but `\')
+;;| `\' (any char)
+;; end  ::= single | `\'
+;;
+;; The grammar is ambiguous, resolved left-to-right:
+;; - a leading ^ is always a negation marker
+;; - an item is always a range if possible
+;; - an end is only `\' if last in the string
+
+(defun 

[elpa] externals/xr updated (7afb247 -> a248977)

2019-03-17 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  7afb247   Increment version to 1.6
   new  db5f17b   Check suspicious curly-bracket constructs
   new  d6740ce   Detect misplaced `]' inside character alternatives
   new  a248977   Parse and lint skip set strings


Summary of changes:
 xr-test.el |  62 
 xr.el  | 243 +
 2 files changed, 292 insertions(+), 13 deletions(-)



[elpa] externals/xr d6740ce 2/3: Detect misplaced `]' inside character alternatives

2019-03-17 Thread Mattias Engdegrd
branch: externals/xr
commit d6740ceb190e71bab2d992f2ad35b9f6418283de
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Detect misplaced `]' inside character alternatives

Add an ad-hoc check for a rare but serious mistake: attempts to include
literal [ and ] inside a character alternative without placing the ] first,
resulting in a [...[...]...] pattern.

There could be false positives but none have been seen in emacs or elpa.
---
 xr-test.el |  4 
 xr.el  | 15 +++
 2 files changed, 19 insertions(+)

diff --git a/xr-test.el b/xr-test.el
index 670a2f2..4d197bf 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -356,6 +356,10 @@
  '((1 . "Uncounted repetition"
   (should (equal (xr-lint "a\\{\\}")
  '((1 . "Implicit zero repetition"
+  (should (equal (xr-lint "[0-9[|]*/]")
+ '((4 . "Suspect `[' in char alternative"
+  (should (equal (xr-lint "[^][-].]")
+ nil))
   )
 
 (provide 'xr-test)
diff --git a/xr.el b/xr.el
index db0adda..eba3a10 100644
--- a/xr.el
+++ b/xr.el
@@ -126,6 +126,21 @@
;; plain character (including ^ or -)
(t
 (let ((ch (following-char)))
+  (when (and (eq ch ?\[)
+ ;; Ad-hoc pattern attempting to catch mistakes
+ ;; on the form [...[...]...]
+ ;; where we are^here
+ (looking-at (rx "["
+ (zero-or-more (not (any "[]")))
+ "]"
+ (zero-or-more (not (any "[]")))
+ (not (any "[\\"))
+ "]"))
+ ;; Only if the alternative didn't start with ]
+ (not (and intervals
+   (eq (aref (car (last intervals)) 0) ?\]
+(xr--report warnings (point)
+"Suspect `[' in char alternative"))
   (push (vector ch ch (point)) intervals))
 (forward-char 1
 



[elpa] externals/xr 7afb247: Increment version to 1.6

2019-03-15 Thread Mattias Engdegrd
branch: externals/xr
commit 7afb24757ce42cd973ff99455e76072493fe879f
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.6
---
 xr.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index d287165..24249aa 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.5
+;; Version: 1.6
 ;; Keywords: lisp, maint, regexps
 
 ;; This program is free software; you can redistribute it and/or modify



[elpa] externals/xr efc0663 2/3: Improved `xr-pp' doc string

2019-03-15 Thread Mattias Engdegrd
branch: externals/xr
commit efc06637a76437b08edbcc27c6427fb67b44dd91
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Improved `xr-pp' doc string
---
 xr.el | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/xr.el b/xr.el
index c9ce0f2..5f644bb 100644
--- a/xr.el
+++ b/xr.el
@@ -706,10 +706,10 @@ It does a slightly better job than standard `pp' for rx 
purposes."
 
 ;;;###autoload
 (defun xr-pp (re-string  dialect)
-  "Convert to `rx' notation and pretty-print.
-This basically does `(pp (xr RE-STRING DIALECT))', but in a slightly
-more readable way.  It is intended for use from an interactive elisp
-session.  Returns nil."
+  "Convert to `rx' notation and output the pretty-printed result.
+This function uses `xr' to translate RE-STRING into DIALECT.
+It is intended for use from an interactive elisp session.
+See `xr' for a description of the DIALECT argument."
   (insert (xr-pp-rx-to-str (xr re-string dialect
 
 (provide 'xr)



[elpa] externals/xr updated (513e815 -> 549cbc5)

2019-03-15 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  513e815   Run with case-fold-search set to nil
   new  d0c434d   Add missing xr-lint unit test
   new  efc0663   Improved `xr-pp' doc string
   new  549cbc5   Detect duplicated branches in alternatives


Summary of changes:
 xr-test.el |  4 
 xr.el  | 14 +-
 2 files changed, 13 insertions(+), 5 deletions(-)



[elpa] externals/xr d0c434d 1/3: Add missing xr-lint unit test

2019-03-15 Thread Mattias Engdegrd
branch: externals/xr
commit d0c434d2c5511d372741e351620e9fe90535e246
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add missing xr-lint unit test
---
 xr-test.el | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/xr-test.el b/xr-test.el
index d4e2d48..c90258a 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -347,6 +347,8 @@
(16 . "Ranges `a-e' and `b-d' overlap")
(22 . "Ranges `g-k' and `i-n' overlap")
(29 . "Character `3' included in range `3-7'"
+  (should (equal (xr-lint "[a[:digit:]b[:punct:]c[:digit:]]")
+ '((22 . "Duplicated character class `[:digit:]'"
   )
 
 (provide 'xr-test)



[elpa] externals/xr 549cbc5 3/3: Detect duplicated branches in alternatives

2019-03-15 Thread Mattias Engdegrd
branch: externals/xr
commit 549cbc55fa3160e4246fefdead4130c85a91b608
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Detect duplicated branches in alternatives

Eg. "A\\|A". Sometimes indication of deeper mistake, always wasteful.
---
 xr-test.el | 2 ++
 xr.el  | 6 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/xr-test.el b/xr-test.el
index c90258a..c1c9b31 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -349,6 +349,8 @@
(29 . "Character `3' included in range `3-7'"
   (should (equal (xr-lint "[a[:digit:]b[:punct:]c[:digit:]]")
  '((22 . "Duplicated character class `[:digit:]'"
+  (should (equal (xr-lint "a*\\|b+\\|\\(?:a\\)*")
+ '((8 . "Duplicated alternative branch"
   )
 
 (provide 'xr-test)
diff --git a/xr.el b/xr.el
index 5f644bb..d287165 100644
--- a/xr.el
+++ b/xr.el
@@ -545,7 +545,11 @@
 (push (xr--parse-seq warnings) alternatives)
 (while (not (looking-at (rx (or "\\)" eos
   (forward-char 2)  ; skip \|
-  (push (xr--parse-seq warnings) alternatives))
+  (let ((pos (point))
+(seq (xr--parse-seq warnings)))
+(when (and warnings (member seq alternatives))
+  (xr--report warnings pos "Duplicated alternative branch"))
+(push seq alternatives)))
 (if (cdr alternatives)
 ;; Simplify (or nonl "\n") to anything
 (if (or (equal alternatives '(nonl "\n"))



[elpa] externals/xr a948847 3/5: Don't complain about [z-a]

2019-03-21 Thread Mattias Engdegrd
branch: externals/xr
commit a948847b2f527a0d19a9db3f5348516304786f32
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Don't complain about [z-a]

z-a is much more likely to be an empty range on purpose than a mistake.
In particular, [^z-a] is occasionally seen as a (arguably misguided)
expression for matching any character.
---
 xr-test.el | 2 ++
 xr.el  | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/xr-test.el b/xr-test.el
index 17b0b09..fd36db2 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -342,6 +342,8 @@
   (should (equal (xr-lint "[]-Qa-fz-t]")
  '((1 . "Reversed range `]-Q' matches nothing")
(7 . "Reversed range `z-t' matches nothing"
+  (should (equal (xr-lint "[z-a][^z-a]")
+ nil))
   (should (equal (xr-lint "[^A-FFGI-LI-Mb-da-eg-ki-ns-t33-7]")
  '((5  . "Character `F' included in range `A-F'")
(10 . "Ranges `I-L' and `I-M' overlap")
diff --git a/xr.el b/xr.el
index 55465e9..e76b150 100644
--- a/xr.el
+++ b/xr.el
@@ -126,6 +126,8 @@
   (cond
((<= start end)
 (push (vector start end (point)) intervals))
+   ;; It's unlikely that anyone writes z-a by mistake; don't complain.
+   ((and (eq start ?z) (eq end ?a)))
(t
 (xr--report warnings (point)
 (format "Reversed range `%s' matches nothing"



[elpa] externals/xr f1afeff 1/5: Add check for `[...]'-framed skip sets

2019-03-21 Thread Mattias Engdegrd
branch: externals/xr
commit f1afeff68c1fb2e52da2f7f6e899801ef96b9349
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add check for `[...]'-framed skip sets

This seems to be a particularly common misunderstanding of skip set
syntax.
Increment version to 1.8.
---
 xr-test.el | 4 +++-
 xr.el  | 6 +-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 860070c..17b0b09 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -413,7 +413,9 @@
(14 . "Duplicated character `!'")
(14 . "Unnecessarily escaped `!'")
(16 . "Character `b' included in range `a-z'"
-  )
+  (should (equal (xr-skip-set-lint "[^a-z]")
+ '((0 . "Suspect skip set framed in `[...]'"
+)
 
 (provide 'xr-test)
 
diff --git a/xr.el b/xr.el
index 2d1eff8..410de13 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.7
+;; Version: 1.8
 ;; Keywords: lisp, maint, regexps
 
 ;; This program is free software; you can redistribute it and/or modify
@@ -619,6 +619,10 @@
 ;; - an end is only `\' if last in the string
 
 (defun xr--parse-skip-set-buffer (warnings)
+  ;; An ad-hoc check, but one that catches lots of mistakes.
+  (when (and (looking-at (rx "[" (one-or-more anything) "]" eos))
+ (not (looking-at (rx "[:" (one-or-more anything) ":]" eos
+(xr--report warnings (point) "Suspect skip set framed in `[...]'"))
   (let ((negated (looking-at (rx "^")))
 (ranges nil)
 (classes nil))



[elpa] externals/xr 2136a7d 5/5: Increment version to 1.9

2019-03-21 Thread Mattias Engdegrd
branch: externals/xr
commit 2136a7d834d6b0ad6b5a0f44ef50c6c033f601bc
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.9
---
 xr.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index 9ebf446..3a17487 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.8
+;; Version: 1.9
 ;; Keywords: lisp, maint, regexps
 
 ;; This program is free software; you can redistribute it and/or modify



[elpa] externals/xr d7325b3 2/5: Edit the package doc comment

2019-03-21 Thread Mattias Engdegrd
branch: externals/xr
commit d7325b3c1fe2e8a64c0057e6d790aa46d7c27700
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Edit the package doc comment
---
 xr.el | 61 -
 1 file changed, 28 insertions(+), 33 deletions(-)

diff --git a/xr.el b/xr.el
index 410de13..55465e9 100644
--- a/xr.el
+++ b/xr.el
@@ -31,54 +31,51 @@
 ;; Please refer to `rx' for more information about the notation.
 ;;
 ;; In addition to Emacs regexps, this package can also parse and
-;; troubleshoot skip set strings, which are arguments to
+;; find mistakes in skip set strings, which are arguments to
 ;; `skip-chars-forward' and `skip-chars-backward'.
 ;;
-;; The exported functions for regexps are:
+;; The exported functions are:
 ;;
+;;  Regexps:
 ;;  `xr'   - returns the converted rx expression
 ;;  `xr-pp'- converts to rx and pretty-prints
 ;;  `xr-lint'  - finds mistakes in a regexp string
 ;;
-;; For skip sets we also have:
-;;
+;;  Skip sets:
 ;;  `xr-skip-set'  - return the converted rx expression
 ;;  `xr-skip-set-pp'   - converts to rx and pretty-prints
 ;;  `xr-skip-set-lint' - finds mistakes in a skip set string
 ;;
-;; There is finally the generally useful:
-;;
+;;  General:
 ;;  `xr-pp-rx-to-str' - pretty-prints an rx expression to a string
 ;;
-;; Suggested use is from an interactive elisp buffer.
-;;
 ;; Example (regexp found in compile.el):
 ;;
 ;;   (xr-pp "\\`\\(?:[^^]\\|\\^\\(?: \\*\\|\\[\\)\\)")
 ;; =>
 ;;   (seq bos
-;;(or
-;; (not (any "^"))
-;; (seq "^"
-;;  (or " *" "["
+;;(or (not (any "^"))
+;;(seq "^"
+;; (or " *" "["
 ;;
-;; The rx notation admits many synonyms; the xr functions mostly
-;; prefer brief variants, such as `seq' to `sequence' and `nonl' to
-;; `not-newline'.  The user is encouraged to edit the result for
-;; maximum readability, consistency and personal preference when
-;; replacing existing regexps in elisp code.
+;; The rx notation admits many synonyms. The user is encouraged to
+;; edit the result for maximum readability, consistency and personal
+;; preference when replacing existing regexps in elisp code.
 
 ;; Related work:
 ;;
 ;; The `lex' package, a lexical analyser generator, provides the
-;; `lex-parse-re' function which performs a similar task, but does not
-;; attempt to handle all the edge cases of Elisp's regexp syntax or
-;; pretty-print the result.
+;; `lex-parse-re' function which translates regexps to rx, but does
+;; not attempt to handle all the edge cases of Elisp's regexp syntax
+;; or pretty-print the result.
+;;
+;; The `pcre2el' package, a regexp syntax converter and interactive
+;; regexp explainer, could also be used for translating regexps to rx.
+;; `xr' is narrower in scope but more accurate for the purpose of
+;; parsing Emacs regexps and printing the results in rx form.
 ;;
-;; The `pcre2el' package, a regexp syntax converter and interactive regexp
-;; explainer, could also be used for the same tasks. `xr' is narrower in
-;; scope but more accurate for the purpose of parsing Emacs regexps and
-;; printing the results in rx form.
+;; Neither of these packages parse skip-set strings or provide
+;; mistake-finding functions.
 
 ;;; Code:
 
@@ -606,17 +603,15 @@
 
 ;; Grammar for skip-set strings:
 ;;
-;; skip-set ::= `^'? item*
+;; skip-set ::= `^'? item* dangling?
 ;; item ::= range | single
-;; range::= single `-' end
-;; single   ::= (any char but `\')
-;;| `\' (any char)
-;; end  ::= single | `\'
+;; range::= single `-' endpoint
+;; single   ::= {any char but `\'}
+;;| `\' {any char}
+;; endpoint ::= single | `\'
+;; dangling ::= `\'
 ;;
-;; The grammar is ambiguous, resolved left-to-right:
-;; - a leading ^ is always a negation marker
-;; - an item is always a range if possible
-;; - an end is only `\' if last in the string
+;; Ambiguities in the above are resolved greedily left-to-right.
 
 (defun xr--parse-skip-set-buffer (warnings)
   ;; An ad-hoc check, but one that catches lots of mistakes.



[elpa] externals/xr updated (a248977 -> 2136a7d)

2019-03-21 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  a248977   Parse and lint skip set strings
   new  f1afeff   Add check for `[...]'-framed skip sets
   new  d7325b3   Edit the package doc comment
   new  a948847   Don't complain about [z-a]
   new  51b1d81   More skip-set warnings
   new  2136a7d   Increment version to 1.9


Summary of changes:
 xr-test.el | 23 +++-
 xr.el  | 91 +-
 2 files changed, 71 insertions(+), 43 deletions(-)



[elpa] externals/xr 51b1d81 4/5: More skip-set warnings

2019-03-21 Thread Mattias Engdegrd
branch: externals/xr
commit 51b1d812498e14da24c9b76a82a2af2ceb7e3256
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

More skip-set warnings

Now complains about empty and negated empty sets, about single-
and two-char ranges, and about unnecessary escapes of range
endpoints (like "A-\\Z").
---
 xr-test.el | 17 -
 xr.el  | 22 +++---
 2 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index fd36db2..8948c2a 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -409,14 +409,21 @@
(3 . "Reversed range `F-A'")
(6 . "Single-element range `M-M'")
(9 . "Stray `\\' at end of string"
-  (should (equal (xr-skip-set-lint "A-Fa-z3D-K!3-7\\!b")
+  (should (equal (xr-skip-set-lint "A-Fa-z3D-KM-N!3-7\\!b")
  '((7 . "Ranges `A-F' and `D-K' overlap")
-   (11 . "Range `3-7' includes character `3'")
-   (14 . "Duplicated character `!'")
-   (14 . "Unnecessarily escaped `!'")
-   (16 . "Character `b' included in range `a-z'"
+   (10 . "Two-element range `M-N'")
+   (14 . "Range `3-7' includes character `3'")
+   (17 . "Duplicated character `!'")
+   (17 . "Unnecessarily escaped `!'")
+   (19 . "Character `b' included in range `a-z'"
+  (should (equal (xr-skip-set-lint "!-\\$")
+ '((2 . "Unnecessarily escaped `$'"
   (should (equal (xr-skip-set-lint "[^a-z]")
  '((0 . "Suspect skip set framed in `[...]'"
+  (should (equal (xr-skip-set-lint "")
+ '((0 . "Empty set matches nothing"
+  (should (equal (xr-skip-set-lint "^")
+ '((0 . "Negated empty set matches anything"
 )
 
 (provide 'xr-test)
diff --git a/xr.el b/xr.el
index e76b150..9ebf446 100644
--- a/xr.el
+++ b/xr.el
@@ -656,16 +656,26 @@
 (xr--report warnings (point)
 (xr--escape-string
  (format "Unnecessarily escaped `%c'" start) nil)))
+  (when (and (match-beginning 3)
+ (not (memq end '(?^ ?- ?\\
+(xr--report warnings (1- (match-beginning 3))
+(xr--escape-string
+ (format "Unnecessarily escaped `%c'" end) nil)))
   (if (and end (> start end))
   (xr--report warnings (point)
   (xr--escape-string
(format "Reversed range `%c-%c'" start end) nil))
-(when (eq start end)
+(cond
+ ((eq start end)
   (xr--report warnings (point)
   (xr--escape-string
(format "Single-element range `%c-%c'" start end)
-   nil))
-  (setq end nil))
+   nil)))
+ ((eq (1+ start) end)
+  (xr--report warnings (point)
+  (xr--escape-string
+   (format "Two-element range `%c-%c'" start end)
+   nil
 (let ((tail ranges))
   (while tail
 (let ((range (car tail)))
@@ -704,6 +714,12 @@
 
   (goto-char (match-end 0)))
 
+(when (and (null ranges) (null classes))
+  (xr--report warnings (point-min)
+  (if negated
+  "Negated empty set matches anything"
+"Empty set matches nothing")))
+
 (cond
  ;; Single non-negated character, like "-": make a string.
  ((and (not negated)



[elpa] reference refs/remotes/elpa/externals/xr created (now 7ba1fc6)

2019-02-12 Thread Mattias Engdegrd
mattiase pushed a change to reference refs/remotes/elpa/externals/xr.

at  7ba1fc6   * xr.el: Fix compilation and use valid email address

No new revisions were added by this update.



[elpa] reference refs/remotes/elpa/externals/xr deleted (was 7ba1fc6)

2019-02-12 Thread Mattias Engdegrd
mattiase pushed a change to reference refs/remotes/elpa/externals/xr.

   was  7ba1fc6   * xr.el: Fix compilation and use valid email address

The revisions that were on this reference are still contained in
other references; therefore, this change does not discard any commits
from the repository.



[elpa] externals/xr updated (7ba1fc6 -> e1c7734)

2019-02-13 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  7ba1fc6   * xr.el: Fix compilation and use valid email address
   new  8425772   Sync with ELPA: compilation workaround
   new  8532df8   Move tests to separate file
   new  2a1de75   Correct parsing of group and backref
   new  4bf6043   Export xr-pp-rx-to-str and fix a typo
   new  4e2bd17   Export xr-pp-rx-to-str and fix a typo
   new  37b2bcb   Merge branch 'master' of https://github.com/mattiase/xr
   new  e8ec2d9   Add reference to the pcre2el package
   new  c2ede95   Improved errors for bad \s and \c sequences
   new  8d052d6   Check for errors in \_
   new  0331e00   Recognise \sW as alias for \sw
   new  41474cb   Accept unknown character categories
   new  f79d50c   Add categories L, R, . and SPC
   new  e1c7734   Merge branch 'externals/xr' of elpa.git (no actual change)


Summary of changes:
 xr-test.el | 243 +++
 xr.el  | 270 +
 2 files changed, 297 insertions(+), 216 deletions(-)
 create mode 100644 xr-test.el



[elpa] externals/xr 8425772 01/13: Sync with ELPA: compilation workaround

2019-02-13 Thread Mattias Engdegrd
branch: externals/xr
commit 84257724a851a4cfd515f6c98dc840c437720b1c
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Sync with ELPA: compilation workaround
---
 xr.el | 21 +
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/xr.el b/xr.el
index 3c8e3d3..199f0e3 100644
--- a/xr.el
+++ b/xr.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2019 Free Software Foundation, Inc.
 
-;; Author: Mattias Engdegård 
+;; Author: Mattias Engdegård 
 ;; Version: 1.0
 ;; Keywords: lisp, maint, regexps
 
@@ -50,6 +50,10 @@
 ;; maximum readability, consistency and personal preference when
 ;; replacing existing regexps in elisp code.
 
+;; Similar functionality is provided by the `lex' package in the form of the
+;; `lex-parse-re' function, but `xr' does not depend on `lex' and does
+;; a more thorough job of handling all corner cases of Elisp's regexp syntax.
+
 ;;; Code:
 
 (require 'rx)
@@ -500,7 +504,18 @@ Returns nil."
   "Verify (xr--pp-rx-to-str RX) against EXPECTED-STR."
   (xr--expect-result 'xr--pp-rx-to-str rx expected-str))
 
+(provide 'xr)
+
 (eval-when-compile
+  ;; FIXME: When byte-compiling the file, this `eval-when-compile' block
+  ;; will be executed at a time where the above functions have been compiled
+  ;; but they're not necessarily known by the current Emacs session yet
+  ;; (because the neither `xr.el' nor `xr.elc' has been loaded yet).
+  ;; As a quick fix, we (require 'xr) here to load the `xr' file (and fail
+  ;; silently if the file is not in `load-path').
+  ;; Maybe a better fix is to move those tests to a separate file, and/or
+  ;; to wrap them in an `ert-deftest'.
+  (when (require 'xr nil 'noerror)
   (xr--expect "a\\$bc\\[\\]\\q"
   "a$b\\c[]q")
   (xr--expect "\\(?:ab\\|c*d\\)?"
@@ -660,8 +675,6 @@ Returns nil."
  "(?? nonl)\n")
   (xr--expect-pp '(repeat 1 63 "a")
  "(repeat 1 63 \"a\")\n")
-  )
-
-(provide 'xr)
+  ))
 
 ;;; xr.el ends here



[elpa] externals/xr e8ec2d9 07/13: Add reference to the pcre2el package

2019-02-13 Thread Mattias Engdegrd
branch: externals/xr
commit e8ec2d9d7a0e65aeb888da353b9d079285787c07
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add reference to the pcre2el package
---
 xr.el | 14 +++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/xr.el b/xr.el
index 761cac7..5a32a52 100644
--- a/xr.el
+++ b/xr.el
@@ -50,9 +50,17 @@
 ;; maximum readability, consistency and personal preference when
 ;; replacing existing regexps in elisp code.
 
-;; Similar functionality is provided by the `lex' package in the form of the
-;; `lex-parse-re' function, but `xr' does not depend on `lex' and does
-;; a more thorough job of handling all corner cases of Elisp's regexp syntax.
+;; Related work:
+;;
+;; The `lex' package, a lexical analyser generator, provides the
+;; `lex-parse-re' function which performs a similar task, but does not
+;; attempt to handle all the edge cases of Elisp's regexp syntax or
+;; pretty-print the result.
+;;
+;; The `pcre2el' package, a regexp syntax converter and interactive regexp
+;; explainer, could also be used for the same tasks. `xr' is narrower in
+;; scope but more accurate for the purpose of parsing Emacs regexps and
+;; printing the results in rx form.
 
 ;;; Code:
 



  1   2   3   4   >