From 73625e0ae9b4fde9c6ff64bd6dc22a1b7797be1a Mon Sep 17 00:00:00 2001 From: Kaz Kylheku 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. --- ChangeLog | 22 ++++++++++++++ match.c | 5 ++- parser.y | 66 +++++++++++++++++++++++----------------- tests/008/empty-clauses.expected | 6 ++++ tests/008/empty-clauses.txr | 18 +++++++++++ 5 files changed, 88 insertions(+), 29 deletions(-) create mode 100644 tests/008/empty-clauses.expected create mode 100644 tests/008/empty-clauses.txr diff --git a/ChangeLog b/ChangeLog index dff5c576..b4bbe9b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2012-02-26 Kaz Kylheku + + 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. + 2012-02-26 Kaz Kylheku Bug #35625 diff --git a/match.c b/match.c index e8fc7f65..5dda9602 100644 --- a/match.c +++ b/match.c @@ -1559,6 +1559,9 @@ static val extract_bindings(val bindings, val output_spec) static void do_output_line(val bindings, val specline, val filter, val out) { + if (specline == t) + return; + for (; specline; specline = rest(specline)) { val elem = first(specline); @@ -1689,7 +1692,7 @@ static void do_output_line(val bindings, val specline, val filter, val out) static void do_output(val bindings, val specs, val filter, val out) { - if (equal(specs, null_list)) + if (specs == t) return; for (; specs; specs = cdr(specs)) { 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 text texts elem var var_op modifiers meta_expr vector %type list exprs exprs_opt expr out_clauses out_clauses_opt out_clause %type repeat_clause repeat_parts_opt o_line -%type o_elems_opt o_elems_opt2 o_elems o_elem o_var rep_elem rep_parts_opt +%type o_elems_opt o_elems o_elem o_var rep_elem rep_parts_opt %type regex lisp_regex regexpr regbranch %type regterm regclass regclassterm regrange %type 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) diff --git a/tests/008/empty-clauses.expected b/tests/008/empty-clauses.expected new file mode 100644 index 00000000..b0cbdaf5 --- /dev/null +++ b/tests/008/empty-clauses.expected @@ -0,0 +1,6 @@ + +b +b +fa +b +b diff --git a/tests/008/empty-clauses.txr b/tests/008/empty-clauses.txr new file mode 100644 index 00000000..486d42a2 --- /dev/null +++ b/tests/008/empty-clauses.txr @@ -0,0 +1,18 @@ +@(bind a ("a" "b")) +@(output) +@(repeat) +@a +@(first) + +@(end) +@(repeat) +@a +@(first) +@(end) +@(repeat) +@a +@(first) +f@a +@(end) +@(rep)@a@(first)@(end) +@(end) -- cgit v1.2.3