summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--match.c47
-rw-r--r--txr.130
3 files changed, 67 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index 83576e3d..d1ecf4ec 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
2011-10-08 Kaz Kylheku <kaz@kylheku.com>
+ * match.c (mintimes_k, maxtimes_k): New keyword variables.
+ (match_line): Implemented :mintimes and :maxtimes, changing
+ the semantics of :times.
+ (match_files): Likewise.
+ (match_init): New keyword variables initialized.
+
+ * txr.1: Updated.
+
+2011-10-08 Kaz Kylheku <kaz@kylheku.com>
+
* HACKING: Formatting.
2011-10-07 Kaz Kylheku <kaz@kylheku.com>
diff --git a/match.c b/match.c
index e01be988..580527e4 100644
--- a/match.c
+++ b/match.c
@@ -47,7 +47,8 @@
int output_produced;
-val mingap_k, maxgap_k, gap_k, times_k, lines_k, chars_k;
+val mingap_k, maxgap_k, gap_k, mintimes_k, maxtimes_k, times_k;
+val lines_k, chars_k;
val choose_s, longest_k, shortest_k, greedy_k;
static void debugf(val fmt, ...)
@@ -556,16 +557,21 @@ static val match_line(val bindings, val specline, val dataline,
val min = getplist(args, mingap_k);
val gap = getplist(args, gap_k);
val times = getplist(args, times_k);
+ val mintimes = getplist(args, mintimes_k);
+ val maxtimes = getplist(args, maxtimes_k);
val chars = getplist(args, chars_k);
cnum cmax = nump(gap) ? c_num(gap) : (nump(max) ? c_num(max) : 0);
cnum cmin = nump(gap) ? c_num(gap) : (nump(min) ? c_num(min) : 0);
cnum mincounter = cmin, maxcounter = 0;
- cnum timescounter = 0, charscounter = 0;
- cnum ctimes = nump(times) ? c_num(times) : 0;
+ cnum ctimax = nump(times) ? c_num(times)
+ : (nump(maxtimes) ? c_num(maxtimes) : 0);
+ cnum ctimin = nump(times) ? c_num(times)
+ : (nump(mintimes) ? c_num(mintimes) : 0);
cnum cchars = nump(chars) ? c_num(chars) : 0;
+ cnum timescounter = 0, charscounter = 0;
val iter;
- if ((times && ctimes == 0) || (chars && cchars == 0))
+ if (((times || maxtimes) && ctimax == 0) || (chars && cchars == 0))
break;
for (;;) {
@@ -621,8 +627,11 @@ static val match_line(val bindings, val specline, val dataline,
pos = new_pos;
bug_unless (length_str_ge(dataline, pos));
- if (times && ++timescounter >= ctimes)
+ timescounter++;
+
+ if ((times || maxtimes) && timescounter >= ctimax)
break;
+
mincounter = 0;
maxcounter = 0;
} else {
@@ -638,6 +647,12 @@ next_coll:
}
}
+ if ((times || mintimes) && timescounter < ctimin) {
+ debuglf(spec_lineno, lit("fewer than ~a iterations collected"),
+ num(ctimin), nao);
+ return nil;
+ }
+
if (!bindings_coll)
debuglf(spec_lineno, lit("nothing was collected"), nao);
@@ -1617,10 +1632,16 @@ repeat_spec_same_data:
val min = getplist(args, mingap_k);
val gap = getplist(args, gap_k);
val times = getplist(args, times_k);
+ val mintimes = getplist(args, mintimes_k);
+ val maxtimes = getplist(args, maxtimes_k);
val lines = getplist(args, lines_k);
cnum cmax = nump(gap) ? c_num(gap) : (nump(max) ? c_num(max) : 0);
cnum cmin = nump(gap) ? c_num(gap) : (nump(min) ? c_num(min) : 0);
cnum mincounter = cmin, maxcounter = 0;
+ cnum ctimax = nump(times) ? c_num(times)
+ : (nump(maxtimes) ? c_num(maxtimes) : 0);
+ cnum ctimin = nump(times) ? c_num(times)
+ : (nump(mintimes) ? c_num(mintimes) : 0);
cnum timescounter = 0, linescounter = 0;
cnum ctimes = nump(times) ? c_num(times) : 0;
cnum clines = nump(lines) ? c_num(lines) : 0;
@@ -1716,15 +1737,17 @@ repeat_spec_same_data:
data = new_data;
data_lineno = new_lineno;
*car_l(success) = nil;
-
- if (times && ++timescounter >= ctimes)
- break;
} else {
debuglf(spec_linenum, lit("collect consumed entire file"), nao);
data = nil;
}
mincounter = 0;
maxcounter = 0;
+
+ timescounter++;
+
+ if ((times || maxtimes) && timescounter >= ctimax)
+ break;
} else {
next_collect:
mincounter++;
@@ -1743,6 +1766,12 @@ repeat_spec_same_data:
return nil;
}
+ if ((times || mintimes) && timescounter < ctimin) {
+ debuglf(spec_linenum, lit("fewer than ~a iterations collected"),
+ num(ctimin), nao);
+ return nil;
+ }
+
if (!bindings_coll)
debuglf(spec_linenum, lit("nothing was collected"), nao);
@@ -2271,6 +2300,8 @@ void match_init(void)
mingap_k = intern(lit("mingap"), keyword_package);
maxgap_k = intern(lit("maxgap"), keyword_package);
gap_k = intern(lit("gap"), keyword_package);
+ mintimes_k = intern(lit("mintimes"), keyword_package);
+ maxtimes_k = intern(lit("maxtimes"), keyword_package);
times_k = intern(lit("times"), keyword_package);
lines_k = intern(lit("lines"), keyword_package);
chars_k = intern(lit("chars"), keyword_package);
diff --git a/txr.1 b/txr.1
index 62bbcd8b..d104be0d 100644
--- a/txr.1
+++ b/txr.1
@@ -1540,14 +1540,15 @@ If it matches successfully, it is tried at the line following the
entire extent of matched data, if there is one. Thus, the collected regions do
not overlap.
-The collect as a whole always succeeds, even if the subquery does not match at
-any position, and even if the until/last clause does not match. That is to say,
-a query will never fail for the reason that a collect didn't collect anything.
+Unless certain keywords are specified, or unless the collect is explicitly
+failed with @(fail), it always succeeds, even if it collects nothing,
+and even if the until/last clause never finds a match.
-If no until/last clause is specified, the collect is unbounded. It consumes the
-entire data file. If any query material follows such the collect clause, it
-will fail if it tries to match anything in the current file; but of course, it
-is possible to continue matching in another file by means of @(next).
+If no until/last clause is specified, and the collect is not limited
+using parameters, the collect is unbounded. It consumes the entire data
+file. If any query material follows such the collect clause, it will fail if it
+tries to match anything in the current file; but of course, it is possible to
+continue matching in another file by means of @(next).
If an until/last clause is specified, the collection stops when that clause
matches at the current position.
@@ -1690,10 +1691,15 @@ used if these other two are not used. Thus:
@a
@(end)
-means collect every other line starting with the current line. Two other
-keywords are :lines and :times. The :lines parameter specifies the upper bound
-on how many lines should be scanned by the collect, and :times specifies the
-upper bound on how many times the collect can match.
+means collect every other line starting with the current line. Several
+other supported keywords are :times, :mintimes, :maxtimes and lines.
+The shorthand :times N means the same thing as :mintimes N :maxtimes N.
+These specify how many matches should be collected. If there are fewer
+than mintimes matches, the collect fails. If maxtimes matches are collected,
+collect stops collecting immediately.
+
+Finally, the :lines parameter specifies the upper bound on how many lines
+should be scanned by the collect.
.SS The Coll Directive
@@ -1825,7 +1831,7 @@ solved with cases:
The @(coll) directive takes most of the same parameters as @(collect).
See the section Collect Keyword Parameters above.
So for instance @(coll :gap 0) means that the collects must be
-consecutive, and @(coll :times 2) means that (at most) two matches
+consecutive, and @(coll :maxtimes 2) means that at most two matches
will be collected. The :lines keyword does not exist, but there is
an analogous :chars keyword.