diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-09-03 23:30:22 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-09-03 23:30:22 -0700 |
commit | 8fdc890bfaae2df85d5437d9ae495c45a54645c4 (patch) | |
tree | 30c09d3692d075ec9de3d5923145d9308b3f2158 | |
parent | 1777ba3dc87c62cf18cd178f2055369979907dc8 (diff) | |
download | txr-8fdc890bfaae2df85d5437d9ae495c45a54645c4.tar.gz txr-8fdc890bfaae2df85d5437d9ae495c45a54645c4.tar.bz2 txr-8fdc890bfaae2df85d5437d9ae495c45a54645c4.zip |
list-builder: bugfix: broken self-appending.
The list builder is failing on the documented example
(build
(add 1 2)
(pend (get))
(pend (get)))
-> (1 2 1 2 1 2 1 2)
wrongly constructing an infinite list.
* share/txr/stdlib/build.tl (list-builder pend): When
destructively appending the next argument, check whether
the current tail is a tail of that object. If so, copy
the object to prevent a cycle from forming.
(list-builder pend*): When appending the old head to the
catenated list, do the tail check and copy the object if
necessary to prevent the creation of a cycle.
-rw-r--r-- | share/txr/stdlib/build.tl | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/share/txr/stdlib/build.tl b/share/txr/stdlib/build.tl index 32df083d..a5960578 100644 --- a/share/txr/stdlib/build.tl +++ b/share/txr/stdlib/build.tl @@ -51,22 +51,25 @@ (while lists (usr:rplacd tl (copy (cdr tl))) (set tl (last tl)) - (usr:rplacd tl (car lists)) + (let ((nx (car lists))) + (usr:rplacd tl (if (tailp tl nx) + (copy nx) + nx))) (set lists (cdr lists))) (set self.tail tl)) nil) (:method pend* (self . lists) - (let* ((h self.head) + (let* ((h (cdr self.head)) (nh (cons nil nil)) (tl nh)) (while lists - (usr:rplacd tl (copy tl)) + (usr:rplacd tl (copy (cdr tl))) (set tl (last tl)) (usr:rplacd tl (car lists)) (set lists (cdr lists))) (set tl (last tl)) - (usr:rplacd tl (cdr h)) + (usr:rplacd tl (if (tailp tl h) (copy h) h)) (set self.head nh)) nil) |