summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2012-01-06 20:37:10 -0800
committerKaz Kylheku <kaz@kylheku.com>2012-01-06 20:37:10 -0800
commit21eb30046e3993ffaf61fcb050702aaeb688fb8c (patch)
tree84e9692a07665ba0484da4e6fed33a57bf1d6388
parent8cdbb92688207d0d9f3bcd37279f89a2cbcdf7a3 (diff)
downloadtxr-21eb30046e3993ffaf61fcb050702aaeb688fb8c.tar.gz
txr-21eb30046e3993ffaf61fcb050702aaeb688fb8c.tar.bz2
txr-21eb30046e3993ffaf61fcb050702aaeb688fb8c.zip
* match.c (fuzz_s): New symbol variable.
(v_fuzz): New static function. (syms_init): fuzz_s initialized. (dir_tables_init): v_fuzz entered into v_directive_table. * txr.1: Documented @(fuzz).
-rw-r--r--ChangeLog9
-rw-r--r--match.c65
-rw-r--r--txr.123
3 files changed, 96 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index b179ae08..8a448fc5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2012-01-06 Kaz Kylheku <kaz@kylheku.com>
+ * match.c (fuzz_s): New symbol variable.
+ (v_fuzz): New static function.
+ (syms_init): fuzz_s initialized.
+ (dir_tables_init): v_fuzz entered into v_directive_table.
+
+ * txr.1: Documented @(fuzz).
+
+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.
diff --git a/match.c b/match.c
index f37aabdf..f13b2578 100644
--- a/match.c
+++ b/match.c
@@ -55,7 +55,7 @@ int opt_arraydims = 1;
val decline_k, next_spec_k, repeat_spec_k;
val mingap_k, maxgap_k, gap_k, mintimes_k, maxtimes_k, times_k;
val lines_k, chars_k;
-val text_s, choose_s, gather_s, do_s, mod_s, modlast_s;
+val text_s, choose_s, gather_s, do_s, mod_s, modlast_s, fuzz_s;
val longest_k, shortest_k, greedy_k;
val vars_k, resolve_k;
val append_k, into_k, var_k, list_k, string_k, env_k, counter_k;
@@ -1909,6 +1909,67 @@ static val v_skip(match_files_ctx *c)
}
}
+static val v_fuzz(match_files_ctx *c)
+{
+ spec_bind (specline, first_spec, c->spec);
+
+ if (rest(specline))
+ return decline_k;
+
+ c->spec = rest(c->spec);
+
+ if (!c->spec)
+ return cons(c->bindings, cons(c->data, c->data_lineno));
+
+ {
+ val fuzz_spec = first(first(c->spec));
+ val args = rest(first_spec);
+ val m = txeval(fuzz_spec, first(args), c->bindings);
+ val n = txeval(fuzz_spec, second(args), c->bindings);
+ cnum cm = fixnump(m) ? c_num(m) : 0;
+ cnum cn = fixnump(n) ? c_num(n) : 0;
+
+ {
+ cnum reps, good;
+
+ for (reps = 0, good = 0; reps < cn; reps++) {
+ match_files_ctx fuzz_ctx = mf_spec(*c, cons(first(c->spec), nil));
+ val result = match_files(fuzz_ctx);
+
+ if (result) {
+ debuglf(fuzz_spec, lit("fuzz matched ~a:~a"), first(c->files),
+ c->data_lineno, nao);
+ good++;
+ } else {
+ debuglf(fuzz_spec, lit("fuzz didn't match ~a:~a"),
+ first(c->files), c->data_lineno, nao);
+ }
+
+ if (!c->data)
+ break;
+ c->data = rest(c->data);
+ c->data_lineno = plus(c->data_lineno, num(1));
+ c->spec = rest(c->spec);
+ if (!c->spec) {
+ if (good >= cm)
+ break;
+ debuglf(fuzz_spec, lit("fuzz failed ~a:~a"), first(c->files),
+ c->data_lineno, nao);
+ return nil;
+ }
+ }
+
+ if (reps == cn && good < cm) {
+ debuglf(fuzz_spec, lit("fuzz failed ~a:~a"), first(c->files),
+ c->data_lineno, nao);
+ return nil;
+ }
+
+ return match_files(*c);
+ }
+ }
+}
+
static val v_trailer(match_files_ctx *c)
{
if (rest(rest(first(c->spec))))
@@ -3467,6 +3528,7 @@ static void syms_init(void)
mod_s = intern(lit("mod"), user_package);
modlast_s = intern(lit("modlast"), user_package);
+ fuzz_s = intern(lit("fuzz"), user_package);
counter_k = intern(lit("counter"), keyword_package);
}
@@ -3478,6 +3540,7 @@ static void dir_tables_init(void)
protect(&h_directive_table, &v_directive_table, (val *) 0);
sethash(v_directive_table, skip_s, cptr((mem_t *) v_skip));
+ sethash(v_directive_table, fuzz_s, cptr((mem_t *) v_fuzz));
sethash(v_directive_table, trailer_s, cptr((mem_t *) v_trailer));
sethash(v_directive_table, freeform_s, cptr((mem_t *) v_freeform));
sethash(v_directive_table, block_s, cptr((mem_t *) v_block));
diff --git a/txr.1 b/txr.1
index 69f1cc5e..20cb876d 100644
--- a/txr.1
+++ b/txr.1
@@ -1129,6 +1129,10 @@ Treat the remainder of the input as one big string, and apply the following
query line to that string. The newline characters (or custom separators) appear
explicitly in that string.
+.IP @(fuzz)
+The fuzz directive, inspired by the patch utility, specifies a partial
+match for some lines.
+
.IP @(some)
Multiple clauses are each applied to the same input. Succeeds if at least one
of the clauses matches the input. The bindings established by earlier
@@ -1620,6 +1624,25 @@ Example:
@(coll)@{token /[^:]*/}:@(end)
@(end)
+.SS The Fuzz Directive
+
+The fuzz directive allows for an imperfect match spanning a set number of
+lines. It takes two arguments, both expressions that should evaluate
+to integers:
+
+ @(fuzz m n)
+ ...
+
+This expresses that over the next n query lines, the matching strictness
+is relaxed a little bit. Only m out of those n lines have to match.
+Afterward, the rest of the query follows normal, strict processing.
+
+In the degenerate situation that there are fewer than n query lines following
+the fuzz directive, then m of them must succeed nevertheless. (If there
+are fewer than m, then this is impossible.)
+
+.B TXR's
+
.SS The Some, All, None, Maybe, Cases and Choose directives
These directives, called the parallel directives, combine multiple subqueries,