aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorBasil L. Contovounesios2018-07-09 18:46:33 -0700
committerPaul Eggert2018-07-09 19:00:43 -0700
commit2fde6275b69fd113e78243790bf112bbdd2fe2bf (patch)
treef28a04fdabc51d275689066b41b9149422d9f3cb /lisp
parente4ad2d1a8fad8c8c786b61083b05cfaa1ea5669c (diff)
downloademacs-2fde6275b69fd113e78243790bf112bbdd2fe2bf.tar.gz
emacs-2fde6275b69fd113e78243790bf112bbdd2fe2bf.zip
Add predicate proper-list-p
For discussion, see emacs-devel thread starting at https://lists.gnu.org/archive/html/emacs-devel/2018-04/msg00460.html. * lisp/subr.el (proper-list-p): New function. Implementation suggested by Paul Eggert <eggert@cs.ucla.edu> in https://lists.gnu.org/archive/html/emacs-devel/2018-06/msg00138.html. * doc/lispref/lists.texi (List Elements): * etc/NEWS: Document proper-list-p. * lisp/org/ob-core.el (org-babel-insert-result): * lisp/emacs-lisp/byte-opt.el (byte-optimize-if): * lisp/emacs-lisp/cl-macs.el (cl--make-usage-args): Use proper-list-p. * lisp/emacs-lisp/ert.el (ert--proper-list-p): Remove. Replaced by proper-list-p in lisp/subr.el. (ert--explain-equal-rec): Use proper-list-length. * lisp/format.el (format-proper-list-p): Remove. Replaced by proper-list-p in lisp/subr.el. (format-annotate-single-property-change): Use proper-list-p. * test/lisp/emacs-lisp/ert-tests.el (ert-test-proper-list-p): Move from here... * test/lisp/subr-tests.el (subr-tests--proper-list-length): ...to here, mutatis mutandis.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/emacs-lisp/byte-opt.el3
-rw-r--r--lisp/emacs-lisp/cl-macs.el2
-rw-r--r--lisp/emacs-lisp/ert.el28
-rw-r--r--lisp/format.el12
-rw-r--r--lisp/org/ob-core.el5
-rw-r--r--lisp/subr.el6
6 files changed, 20 insertions, 36 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 3bc4c438d6a..5c0b5e340bb 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -982,8 +982,7 @@
982 ;; (if <test> <then> nil) ==> (if <test> <then>) 982 ;; (if <test> <then> nil) ==> (if <test> <then>)
983 (let ((clause (nth 1 form))) 983 (let ((clause (nth 1 form)))
984 (cond ((and (eq (car-safe clause) 'progn) 984 (cond ((and (eq (car-safe clause) 'progn)
985 ;; `clause' is a proper list. 985 (proper-list-p clause))
986 (null (cdr (last clause))))
987 (if (null (cddr clause)) 986 (if (null (cddr clause))
988 ;; A trivial `progn'. 987 ;; A trivial `progn'.
989 (byte-optimize-if `(if ,(cadr clause) ,@(nthcdr 2 form))) 988 (byte-optimize-if `(if ,(cadr clause) ,@(nthcdr 2 form)))
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index b50961adac9..011965acb54 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -498,7 +498,7 @@ its argument list allows full Common Lisp conventions."
498 ;; `&aux' args aren't arguments, so let's just drop them from the 498 ;; `&aux' args aren't arguments, so let's just drop them from the
499 ;; usage info. 499 ;; usage info.
500 (setq arglist (cl-subseq arglist 0 aux)))) 500 (setq arglist (cl-subseq arglist 0 aux))))
501 (if (cdr-safe (last arglist)) ;Not a proper list. 501 (if (not (proper-list-p arglist))
502 (let* ((last (last arglist)) 502 (let* ((last (last arglist))
503 (tail (cdr last))) 503 (tail (cdr last)))
504 (unwind-protect 504 (unwind-protect
diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el
index 32bb367cdb3..cad21044f15 100644
--- a/lisp/emacs-lisp/ert.el
+++ b/lisp/emacs-lisp/ert.el
@@ -472,18 +472,6 @@ Errors during evaluation are caught and handled like nil."
472;; buffer. Perhaps explanations should be reported through `ert-info' 472;; buffer. Perhaps explanations should be reported through `ert-info'
473;; rather than as part of the condition. 473;; rather than as part of the condition.
474 474
475(defun ert--proper-list-p (x)
476 "Return non-nil if X is a proper list, nil otherwise."
477 (cl-loop
478 for firstp = t then nil
479 for fast = x then (cddr fast)
480 for slow = x then (cdr slow) do
481 (when (null fast) (cl-return t))
482 (when (not (consp fast)) (cl-return nil))
483 (when (null (cdr fast)) (cl-return t))
484 (when (not (consp (cdr fast))) (cl-return nil))
485 (when (and (not firstp) (eq fast slow)) (cl-return nil))))
486
487(defun ert--explain-format-atom (x) 475(defun ert--explain-format-atom (x)
488 "Format the atom X for `ert--explain-equal'." 476 "Format the atom X for `ert--explain-equal'."
489 (pcase x 477 (pcase x
@@ -494,17 +482,17 @@ Errors during evaluation are caught and handled like nil."
494(defun ert--explain-equal-rec (a b) 482(defun ert--explain-equal-rec (a b)
495 "Return a programmer-readable explanation of why A and B are not `equal'. 483 "Return a programmer-readable explanation of why A and B are not `equal'.
496Returns nil if they are." 484Returns nil if they are."
497 (if (not (equal (type-of a) (type-of b))) 485 (if (not (eq (type-of a) (type-of b)))
498 `(different-types ,a ,b) 486 `(different-types ,a ,b)
499 (pcase-exhaustive a 487 (pcase-exhaustive a
500 ((pred consp) 488 ((pred consp)
501 (let ((a-proper-p (ert--proper-list-p a)) 489 (let ((a-length (proper-list-p a))
502 (b-proper-p (ert--proper-list-p b))) 490 (b-length (proper-list-p b)))
503 (if (not (eql (not a-proper-p) (not b-proper-p))) 491 (if (not (eq (not a-length) (not b-length)))
504 `(one-list-proper-one-improper ,a ,b) 492 `(one-list-proper-one-improper ,a ,b)
505 (if a-proper-p 493 (if a-length
506 (if (not (equal (length a) (length b))) 494 (if (/= a-length b-length)
507 `(proper-lists-of-different-length ,(length a) ,(length b) 495 `(proper-lists-of-different-length ,a-length ,b-length
508 ,a ,b 496 ,a ,b
509 first-mismatch-at 497 first-mismatch-at
510 ,(cl-mismatch a b :test 'equal)) 498 ,(cl-mismatch a b :test 'equal))
@@ -523,7 +511,7 @@ Returns nil if they are."
523 (cl-assert (equal a b) t) 511 (cl-assert (equal a b) t)
524 nil)))))))) 512 nil))))))))
525 ((pred arrayp) 513 ((pred arrayp)
526 (if (not (equal (length a) (length b))) 514 (if (/= (length a) (length b))
527 `(arrays-of-different-length ,(length a) ,(length b) 515 `(arrays-of-different-length ,(length a) ,(length b)
528 ,a ,b 516 ,a ,b
529 ,@(unless (char-table-p a) 517 ,@(unless (char-table-p a)
diff --git a/lisp/format.el b/lisp/format.el
index 2f198e3eb71..1222abbf658 100644
--- a/lisp/format.el
+++ b/lisp/format.el
@@ -539,14 +539,6 @@ Compare using `equal'."
539 (setq tail next))) 539 (setq tail next)))
540 (cons acopy bcopy))) 540 (cons acopy bcopy)))
541 541
542(defun format-proper-list-p (list)
543 "Return t if LIST is a proper list.
544A proper list is a list ending with a nil cdr, not with an atom "
545 (when (listp list)
546 (while (consp list)
547 (setq list (cdr list)))
548 (null list)))
549
550(defun format-reorder (items order) 542(defun format-reorder (items order)
551 "Arrange ITEMS to follow partial ORDER. 543 "Arrange ITEMS to follow partial ORDER.
552Elements of ITEMS equal to elements of ORDER will be rearranged 544Elements of ITEMS equal to elements of ORDER will be rearranged
@@ -1005,8 +997,8 @@ either strings, or lists of the form (PARAMETER VALUE)."
1005 ;; If either old or new is a list, have to treat both that way. 997 ;; If either old or new is a list, have to treat both that way.
1006 (if (and (or (listp old) (listp new)) 998 (if (and (or (listp old) (listp new))
1007 (not (get prop 'format-list-atomic-p))) 999 (not (get prop 'format-list-atomic-p)))
1008 (if (or (not (format-proper-list-p old)) 1000 (if (not (and (proper-list-p old)
1009 (not (format-proper-list-p new))) 1001 (proper-list-p new)))
1010 (format-annotate-atomic-property-change prop-alist old new) 1002 (format-annotate-atomic-property-change prop-alist old new)
1011 (let* ((old (if (listp old) old (list old))) 1003 (let* ((old (if (listp old) old (list old)))
1012 (new (if (listp new) new (list new))) 1004 (new (if (listp new) new (list new)))
diff --git a/lisp/org/ob-core.el b/lisp/org/ob-core.el
index 5d5faaa6fd0..a5449fe35e9 100644
--- a/lisp/org/ob-core.el
+++ b/lisp/org/ob-core.el
@@ -2310,10 +2310,9 @@ INFO may provide the values of these header arguments (in the
2310 (lambda (r) 2310 (lambda (r)
2311 ;; Non-nil when result R can be turned into 2311 ;; Non-nil when result R can be turned into
2312 ;; a table. 2312 ;; a table.
2313 (and (listp r) 2313 (and (proper-list-p r)
2314 (null (cdr (last r)))
2315 (cl-every 2314 (cl-every
2316 (lambda (e) (or (atom e) (null (cdr (last e))))) 2315 (lambda (e) (or (atom e) (proper-list-p e)))
2317 result))))) 2316 result)))))
2318 ;; insert results based on type 2317 ;; insert results based on type
2319 (cond 2318 (cond
diff --git a/lisp/subr.el b/lisp/subr.el
index ca184d8fc81..c1d90e3fb18 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -555,6 +555,12 @@ If N is omitted or nil, remove the last element."
555 (declare (compiler-macro (lambda (_) `(= 0 ,number)))) 555 (declare (compiler-macro (lambda (_) `(= 0 ,number))))
556 (= 0 number)) 556 (= 0 number))
557 557
558(defun proper-list-p (object)
559 "Return OBJECT's length if it is a proper list, nil otherwise.
560A proper list is neither circular nor dotted (i.e., its last cdr
561is nil)."
562 (and (listp object) (ignore-errors (length object))))
563
558(defun delete-dups (list) 564(defun delete-dups (list)
559 "Destructively remove `equal' duplicates from LIST. 565 "Destructively remove `equal' duplicates from LIST.
560Store the result in LIST and return it. LIST must be a proper list. 566Store the result in LIST and return it. LIST must be a proper list.