summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-12-22 06:55:54 -0800
committerKaz Kylheku <kaz@kylheku.com>2015-12-22 06:55:54 -0800
commit8ba69bdf267a2cf013e8d696d382f8aee3ca7e1f (patch)
tree558174003e60cb0ffa6af6969ed435bda200af9e
parentd52980a49d0ddaa9c5b6d1344c6a652a82afce43 (diff)
downloadtxr-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.c46
-rw-r--r--txr.1109
2 files changed, 154 insertions, 1 deletions
diff --git a/match.c b/match.c
index 230e23f3..cf648a9f 100644
--- a/match.c
+++ b/match.c
@@ -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);
diff --git a/txr.1 b/txr.1
index 39aa1c61..004dd105 100644
--- a/txr.1
+++ b/txr.1
@@ -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,