summaryrefslogtreecommitdiffstats
path: root/match.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-02-15 19:23:50 -0800
committerKaz Kylheku <kaz@kylheku.com>2017-02-15 19:23:50 -0800
commitfca282dfac0b6e27c67afab2fcd8cc67a31d6c17 (patch)
tree6c2203e5ae91e05590159a0c185ed837970d3c23 /match.c
parentdc0ecebee11c7dc7a8650efd2f8537cb1a869ad4 (diff)
downloadtxr-fca282dfac0b6e27c67afab2fcd8cc67a31d6c17.tar.gz
txr-fca282dfac0b6e27c67afab2fcd8cc67a31d6c17.tar.bz2
txr-fca282dfac0b6e27c67afab2fcd8cc67a31d6c17.zip
Support horizontal @(block), phase 2.
Accepts produce a return value which is a vector object carrying both vertical (data pointer + line number) and horizontal context (position within line). Both a vertical and horizontal @(block) construct look at this and behave in some intelligent way. * match.c (match_line_ctx): New member, data. Thus, horizontal contexts now know the vertical list from whcih they are derived. (ml_all): Take data argument, and initialize new member. (h_block): If a vector object emerges from the block, that means the block terminated due to an accept. If the accept is from a different line, or from vertical context, then just keep whatever horizontal position is current in the horizontal context. (We have no way of knowing how far we advanced between the start of the block and the elem which triggered the accept.) If the accept is from the same line then advance to the indicated position. (h_accept_fail): Produce a three-element vector object for the accept long return value. This carries the bindings, the vertical-style result value, and the horizontal position. (freeform_prepare): Update ml_all call to include c->data. (v_block): Like in h_block, handle a vector result value. An accept emanating from horizontal context for the current line causes the vertical context to advance to the next line. Horizontal accept from a different line doesn't advance the data. Accept from a vertical context behaves as before. (v_accept_fail): Produce vector object for accept. (v_trailer): When intercepting accept, patch new vector representation of accept value. (match_files): Pass c.data to ml_all.
Diffstat (limited to 'match.c')
-rw-r--r--match.c74
1 files changed, 62 insertions, 12 deletions
diff --git a/match.c b/match.c
index 25133444..4c7594a5 100644
--- a/match.c
+++ b/match.c
@@ -416,11 +416,11 @@ static val vars_to_bindings(val spec, val vars, val bindings)
}
typedef struct {
- val bindings, specline, dataline, base, pos, data_lineno, file;
+ val bindings, specline, dataline, base, pos, data, data_lineno, file;
} match_line_ctx;
-static match_line_ctx ml_all(val bindings, val specline, val dataline,
- val pos, val data_lineno, val file)
+static match_line_ctx ml_all(val bindings, val specline, val dataline, val pos,
+ val data, val data_lineno, val file)
{
match_line_ctx c;
c.bindings = bindings;
@@ -428,6 +428,7 @@ static match_line_ctx ml_all(val bindings, val specline, val dataline,
c.dataline = dataline;
c.base = zero;
c.pos = pos;
+ c.data = data;
c.data_lineno = data_lineno;
c.file = file;
@@ -820,7 +821,24 @@ static val h_block(match_line_ctx *c)
uw_block_begin(name, result);
result = match_line(ml_specline(*c, specs));
uw_block_end;
- if (result) {
+
+ if (vectorp(result)) {
+ val bindings = vecref(result, zero);
+ val vpos = vecref(result, one);
+ val hpos = vecref(result, two);
+ c->bindings = bindings;
+
+ if (hpos && car(vpos) == c->data) {
+ debuglf(elem, lit("accept from horiz. context in same line: advancing"),
+ nao);
+ c->pos = minus(hpos, c->base);
+ } else if (hpos) {
+ debuglf(elem, lit("accept from horiz. context in diff line"), nao);
+ } else {
+ debuglf(elem, lit("accept from vertical context"), nao);
+ }
+ return next_spec_k;
+ } else if (result) {
cons_bind (bindings, new_pos, result);
c->bindings = bindings;
c->pos = minus(new_pos, c->base);
@@ -838,7 +856,10 @@ static val h_accept_fail(match_line_ctx *c)
uw_block_return_proto(target,
if2(sym == accept_s,
- cons(c->bindings, c->pos)),
+ vec(c->bindings,
+ if3(c->data, cons(c->data, c->data_lineno), t),
+ plus(c->pos, c->base),
+ nao)),
sym);
/* TODO: uw_block_return could just throw this */
@@ -2319,8 +2340,10 @@ static val v_trailer(match_files_ctx *c)
*/
uw_unwind {
uw_frame_t *ex = uw_current_exit_point();
- if (ex && ex->uw.type == UW_BLOCK && ex->bl.protocol == accept_s)
- rplacd(ex->bl.result, cons(c->data, c->data_lineno));
+ if (ex && ex->uw.type == UW_BLOCK && ex->bl.protocol == accept_s) {
+ set(vecref_l(ex->bl.result, one), cons(c->data, c->data_lineno));
+ set(vecref_l(ex->bl.result, two), nil);
+ }
}
uw_catch_end;
@@ -2382,7 +2405,8 @@ val freeform_prepare(val vals, match_files_ctx *c, match_line_ctx *mlc)
val term = or2(if2(stringp(first(vals)), first(vals)),
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_lineno, c->curfile);
+ *mlc = ml_all(c->bindings, first_spec, dataline, zero,
+ c->data, c->data_lineno, c->curfile);
return limit;
}
@@ -2420,6 +2444,31 @@ static val v_block(match_files_ctx *c)
result = match_files(mf_spec(*c, spec));
uw_block_end;
+ if (vectorp(result))
+ {
+ val bindings = vecref(result, zero);
+ val vpos = vecref(result, one);
+ val hpos = vecref(result, two);
+ c->bindings = bindings;
+
+ if (hpos && car(vpos) == c->data) {
+ debuglf(specline, lit("accept from horiz. context in same line: advancing"),
+ nao);
+ c->data = cdr(c->data);
+ } else if (hpos) {
+ debuglf(specline, lit("accept from horiz. context in diff line"), nao);
+ } else {
+ debuglf(specline, lit("accept from vertical context"), nao);
+ if (vpos == t) {
+ c->data = nil;
+ } else {
+ c->data = car(vpos);
+ c->data_lineno = cdr(vpos);
+ }
+ }
+ return next_spec_k;
+ }
+
return maybe_next(c, result);
}
}
@@ -2435,9 +2484,10 @@ static val v_accept_fail(match_files_ctx *c)
uw_block_return_proto(target,
if2(sym == accept_s,
- cons(c->bindings,
- if3(c->data, cons(c->data, c->data_lineno),
- t))),
+ vec(c->bindings,
+ if3(c->data, cons(c->data, c->data_lineno), t),
+ nil,
+ nao)),
sym);
/* TODO: uw_block_return could just throw this */
@@ -4340,7 +4390,7 @@ repeat_spec_same_data:
cons_bind (new_bindings, success,
match_line_completely(ml_all(c.bindings, specline,
dataline, zero,
- c.data_lineno, c.curfile)));
+ c.data, c.data_lineno, c.curfile)));
if (!success)
debug_return (nil);