summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2012-01-06 15:39:33 -0800
committerKaz Kylheku <kaz@kylheku.com>2012-01-06 15:39:33 -0800
commit8cdbb92688207d0d9f3bcd37279f89a2cbcdf7a3 (patch)
tree96490ccd1ccd4c1c3f71802a59f5a1cdc1790478
parentb6fdf456e413412aaa7cd132b1f340b5b706eddd (diff)
downloadtxr-8cdbb92688207d0d9f3bcd37279f89a2cbcdf7a3.tar.gz
txr-8cdbb92688207d0d9f3bcd37279f89a2cbcdf7a3.tar.bz2
txr-8cdbb92688207d0d9f3bcd37279f89a2cbcdf7a3.zip
* match.c (v_gather): Implemented until/last clause.
* parser.y (gather_parts, additional_gather_parts): New nonterminals. (gather_clause): Syntax refactored for until/last clause. * txr.1: Updated.
-rw-r--r--ChangeLog9
-rw-r--r--match.c28
-rw-r--r--parser.y23
-rw-r--r--txr.116
4 files changed, 74 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index d59677a1..b179ae08 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2012-01-06 Kaz Kylheku <kaz@kylheku.com>
+
+ * match.c (v_gather): Implemented until/last clause.
+
+ * parser.y (gather_parts, additional_gather_parts): New nonterminals.
+ (gather_clause): Syntax refactored for until/last clause.
+
+ * txr.1: Updated.
+
2012-01-02 Kaz Kylheku <kaz@kylheku.com>
* eval.c (eval_init): Fix regression introduced in
diff --git a/match.c b/match.c
index 044e1300..f37aabdf 100644
--- a/match.c
+++ b/match.c
@@ -2312,6 +2312,7 @@ static val v_gather(match_files_ctx *c)
spec_bind (specline, first_spec, c->spec);
val specs = copy_list(second(first_spec));
val args = third(first_spec);
+ val until_last = fourth(first_spec);
val vars = vars_to_bindings(specline, getplist(args, vars_k), c->bindings);
while (specs && c->data) {
@@ -2319,6 +2320,7 @@ static val v_gather(match_files_ctx *c)
val max_line = zero;
val max_data = nil;
val iter, next;
+ val orig_bindings = c->bindings;
for (iter = specs, next = cdr(iter); iter != nil; iter = next, next = cdr(iter)) {
val nested_spec = first(iter);
@@ -2341,6 +2343,32 @@ static val v_gather(match_files_ctx *c)
}
}
+ if (until_last)
+ {
+ cons_bind (sym, ul_spec, until_last);
+ cons_bind (until_last_bindings, success,
+ match_files(mf_spec(*c, ul_spec)));
+
+ if (success) {
+ debuglf(specline, lit("until/last matched ~a:~a"),
+ first(c->files), c->data_lineno, nao);
+ /* Until discards bindings and position, last keeps them. */
+ if (sym == last_s) {
+ val last_bindings = set_diff(until_last_bindings, c->bindings, eq_f, nil);
+ c->bindings = nappend2(last_bindings, orig_bindings);
+
+ if (success == t) {
+ c->data = t;
+ } else {
+ cons_bind (new_data, new_line, success);
+ c->data = new_data;
+ c->data_lineno = new_line;
+ }
+ }
+ break;
+ }
+ }
+
specs = new_specs;
if (consp(max_data)) {
diff --git a/parser.y b/parser.y
index c6e53276..21571920 100644
--- a/parser.y
+++ b/parser.y
@@ -82,7 +82,7 @@ static val parsed_spec;
%type <val> spec clauses clauses_opt clause
%type <val> all_clause some_clause none_clause maybe_clause
%type <val> cases_clause choose_clause gather_clause collect_clause until_last
-%type <val> clause_parts additional_parts
+%type <val> clause_parts additional_parts gather_parts additional_gather_parts
%type <val> output_clause define_clause try_clause catch_clauses_opt
%type <val> line elems_opt elems clause_parts_h additional_parts_h
%type <val> text texts elem var var_op meta_expr vector
@@ -208,11 +208,23 @@ choose_clause : CHOOSE exprs_opt ')'
;
gather_clause : GATHER exprs_opt ')'
- newl clause_parts { $$ = list(gather_s,
+ newl gather_parts
+ END newl { $$ = list(gather_s,
append2(mapcar(curry_12_1(func_n2(cons), nil),
first($5)), rest($5)),
$2, nao);
rl($$, num($1)); }
+
+ | GATHER exprs_opt ')'
+ newl gather_parts
+ until_last newl
+ clauses
+ END newl { $$ = list(gather_s,
+ append2(mapcar(curry_12_1(func_n2(cons), nil),
+ first($5)), rest($5)),
+ $2, cons(cdr($6), $8), nao);
+ rl($$, num($1)); }
+
| GATHER exprs_opt ')'
newl error { $$ = nil;
yybadtoken(yychar,
@@ -222,6 +234,13 @@ gather_clause : GATHER exprs_opt ')'
yyerror("empty gather clause"); }
;
+gather_parts : clauses additional_gather_parts { $$ = cons($1, $2); }
+ ;
+
+additional_gather_parts : AND newl clauses additional_gather_parts { $$ = cons($3, $4); }
+ | OR newl clauses additional_parts { $$ = cons($3, $4); }
+ | /* empty */ { $$ = nil; }
+ ;
collect_clause : COLLECT exprs_opt ')' newl
clauses END newl { $$ = list(collect_s,
diff --git a/txr.1 b/txr.1
index 8ba7afaf..69f1cc5e 100644
--- a/txr.1
+++ b/txr.1
@@ -1829,6 +1829,14 @@ The syntax follows this pattern
Of course the multi-line clauses are optional. The gather directive takes
keyword parameters, see below.
+Similarly to @(collect), @(gather) has an optional until/last clause:
+
+ @(gather)
+ ...
+ @(until)
+ ...
+ @(end)
+
How gather works is that the text is searched for matches for the single line
and multi-line queries. The clauses are applied in the order in which they appear.
Whenever one of the clauses matches, any bindings it produces are retained and
@@ -1849,6 +1857,14 @@ order:
SHELL=@SHELL
@(end)
+If the until or last clause is present and a match occurs, then the matches
+from the other clauses are discarded and the gather terminates. The difference
+between until and last is that any bindings bindings established in last are
+retained, and the input position is advanced past the matched material.
+The until/last clause has visibility to bindings established in the
+previous clauses in that same iteration, even though those bindings
+end up thrown away.
+
.SS Gather Keyword Parameters
The gather diretive accepts the keyword parameter :vars. The argument to vars is a list