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