summaryrefslogtreecommitdiffstats
path: root/lib.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-11-21 19:25:54 -0800
committerKaz Kylheku <kaz@kylheku.com>2017-11-21 19:25:54 -0800
commit68ddbfb634809be74722e9252993c6089a0c4d7a (patch)
tree7f324cecd2a447703d6548c678dc835d9198e5c1 /lib.c
parent368b33e560b541b20a9a28e6ba307a22a813049e (diff)
downloadtxr-68ddbfb634809be74722e9252993c6089a0c4d7a.tar.gz
txr-68ddbfb634809be74722e9252993c6089a0c4d7a.tar.bz2
txr-68ddbfb634809be74722e9252993c6089a0c4d7a.zip
bugfix: two issues in mappend* and append*.
Two bugs in these functions, both attributable to the lazy_appendv implementation: They destructively catenate the input lists, much like nconc, even though documented as non-destructive. If any input list is infinite, other than the last input list, that list is forced, resulting in an infinite loop. * lib.c (lazy_appendv_func): Rewritten to use a different algorithm which earnestly allocates a new lazy cons for each element of the output sequence, except for the tail part corresponding to the last list. (lazy_appendv): Set up the lazy cons according to the new representation and just return it. No searching for the tail of the nonempty list, and no destructive manipulation.
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c52
1 files changed, 23 insertions, 29 deletions
diff --git a/lib.c b/lib.c
index 18ba967f..97d0eece 100644
--- a/lib.c
+++ b/lib.c
@@ -1357,34 +1357,31 @@ val replace_list(val list, val items, val from, val to)
static val lazy_appendv_func(val env, val lcons)
{
- cons_bind (last, lists, env);
- val nonempty = nil;
-
- while (lists) {
- nonempty = nullify(pop(&lists));
- if (nonempty)
- break;
- }
+ cons_bind (fl, rl, env);
+ cons_bind (fe, re, fl);
- rplaca(lcons, last);
+ rplaca(lcons, fe);
- if (nilp(lists)) {
- rplacd(lcons, nonempty);
- return nil;
+ if (re) {
+ rplaca(env, re);
+ rplacd(lcons, make_lazy_cons(lcons_fun(lcons)));
+ } else if (rl) {
+ do {
+ fl = car(rl);
+ rl = cdr(rl);
+ } while (!fl && rl);
+
+ if (fl) {
+ if (rl) {
+ rplaca(env, fl);
+ rplacd(env, rl);
+ rplacd(lcons, make_lazy_cons(lcons_fun(lcons)));
+ } else {
+ rplacd(lcons, fl);
+ }
+ }
}
- if (atom(nonempty))
- uw_throwf(error_s, lit("append*: cannot append to atom ~s"),
- nonempty, nao);
-
- rplacd(env, lists);
-
- {
- loc ptail = ltail(mkcloc(nonempty));
- rplaca(env, car(deref(ptail)));
- set(ptail, make_lazy_cons(lcons_fun(lcons)));
- rplacd(lcons, nonempty);
- }
return nil;
}
@@ -1407,11 +1404,8 @@ val lazy_appendv(struct args *args)
nonempty, nao);
{
- loc ptail = ltail(mkcloc(nonempty));
- set(ptail, make_lazy_cons(func_f1(cons(car(deref(ptail)),
- args_get_rest(args, index)),
- lazy_appendv_func)));
- return nonempty;
+ return make_lazy_cons(func_f1(cons(nonempty, args_get_rest(args, index)),
+ lazy_appendv_func));
}
}