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.
This commit is contained in:
parent
8c9377b6c4
commit
3a1285caba
6 changed files with 51 additions and 11 deletions
|
@ -696,16 +696,17 @@ not a list, the sequence's elements do not become elements of the
|
|||
resulting list. Instead, the sequence becomes the final @sc{cdr}, like
|
||||
any other non-list final argument.
|
||||
|
||||
@defun copy-tree tree &optional vecp
|
||||
@defun copy-tree tree &optional vector-like-p
|
||||
This function returns a copy of the tree @var{tree}. If @var{tree} is a
|
||||
cons cell, this makes a new cons cell with the same @sc{car} and
|
||||
@sc{cdr}, then recursively copies the @sc{car} and @sc{cdr} in the
|
||||
same way.
|
||||
|
||||
Normally, when @var{tree} is anything other than a cons cell,
|
||||
@code{copy-tree} simply returns @var{tree}. However, if @var{vecp} is
|
||||
non-@code{nil}, it copies vectors too (and operates recursively on
|
||||
their elements). This function cannot cope with circular lists.
|
||||
@code{copy-tree} simply returns @var{tree}. However, if
|
||||
@var{vector-like-p} is non-@code{nil}, it copies vectors and records
|
||||
too (and operates recursively on their elements). This function
|
||||
cannot cope with circular lists.
|
||||
@end defun
|
||||
|
||||
@defun flatten-tree tree
|
||||
|
|
|
@ -81,6 +81,9 @@ This function returns a new record with type @var{type} and
|
|||
@end example
|
||||
@end defun
|
||||
|
||||
@code{copy-tree} works with records when its optional second argument
|
||||
is non-@code{nil} (@pxref{Building Lists}).
|
||||
|
||||
@node Backward Compatibility
|
||||
@section Backward Compatibility
|
||||
|
||||
|
|
3
etc/NEWS
3
etc/NEWS
|
@ -585,6 +585,9 @@ Since circular alias chains now cannot occur, 'function-alias-p',
|
|||
'indirect-function' and 'indirect-variable' will never signal an error.
|
||||
Their 'noerror' arguments have no effect and are therefore obsolete.
|
||||
|
||||
+++
|
||||
** 'copy-tree' now copies records when its optional argument is non-nil.
|
||||
|
||||
|
||||
* Changes in Emacs 30.1 on Non-Free Operating Systems
|
||||
|
||||
|
|
|
@ -833,6 +833,8 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'),
|
|||
(seq-subseq
|
||||
:eval (seq-subseq [1 2 3 4 5] 1 3)
|
||||
:eval (seq-subseq [1 2 3 4 5] 1))
|
||||
(copy-tree
|
||||
:eval (copy-tree [1 2 3 4]))
|
||||
"Mapping Over Vectors"
|
||||
(mapcar
|
||||
:eval (mapcar #'identity [1 2 3]))
|
||||
|
|
14
lisp/subr.el
14
lisp/subr.el
|
@ -824,26 +824,26 @@ of course, also replace TO with a slightly larger value
|
|||
next (+ from (* n inc)))))
|
||||
(nreverse seq))))
|
||||
|
||||
(defun copy-tree (tree &optional vecp)
|
||||
(defun copy-tree (tree &optional vector-like-p)
|
||||
"Make a copy of TREE.
|
||||
If TREE is a cons cell, this recursively copies both its car and its cdr.
|
||||
Contrast to `copy-sequence', which copies only along the cdrs. With second
|
||||
argument VECP, this copies vectors as well as conses."
|
||||
argument VECTOR-LIKE-P, this copies vectors and records as well as conses."
|
||||
(declare (side-effect-free error-free))
|
||||
(if (consp tree)
|
||||
(let (result)
|
||||
(while (consp tree)
|
||||
(let ((newcar (car tree)))
|
||||
(if (or (consp (car tree)) (and vecp (vectorp (car tree))))
|
||||
(setq newcar (copy-tree (car tree) vecp)))
|
||||
(if (or (consp (car tree)) (and vector-like-p (or (vectorp (car tree)) (recordp (car tree)))))
|
||||
(setq newcar (copy-tree (car tree) vector-like-p)))
|
||||
(push newcar result))
|
||||
(setq tree (cdr tree)))
|
||||
(nconc (nreverse result)
|
||||
(if (and vecp (vectorp tree)) (copy-tree tree vecp) tree)))
|
||||
(if (and vecp (vectorp tree))
|
||||
(if (and vector-like-p (or (vectorp tree) (recordp tree))) (copy-tree tree vector-like-p) tree)))
|
||||
(if (and vector-like-p (or (vectorp tree) (recordp tree)))
|
||||
(let ((i (length (setq tree (copy-sequence tree)))))
|
||||
(while (>= (setq i (1- i)) 0)
|
||||
(aset tree i (copy-tree (aref tree i) vecp)))
|
||||
(aset tree i (copy-tree (aref tree i) vector-like-p)))
|
||||
tree)
|
||||
tree)))
|
||||
|
||||
|
|
|
@ -1206,5 +1206,36 @@ final or penultimate step during initialization."))
|
|||
(should (equal a-dedup '("a" "b" "a" "b" "c")))
|
||||
(should (eq a a-dedup))))
|
||||
|
||||
(ert-deftest subr--copy-tree ()
|
||||
(should (eq (copy-tree nil) nil))
|
||||
(let* ((a (list (list "a") "b" (list "c") "g"))
|
||||
(copy1 (copy-tree a))
|
||||
(copy2 (copy-tree a t)))
|
||||
(should (equal a copy1))
|
||||
(should (equal a copy2))
|
||||
(should-not (eq a copy1))
|
||||
(should-not (eq a copy2)))
|
||||
(let* ((a (list (list "a") "b" (list "c" (record 'foo "d")) (list ["e" "f"]) "g"))
|
||||
(copy1 (copy-tree a))
|
||||
(copy2 (copy-tree a t)))
|
||||
(should (equal a copy1))
|
||||
(should (equal a copy2))
|
||||
(should-not (eq a copy1))
|
||||
(should-not (eq a copy2)))
|
||||
(let* ((a (record 'foo "a" (record 'bar "b")))
|
||||
(copy1 (copy-tree a))
|
||||
(copy2 (copy-tree a t)))
|
||||
(should (equal a copy1))
|
||||
(should (equal a copy2))
|
||||
(should (eq a copy1))
|
||||
(should-not (eq a copy2)))
|
||||
(let* ((a ["a" "b" ["c" ["d"]]])
|
||||
(copy1 (copy-tree a))
|
||||
(copy2 (copy-tree a t)))
|
||||
(should (equal a copy1))
|
||||
(should (equal a copy2))
|
||||
(should (eq a copy1))
|
||||
(should-not (eq a copy2))))
|
||||
|
||||
(provide 'subr-tests)
|
||||
;;; subr-tests.el ends here
|
||||
|
|
Loading…
Add table
Reference in a new issue