summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--match.c61
-rw-r--r--txr.147
2 files changed, 104 insertions, 4 deletions
diff --git a/match.c b/match.c
index b4306d4a..a46ff145 100644
--- a/match.c
+++ b/match.c
@@ -814,6 +814,16 @@ static val h_coll(match_line_ctx *c)
val mintimes = txeval(elem, getplist(args, mintimes_k), c->bindings);
val maxtimes = txeval(elem, getplist(args, maxtimes_k), c->bindings);
val chars = txeval(elem, getplist(args, chars_k), c->bindings);
+ val counter_spec = getplist(args, counter_k);
+ val consp_counter = consp(counter_spec);
+ val counter = if3(consp_counter, first(counter_spec), counter_spec);
+ val counter_base = if3(consp_counter,
+ eval_with_bindings(second(counter_spec),
+ elem,
+ c->bindings,
+ counter_spec), zero);
+ val counter_binding = if2(counter, cons(counter, nil));
+ val bindings_with_counter = if2(counter, cons(counter_binding, nil));
val have_vars;
val vars = getplist_f(args, vars_k, mkcloc(have_vars));
cnum cmax = fixnump(gap) ? c_num(gap) : (fixnump(max) ? c_num(max) : 0);
@@ -834,6 +844,11 @@ static val h_coll(match_line_ctx *c)
have_vars = t;
}
+ if (counter && !bindable(counter))
+ sem_error(elem, lit("~s: ~s specified as :counter isn't a bindable symbol"),
+ op_sym, counter, nao);
+
+
vars = vars_to_bindings(elem, vars, c->bindings);
if (((times || maxtimes) && ctimax == 0) || (chars && cchars == 0))
@@ -849,8 +864,20 @@ static val h_coll(match_line_ctx *c)
break;
{
- cons_set (new_bindings, new_pos,
- match_line(ml_specline(*c, coll_specline)));
+ if (counter) {
+ rplacd(counter_binding, plus(num(timescounter), counter_base));
+ rplacd(bindings_with_counter, c->bindings);
+ cons_set (new_bindings, new_pos,
+ match_line(ml_bindings_specline(*c, bindings_with_counter, coll_specline)));
+
+ if (!new_bindings) {
+ rplacd(counter_binding, nil);
+ new_bindings = bindings_with_counter;
+ }
+ } else {
+ cons_set (new_bindings, new_pos,
+ match_line(ml_specline(*c, coll_specline)));
+ }
if (until_last_specline) {
uses_or2;
@@ -2840,6 +2867,16 @@ static val v_collect(match_files_ctx *c)
val mintimes = txeval(specline, getplist(args, mintimes_k), c->bindings);
val maxtimes = txeval(specline, getplist(args, maxtimes_k), c->bindings);
val lines = txeval(specline, getplist(args, lines_k), c->bindings);
+ val counter_spec = getplist(args, counter_k);
+ val consp_counter = consp(counter_spec);
+ val counter = if3(consp_counter, first(counter_spec), counter_spec);
+ val counter_base = if3(consp_counter,
+ eval_with_bindings(second(counter_spec),
+ specline,
+ c->bindings,
+ counter_spec), zero);
+ val counter_binding = if2(counter, cons(counter, nil));
+ val bindings_with_counter = if2(counter, cons(counter_binding, nil));
val have_vars;
volatile val vars = getplist_f(args, vars_k, mkcloc(have_vars));
cnum cmax = fixnump(gap) ? c_num(gap) : (fixnump(max) ? c_num(max) : 0);
@@ -2867,6 +2904,10 @@ static val v_collect(match_files_ctx *c)
have_vars = t;
}
+ if (counter && !bindable(counter))
+ sem_error(specline, lit("~s: ~s specified as :counter isn't a bindable symbol"),
+ op_sym, counter, nao);
+
vars = vars_to_bindings(specline, vars, c->bindings);
if ((times && ctimes == 0) || (lines && clines == 0))
@@ -2884,8 +2925,20 @@ static val v_collect(match_files_ctx *c)
break;
{
- cons_set (new_bindings, success,
- match_files(mf_spec(*c, coll_spec)));
+ if (counter) {
+ rplacd(counter_binding, plus(num(timescounter), counter_base));
+ rplacd(bindings_with_counter, c->bindings);
+ cons_set (new_bindings, success,
+ match_files(mf_spec_bindings(*c, coll_spec, bindings_with_counter)));
+
+ if (!new_bindings) {
+ rplacd(counter_binding, nil);
+ new_bindings = bindings_with_counter;
+ }
+ } else {
+ cons_set (new_bindings, success,
+ match_files(mf_spec(*c, coll_spec)));
+ }
/* Until/last clause sees un-collated bindings from collect. */
if (until_last_spec)
diff --git a/txr.1 b/txr.1
index 068254a3..dcfe145b 100644
--- a/txr.1
+++ b/txr.1
@@ -5015,6 +5015,53 @@ The behavior of the
.code :vars
keyword is specified in the following section, "Specifying variables in
.codn collect \(dq.
+
+.meIP :counter >> { variable | >> ( variable << starting-value )}
+The
+.code :counter
+keyword's argument is a variable name symbol,
+or a compound expression consisting of a variable name symbol
+and an \*(TL expression.
+If this keyword argument is specified, then a binding for
+.meta variable
+is established prior to each repetition of the
+.code collect
+body, to an integer value representing the repetition count.
+By default, repetition counts begin at zero.
+If
+.meta starting-value
+is specified, it must evaluate to a number. This number is
+then added to each repetition count, and
+.meta variable
+takes on the resulting displaced value.
+
+If there is an existing binding for
+.meta variable
+prior to the processing of the
+.codn collect ,
+then the variable is shadowed.
+
+The binding is collected in the same way as other bindings
+that are established in the
+.code collect
+body.
+
+The repetition count only increments after a successful match.
+
+The
+.code variable
+is visible to the
+.codn collect 's
+.cod3 until / last
+clause. If that clause is being processed after a successful match
+of the body, then
+.meta variable
+holds an integer value. If the body fails to match, then the
+.cod3 until / last
+clause sees a binding for
+.code variable
+with a value of
+.codn nil .
.PP
.coNP Specifying variables in @ collect