From 68ca87bc780e25dea1418019161d99727225d1ce Mon Sep 17 00:00:00 2001
From: Kaz Kylheku <kaz@kylheku.com>
Date: Thu, 17 Nov 2011 11:18:42 -0800
Subject: * 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.
---
 match.c | 43 +++++++++++++++++++++++++++++++------------
 1 file changed, 31 insertions(+), 12 deletions(-)

(limited to 'match.c')

diff --git a/match.c b/match.c
index 3e10b9bb..a4efdf4b 100644
--- a/match.c
+++ b/match.c
@@ -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);
 
-- 
cgit v1.2.3