summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib.c86
-rw-r--r--tests/012/iter.tl42
-rw-r--r--txr.153
3 files changed, 178 insertions, 3 deletions
diff --git a/lib.c b/lib.c
index 206cd295..68f95d01 100644
--- a/lib.c
+++ b/lib.c
@@ -545,6 +545,42 @@ static int seq_iter_peek_range_bignum(seq_iter_t *it, val *pval)
return 0;
}
+static int seq_iter_get_range_str(seq_iter_t *it, val *pval)
+{
+ if (it->ui.vn) {
+ val init = from(it->inf.obj);
+ val len = length_str(init);
+ val next = copy_str(it->ui.vn);
+ cnum l = c_num(len, nil);
+ wchar_t *nx = strip_qual(wchar_t *, c_str(next, nil));
+ const wchar_t *in = c_str(init, nil);
+ const wchar_t *bn = c_str(it->ul.vbound, nil);
+
+ *pval = it->ui.vn;
+
+ for (; l > 0; l--) {
+ if (++nx[l - 1] <= bn[l - 1])
+ break;
+ nx[l - 1] = in[l - 1];
+ }
+
+ it->ui.vn = if2(l > 0, next);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int seq_iter_peek_range_str(seq_iter_t *it, val *pval)
+{
+ if (it->ui.vn) {
+ *pval = it->ui.vn;
+ return 1;
+ }
+ return 0;
+}
+
static int seq_iter_get_rev_range_cnum(seq_iter_t *it, val *pval)
{
if (it->ui.cn > it->ul.cbound) {
@@ -599,6 +635,32 @@ static int seq_iter_peek_rev_range_bignum(seq_iter_t *it, val *pval)
return 0;
}
+static int seq_iter_get_rev_range_str(seq_iter_t *it, val *pval)
+{
+ if (it->ui.vn) {
+ val init = from(it->inf.obj);
+ val len = length_str(init);
+ val next = copy_str(it->ui.vn);
+ cnum l = c_num(len, nil);
+ wchar_t *nx = strip_qual(wchar_t *, c_str(next, nil));
+ const wchar_t *in = c_str(init, nil);
+ const wchar_t *bn = c_str(it->ul.vbound, nil);
+
+ *pval = it->ui.vn;
+
+ for (; l > 0; l--) {
+ if (--nx[l - 1] >= bn[l - 1])
+ break;
+ nx[l - 1] = in[l - 1];
+ }
+
+ it->ui.vn = if2(l > 0, next);
+
+ return 1;
+ }
+
+ return 0;
+}
static int seq_iter_get_chr(seq_iter_t *it, val *pval)
{
@@ -815,7 +877,7 @@ void seq_iter_init_with_info(val self, seq_iter_t *it,
break;
}
- if (lt(rf, rt)) switch (type(rf)) {
+ if (less(rf, rt)) switch (type(rf)) {
case NUM:
it->ui.cn = c_num(rf, self);
it->ul.cbound = c_num(rt, self);
@@ -834,9 +896,19 @@ void seq_iter_init_with_info(val self, seq_iter_t *it,
it->get = seq_iter_get_range_bignum;
it->peek = seq_iter_peek_range_bignum;
break;
+ case LIT:
+ case STR:
+ case LSTR:
+ it->ui.vn = copy_str(rf);
+ it->ul.vbound = rt;
+ it->get = seq_iter_get_range_str;
+ it->peek = seq_iter_peek_range_str;
+ if (eql(length_str(rf), length_str(rt)))
+ break;
+ /* fallthrough */
default:
unsup_obj(self, it->inf.obj);
- } else if (gt(rf, rt)) switch (type(rf)) {
+ } else if (!equal(rf, rt)) switch (type(rf)) {
case NUM:
it->ui.cn = c_num(rf, self);
it->ul.cbound = c_num(rt, self);
@@ -855,6 +927,16 @@ void seq_iter_init_with_info(val self, seq_iter_t *it,
it->get = seq_iter_get_rev_range_bignum;
it->peek = seq_iter_peek_rev_range_bignum;
break;
+ case LIT:
+ case STR:
+ case LSTR:
+ it->ui.vn = copy_str(rf);
+ it->ul.vbound = rt;
+ it->get = seq_iter_get_rev_range_str;
+ it->peek = seq_iter_peek_range_str;
+ if (eql(length_str(rf), length_str(rt)))
+ break;
+ /* fallthrough */
default:
unsup_obj(self, it->inf.obj);
} else {
diff --git a/tests/012/iter.tl b/tests/012/iter.tl
new file mode 100644
index 00000000..f98107a5
--- /dev/null
+++ b/tests/012/iter.tl
@@ -0,0 +1,42 @@
+(load "../common")
+
+(mtest
+ [mapcar identity "A".."D"] ("A" "B" "C" "D")
+ [mapcar identity "A1".."C2"] ("A1" "A2" "B1" "B2" "C1" "C2")
+ [mapcar identity "D".."A"] ("D" "C" "B" "A")
+ [mapcar identity "C2".."A1"] ("C2" "C1" "B2" "B1" "A2" "A1"))
+
+(test
+ [maprod append "AA".."DD" "01".."19"]
+ ("AA01" "AA02" "AA03" "AA04" "AA05" "AA06" "AA07" "AA08" "AA09"
+ "AA11" "AA12" "AA13" "AA14" "AA15" "AA16" "AA17" "AA18" "AA19"
+ "AB01" "AB02" "AB03" "AB04" "AB05" "AB06" "AB07" "AB08" "AB09"
+ "AB11" "AB12" "AB13" "AB14" "AB15" "AB16" "AB17" "AB18" "AB19"
+ "AC01" "AC02" "AC03" "AC04" "AC05" "AC06" "AC07" "AC08" "AC09"
+ "AC11" "AC12" "AC13" "AC14" "AC15" "AC16" "AC17" "AC18" "AC19"
+ "AD01" "AD02" "AD03" "AD04" "AD05" "AD06" "AD07" "AD08" "AD09"
+ "AD11" "AD12" "AD13" "AD14" "AD15" "AD16" "AD17" "AD18" "AD19"
+ "BA01" "BA02" "BA03" "BA04" "BA05" "BA06" "BA07" "BA08" "BA09"
+ "BA11" "BA12" "BA13" "BA14" "BA15" "BA16" "BA17" "BA18" "BA19"
+ "BB01" "BB02" "BB03" "BB04" "BB05" "BB06" "BB07" "BB08" "BB09"
+ "BB11" "BB12" "BB13" "BB14" "BB15" "BB16" "BB17" "BB18" "BB19"
+ "BC01" "BC02" "BC03" "BC04" "BC05" "BC06" "BC07" "BC08" "BC09"
+ "BC11" "BC12" "BC13" "BC14" "BC15" "BC16" "BC17" "BC18" "BC19"
+ "BD01" "BD02" "BD03" "BD04" "BD05" "BD06" "BD07" "BD08" "BD09"
+ "BD11" "BD12" "BD13" "BD14" "BD15" "BD16" "BD17" "BD18" "BD19"
+ "CA01" "CA02" "CA03" "CA04" "CA05" "CA06" "CA07" "CA08" "CA09"
+ "CA11" "CA12" "CA13" "CA14" "CA15" "CA16" "CA17" "CA18" "CA19"
+ "CB01" "CB02" "CB03" "CB04" "CB05" "CB06" "CB07" "CB08" "CB09"
+ "CB11" "CB12" "CB13" "CB14" "CB15" "CB16" "CB17" "CB18" "CB19"
+ "CC01" "CC02" "CC03" "CC04" "CC05" "CC06" "CC07" "CC08" "CC09"
+ "CC11" "CC12" "CC13" "CC14" "CC15" "CC16" "CC17" "CC18" "CC19"
+ "CD01" "CD02" "CD03" "CD04" "CD05" "CD06" "CD07" "CD08" "CD09"
+ "CD11" "CD12" "CD13" "CD14" "CD15" "CD16" "CD17" "CD18" "CD19"
+ "DA01" "DA02" "DA03" "DA04" "DA05" "DA06" "DA07" "DA08" "DA09"
+ "DA11" "DA12" "DA13" "DA14" "DA15" "DA16" "DA17" "DA18" "DA19"
+ "DB01" "DB02" "DB03" "DB04" "DB05" "DB06" "DB07" "DB08" "DB09"
+ "DB11" "DB12" "DB13" "DB14" "DB15" "DB16" "DB17" "DB18" "DB19"
+ "DC01" "DC02" "DC03" "DC04" "DC05" "DC06" "DC07" "DC08" "DC09"
+ "DC11" "DC12" "DC13" "DC14" "DC15" "DC16" "DC17" "DC18" "DC19"
+ "DD01" "DD02" "DD03" "DD04" "DD05" "DD06" "DD07" "DD08" "DD09"
+ "DD11" "DD12" "DD13" "DD14" "DD15" "DD16" "DD17" "DD18" "DD19"))
diff --git a/txr.1 b/txr.1
index c81e1063..8b0f53a3 100644
--- a/txr.1
+++ b/txr.1
@@ -35626,7 +35626,9 @@ is iterable, an object of type
.code seq-iter
is returned.
-Range objects are iterable.
+Range objects are iterable if they are numeric. A range consisting of
+two strings may also be iterable, as described below.
+
A range is considered to be a numeric or character range if the
.code from
element is a number or character. The
@@ -35645,6 +35647,55 @@ and
.code "(iter-begin X..t)"
are equivalent to
.codn "(iter-begin X)" .
+Numeric ranges are half-open: the
+.code to
+value of ascending ranges is excluded, as is the
+.code from
+value of descending ranges, so that
+.code 0..10
+steps through the values
+.code 0
+through
+.codn 9 ,
+and
+.code 10..0
+steps through the same values in reverse order.
+
+A string range consists of two strings of equal length. If the strings are
+of unequal length, an error exception is thrown. For the range to operate
+as intended, the strings must meet some additional requirements. If the
+.code from
+string is lexicographically lesser than the
+.code to
+string, as determined by the
+.code less
+function, then the range is ascending, otherwise it is descending. The string
+range iterates by incrementing (or decrementing, in the case of a descending range)
+the characters of the
+.code from
+string until they are equal to those of the
+.code to
+string. The last character has priority. For instance, the range
+.code "\(dqAA\(dq..\(dqCC\(dq"
+iterates over the strings
+.codn "AA" ,
+.codn "AB" ,
+.codn "AC" ,
+.codn "BA" ,
+.codn "BB" ,
+.codn "BC" ,
+.codn "CA" ,
+.code "CB"
+and
+.codn "CC" .
+The descending range
+.code "\(dqCC\(dq..\(dqAA\(dq"
+iterates over the same strings, in reverse order. Whenever the incrementing
+character attains the value of the corresponding character in the
+.code to
+string, that character is reset to its starting value, and its left neighbor,
+if it exists, is incremented instead. If no left neighbor exists, the
+iteration terminates.
Search trees are iterable. Iteration entails an in-order visits of the elements
of a tree. A tree iterator created by