cex: don't display twice unifying examples if there is no color

Akim Demaille <[email protected]>
Newsgroups gmane.comp.parsers.bison.patches
Message-ID <[email protected]>
commit 0f120354b623b10dc7e130f931348a030839cd75
Author: Akim Demaille <[email protected]>
Date:   Fri Jun 19 07:06:24 2020 +0200

    cex: don't display twice unifying examples if there is no color
    
    It makes no sense, and is actually confusing, to display twice the
    same example with no visible difference.
    
    * src/complain.h, src/complain.c (is_styled): New.
    * src/counterexample.c (print_counterexample): Display the unified
    example a second time only if it makes a difference.
    * tests/conflicts.at, tests/counterexample.at, tests/report.at: Adjust.
    * tests/diagnostics.at: Make sure we do display the unifying examples
    twice when colors are enabled.  And check those colors.

diff --git a/src/complain.c b/src/complain.c
index 92d5fc52..889f0ae6 100644
--- a/src/complain.c
+++ b/src/complain.c
@@ -104,6 +104,23 @@ flush (FILE *out)
   fflush (out);
 }
 
+bool
+is_styled (FILE *out)
+{
+  if (out != stderr)
+    return false;
+  if (color_debug)
+    return true;
+#if HAVE_LIBTEXTSTYLE
+  return (color_mode == color_yes
+          || color_mode == color_html
+          || (color_mode == color_tty && isatty (STDERR_FILENO)));
+#else
+  return false;
+#endif
+}
+
+
 /*------------------------.
 | --warnings's handling.  |
 `------------------------*/
@@ -288,9 +305,7 @@ void
 complain_init_color (void)
 {
 #if HAVE_LIBTEXTSTYLE
-  if (color_mode == color_yes
-      || color_mode == color_html
-      || (color_mode == color_tty && isatty (STDERR_FILENO)))
+  if (is_styled (stderr))
     {
       style_file_prepare ("BISON_STYLE", "BISON_STYLEDIR", pkgdatadir (),
                           "bison-default.css");
diff --git a/src/complain.h b/src/complain.h
index eab5720d..303d0a54 100644
--- a/src/complain.h
+++ b/src/complain.h
@@ -36,6 +36,8 @@ void end_use_class (const char *style, FILE *out);
 /** Flush \a out.  */
 void flush (FILE *out);
 
+/** Whether there's styling on OUT.  */
+bool is_styled (FILE *out);
 
 /*-------------.
 | --warnings.  |
diff --git a/src/counterexample.c b/src/counterexample.c
index 01114fdf..e5b3a0af 100644
--- a/src/counterexample.c
+++ b/src/counterexample.c
@@ -27,6 +27,7 @@
 #include <gl_rbtreehash_list.h>
 #include <hash.h>
 #include <stdlib.h>
+#include <textstyle.h>
 #include <time.h>
 
 #include "closure.h"
@@ -109,9 +110,15 @@ print_counterexample (counterexample *cex, FILE *out, const char *prefix)
            prefix, _("First derivation"));
   derivation_print (cex->d1, out, prefix);
 
-  fprintf (out, "  %s%-20s ",
-           prefix, cex->unifying ? _("Example") : _("Second example"));
-  derivation_print_leaves (cex->d2, out, prefix);
+  // If we output to the terminal (via stderr) and we have color
+  // support, display unifying examples a second time, as color allows
+  // to see the differences.
+  if (!cex->unifying || is_styled (stderr))
+    {
+      fprintf (out, "  %s%-20s ",
+               prefix, cex->unifying ? _("Example") : _("Second example"));
+      derivation_print_leaves (cex->d2, out, prefix);
+    }
   fprintf (out, "  %s%-20s ",
            prefix, _("Second derivation"));
   derivation_print (cex->d2, out, prefix);
diff --git a/tests/conflicts.at b/tests/conflicts.at
index a3aadbff..95ab79df 100644
--- a/tests/conflicts.at
+++ b/tests/conflicts.at
@@ -763,7 +763,7 @@ AT_CLEANUP
 
 AT_SETUP([Unresolved SR Conflicts])
 
-AT_KEYWORDS([report])
+AT_KEYWORDS([cex report])
 
 AT_DATA([input.y],
 [[%token NUM OP
@@ -866,7 +866,6 @@ State 5
         1 exp: exp . OP exp
       Example                  exp OP exp . OP exp
       First derivation         exp ::=[ exp ::=[ exp OP exp . ] OP exp ]
-      Example                  exp OP exp . OP exp
       Second derivation        exp ::=[ exp OP exp ::=[ exp . OP exp ] ]
 
 ]])
@@ -1209,7 +1208,6 @@ State 1
         4 id: '0' .
       Example                  '0' .
       First derivation         exp ::=[ num ::=[ '0' . ] ]
-      Example                  '0' .
       Second derivation        exp ::=[ id ::=[ '0' . ] ]
 
 
@@ -1776,7 +1774,6 @@ State 5
         9 reported_conflicts: 'a' .
       Example                  'a' .
       First derivation         reported_conflicts ::=[ 'a' . ]
-      Example                  'a' .
       Second derivation        reported_conflicts ::=[ 'a' . ]
 
 
@@ -1961,7 +1958,6 @@ AT_CHECK([[cat input.output | sed -n '/^State 0$/,/^State 1$/p']], 0,
        13 empty_c3: . %empty
       Example                  . 'c'
       First derivation         start ::=[ empty_c2 ::=[ . ] 'c' ]
-      Example                  . 'c'
       Second derivation        start ::=[ empty_c3 ::=[ . ] 'c' ]
 
 
diff --git a/tests/counterexample.at b/tests/counterexample.at
index 65dc03cc..48d5acf3 100644
--- a/tests/counterexample.at
+++ b/tests/counterexample.at
@@ -48,7 +48,6 @@ AT_BISON_CHECK_CEX([input.y], [], [],
 Shift/reduce conflict on token B:
   Example              A . B C
   First derivation     s ::=[ a ::=[ A . ] x ::=[ B C ] ]
-  Example              A . B C
   Second derivation    s ::=[ y ::=[ A . B ] c ::=[ C ] ]
 
 input.y:4.4: warning: rule useless in parser due to conflicts [-Wother]
@@ -78,7 +77,6 @@ AT_BISON_CHECK_CEX([input.y], [], [],
 Shift/reduce conflict on token B:
   Example              A . B C
   First derivation     s ::=[ a ::=[ A . ] bc ::=[ B C ] ]
-  Example              A . B C
   Second derivation    s ::=[ ac ::=[ A ac ::=[ b ::=[ . B ] ] C ] ]
 
 input.y:6.4: warning: rule useless in parser due to conflicts [-Wother]
@@ -109,7 +107,6 @@ AT_BISON_CHECK_CEX([input.y], [], [],
 Shift/reduce conflict on token B:
   Example              A . B
   First derivation     s ::=[ ax ::=[ A x ::=[ . ] ] by ::=[ B y ::=[ ] ] ]
-  Example              A . B
   Second derivation    s ::=[ A xby ::=[ . B ] ]
 
 Shift/reduce conflict on token B:
@@ -208,7 +205,6 @@ AT_BISON_CHECK_CEX([input.y], [], [],
 Shift/reduce conflict on token A:
   Example              b . A X X Y
   First derivation     a ::=[ r ::=[ b . ] t ::=[ A x ::=[ X ] xy ::=[ X Y ] ] ]
-  Example              b . A X X Y
   Second derivation    a ::=[ s ::=[ b . xx ::=[ A X X ] y ::=[ Y ] ] ]
 
 Shift/reduce conflict on token X:
@@ -242,7 +238,6 @@ AT_BISON_CHECK_CEX([input.y], [], [],
 Reduce/reduce conflict on token $end:
   Example              A b .
   First derivation     a ::=[ A b . ]
-  Example              A b .
   Second derivation    a ::=[ A b ::=[ b . ] ]
 
 input.y:4.9: warning: rule useless in parser due to conflicts [-Wother]
@@ -331,7 +326,6 @@ AT_BISON_CHECK_CEX([input.y], [], [],
 Shift/reduce conflict on token B:
   Example              N A . B C
   First derivation     s ::=[ n ::=[ N a ::=[ A . ] B ] C ]
-  Example              N A . B C
   Second derivation    s ::=[ n ::=[ N b ::=[ A . B C ] ] ]
 
 input.y:5.4: warning: rule useless in parser due to conflicts [-Wother]
@@ -364,13 +358,11 @@ AT_BISON_CHECK_CEX([input.y], [], [],
 Reduce/reduce conflict on tokens b, c:
   Example              B . b c
   First derivation     S ::=[ B ::=[ A ::=[ B . ] b A ::=[ ] ] C ::=[ A ::=[ ] c A ::=[ ] ] ]
-  Example              B . b c
   Second derivation    S ::=[ B C ::=[ A ::=[ B ::=[ A ::=[ . ] b A ::=[ ] ] ] c A ::=[ ] ] ]
 
 Reduce/reduce conflict on tokens b, c:
   Example              C . c b
   First derivation     S ::=[ C ::=[ A ::=[ C . ] c A ::=[ ] ] B ::=[ A ::=[ ] b A ::=[ ] ] ]
-  Example              C . c b
   Second derivation    S ::=[ C B ::=[ A ::=[ C ::=[ A ::=[ . ] c A ::=[ ] ] ] b A ::=[ ] ] ]
 
 ]])
@@ -438,13 +430,11 @@ Shift/reduce conflict on token A:
 Reduce/reduce conflict on token $end:
   Example              b d .
   First derivation     a ::=[ b d . ]
-  Example              b d .
   Second derivation    a ::=[ b d ::=[ d . ] ]
 
 Reduce/reduce conflict on token $end:
   Example              c d .
   First derivation     a ::=[ c d . ]
-  Example              c d .
   Second derivation    a ::=[ c d ::=[ d . ] ]
 
 input.y:5.4: warning: rule useless in parser due to conflicts [-Wother]
@@ -476,7 +466,6 @@ AT_BISON_CHECK_CEX([input.y], [], [],
 Shift/reduce conflict on token J:
   Example              H i J . J J
   First derivation     s ::=[ a ::=[ H i ::=[ i J . ] J J ] ]
-  Example              H i J . J J
   Second derivation    s ::=[ a ::=[ H i J . J ] J ]
 
 input.y:5.13-15: warning: rule useless in parser due to conflicts [-Wother]
@@ -509,7 +498,6 @@ AT_BISON_CHECK_CEX([input.y], [], [],
 Shift/reduce conflict on token D:
   Example              A a . D
   First derivation     s ::=[ A a a ::=[ b ::=[ c ::=[ . ] ] ] d ::=[ D ] ]
-  Example              A a . D
   Second derivation    s ::=[ A a d ::=[ . D ] ]
 
 ]])
diff --git a/tests/diagnostics.at b/tests/diagnostics.at
index 035948c4..6d3ead97 100644
--- a/tests/diagnostics.at
+++ b/tests/diagnostics.at
@@ -49,15 +49,24 @@ if $EGREP ['\^M|\\[0-9][0-9][0-9]'] input.y experr >/dev/null; then
   AT_PERL_REQUIRE([-pi -e 's{\^M}{\r}g;s{\\(\d{3}|.)}{$v = $[]1; $v =~ /\A\d+\z/ ? chr($v) : $v}ge' input.y experr])
 fi
 
-AT_CHECK([LC_ALL="$locale" $5 bison -fcaret --color=debug -Wall input.y], [$3], [], [experr])
+AT_CHECK([LC_ALL="$locale" $5 bison -fcaret --color=debug -Wall,cex input.y], [$3], [], [experr])
 
 # When no style, same messages, but without style.
-AT_PERL_REQUIRE([-pi -e 's{(</?(-|\w)+>)}{ $[]1 eq "<tag>" ? $[]1 : "" }ge' experr])
+# Except for the second display of the counterexample,
+# which is not displayed at all.
+AT_PERL_REQUIRE([-pi -e '
+  s{(</?(-|\w)+>)}{ $[]1 eq "<tag>" ? $[]1 : "" }ge;
+  if (/Example/)
+    {
+      ++$example;
+      $_ = "" if $example % 2 == 0;
+    }
+' experr])
 
 # Cannot use AT_BISON_CHECK easily as we need to change the
 # environment.
 # FIXME: Enhance AT_BISON_CHECK.
-AT_CHECK([LC_ALL="$locale" $5 bison -fcaret -Wall input.y], [$3], [], [experr])
+AT_CHECK([LC_ALL="$locale" $5 bison -fcaret -Wall,cex input.y], [$3], [], [experr])
 
 
 AT_BISON_OPTION_POPDEFS
@@ -509,6 +518,41 @@ input.y:11.6-9: <error>error:</error> symbol 'QUUX' is used, but is not defined
 ]])
 
 
+## ----------------- ##
+## Counterexamples.  ##
+## ----------------- ##
+
+AT_TEST([[Counterexamples]],
+[[%expect 0
+%%
+exp
+: "if" exp "then" exp
+| "if" exp "then" exp "else" exp
+| exp "+" exp
+| "num"
+]],
+[1],
+[[input.y: <error>error:</error> shift/reduce conflicts: 4 found, 0 expected
+Shift/reduce conflict on token "+":
+  Example              <cex-0><cex-1><cex-leaf>exp</cex-leaf> <cex-leaf>"+"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot></cex-1> <cex-leaf>"+"</cex-leaf> <cex-leaf>exp</cex-leaf></cex-0>
+  First derivation     <cex-0><cex-step>exp ::=[ </cex-step><cex-1><cex-step>exp ::=[ </cex-step><cex-leaf>exp</cex-leaf> <cex-leaf>"+"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot><cex-step> ]</cex-step></cex-1> <cex-leaf>"+"</cex-leaf> <cex-leaf>exp</cex-leaf><cex-step> ]</cex-step></cex-0>
+  Example              <cex-0><cex-leaf>exp</cex-leaf> <cex-leaf>"+"</cex-leaf><cex-1> <cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot> <cex-leaf>"+"</cex-leaf> <cex-leaf>exp</cex-leaf></cex-1></cex-0>
+  Second derivation    <cex-0><cex-step>exp ::=[ </cex-step><cex-leaf>exp</cex-leaf> <cex-leaf>"+"</cex-leaf><cex-1> <cex-step>exp ::=[ </cex-step><cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot> <cex-leaf>"+"</cex-leaf> <cex-leaf>exp</cex-leaf><cex-step> ]</cex-step></cex-1><cex-step> ]</cex-step></cex-0>
+
+Shift/reduce conflict on token "else":
+  Example              <cex-0><cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf><cex-1> <cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot></cex-1> <cex-leaf>"else"</cex-leaf> <cex-leaf>exp</cex-leaf></cex-0>
+  First derivation     <cex-0><cex-step>exp ::=[ </cex-step><cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf><cex-1> <cex-step>exp ::=[ </cex-step><cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot><cex-step> ]</cex-step></cex-1> <cex-leaf>"else"</cex-leaf> <cex-leaf>exp</cex-leaf><cex-step> ]</cex-step></cex-0>
+  Example              <cex-0><cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf><cex-1> <cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot> <cex-leaf>"else"</cex-leaf> <cex-leaf>exp</cex-leaf></cex-1></cex-0>
+  Second derivation    <cex-0><cex-step>exp ::=[ </cex-step><cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf><cex-1> <cex-step>exp ::=[ </cex-step><cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot> <cex-leaf>"else"</cex-leaf> <cex-leaf>exp</cex-leaf><cex-step> ]</cex-step></cex-1><cex-step> ]</cex-step></cex-0>
+
+Shift/reduce conflict on token "+":
+  Example              <cex-0><cex-1><cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"else"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot></cex-1> <cex-leaf>"+"</cex-leaf> <cex-leaf>exp</cex-leaf></cex-0>
+  First derivation     <cex-0><cex-step>exp ::=[ </cex-step><cex-1><cex-step>exp ::=[ </cex-step><cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"else"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot><cex-step> ]</cex-step></cex-1> <cex-leaf>"+"</cex-leaf> <cex-leaf>exp</cex-leaf><cex-step> ]</cex-step></cex-0>
+  Example              <cex-0><cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"else"</cex-leaf><cex-1> <cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot> <cex-leaf>"+"</cex-leaf> <cex-leaf>exp</cex-leaf></cex-1></cex-0>
+  Second derivation    <cex-0><cex-step>exp ::=[ </cex-step><cex-leaf>"if"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"then"</cex-leaf> <cex-leaf>exp</cex-leaf> <cex-leaf>"else"</cex-leaf><cex-1> <cex-step>exp ::=[ </cex-step><cex-leaf>exp</cex-leaf> <cex-dot>•</cex-dot> <cex-leaf>"+"</cex-leaf> <cex-leaf>exp</cex-leaf><cex-step> ]</cex-step></cex-1><cex-step> ]</cex-step></cex-0>
+
+]])
+
 
 
 
diff --git a/tests/report.at b/tests/report.at
index bc2e5dbb..1d93f9a5 100644
--- a/tests/report.at
+++ b/tests/report.at
@@ -1173,25 +1173,21 @@ input.y: warning: 3 reduce/reduce conflicts [-Wconflicts-rr]
 Shift/reduce conflict on token "⊕":
   Example              exp "+" exp • "⊕" exp
   First derivation     exp ::=[ exp ::=[ exp "+" exp • ] "⊕" exp ]
-  Example              exp "+" exp • "⊕" exp
   Second derivation    exp ::=[ exp "+" exp ::=[ exp • "⊕" exp ] ]
 
 Reduce/reduce conflict on tokens $end, "+", "⊕":
   Example              exp "+" exp •
   First derivation     exp ::=[ exp "+" exp • ]
-  Example              exp "+" exp •
   Second derivation    exp ::=[ exp "+" exp • ]
 
 Shift/reduce conflict on token "⊕":
   Example              exp "+" exp • "⊕" exp
   First derivation     exp ::=[ exp ::=[ exp "+" exp • ] "⊕" exp ]
-  Example              exp "+" exp • "⊕" exp
   Second derivation    exp ::=[ exp "+" exp ::=[ exp • "⊕" exp ] ]
 
 Shift/reduce conflict on token "⊕":
   Example              exp "⊕" exp • "⊕" exp
   First derivation     exp ::=[ exp ::=[ exp "⊕" exp • ] "⊕" exp ]
-  Example              exp "⊕" exp • "⊕" exp
   Second derivation    exp ::=[ exp "⊕" exp ::=[ exp • "⊕" exp ] ]
 
 input.y:6.3-13: warning: rule useless in parser due to conflicts [-Wother]
@@ -1342,7 +1338,6 @@ State 7
         1 exp: exp • "⊕" exp
       Example                  exp "+" exp • "⊕" exp
       First derivation         exp ::=[ exp ::=[ exp "+" exp • ] "⊕" exp ]
-      Example                  exp "+" exp • "⊕" exp
       Second derivation        exp ::=[ exp "+" exp ::=[ exp • "⊕" exp ] ]
 
     Reduce/reduce conflict on tokens $end, "+", "⊕":
@@ -1350,7 +1345,6 @@ State 7
         3 exp: exp "+" exp •
       Example                  exp "+" exp •
       First derivation         exp ::=[ exp "+" exp • ]
-      Example                  exp "+" exp •
       Second derivation        exp ::=[ exp "+" exp • ]
 
     Shift/reduce conflict on token "⊕":
@@ -1358,7 +1352,6 @@ State 7
         1 exp: exp • "⊕" exp
       Example                  exp "+" exp • "⊕" exp
       First derivation         exp ::=[ exp ::=[ exp "+" exp • ] "⊕" exp ]
-      Example                  exp "+" exp • "⊕" exp
       Second derivation        exp ::=[ exp "+" exp ::=[ exp • "⊕" exp ] ]
 
 
@@ -1382,7 +1375,6 @@ State 8
         1 exp: exp • "⊕" exp
       Example                  exp "⊕" exp • "⊕" exp
       First derivation         exp ::=[ exp ::=[ exp "⊕" exp • ] "⊕" exp ]
-      Example                  exp "⊕" exp • "⊕" exp
       Second derivation        exp ::=[ exp "⊕" exp ::=[ exp • "⊕" exp ] ]
 
 ]])
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.