summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--match.c49
-rw-r--r--match.h2
-rw-r--r--txr.167
-rw-r--r--txr.vim24
5 files changed, 143 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index a4061b30..633eaecd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2014-10-16 Kaz Kylheku <kaz@kylheku.com>
+
+ New @(line) and @(chr) directives.
+
+ * match.c (line_s): New variable.
+ (h_chr, v_line): New static functions.
+ (syms_init): line_s initialized.
+ (dir_tables_init): Register v_line and h_chr.
+
+ * match.h (line_s): Declared.
+
+ * txr.1: Document @(line) and @(chr) directives.
+
+ * txr.vim: Regenerated.
+
2014-10-15 Kaz Kylheku <kaz@kylheku.com>
* match.c (subst_vars): Fix buggy rendering of TXR Lisp expressions
diff --git a/match.c b/match.c
index aad77c91..44779f61 100644
--- a/match.c
+++ b/match.c
@@ -56,7 +56,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, fuzz_s, load_s;
+val text_s, choose_s, gather_s, do_s, mod_s, modlast_s, line_s, fuzz_s, load_s;
val close_s, require_s;
val longest_k, shortest_k, greedy_k;
val vars_k, resolve_k;
@@ -1142,6 +1142,28 @@ static val h_eol(match_line_ctx *c)
return nil;
}
+static val h_chr(match_line_ctx *c)
+{
+ val elem = first(c->specline);
+ val args = rest(elem);
+ val pat = car(args);
+
+ if (!args || rest(args))
+ sem_error(elem, lit("chr directive takes one argument"), nao);
+
+ uw_env_begin;
+ uw_set_match_context(cons(cons(c->specline, nil), c->bindings));
+ c->bindings = dest_bind(elem, c->bindings, pat, c->pos, eql_f);
+ uw_env_end;
+
+ if (c->bindings == t) {
+ debuglf(elem, lit("chr mismatch (position ~a vs. ~a)"), c->pos, pat, nao);
+ return nil;
+ }
+
+ return next_spec_k;
+}
+
typedef struct {
val spec, files, curfile, bindings, data, data_lineno;
} match_files_ctx;
@@ -3746,6 +3768,28 @@ static val v_close(match_files_ctx *c)
return next_spec_k;
}
+static val v_line(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("line directive takes one argument"), nao);
+
+ uw_env_begin;
+ uw_set_match_context(cons(c->spec, c->bindings));
+ c->bindings = dest_bind(specline, c->bindings, pat, c->data_lineno, eql_f);
+ uw_env_end;
+
+ if (c->bindings == t) {
+ debuglf(specline, lit("line mismatch (line ~a vs. ~a)"), c->data_lineno, pat, nao);
+ return nil;
+ }
+
+ return next_spec_k;
+}
+
static val h_do(match_line_ctx *c)
{
@@ -4033,6 +4077,7 @@ 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);
fuzz_s = intern(lit("fuzz"), user_package);
counter_k = intern(lit("counter"), keyword_package);
}
@@ -4084,6 +4129,7 @@ static void dir_tables_init(void)
sethash(v_directive_table, assert_s, cptr((mem_t *) v_assert));
sethash(v_directive_table, load_s, cptr((mem_t *) v_load));
sethash(v_directive_table, close_s, cptr((mem_t *) v_close));
+ sethash(v_directive_table, line_s, cptr((mem_t *) v_line));
sethash(h_directive_table, text_s, cptr((mem_t *) h_text));
sethash(h_directive_table, var_s, cptr((mem_t *) h_var));
@@ -4107,6 +4153,7 @@ static void dir_tables_init(void)
sethash(h_directive_table, trailer_s, cptr((mem_t *) h_trailer));
sethash(h_directive_table, define_s, cptr((mem_t *) h_define));
sethash(h_directive_table, eol_s, cptr((mem_t *) h_eol));
+ sethash(h_directive_table, chr_s, cptr((mem_t *) h_chr));
sethash(h_directive_table, do_s, cptr((mem_t *) h_do));
sethash(h_directive_table, require_s, cptr((mem_t *) hv_trampoline));
sethash(h_directive_table, assert_s, cptr((mem_t *) h_assert));
diff --git a/match.h b/match.h
index 132cbca9..176edcc7 100644
--- a/match.h
+++ b/match.h
@@ -25,7 +25,7 @@
*/
extern val text_s, choose_s, gather_s, do_s, require_s;
-extern val close_s, load_s, mod_s, modlast_s, counter_k, env_k;
+extern val close_s, load_s, mod_s, modlast_s, line_s, counter_k, env_k;
val format_field(val string_or_list, val modifier, val filter, val eval_fun);
val match_filter(val name, val arg, val other_args);
val match_fun(val name, val args, val input, val files);
diff --git a/txr.1 b/txr.1
index d84467dc..0120ef56 100644
--- a/txr.1
+++ b/txr.1
@@ -91,6 +91,7 @@
..
.\" Multiple directive heading
.de dirs
+. ds s "
. while (\\n[.$]>2) \{\
. as s \f[4]\\$1\f[],
. shift
@@ -2646,6 +2647,10 @@ explicitly in that string.
The fuzz directive, inspired by the patch utility, specifies a partial
match for some lines.
+.ccIP @ @(line) and @ @(chr)
+These directives match a variable or expression against the current line
+number or character position.
+
.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
@@ -3611,6 +3616,68 @@ the
directive, then m of them must succeed nevertheless. (If there
are fewer than m, then this is impossible.)
+.dirs line chr
+
+The
+.code line
+and
+.code chr
+directives perform binding between the current input line number or character
+position within a line, against an expression or variable:
+
+.cblk
+ @(line 42)
+ @(line x)
+ abc@(chr 3)def@(chr y)
+.cble
+
+The directive
+.code @(line 42)
+means "match the current input line number against the integer 42". If
+the current line is 42, then the directive matches, otherwise it fails.
+.code line
+is a vertical directive which doesn't consume a line of input. Thus,
+the following matches at the beginning of an input stream, and
+.code x
+ends up bound to the first line of input:
+
+.cblk
+ @(line 1)
+ @(line 1)
+ @(line 1)
+ @x
+.cble
+
+The directive
+.code @(line x)
+binds variable
+.code x
+to the current input line number, if
+.code x
+is an unbound variable. If
+.code x
+is already bound, then the value of
+.code x
+must match the current line number, otherwise the directive fails.
+
+The
+.code chr
+directive is similar to
+.code line
+except that it's a horizontal directive, and matches the character position
+rather than the line position. Character positions are measured from zero,
+rather than one.
+.code chr
+does not consume a character. Hence the two occurrences of
+.code chr
+in the following example both match, and
+.code x
+takes the entire line of input:
+
+.cblk
+ @(chr 0)@(chr 0)@x
+.cble
+
.dirs some all none maybe cases choose
These directives, called the parallel directives, combine multiple subqueries,
diff --git a/txr.vim b/txr.vim
index 7bd4e810..ab62aec3 100644
--- a/txr.vim
+++ b/txr.vim
@@ -21,18 +21,18 @@ setlocal iskeyword=a-z,A-Z,48-57,!,$,&,*,+,-,<,=,>,?,\\,_,~,/
syn keyword txr_keyword contained accept all and assert
syn keyword txr_keyword contained bind block cases cat
-syn keyword txr_keyword contained catch choose close coll
-syn keyword txr_keyword contained collect defex deffilter define
-syn keyword txr_keyword contained do elif else end
-syn keyword txr_keyword contained eof eol fail filter
-syn keyword txr_keyword contained finally flatten forget freeform
-syn keyword txr_keyword contained fuzz gather if last
-syn keyword txr_keyword contained load local maybe merge
-syn keyword txr_keyword contained next none or output
-syn keyword txr_keyword contained rebind rep repeat require
-syn keyword txr_keyword contained set skip some text
-syn keyword txr_keyword contained throw trailer try until
-syn keyword txr_keyword contained var
+syn keyword txr_keyword contained catch choose chr close
+syn keyword txr_keyword contained coll collect defex deffilter
+syn keyword txr_keyword contained define do elif else
+syn keyword txr_keyword contained end eof eol fail
+syn keyword txr_keyword contained filter finally flatten forget
+syn keyword txr_keyword contained freeform fuzz gather if
+syn keyword txr_keyword contained last line load local
+syn keyword txr_keyword contained maybe merge next none
+syn keyword txr_keyword contained or output rebind rep
+syn keyword txr_keyword contained repeat require set skip
+syn keyword txr_keyword contained some text throw trailer
+syn keyword txr_keyword contained try until var
syn keyword txl_keyword contained * *args* *e* *flo-dig*
syn keyword txl_keyword contained *flo-epsilon* *flo-max* *flo-min* *full-args*