summaryrefslogtreecommitdiffstats
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
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.
-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));
}
}