diff options
| author | Joseph Turner | 2023-05-14 21:02:15 -0700 |
|---|---|---|
| committer | Eli Zaretskii | 2023-05-19 09:00:27 +0300 |
| commit | 3a1285caba9cd25abaddbc541e3217e2559d79ab (patch) | |
| tree | 5cfae8c27c61e780926d22fe1bb025ce9268ddf5 | |
| parent | 8c9377b6c4e907e65712fbf0ba0cf90f51da5ef6 (diff) | |
| download | emacs-3a1285caba9cd25abaddbc541e3217e2559d79ab.tar.gz emacs-3a1285caba9cd25abaddbc541e3217e2559d79ab.zip | |
Make 'copy-tree' work with records
* doc/lispref/lists.texi (Building Cons Cells and Lists): Document
new behavior of 'copy-tree'.
* doc/lispref/records.texi (Record Functions): Cross-reference to
lists.texi.
* etc/NEWS: Mention change. (Bug#63509)
* lisp/emacs-lisp/shortdoc.el: Add 'copy-tree' example to vector
group.
* lisp/subr.el (copy-tree): Recurse into records as well as
vectors when optional second argument is non-nil. Rename second
argument from VECP to VECTOR-LIKE-P.
* test/lisp/subr-tests.el: Test new behavior.
| -rw-r--r-- | doc/lispref/lists.texi | 9 | ||||
| -rw-r--r-- | doc/lispref/records.texi | 3 | ||||
| -rw-r--r-- | etc/NEWS | 3 | ||||
| -rw-r--r-- | lisp/emacs-lisp/shortdoc.el | 2 | ||||
| -rw-r--r-- | lisp/subr.el | 14 | ||||
| -rw-r--r-- | test/lisp/subr-tests.el | 31 |
6 files changed, 51 insertions, 11 deletions
diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index 22a5f7f1239..16ed0358974 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi | |||
| @@ -696,16 +696,17 @@ not a list, the sequence's elements do not become elements of the | |||
| 696 | resulting list. Instead, the sequence becomes the final @sc{cdr}, like | 696 | resulting list. Instead, the sequence becomes the final @sc{cdr}, like |
| 697 | any other non-list final argument. | 697 | any other non-list final argument. |
| 698 | 698 | ||
| 699 | @defun copy-tree tree &optional vecp | 699 | @defun copy-tree tree &optional vector-like-p |
| 700 | This function returns a copy of the tree @var{tree}. If @var{tree} is a | 700 | This function returns a copy of the tree @var{tree}. If @var{tree} is a |
| 701 | cons cell, this makes a new cons cell with the same @sc{car} and | 701 | cons cell, this makes a new cons cell with the same @sc{car} and |
| 702 | @sc{cdr}, then recursively copies the @sc{car} and @sc{cdr} in the | 702 | @sc{cdr}, then recursively copies the @sc{car} and @sc{cdr} in the |
| 703 | same way. | 703 | same way. |
| 704 | 704 | ||
| 705 | Normally, when @var{tree} is anything other than a cons cell, | 705 | Normally, when @var{tree} is anything other than a cons cell, |
| 706 | @code{copy-tree} simply returns @var{tree}. However, if @var{vecp} is | 706 | @code{copy-tree} simply returns @var{tree}. However, if |
| 707 | non-@code{nil}, it copies vectors too (and operates recursively on | 707 | @var{vector-like-p} is non-@code{nil}, it copies vectors and records |
| 708 | their elements). This function cannot cope with circular lists. | 708 | too (and operates recursively on their elements). This function |
| 709 | cannot cope with circular lists. | ||
| 709 | @end defun | 710 | @end defun |
| 710 | 711 | ||
| 711 | @defun flatten-tree tree | 712 | @defun flatten-tree tree |
diff --git a/doc/lispref/records.texi b/doc/lispref/records.texi index 26c6f30a6b5..d2c80a27f98 100644 --- a/doc/lispref/records.texi +++ b/doc/lispref/records.texi | |||
| @@ -81,6 +81,9 @@ This function returns a new record with type @var{type} and | |||
| 81 | @end example | 81 | @end example |
| 82 | @end defun | 82 | @end defun |
| 83 | 83 | ||
| 84 | @code{copy-tree} works with records when its optional second argument | ||
| 85 | is non-@code{nil} (@pxref{Building Lists}). | ||
| 86 | |||
| 84 | @node Backward Compatibility | 87 | @node Backward Compatibility |
| 85 | @section Backward Compatibility | 88 | @section Backward Compatibility |
| 86 | 89 | ||
| @@ -585,6 +585,9 @@ Since circular alias chains now cannot occur, 'function-alias-p', | |||
| 585 | 'indirect-function' and 'indirect-variable' will never signal an error. | 585 | 'indirect-function' and 'indirect-variable' will never signal an error. |
| 586 | Their 'noerror' arguments have no effect and are therefore obsolete. | 586 | Their 'noerror' arguments have no effect and are therefore obsolete. |
| 587 | 587 | ||
| 588 | +++ | ||
| 589 | ** 'copy-tree' now copies records when its optional argument is non-nil. | ||
| 590 | |||
| 588 | 591 | ||
| 589 | * Changes in Emacs 30.1 on Non-Free Operating Systems | 592 | * Changes in Emacs 30.1 on Non-Free Operating Systems |
| 590 | 593 | ||
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index 9a6f5dd12ce..6580e0e4e0c 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el | |||
| @@ -833,6 +833,8 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'), | |||
| 833 | (seq-subseq | 833 | (seq-subseq |
| 834 | :eval (seq-subseq [1 2 3 4 5] 1 3) | 834 | :eval (seq-subseq [1 2 3 4 5] 1 3) |
| 835 | :eval (seq-subseq [1 2 3 4 5] 1)) | 835 | :eval (seq-subseq [1 2 3 4 5] 1)) |
| 836 | (copy-tree | ||
| 837 | :eval (copy-tree [1 2 3 4])) | ||
| 836 | "Mapping Over Vectors" | 838 | "Mapping Over Vectors" |
| 837 | (mapcar | 839 | (mapcar |
| 838 | :eval (mapcar #'identity [1 2 3])) | 840 | :eval (mapcar #'identity [1 2 3])) |
diff --git a/lisp/subr.el b/lisp/subr.el index 03d3324f3d8..83735933963 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -824,26 +824,26 @@ of course, also replace TO with a slightly larger value | |||
| 824 | next (+ from (* n inc))))) | 824 | next (+ from (* n inc))))) |
| 825 | (nreverse seq)))) | 825 | (nreverse seq)))) |
| 826 | 826 | ||
| 827 | (defun copy-tree (tree &optional vecp) | 827 | (defun copy-tree (tree &optional vector-like-p) |
| 828 | "Make a copy of TREE. | 828 | "Make a copy of TREE. |
| 829 | If TREE is a cons cell, this recursively copies both its car and its cdr. | 829 | If TREE is a cons cell, this recursively copies both its car and its cdr. |
| 830 | Contrast to `copy-sequence', which copies only along the cdrs. With second | 830 | Contrast to `copy-sequence', which copies only along the cdrs. With second |
| 831 | argument VECP, this copies vectors as well as conses." | 831 | argument VECTOR-LIKE-P, this copies vectors and records as well as conses." |
| 832 | (declare (side-effect-free error-free)) | 832 | (declare (side-effect-free error-free)) |
| 833 | (if (consp tree) | 833 | (if (consp tree) |
| 834 | (let (result) | 834 | (let (result) |
| 835 | (while (consp tree) | 835 | (while (consp tree) |
| 836 | (let ((newcar (car tree))) | 836 | (let ((newcar (car tree))) |
| 837 | (if (or (consp (car tree)) (and vecp (vectorp (car tree)))) | 837 | (if (or (consp (car tree)) (and vector-like-p (or (vectorp (car tree)) (recordp (car tree))))) |
| 838 | (setq newcar (copy-tree (car tree) vecp))) | 838 | (setq newcar (copy-tree (car tree) vector-like-p))) |
| 839 | (push newcar result)) | 839 | (push newcar result)) |
| 840 | (setq tree (cdr tree))) | 840 | (setq tree (cdr tree))) |
| 841 | (nconc (nreverse result) | 841 | (nconc (nreverse result) |
| 842 | (if (and vecp (vectorp tree)) (copy-tree tree vecp) tree))) | 842 | (if (and vector-like-p (or (vectorp tree) (recordp tree))) (copy-tree tree vector-like-p) tree))) |
| 843 | (if (and vecp (vectorp tree)) | 843 | (if (and vector-like-p (or (vectorp tree) (recordp tree))) |
| 844 | (let ((i (length (setq tree (copy-sequence tree))))) | 844 | (let ((i (length (setq tree (copy-sequence tree))))) |
| 845 | (while (>= (setq i (1- i)) 0) | 845 | (while (>= (setq i (1- i)) 0) |
| 846 | (aset tree i (copy-tree (aref tree i) vecp))) | 846 | (aset tree i (copy-tree (aref tree i) vector-like-p))) |
| 847 | tree) | 847 | tree) |
| 848 | tree))) | 848 | tree))) |
| 849 | 849 | ||
diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el index 8f46c2af136..4ebb68556be 100644 --- a/test/lisp/subr-tests.el +++ b/test/lisp/subr-tests.el | |||
| @@ -1206,5 +1206,36 @@ final or penultimate step during initialization.")) | |||
| 1206 | (should (equal a-dedup '("a" "b" "a" "b" "c"))) | 1206 | (should (equal a-dedup '("a" "b" "a" "b" "c"))) |
| 1207 | (should (eq a a-dedup)))) | 1207 | (should (eq a a-dedup)))) |
| 1208 | 1208 | ||
| 1209 | (ert-deftest subr--copy-tree () | ||
| 1210 | (should (eq (copy-tree nil) nil)) | ||
| 1211 | (let* ((a (list (list "a") "b" (list "c") "g")) | ||
| 1212 | (copy1 (copy-tree a)) | ||
| 1213 | (copy2 (copy-tree a t))) | ||
| 1214 | (should (equal a copy1)) | ||
| 1215 | (should (equal a copy2)) | ||
| 1216 | (should-not (eq a copy1)) | ||
| 1217 | (should-not (eq a copy2))) | ||
| 1218 | (let* ((a (list (list "a") "b" (list "c" (record 'foo "d")) (list ["e" "f"]) "g")) | ||
| 1219 | (copy1 (copy-tree a)) | ||
| 1220 | (copy2 (copy-tree a t))) | ||
| 1221 | (should (equal a copy1)) | ||
| 1222 | (should (equal a copy2)) | ||
| 1223 | (should-not (eq a copy1)) | ||
| 1224 | (should-not (eq a copy2))) | ||
| 1225 | (let* ((a (record 'foo "a" (record 'bar "b"))) | ||
| 1226 | (copy1 (copy-tree a)) | ||
| 1227 | (copy2 (copy-tree a t))) | ||
| 1228 | (should (equal a copy1)) | ||
| 1229 | (should (equal a copy2)) | ||
| 1230 | (should (eq a copy1)) | ||
| 1231 | (should-not (eq a copy2))) | ||
| 1232 | (let* ((a ["a" "b" ["c" ["d"]]]) | ||
| 1233 | (copy1 (copy-tree a)) | ||
| 1234 | (copy2 (copy-tree a t))) | ||
| 1235 | (should (equal a copy1)) | ||
| 1236 | (should (equal a copy2)) | ||
| 1237 | (should (eq a copy1)) | ||
| 1238 | (should-not (eq a copy2)))) | ||
| 1239 | |||
| 1209 | (provide 'subr-tests) | 1240 | (provide 'subr-tests) |
| 1210 | ;;; subr-tests.el ends here | 1241 | ;;; subr-tests.el ends here |