diff options
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | match.c | 49 | ||||
-rw-r--r-- | match.h | 2 | ||||
-rw-r--r-- | txr.1 | 67 | ||||
-rw-r--r-- | txr.vim | 24 |
5 files changed, 143 insertions, 14 deletions
@@ -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 @@ -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)); @@ -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); @@ -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, @@ -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* |