From 73625e0ae9b4fde9c6ff64bd6dc22a1b7797be1a Mon Sep 17 00:00:00 2001
From: Kaz Kylheku <kaz@kylheku.com>
Date: Sun, 26 Feb 2012 20:58:31 -0800
Subject: Fixing long-time (pre-GIT) bug. The object (nil) was stupidly used to
 represent empty optional output clauses, distinguishing them from missing
 clauses. This creates an ambiguity, so that an @(output) block which puts out
 a single empty line is treated as empty. Present but empty clauses are now
 represented by t.

* match.c (do_output_line): Check for t and bail.
(do_output): Check for t instead of (nil) and bail.

* parser.y (o_elems_opt2): Nonterminal deleted.
(out_clauses_opt): Empty case generates nil.
(req_parts_opt): o_elems_opt2 replaced by o_elems_opt.
(repeat_rep_helper): Function now keeps track of which
clauses were specified. For those that were specified, but
empty, it substitutes t.

* tests/008/empty-clauses.expected: New file.

* tests/008/empty-clauses.txr: New file.
---
 parser.y | 66 +++++++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 38 insertions(+), 28 deletions(-)

(limited to 'parser.y')

diff --git a/parser.y b/parser.y
index e5f06b54..8df15ae5 100644
--- a/parser.y
+++ b/parser.y
@@ -88,7 +88,7 @@ static val parsed_spec;
 %type <val> text texts elem var var_op modifiers meta_expr vector
 %type <val> list exprs exprs_opt expr out_clauses out_clauses_opt out_clause
 %type <val> repeat_clause repeat_parts_opt o_line
-%type <val> o_elems_opt o_elems_opt2 o_elems o_elem o_var rep_elem rep_parts_opt
+%type <val> o_elems_opt o_elems o_elem o_var rep_elem rep_parts_opt
 %type <val> regex lisp_regex regexpr regbranch
 %type <val> regterm regclass regclassterm regrange
 %type <val> strlit chrlit quasilit quasi_items quasi_item litchars
@@ -532,7 +532,7 @@ repeat_parts_opt : SINGLE newl
 
 
 out_clauses_opt : out_clauses   { $$ = $1; }
-                | /* empty */   { $$ = null_list; }
+                | /* empty */   { $$ = nil; }
 
 o_line : o_elems_opt '\n'       { $$ = $1; }
        ;
@@ -542,11 +542,6 @@ o_elems_opt : o_elems           { $$ = o_elems_transform($1);
             |                   { $$ = nil; }
             ;
 
-o_elems_opt2 : o_elems          { $$ = o_elems_transform($1);
-                                  rl($$, num(lineno)); }
-             |                  { $$ = null_list; }
-             ;
-
 o_elems : o_elem                { $$ = cons($1, nil); }
         | o_elem o_elems        { $$ = cons($1, $2); }
         ;
@@ -570,25 +565,25 @@ rep_elem : REP exprs_opt ')' o_elems_opt
                                   yybadtoken(yychar, lit("rep clause")); }
          ;
 
-rep_parts_opt : SINGLE o_elems_opt2
+rep_parts_opt : SINGLE o_elems_opt
                 rep_parts_opt           { $$ = cons(cons(single_s, $2), $3);
                                           rl($$, num($1)); }
-              | FIRST o_elems_opt2
+              | FIRST o_elems_opt
                 rep_parts_opt           { $$ = cons(cons(first_s, $2), $3);
                                           rl($$, num($1)); }
-              | LAST o_elems_opt2
+              | LAST o_elems_opt
                 rep_parts_opt           { $$ = cons(cons(last_s, $2), $3);
                                           rl($$, num($1)); }
-              | EMPTY o_elems_opt2
+              | EMPTY o_elems_opt
                 rep_parts_opt           { $$ = cons(cons(empty_s, $2), $3);
                                           rl($$, num($1)); }
               | MOD exprs_opt ')'
-                o_elems_opt2
+                o_elems_opt
                 rep_parts_opt           { $$ = cons(cons(mod_s, 
                                                          cons($2, $4)), $5);
                                           rl($$, num($1)); }
               | MODLAST exprs_opt ')'
-                o_elems_opt2
+                o_elems_opt
                 rep_parts_opt           { $$ = cons(cons(modlast_s, 
                                                          cons($2, $4)), $5);
                                           rl($$, num($1)); }
@@ -857,12 +852,13 @@ litchars : LITCHAR              { $$ = cons(chr($1), nil); }
 
 static val repeat_rep_helper(val sym, val args, val main, val parts)
 {
-  val single_parts = nil;
-  val first_parts = nil;
-  val last_parts = nil;
-  val empty_parts = nil;
-  val mod_parts = nil;
-  val modlast_parts = nil;
+  uses_or2;
+  val single_parts = nil, single_parts_p = nil;
+  val first_parts = nil, first_parts_p = nil;
+  val last_parts = nil, last_parts_p = nil;
+  val empty_parts = nil, empty_parts_p = nil;
+  val mod_parts = nil, mod_parts_p = nil;
+  val modlast_parts = nil, modlast_parts_p = nil;
   val iter;
 
   for (iter = parts; iter != nil; iter = cdr(iter)) {
@@ -870,25 +866,39 @@ static val repeat_rep_helper(val sym, val args, val main, val parts)
     val sym = car(part);
     val clauses = copy_list(cdr(part));
 
-    if (sym == single_s)
+    if (sym == single_s) {
       single_parts = nappend2(single_parts, clauses);
-    else if (sym == first_s)
+      single_parts_p = t;
+    } else if (sym == first_s) {
       first_parts = nappend2(first_parts, clauses);
-    else if (sym == last_s)
+      first_parts_p = t;
+    } else if (sym == last_s) {
       last_parts = nappend2(last_parts, clauses);
-    else if (sym == empty_s)
+      last_parts_p = t;
+    } else if (sym == empty_s) {
       empty_parts = nappend2(empty_parts, clauses);
-    else if (sym == mod_s)
+      empty_parts_p = t;
+    } else if (sym == mod_s) {
       mod_parts = cons(clauses, mod_parts);
-    else if (sym == modlast_s)
+      mod_parts_p = t;
+    } else if (sym == modlast_s) {
       modlast_parts = cons(clauses, modlast_parts);
-    else
+      modlast_parts_p = t;
+    } else {
       abort();
+    }
   }
 
+  single_parts = or2(single_parts, single_parts_p);
+  first_parts = or2(first_parts, first_parts_p);
+  last_parts = or2(last_parts, last_parts_p);
+  empty_parts = or2(empty_parts, empty_parts_p);
+  mod_parts = or2(nreverse(mod_parts), mod_parts_p);
+  modlast_parts = or2(nreverse(modlast_parts), modlast_parts_p);
+
   return list(sym, args, main, single_parts, first_parts,
-              last_parts, empty_parts,
-              nreverse(mod_parts), nreverse(modlast_parts), nao);
+              last_parts, empty_parts, nreverse(mod_parts),
+              nreverse(modlast_parts), nao);
 }
 
 static val o_elems_transform(val o_elems)
-- 
cgit v1.2.3