diff options
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | match.c | 43 | ||||
-rw-r--r-- | txr.1 | 9 |
3 files changed, 53 insertions, 14 deletions
@@ -1,5 +1,20 @@ 2011-11-17 Kaz Kylheku <kaz@kylheku.com> + * match.c (h_fun, v_fun): Bugfix! copy_list should be used for copying + the bindings, not copy_alist. Otherwise functions cannot destructively + update a binding, which is useless. We want a function not to + manipulate the binding list, but to be able to manipulate the + contents of bindings. + (match_files_ctx): Declaration moved ahead of match_line. + (v_fun): Forward declaration added. + (match_line): Allow vertical functions to be called from + a horizontal context, in a limited way. + + * txr.1: Mention the possibility of a call from a horizontal + context falling back on a vertical function. + +2011-11-17 Kaz Kylheku <kaz@kylheku.com> + * parser.y: Bugfix: precedence of { } must be low, close to that of IDENT, otherwise @{var}@(foo) doesn't parse. @@ -941,7 +941,7 @@ static val h_fun(match_line_ctx c, match_line_ctx *cout) val ub_p_a_pairs = nil; val body = cdr(func); val piter, aiter; - val bindings_cp = copy_alist(c.bindings); + val bindings_cp = copy_list(c.bindings); if (!equal(length(args), length(params))) sem_error(elem, lit("function ~a takes ~a argument(s)"), @@ -1031,6 +1031,15 @@ static val h_eol(match_line_ctx c, match_line_ctx *cout) return nil; } +typedef struct { + val spec, files, bindings, data, data_lineno; +} match_files_ctx; + +static match_files_ctx mf_all(val spec, val files, val bindings, + val data, val data_lineno); + +static val v_fun(match_files_ctx *c); + static val match_line(match_line_ctx c) { for (;;) { @@ -1095,12 +1104,26 @@ static val match_line(match_line_ctx c) c = nc; continue; } else if (result == decline_k) { - if (gethash(v_directive_table, directive)) - sem_error(elem, lit("~a only exists as a vertical directive"), - directive, nao); - else - sem_error(elem, lit("no such function or directive: ~a"), - directive, nao); + val spec = rlcp(cons(cons(elem, nil), nil), elem); + match_files_ctx vc = mf_all(spec, nil, c.bindings, nil, num(0)); + val vresult = v_fun(&vc); + + if (vresult == next_spec_k) { + c.bindings = vc.bindings; + break; + } else if (vresult == repeat_spec_k) { + c.bindings = vc.bindings; + continue; + } else if (vresult == decline_k) { + if (gethash(v_directive_table, directive)) + sem_error(elem, lit("~a only exists as a vertical directive"), + directive, nao); + else + sem_error(elem, lit("no such function or directive: ~a"), + directive, nao); + } else { + return vresult; + } } else { return result; } @@ -1539,10 +1562,6 @@ static void do_output(val bindings, val specs, val filter, val out) } } -typedef struct { - val spec, files, bindings, data, data_lineno; -} match_files_ctx; - static match_files_ctx mf_all(val spec, val files, val bindings, val data, val data_lineno) { @@ -2889,7 +2908,7 @@ static val v_fun(match_files_ctx *c) val ub_p_a_pairs = nil; val body = cdr(func); val piter, aiter; - val bindings_cp = copy_alist(c->bindings); + val bindings_cp = copy_list(c->bindings); debug_check(specline, c->bindings, if2(consp(c->data), car(c->data)), c->data_lineno, nil); @@ -3021,8 +3021,13 @@ Example: Output: fun="horizontal" -A call made in a clearly horizontal context will ignore -the vertical definition, if any, and require the horizontal function. +A call made in a clearly horizontal context will prefer the +horizontal function, and only fall back on the vertical one +if the horizontal one doesn't exist. (In this fall-back case, +the vertical function is called with empty data; it is useful +for calling vertical functions which process arguments and +produce values.) + In the next example, the call is followed by trailing material, placing it in a horizontal context. Leading material will do the same thing: |