diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2015-12-22 06:55:54 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2015-12-22 06:55:54 -0800 |
commit | 8ba69bdf267a2cf013e8d696d382f8aee3ca7e1f (patch) | |
tree | 558174003e60cb0ffa6af6969ed435bda200af9e | |
parent | d52980a49d0ddaa9c5b6d1344c6a652a82afce43 (diff) | |
download | txr-8ba69bdf267a2cf013e8d696d382f8aee3ca7e1f.tar.gz txr-8ba69bdf267a2cf013e8d696d382f8aee3ca7e1f.tar.bz2 txr-8ba69bdf267a2cf013e8d696d382f8aee3ca7e1f.zip |
New directives @(data) and @(name)
* match.c (data_s, name_s): New symbol variables.
(v_data, v_name): New static functions.
(syms_init): Initialize data_s and name_s.
(dir_tables_init): Register v_data and v_name as vertical
directives, and enable them in horozintal context too
using hv_trampoline.
* txr.1: Documented.
-rw-r--r-- | match.c | 46 | ||||
-rw-r--r-- | txr.1 | 109 |
2 files changed, 154 insertions, 1 deletions
@@ -59,7 +59,8 @@ 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, line_s, fuzz_s, load_s; +val text_s, choose_s, gather_s, do_s, mod_s, modlast_s; +val line_s, data_s, name_s, fuzz_s, load_s; val include_s, close_s, require_s; val longest_k, shortest_k, greedy_k; val vars_k, resolve_k; @@ -3863,6 +3864,43 @@ static val v_line(match_files_ctx *c) return next_spec_k; } +static val v_data(match_files_ctx *c) +{ + spec_bind (specline, first_spec, c->spec); + val args = rest(first_spec); + val pat = car(args); + + if (!args || rest(args)) + sem_error(specline, lit("data directive takes one argument"), nao); + + c->bindings = dest_bind(specline, c->bindings, pat, c->data, eql_f); + + if (c->bindings == t) { + debuglf(specline, lit("data mismatch (data vs. ~s)"), pat, nao); + return nil; + } + + return next_spec_k; +} + +static val v_name(match_files_ctx *c) +{ + spec_bind (specline, first_spec, c->spec); + val args = rest(first_spec); + val pat = car(args); + + if (!args || rest(args)) + sem_error(specline, lit("name directive takes one argument"), nao); + + c->bindings = dest_bind(specline, c->bindings, pat, c->curfile, equal_f); + + if (c->bindings == t) { + debuglf(specline, lit("name mismatch (~s vs. ~s)"), c->curfile, pat, nao); + return nil; + } + + return next_spec_k; +} static val h_do(match_line_ctx *c) { @@ -4157,6 +4195,8 @@ static void syms_init(void) mod_s = intern(lit("mod"), user_package); modlast_s = intern(lit("modlast"), user_package); line_s = intern(lit("line"), user_package); + data_s = intern(lit("data"), user_package); + name_s = intern(lit("name"), user_package); fuzz_s = intern(lit("fuzz"), user_package); counter_k = intern(lit("counter"), keyword_package); } @@ -4209,6 +4249,8 @@ static void dir_tables_init(void) sethash(v_directive_table, load_s, cptr(coerce(mem_t *, v_load))); sethash(v_directive_table, close_s, cptr(coerce(mem_t *, v_close))); sethash(v_directive_table, line_s, cptr(coerce(mem_t *, v_line))); + sethash(v_directive_table, data_s, cptr(coerce(mem_t *, v_data))); + sethash(v_directive_table, name_s, cptr(coerce(mem_t *, v_name))); sethash(h_directive_table, text_s, cptr(coerce(mem_t *, h_text))); sethash(h_directive_table, var_s, cptr(coerce(mem_t *, h_var))); @@ -4238,6 +4280,8 @@ static void dir_tables_init(void) sethash(h_directive_table, require_s, cptr(coerce(mem_t *, hv_trampoline))); sethash(h_directive_table, assert_s, cptr(coerce(mem_t *, h_assert))); sethash(h_directive_table, line_s, cptr(coerce(mem_t *, hv_trampoline))); + sethash(h_directive_table, data_s, cptr(coerce(mem_t *, hv_trampoline))); + sethash(h_directive_table, name_s, cptr(coerce(mem_t *, hv_trampoline))); sethash(non_matching_directive_table, block_s, t); sethash(non_matching_directive_table, accept_s, t); @@ -2833,6 +2833,12 @@ match for some lines. These directives match a variable or expression against the current line number or character position. +.coIP @(name) +Match a variable against the name of the current data source. + +.coIP @(data) +Match a variable against the remaining data (lazy list of strings). + .coIP @(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 @@ -3882,6 +3888,109 @@ character positions: @(line @(+ a (* b c))) .cble +.dir name + +The +.code name +directive performs a binding between the name of the current +data source and a variable or expression: + +.cblk + @(name na) + @(name "data.txt") +.cble + +If +.code na +is an unbound variable, it is bound and takes on the name +of the data source, such as a file name. If +.code na +is bound, then it has to match the name of the data source, +otherwise the directive fails. + +The directive +.code @(name "data.txt") +fails unless the current data source has that name. + +.dir data + +The +.code data +directive performs a binding between the unmatched data +at the current position, and and a variable or expression. +The unmatched data takes the form of a list of strings: + +.cblk + @(data d) +.cble + +The binding is performed on object equality. If +.code d +is already bound, a matching failure occurs unless +.code d +contains the current unmatched data. + +Matching the current data has various uses. + +For instance, two branches of pattern matching can, at some point, bind the +current data into different variables. When those paths join, the variables can +be bound together to create the assertion that the current data had been the +same at those points: + +.cblk + @(all) + @ (skip) + foo + @ (skip) + bar + @ (data x) + @(or) + @ (skip) + xyzzy + @ (skip) + bar + @ (data y) + @(end) + @(require (eq x y)) +.cblk + +Here, two branches of the +.code @(all) +match some material which ends in the line +.codn "bar" . +However, it is possible that this is a different line. The +.code data +directives are used to create an assertion that the data regions matched +by the two branches are identical. That is to say, the unmatched data +.code x +captured after the first +.code "bar" +and the unmatched data +.code y +captured after the second +.code "bar" +must be the same object in order for +.code @(require (eq x y)) +to succeed, which implies that the same +.code "bar" +was matched in both branches of the +.codn @(all) . + +Another use of +.code data +is simply to gain access to the trailing remainder of the unmatched +input in order to print it, or do some special processing on it. + +The +.code tprint +Lisp function is useful for printing the unmatched data as newline-terminated +lines: + +.cblk + @(data remainder) + @(do (tprint remainder)) +.cble + .dirs some all none maybe cases choose These directives, called the parallel directives, combine multiple subqueries, |