aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoseph Turner2023-05-14 21:02:15 -0700
committerEli Zaretskii2023-05-19 09:00:27 +0300
commit3a1285caba9cd25abaddbc541e3217e2559d79ab (patch)
tree5cfae8c27c61e780926d22fe1bb025ce9268ddf5
parent8c9377b6c4e907e65712fbf0ba0cf90f51da5ef6 (diff)
downloademacs-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.texi9
-rw-r--r--doc/lispref/records.texi3
-rw-r--r--etc/NEWS3
-rw-r--r--lisp/emacs-lisp/shortdoc.el2
-rw-r--r--lisp/subr.el14
-rw-r--r--test/lisp/subr-tests.el31
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
696resulting list. Instead, the sequence becomes the final @sc{cdr}, like 696resulting list. Instead, the sequence becomes the final @sc{cdr}, like
697any other non-list final argument. 697any other non-list final argument.
698 698
699@defun copy-tree tree &optional vecp 699@defun copy-tree tree &optional vector-like-p
700This function returns a copy of the tree @var{tree}. If @var{tree} is a 700This function returns a copy of the tree @var{tree}. If @var{tree} is a
701cons cell, this makes a new cons cell with the same @sc{car} and 701cons 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
703same way. 703same way.
704 704
705Normally, when @var{tree} is anything other than a cons cell, 705Normally, 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
707non-@code{nil}, it copies vectors too (and operates recursively on 707@var{vector-like-p} is non-@code{nil}, it copies vectors and records
708their elements). This function cannot cope with circular lists. 708too (and operates recursively on their elements). This function
709cannot 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
85is 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
diff --git a/etc/NEWS b/etc/NEWS
index ce865c9904d..c5063a718b9 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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.
586Their 'noerror' arguments have no effect and are therefore obsolete. 586Their '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.
829If TREE is a cons cell, this recursively copies both its car and its cdr. 829If TREE is a cons cell, this recursively copies both its car and its cdr.
830Contrast to `copy-sequence', which copies only along the cdrs. With second 830Contrast to `copy-sequence', which copies only along the cdrs. With second
831argument VECP, this copies vectors as well as conses." 831argument 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