summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2025-03-07 00:11:37 -0800
committerKaz Kylheku <kaz@kylheku.com>2025-03-07 00:11:37 -0800
commit07e40c025d65beeced5ac83485eb13dab9b7d2ae (patch)
tree8a6569af89018d5d9ff2622c8f7ad40fd236fd0e
parenta68a67376127cb9accf26c4ed43438f188eb24c8 (diff)
downloadtxr-07e40c025d65beeced5ac83485eb13dab9b7d2ae.tar.gz
txr-07e40c025d65beeced5ac83485eb13dab9b7d2ae.tar.bz2
txr-07e40c025d65beeced5ac83485eb13dab9b7d2ae.zip
New function: iterp.
* eval.c (eval_init): Register iterp intrinsic. * lib.[ch] (iterp): New function. * tests/012/iter.tl: New tests. * txr.1: Document iterp. Update documentation for iter-more, iter-item and iter-step to more precisely identify which objects are valid arguments in terms of iterp and additional conditions, and that other objects throw a type-error exception. Fix wrong references to iter-more under documentation for iter-item. Removed obsolete text specifying that iter-step uses car on list-like sequences, a dubious behavior removed in the previous commit.
-rw-r--r--eval.c1
-rw-r--r--lib.c22
-rw-r--r--lib.h1
-rw-r--r--tests/012/iter.tl20
-rw-r--r--txr.1126
5 files changed, 139 insertions, 31 deletions
diff --git a/eval.c b/eval.c
index 9fcb98a6..cc4a21eb 100644
--- a/eval.c
+++ b/eval.c
@@ -7854,6 +7854,7 @@ void eval_init(void)
reg_fun(intern(lit("iter-item"), user_package), func_n1(iter_item));
reg_fun(intern(lit("iter-step"), user_package), func_n1(iter_step));
reg_fun(intern(lit("iter-reset"), user_package), func_n2(iter_reset));
+ reg_fun(intern(lit("iterp"), user_package), func_n1(iterp));
reg_fun(intern(lit("iter-cat"), user_package), func_n0v(iter_catv));
reg_fun(intern(lit("copy-iter"), user_package), func_n1(copy_iter));
diff --git a/lib.c b/lib.c
index 1e127e88..cf137699 100644
--- a/lib.c
+++ b/lib.c
@@ -1440,6 +1440,28 @@ val iter_reset(val iter, val obj)
}
}
+val iterp(val obj)
+{
+ switch (type(obj)) {
+ case NIL:
+ case CHR:
+ case NUM:
+ case BGNUM:
+ case FLNUM:
+ case CONS:
+ case LCONS:
+ return t;
+ case COBJ:
+ if (obj->co.cls == seq_iter_cls)
+ return t;
+ if (obj_struct_p(obj) && get_special_slot(obj, iter_step_m))
+ return t;
+ /* fallthrough */
+ default:
+ return nil;
+ }
+}
+
val iter_catv(varg iters)
{
cnum index = 0;
diff --git a/lib.h b/lib.h
index a17a6d6d..649fc291 100644
--- a/lib.h
+++ b/lib.h
@@ -775,6 +775,7 @@ val iter_more(val iter);
val iter_item(val iter);
val iter_step(val iter);
val iter_reset(val iter, val obj);
+val iterp(val obj);
val iter_catv(varg iters);
val copy_iter(val iter);
void seq_build_init(val self, seq_build_t *bu, val likeobj);
diff --git a/tests/012/iter.tl b/tests/012/iter.tl
index 94a50f34..cebbca55 100644
--- a/tests/012/iter.tl
+++ b/tests/012/iter.tl
@@ -154,3 +154,23 @@
(iter-item #()) :error
(iter-item #(1)) :error
(iter-item #(1 2 3)) :error)
+
+(defstruct iter ()
+ (:method iter-step (self)))
+
+(defstruct not-iter ())
+
+(mtest
+ (iterp nil) t
+ (iterp '(a . b)) t
+ (iterp (lcons 3 4)) t
+ (iterp #\a) t
+ (iterp 42) t
+ (iterp (expt 2 512)) t
+ (iterp 3.14) t
+ (iterp (new iter)) t
+ (iterp (new not-iter)) nil
+ (iterp "abc") nil
+ (iterp (fun list)) nil
+ (iterp #/regex/) nil
+ (iterp #(vec)) nil)
diff --git a/txr.1 b/txr.1
index 07d346ed..0409b569 100644
--- a/txr.1
+++ b/txr.1
@@ -34399,6 +34399,10 @@ Additional objects that are not sequences are also iterable:
numeric or character ranges, and numbers. Future revisions
of the language may specify additional iterable objects.
+Iterable objects are suitable arguments to the
+.code iter-begin
+function.
+
.coNP Functions @ make-like and @ seq-like
.synb
.mets (make-like < seq << object )
@@ -40086,6 +40090,53 @@ If
.code seq
is not an iterable object, an error exception is thrown.
+.coNP Function @ iterp
+.synb
+.mets (iterp << obj )
+.syne
+.desc
+The
+.code iterp
+function returns
+.code t
+if
+.meta obj
+is an iterator object, otherwise
+.codn nil .
+
+Note that this test is different from the
+.code iterable
+function, which tests whether it is possible to invoke
+.code iter-begin
+on an object to obtain an iterator.
+
+It is possible for an object to satisfy both
+.code iterp
+and
+.codn iterable .
+
+The
+.code iterp
+function returns
+.code t
+for the following objects or types:
+the empty list
+.codn nil ;
+conses, including lazy conses;
+characters; and numbers both integer and floating-point.
+
+In addition,
+.code iterp
+returns
+.code t
+for struct objects which have an
+.code iter-step
+method. Note that such objects must satisfy additional
+requirements to usefully behave as iterators.
+
+For all other objects, the function returns
+.codn nil .
+
.coNP Function @ iter-more
.synb
.mets (iter-more << iter )
@@ -40101,11 +40152,19 @@ Otherwise it returns
The
.meta iter
-argument must be a valid iterator returned by a call to
-.metn iter-begin ,
-.meta iter-step
-or
-.metn iter-reset .
+argument must be a valid iterator object, for which the
+.code iterp
+function returns
+.codn t ,
+or else it must be a struct. As a special behavior in support
+of the fast iteration protocol, if
+.meta iter
+is a struct which does not support the
+.code iter-more
+method, the
+.code iter-more
+function unconditionally returns
+.codn t .
The
.code iter-more
@@ -40189,6 +40248,11 @@ method, then
.code t
is returned.
+For any other object, the
+.code iter-more
+throws an exception of type
+.codn type-error .
+
.coNP Function @ iter-item
.synb
.mets (iter-item << iter )
@@ -40200,21 +40264,25 @@ function indicates that more items remain to be visited, then
the next item can be retrieved using
.codn iter-item .
-The
+Except if it is a struct, the
.meta iter
-argument must be a valid iterator returned by a call to
-.metn iter-begin ,
-.meta iter-step
-or
-.metn iter-reset .
+argument must be a valid iterator object, for which the
+.code iterp
+function returns
+.codn t .
+If
+.meta iter
+is a struct, it must implement the
+.code iter-item
+method.
The
-.code iter-more
+.code iter-item
function doesn't change the state of
.metn iter .
If
-.code iter-more
+.code iter-item
is invoked on an iterator which indicates that no more items
remain to be visited, the return value is
.codn nil .
@@ -40281,6 +40349,11 @@ is a structure which supports the
.code iter-item
method, then that method is called and its return value is returned.
+For all other objects,
+.code iter-item
+throws an exception of type
+.codn type-error .
+
.coNP Function @ iter-step
.synb
.mets (iter-step << iter )
@@ -40297,11 +40370,10 @@ remaining items in the sequence.
The
.meta iter
-argument must be a valid iterator returned by a call to
-.metn iter-begin ,
-.meta iter-step
-or
-.metn iter-reset .
+argument must be a valid iterator object, for which the
+.code iterp
+function returns
+.codn t .
The
.code iter-step
@@ -40357,19 +40429,6 @@ and so on.
If
.meta iter
-is a list-like sequence, then
-.code cdr
-is invoked on it and that value is returned.
-The value must also be a list-like sequence, or else
-.codn nil .
-The reasoning for this is the same as for the similar
-restriction imposed in the case when
-.meta iter
-is a
-.codn cons .
-
-If
-.meta iter
is a character or number, then
.code iter-step
returns its successor, as if using the
@@ -40382,6 +40441,11 @@ is a structure which supports the
.code iter-step
method, then that method is called and its return value is returned.
+For all other objects,
+.code iter-step
+throws an exception of type
+.codn type-error .
+
.coNP Function @ iter-reset
.synb
.mets (iter-reset < iter << seq )