From 57f625f68909a4420e5621a2f40717427ecf63e2 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Fri, 23 Sep 2016 21:33:01 -0700 Subject: Bugfix: out-of-range negative indices into lists. We have a problem not handling negative list indices which index beyond the beginning of the list. Such accesses are just storing and retrieving the first element! * lib.c (listref): If a negative index is still negative after the length of the list is added to it, then return nil. Do not return car(list)! (listref_l): Similary, do not return car_l(list) if the index is less than zero, so that an error occurs for an out-of-range negative index. * txr.1: Update the documentation for ref to describe these indexing constraints, and also to include hashes. --- lib.c | 7 +++++-- txr.1 | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/lib.c b/lib.c index 47b028cf..85ff5d33 100644 --- a/lib.c +++ b/lib.c @@ -520,8 +520,11 @@ val lazy_conses(val list) val listref(val list, val ind) { gc_hint(list); - if (lt(ind, zero)) + if (lt(ind, zero)) { ind = plus(ind, length_list(list)); + if (lt(ind, zero)) + return nil; + } for (; gt(ind, zero); ind = minus(ind, one)) list = cdr(list); return car(list); @@ -537,7 +540,7 @@ loc listref_l(val list, val ind) for (; gt(ind, zero) && list; ind = minus(ind, one)) list = cdr(list); - if (consp(list)) + if (ge(ind, zero) && consp(list)) return car_l(list); uw_throwf(error_s, lit("~s has no assignable location at ~s"), diff --git a/txr.1 b/txr.1 index a47e776f..55be9bbc 100644 --- a/txr.1 +++ b/txr.1 @@ -22433,6 +22433,13 @@ The and .code refset functions perform array-like indexing into sequences. +If the +.meta seq +parameter is a hash, then these functions perform +has retrieval and storage; in that case +.meta index +isn't restricted to an integer value. + The .code ref function retrieves an element of @@ -22444,17 +22451,42 @@ element of .meta seq with a new value. -The +If +.meta seq +is a sequence then .meta index -argument is based from zero, and negative values are permitted, -with a special meaning as described in the Range Indexing section under the +argument must be an integer. The first element of the sequence +is indexed by zero. Negative values are permitted, +denoting backward indexing from the end of the sequence, such that +the last element is indexed by -1, the second last by -2 and so on. +See also the Range Indexing section under the description of the .code dwim operator. +If +.meta seq +is a list, then out-of-range indices, whether positive or negative, +are treated leniently by +.codn ref : +such accesses produce the value +.codn nil , +rather than an error. For other sequence types, such accesses +are erroneous. For hashes, accesses to nonexistent elements +are treated leniently, and produce +.codn nil . + The .code refset -function returns the new value. +function is strict for out-of-range indices over all sequences, +including lists. In the case of hashes, a +.code refset +of a nonexistent key creates the key. + +The +.code refset +function returns +.codn new-value . The following equivalences hold between .code ref -- cgit v1.2.3