diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2012-01-06 20:37:10 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2012-01-06 20:37:10 -0800 |
commit | 21eb30046e3993ffaf61fcb050702aaeb688fb8c (patch) | |
tree | 84e9692a07665ba0484da4e6fed33a57bf1d6388 | |
parent | 8cdbb92688207d0d9f3bcd37279f89a2cbcdf7a3 (diff) | |
download | txr-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-- | ChangeLog | 9 | ||||
-rw-r--r-- | match.c | 65 | ||||
-rw-r--r-- | txr.1 | 23 |
3 files changed, 96 insertions, 1 deletions
@@ -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. @@ -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)); @@ -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, |