summaryrefslogtreecommitdiffstats
path: root/match.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-08-05 06:52:25 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-08-05 06:52:25 -0700
commitb7f76edb07c6395e8ae6f3a336292666ea1c8eda (patch)
tree172ce301714bb02a3ea42565003f1319a64cd1dc /match.c
parent29b5a31ad6d3783e9bb178f35d21110bea06451e (diff)
downloadtxr-b7f76edb07c6395e8ae6f3a336292666ea1c8eda.tar.gz
txr-b7f76edb07c6395e8ae6f3a336292666ea1c8eda.tar.bz2
txr-b7f76edb07c6395e8ae6f3a336292666ea1c8eda.zip
txr: @(eof) takes argument for binding termination status.
We extend the matching context structures to keep track of the underlying stream from which lines are being taken via the lazy list. Then the implementation of the @(eof) directive, when it hits the eof condition, can use this stream to gain access to the termination status. * match.c (match_line_ctx, match_files_ctx): New member, stream. (ml_all): Take stream argument and initialize new member. (h_call, do_match_line): Pass stream argument to h_call. (mf_all, mf_file_data): Take stream argument and initialize new member. (mf_from_ml): Propagate stream from line context to file context. (freeform_prepare, v_next_impl, match_filter, match_fun, extract): Pass stream argument where now needed. (v_eof): Implement termination status binding via the stream stored in the context. (open_data_source): Store stream in match files context. * tests/010/eof-status.txr: New file. * tests/010/eof-status.expected: New file. * Makefile (tst/tests/010/eof-status.ok): -B option for new test. * txr.1: Documented eof directive, argument and all. * stdlib/doc-syms.tl: Updated.
Diffstat (limited to 'match.c')
-rw-r--r--match.c69
1 files changed, 48 insertions, 21 deletions
diff --git a/match.c b/match.c
index f80aa548..f0ed32f4 100644
--- a/match.c
+++ b/match.c
@@ -454,11 +454,11 @@ static val vars_to_bindings(val spec, val vars, val bindings)
}
typedef struct {
- val bindings, specline, dataline, base, pos, data, data_lineno, file;
+ val bindings, specline, dataline, base, pos, data, data_lineno, file, stream;
} match_line_ctx;
static match_line_ctx ml_all(val bindings, val specline, val dataline, val pos,
- val data, val data_lineno, val file)
+ val data, val data_lineno, val file, val stream)
{
match_line_ctx c;
c.bindings = bindings;
@@ -469,6 +469,7 @@ static match_line_ctx ml_all(val bindings, val specline, val dataline, val pos,
c.data = data;
c.data_lineno = data_lineno;
c.file = file;
+ c.stream = stream;
return c;
}
@@ -1485,11 +1486,11 @@ static val h_chr(match_line_ctx *c)
}
typedef struct {
- val spec, files, curfile, bindings, data, data_lineno;
+ val spec, files, curfile, stream, bindings, data, data_lineno;
} match_files_ctx;
static match_files_ctx mf_all(val spec, val files, val bindings, val data,
- val curfile);
+ val curfile, val stream);
static val v_fun(match_files_ctx *c);
@@ -1513,7 +1514,7 @@ static val h_call(match_line_ctx *c)
if (ret == decline_k) {
val spec = cons(new_specline, nil);
- match_files_ctx vc = mf_all(spec, nil, c->bindings, nil, c->file);
+ match_files_ctx vc = mf_all(spec, nil, c->bindings, nil, c->file, c->stream);
val vresult = v_fun(&vc);
if (vresult == next_spec_k) {
@@ -1585,7 +1586,7 @@ static val do_match_line(match_line_ctx *c)
} else if (result == decline_k) {
val spec = rlcp(cons(cons(elem, nil), nil), elem);
match_files_ctx vc = mf_all(spec, nil, c->bindings,
- nil, c->file);
+ nil, c->file, c->stream);
val vresult = v_fun(&vc);
if (vresult == next_spec_k) {
@@ -2233,12 +2234,13 @@ void do_output(val bindings, val specs, val filter, val out)
}
static match_files_ctx mf_all(val spec, val files, val bindings,
- val data, val curfile)
+ val data, val curfile, val stream)
{
match_files_ctx c;
c.spec = spec;
c.files = files;
c.curfile = curfile;
+ c.stream = stream;
c.bindings = bindings;
c.data = data;
c.data_lineno = if3(data, one, zero);
@@ -2279,11 +2281,12 @@ static match_files_ctx mf_spec_bindings(match_files_ctx c, val spec,
}
static match_files_ctx mf_file_data(match_files_ctx c, val file,
- val data, val data_lineno)
+ val stream, val data, val data_lineno)
{
match_files_ctx nc = c;
nc.files = cons(file, c.files);
nc.curfile = file;
+ nc.stream = stream;
nc.data = data;
nc.data_lineno = data_lineno;
return nc;
@@ -2296,6 +2299,7 @@ static match_files_ctx mf_from_ml(match_line_ctx ml)
mf.spec = cons(ml.specline, nil);
mf.files = nil;
mf.curfile = ml.file;
+ mf.stream = ml.stream;
mf.bindings = ml.bindings;
mf.data = nil;
mf.data_lineno = ml.data_lineno;
@@ -2556,7 +2560,7 @@ val freeform_prepare(val vals, match_files_ctx *c, match_line_ctx *mlc)
if2(stringp(second(vals)), second(vals)));
val dataline = lazy_str(c->data, term, limit);
*mlc = ml_all(c->bindings, first_spec, dataline, zero,
- c->data, c->data_lineno, c->curfile);
+ c->data, c->data_lineno, c->curfile, c->stream);
return limit;
}
@@ -2684,7 +2688,7 @@ static val v_next_impl(match_files_ctx *c)
sem_error(specline, lit("(next :env) takes no additional arguments"), nao);
} else {
cons_bind (new_bindings, success,
- match_files(mf_file_data(*c, lit("env"), env(), one)));
+ match_files(mf_file_data(*c, lit("env"), nil, env(), one)));
if (success)
return cons(new_bindings,
@@ -2697,7 +2701,8 @@ static val v_next_impl(match_files_ctx *c)
meta = t;
} else if (!source) {
cons_bind (new_bindings, success,
- match_files(mf_all(c->spec, nil, c->bindings, nil, lit("empty"))));
+ match_files(mf_all(c->spec, nil, c->bindings, nil,
+ lit("empty"), nil)));
if (success)
return cons(new_bindings,
@@ -2757,7 +2762,7 @@ static val v_next_impl(match_files_ctx *c)
{
cons_bind (new_bindings, success,
- match_files(mf_file_data(*c, lit("var"),
+ match_files(mf_file_data(*c, lit("var"), nil,
lazy_flatten(cdr(existing)), one)));
if (success)
@@ -2775,7 +2780,7 @@ static val v_next_impl(match_files_ctx *c)
{
cons_bind (new_bindings, success,
- match_files(mf_file_data(*c, lit("var"),
+ match_files(mf_file_data(*c, lit("var"), nil,
lazy_flatten(list_val), one)));
if (success)
@@ -2786,7 +2791,7 @@ static val v_next_impl(match_files_ctx *c)
} else if (tlist_p) {
val list_val = txeval(specline, tlist_expr, c->bindings);
cons_bind (new_bindings, success,
- match_files(mf_file_data(*c, lit("var"),
+ match_files(mf_file_data(*c, lit("var"), nil,
lazy_flatten(list_val), one)));
if (success)
@@ -2804,7 +2809,7 @@ static val v_next_impl(match_files_ctx *c)
{
cons_bind (new_bindings, success,
- match_files(mf_file_data(*c, lit("var"),
+ match_files(mf_file_data(*c, lit("var"), nil,
split_str(str_val, lit("\n")), one)));
if (success)
@@ -2837,7 +2842,7 @@ static val v_next_impl(match_files_ctx *c)
if (stream) {
cons_bind (new_bindings, success,
- match_files(mf_file_data(*c, str,
+ match_files(mf_file_data(*c, str, stream,
lazy_stream_cons(stream), one)));
if (success)
@@ -4159,7 +4164,26 @@ static val v_eof(match_files_ctx *c)
if (c->data && car(c->data)) {
debuglf(c->spec, lit("eof failed to match at ~d"), c->data_lineno, nao);
return nil;
+ } else {
+ spec_bind (specline, first_spec, c->spec);
+ val args = rest(first_spec);
+
+ if (rest(args))
+ sem_error(specline, lit("eof directive takes takes at most one argument"), nao);
+
+ if (args) {
+ val pat = car(args);
+ val close_status = if3(streamp(c->stream), close_stream(c->stream, t), t);
+
+ c->bindings = dest_bind(specline, c->bindings, pat, close_status, eql_f);
+
+ if (c->bindings == t) {
+ debuglf(specline, lit("line mismatch (line ~d vs. ~s)"), c->data_lineno, pat, nao);
+ return nil;
+ }
+ }
}
+
return next_spec_k;
}
@@ -4602,6 +4626,7 @@ static void open_data_source(match_files_ctx *c)
c->files = cons(name, cdr(c->files)); /* Get rid of cons and nothrow */
c->curfile = source_spec;
+ c->stream = stream;
if ((c->data = lazy_stream_cons(stream)) != nil)
c->data_lineno = one;
@@ -4685,7 +4710,8 @@ repeat_spec_same_data:
cons_bind (new_bindings, success,
match_line_completely(ml_all(c.bindings, specline,
dataline, zero,
- c.data, c.data_lineno, c.curfile)));
+ c.data, c.data_lineno,
+ c.curfile, c.stream)));
if (!success)
return nil;
@@ -4712,7 +4738,7 @@ val match_filter(val name, val arg, val other_args)
val spec = cons(list(cons(name,
cons(in_arg_sym, cons(out_arg_sym, other_args))),
nao), nil);
- match_files_ctx c = mf_all(spec, nil, bindings, nil, nil);
+ match_files_ctx c = mf_all(spec, nil, bindings, nil, nil, nil);
val ret = v_fun(&c);
(void) first_spec;
@@ -4750,7 +4776,8 @@ val match_fun(val name, val args, val input_in, val files_in)
lazy_stream_cons(input),
input);
/* TODO: pass through source location context */
- match_files_ctx c = mf_all(spec, files, in_bindings, data, curfile);
+ match_files_ctx c = mf_all(spec, files, in_bindings, data,
+ curfile, if2(streamp(input), input));
val ret;
ret = v_fun(&c);
@@ -4767,14 +4794,14 @@ val match_fun(val name, val args, val input_in, val files_in)
val include(val specline)
{
val spec = cons(specline, nil);
- match_files_ctx c = mf_all(spec, nil, nil, nil, nil);
+ match_files_ctx c = mf_all(spec, nil, nil, nil, nil, nil);
return v_load(&c);
}
val extract(val spec, val files, val predefined_bindings)
{
val result = match_files(mf_all(spec, files, predefined_bindings,
- t, nil));
+ t, nil, nil));
cons_bind (bindings, success, result);
if (opt_print_bindings) {