summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-08-07 00:25:46 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-08-07 00:25:46 -0700
commit25eb966ccb8b61dbe4ff2b2e1970e1e9caa0282f (patch)
tree427b31848c6040b83e69003c95f5f7c2d06bfd0d
parent586d5d840219a76bd8d36e3b04951e3377709fbd (diff)
downloadtxr-25eb966ccb8b61dbe4ff2b2e1970e1e9caa0282f.tar.gz
txr-25eb966ccb8b61dbe4ff2b2e1970e1e9caa0282f.tar.bz2
txr-25eb966ccb8b61dbe4ff2b2e1970e1e9caa0282f.zip
lazy-stream-cons: control close throwing behavior.
* eval.c (eval_init): Update registrations of lazy-stream-cons and get-lines with one more optional argument. * lib.c (simple_lazy_stream_func_nt, lazy_stream_func_nt): New static functions. (lazy_stream_cons): Take a new argument, no_throw_close, defaulting it to nil. When calling close_stream directly, pass the inverted value of no_throw_close. Choose the new _nt functions for the lazy list if no_throw_close is true; those functions pass nil as the second argument of close_stream. * lib.h (lazy_stream_cons): Declaration updated. * match.c (v_next_impl, open_data_source, match_fun): Pass down the nothrow value to lazy_stream_cons, or else nil in situations when that is not applicable or there is no such value. Thus the :nothrow feature of v_next will now not only ensure that there is no exception when opening the stream but also when closing it. Unusual situations encountered when the lazy list reads from the stream still throw. * txr.1: Documented.
-rw-r--r--eval.c4
-rw-r--r--lib.c44
-rw-r--r--lib.h2
-rw-r--r--match.c11
-rw-r--r--txr.139
-rw-r--r--txr.c2
6 files changed, 82 insertions, 20 deletions
diff --git a/eval.c b/eval.c
index 6b2ac391..fcd802d9 100644
--- a/eval.c
+++ b/eval.c
@@ -7123,8 +7123,8 @@ void eval_init(void)
reg_fun(intern(lit("compl-span-str"), user_package), func_n2(compl_span_str));
reg_fun(intern(lit("break-str"), user_package), func_n2(break_str));
- reg_fun(intern(lit("lazy-stream-cons"), user_package), func_n1(lazy_stream_cons));
- reg_fun(intern(lit("get-lines"), user_package), func_n1o(lazy_stream_cons, 0));
+ reg_fun(intern(lit("lazy-stream-cons"), user_package), func_n2o(lazy_stream_cons, 1));
+ reg_fun(intern(lit("get-lines"), user_package), func_n2o(lazy_stream_cons, 0));
reg_fun(intern(lit("lazy-str"), user_package), func_n3o(lazy_str, 1));
reg_fun(intern(lit("lazy-stringp"), user_package), func_n1(lazy_stringp));
reg_fun(intern(lit("lazy-str-force-upto"), user_package), func_n2(lazy_str_force_upto));
diff --git a/lib.c b/lib.c
index 5de9f170..79b3c1e4 100644
--- a/lib.c
+++ b/lib.c
@@ -8995,12 +8995,24 @@ static val simple_lazy_stream_func(val stream, val lcons)
return nil;
}
-static val lazy_stream_cont(val stream, val func, val env)
+static val simple_lazy_stream_func_nt(val stream, val lcons)
+{
+ if (set(mkloc(lcons->lc.car, lcons), get_line(stream)) != nil) {
+ set(mkloc(lcons->lc.cdr, lcons), make_lazy_cons(us_lcons_fun(lcons)));
+ } else {
+ close_stream(stream, nil);
+ lcons->lc.cdr = nil;
+ }
+
+ return nil;
+}
+
+static val lazy_stream_cont(val stream, val func, val env, val throw_p)
{
val next = get_line(stream);
if (!next) {
- close_stream(stream, t);
+ close_stream(stream, throw_p);
return nil;
}
@@ -9015,27 +9027,45 @@ static val lazy_stream_func(val env, val lcons)
set(mkloc(lcons->lc.car, lcons), prefetched_line);
set(mkloc(lcons->lc.cdr, lcons), lazy_stream_cont(stream,
- us_lcons_fun(lcons), env));
+ us_lcons_fun(lcons), env, t));
return prefetched_line;
}
-val lazy_stream_cons(val stream)
+static val lazy_stream_func_nt(val env, val lcons)
+{
+ val stream = car(env);
+ val prefetched_line = cdr(env);
+
+ set(mkloc(lcons->lc.car, lcons), prefetched_line);
+ set(mkloc(lcons->lc.cdr, lcons), lazy_stream_cont(stream,
+ us_lcons_fun(lcons), env, nil));
+
+ return prefetched_line;
+}
+
+
+val lazy_stream_cons(val stream, val no_throw_close)
{
stream = default_arg_strict(stream, std_input);
+ no_throw_close = default_null_arg(no_throw_close);
if (real_time_stream_p(stream)) {
- return make_lazy_cons(func_f1(stream, simple_lazy_stream_func));
+ return make_lazy_cons(func_f1(stream, if3(no_throw_close,
+ simple_lazy_stream_func_nt,
+ simple_lazy_stream_func)));
} else {
val first = get_line(stream);
if (!first) {
- close_stream(stream, t);
+ close_stream(stream, null(no_throw_close));
return nil;
}
return make_lazy_cons(func_f1(cons(stream, first),
- lazy_stream_func));
+ if3(no_throw_close,
+ lazy_stream_func_nt,
+ lazy_stream_func)));
}
}
diff --git a/lib.h b/lib.h
index e3b89087..5fdf9bde 100644
--- a/lib.h
+++ b/lib.h
@@ -1089,7 +1089,7 @@ val replace_vec(val vec_in, val items, val from, val to);
val replace_obj(val obj, val items, val from, val to);
val fill_vec(val vec, val item, val from_in, val to_in);
val cat_vec(val list);
-val lazy_stream_cons(val stream);
+val lazy_stream_cons(val stream, val no_throw_close);
val lazy_str(val list, val term, val limit);
val lazy_str_force_upto(val lstr, val index);
val lazy_str_force(val lstr);
diff --git a/match.c b/match.c
index f0ed32f4..d2bcf41a 100644
--- a/match.c
+++ b/match.c
@@ -2843,7 +2843,8 @@ static val v_next_impl(match_files_ctx *c)
if (stream) {
cons_bind (new_bindings, success,
match_files(mf_file_data(*c, str, stream,
- lazy_stream_cons(stream), one)));
+ lazy_stream_cons(stream, nothrow),
+ one)));
if (success)
return cons(new_bindings,
@@ -4604,7 +4605,7 @@ static void open_data_source(match_files_ctx *c)
} else {
debuglf(first_spec, lit("opening standard input as data source"), nao);
c->curfile = lit("-");
- c->data = lazy_stream_cons(std_input);
+ c->data = lazy_stream_cons(std_input, nil);
c->data_lineno = one;
}
} else if (non_matching_dir) {
@@ -4628,10 +4629,10 @@ static void open_data_source(match_files_ctx *c)
c->curfile = source_spec;
c->stream = stream;
- if ((c->data = lazy_stream_cons(stream)) != nil)
+ if ((c->data = lazy_stream_cons(stream, nothrow)) != nil)
c->data_lineno = one;
} else if (streamp(name)) {
- if ((c->data = lazy_stream_cons(name)))
+ if ((c->data = lazy_stream_cons(name, nil)))
c->data_lineno = one;
} else {
sem_error(specline, lit("~s doesn't denote a valid data source"), name, nao);
@@ -4773,7 +4774,7 @@ val match_fun(val name, val args, val input_in, val files_in)
val files = cons(curfile, default_null_arg(files_in));
val in_bindings = cdr(uw_get_match_context());
val data = if3(streamp(input),
- lazy_stream_cons(input),
+ lazy_stream_cons(input, nil),
input);
/* TODO: pass through source location context */
match_files_ctx c = mf_all(spec, files, in_bindings, data,
diff --git a/txr.1 b/txr.1
index 7586af51..557422c2 100644
--- a/txr.1
+++ b/txr.1
@@ -4045,7 +4045,21 @@ is invoked with the
.code :nothrow
keyword, then if the input
source cannot be opened, the situation is treated as a simple
-match failure.
+match failure. The
+.code :nothrow
+keyword also ensures that when the stream is later closed,
+which occurs when the lazy list reads all of the available data,
+the implicit call to the
+.code close-stream
+function specifies
+.code nil
+as the argument value to that function's
+.meta throw-on-error-p
+parameter. This
+.code :nothrow
+mechanism does not suppress all exceptions related to the processing
+of that stream; unusual conditions encountered during the reading of
+data from the stream may throw exceptions.
The variant
.code "@(next :args)"
@@ -22855,8 +22869,8 @@ function:
.coNP Functions @ lazy-stream-cons and @ get-lines
.synb
-.mets (lazy-stream-cons << stream )
-.mets (get-lines <> [ stream ])
+.mets (lazy-stream-cons << stream <> [ no-throw-close-p ])
+.mets (get-lines >> [ stream <> [ no-throw-close-p ]])
.syne
.desc
The
@@ -22903,7 +22917,8 @@ by making another call to
.codn lazy-stream-cons ,
installing the result into the
.code cdr
-field.
+field. When this lazy list obtains an end-of-file indication from the stream,
+it closes the stream.
.code lazy-stream-cons
inspects the real-time property of a stream
@@ -22928,6 +22943,22 @@ a one-line stream translates to
.onom
and so forth.
+If and when
+.meta stream
+is closed by the function directly, or else by the returned lazy list, the
+.meta no-throw-close-p
+Boolean argument, defaulting to
+.codn nil ,
+controls the
+.meta throw-on-error-p
+argument of the call to the
+.code close-stream
+function. These arguments have opposite polarity: if
+.meta no-throw-close-p
+is true, then
+.meta throw-on-error-p
+shall be false, and vice versa.
+
.coNP Macro @ delay
.synb
.mets (delay << expression )
diff --git a/txr.c b/txr.c
index 159218a9..341b242a 100644
--- a/txr.c
+++ b/txr.c
@@ -381,7 +381,7 @@ static int license(void)
for (iter = path_list; iter; iter = cdr(iter)) {
val lic = open_file(car(iter), lit("r"));
- put_lines(lazy_stream_cons(lic), std_output);
+ put_lines(lazy_stream_cons(lic, nil), std_output);
put_char(chr('\n'), std_output);
}
}