From d68e7fd3b31fe1cc619a3a0547db3f506510955e Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Wed, 22 Mar 2017 21:18:53 -0700 Subject: Bind variable during directive delimited match. The existing behavior is: when a situation like @a@(foo) performs a search for the match for @(foo) in order to determine the extent of the text matched by variable a, the variable a is not bound. That is to say, @(foo) is tried in an environment in which a doesn't exist. The variable is only bound when the search succeeds, and then @(foo) is processed again, with the variable now available. The new behavior is that @(foo) is tested in an environment in which a is bound. The variable's value is bound to the range of text between the original position and the tested position where @(foo) is tried. This is subject to the copatibility option. * match.c (ml_bindings_specline_pos): New static function. (search_match_binding_var): New static function, variant of search_match. (h_var): In the var-delimited-by-directive case, perform the search using search_match_binding_var, unless <= 172 compatibility is requested. * txr.1: Compatibility note added. --- match.c | 38 +++++++++++++++++++++++++++++++++++++- txr.1 | 11 +++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/match.c b/match.c index 98c2ee6c..b25502fe 100644 --- a/match.c +++ b/match.c @@ -460,6 +460,16 @@ static match_line_ctx ml_bindings_specline(match_line_ctx c, val bindings, return nc; } +static match_line_ctx ml_bindings_specline_pos(match_line_ctx c, val bindings, + val specline, val pos) +{ + match_line_ctx nc = c; + nc.bindings = bindings; + nc.specline = specline; + nc.pos = pos; + return nc; +} + static val do_match_line(match_line_ctx *c); static val match_line(match_line_ctx c); @@ -534,6 +544,30 @@ static val search_match(match_line_ctx *c, val from_end, val spec) return nil; } +static val search_match_binding_var(match_line_ctx *c, val sym, + val from_end, val spec) +{ + val pos = from_end ? length_str(c->dataline) : c->pos; + val step = from_end ? negone : one; + + for (; (from_end && ge(pos, c->pos)) || + (!from_end && length_str_ge(c->dataline, pos)); + pos = plus(pos, step)) + { + val nbind = acons(sym, sub_str(c->dataline, c->pos, pos), c->bindings); + val new_pos = cdr(match_line(ml_bindings_specline_pos(*c, nbind, + spec, pos))); + if (new_pos == t) { + return cons(pos, t); + } else if (new_pos) { + new_pos = minus(new_pos, c->base); + return cons(pos, minus(new_pos, pos)); + } + } + + return nil; +} + static val h_var(match_line_ctx *c) { val elem = pop(&c->specline); @@ -722,7 +756,9 @@ static val h_var(match_line_ctx *c) c->bindings = acons(sym, sub_str(c->dataline, c->pos, find), c->bindings); c->pos = plus(find, len); } else { - val find = search_match(c, modifier, c->specline); + val find = if3(opt_compat && opt_compat <= 172, + search_match(c, modifier, c->specline), + search_match_binding_var(c, sym, modifier, c->specline)); val fpos = car(find); if (!find) { LOG_MISMATCH("var delimiting spec"); diff --git a/txr.1 b/txr.1 index 9c7cdf34..ec45060f 100644 --- a/txr.1 +++ b/txr.1 @@ -53114,6 +53114,17 @@ of these version values, the described behaviors are provided if is given an argument which is equal or lower. For instance .code "-C 103" selects the behaviors described below for version 105, but not those for 102. +.IP 172 +A value of 172 or lower restores a behavior of the \*(TX pattern +matching language when matching a variable followed by a directive, such as +.codn "@a@(fun b)" . +The old behavior is that the scan for a match for the directive +takes place in an environment in which a binding for +.code a +has not yet been established. The new behavior is that the variable +is always bound prior to the processing of the directive. During +the search, it is bound to the range of text spanning between the +starting position and the position being tried. .IP 170 A value of 170 or lower disables the behavior that \*(TX scans standard input when no input sources are specified on the command line. Standard input must -- cgit v1.2.3