Skip to content

Commit 46423da

Browse files
authored
Emit a warning when the cached parser is not used. (#204)
This change checks to see if the cached parser was discarded due to a mismatch between the cached parser and the grammar specified in module_ir.py, and, if so, emits a warning that the cached parser was not used, along with informational messages on the nature of the mismatch. Adjusted the "warning" color from magenta to yellow. (This is the first warning in Emboss, so no magenta messages would have ever been emitted.) Adjusted the "note" color from "bright black" (dark grey) to "white" (light grey), becaused at least some terminals display "bright black" as just black.
1 parent bd276c4 commit 46423da

File tree

4 files changed

+80
-20
lines changed

4 files changed

+80
-20
lines changed

compiler/front_end/emboss_front_end.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
from compiler.front_end import glue
3131
from compiler.front_end import module_ir
32+
from compiler.front_end import parser
3233
from compiler.util import error
3334
from compiler.util import ir_data_utils
3435

@@ -151,6 +152,34 @@ def _find_and_read(file_name):
151152
return _find_and_read
152153

153154

155+
def _warn_if_cached_parser_is_mismatched(color_output):
156+
cached_parser_mismatch = parser.module_parser_cache_mismatch()
157+
extra_production_notes = [
158+
error.note("<internal>", None, f"New production {prod}")
159+
for prod in cached_parser_mismatch[1]
160+
]
161+
missing_production_notes = [
162+
error.note("<internal>", None, f"Missing production {prod}")
163+
for prod in cached_parser_mismatch[0]
164+
]
165+
if extra_production_notes or missing_production_notes:
166+
_show_errors(
167+
[
168+
[
169+
error.warn(
170+
"<internal>",
171+
None,
172+
"Cached parser does not match actual grammar; using newly-generated parser.",
173+
)
174+
]
175+
+ extra_production_notes
176+
+ missing_production_notes
177+
],
178+
None,
179+
color_output,
180+
)
181+
182+
154183
def parse_and_log_errors(input_file, import_dirs, color_output, stop_before_step=None):
155184
"""Fully parses an .emb and logs any errors.
156185
@@ -162,6 +191,7 @@ def parse_and_log_errors(input_file, import_dirs, color_output, stop_before_step
162191
Returns:
163192
(ir, debug_info, errors)
164193
"""
194+
_warn_if_cached_parser_is_mismatched(color_output)
165195
ir, debug_info, errors = glue.parse_emboss_file(
166196
input_file,
167197
_find_in_dirs_and_read(import_dirs),

compiler/front_end/parser.py

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,70 @@
1414

1515
"""Routines to load a shift-reduce parser for the module_ir module."""
1616

17+
import collections
18+
1719
from compiler.front_end.generated import cached_parser
1820
from compiler.front_end import lr1
1921
from compiler.front_end import make_parser
2022
from compiler.front_end import module_ir
2123
from compiler.util import parser_types
2224
from compiler.util import simple_memoizer
2325

26+
ParserAndIsCached = collections.namedtuple(
27+
"ParserAndIsCached",
28+
[
29+
"parser",
30+
"cache_mismatch",
31+
],
32+
)
33+
2434

2535
@simple_memoizer.memoize
2636
def _load_module_parser():
2737
module_parser = cached_parser.module_parser()
28-
if module_parser.productions == set(module_ir.PRODUCTIONS) | {
38+
module_ir_productions = set(module_ir.PRODUCTIONS) | {
2939
parser_types.Production(lr1.START_PRIME, (module_ir.START_SYMBOL,))
30-
}:
31-
return module_parser
32-
return make_parser.build_module_parser()
40+
}
41+
if module_parser.productions == module_ir_productions:
42+
return ParserAndIsCached(module_parser, (set(), set()))
43+
return ParserAndIsCached(
44+
make_parser.build_module_parser(),
45+
(
46+
module_parser.productions - module_ir_productions,
47+
module_ir_productions - module_parser.productions,
48+
),
49+
)
3350

3451

3552
@simple_memoizer.memoize
3653
def _load_expression_parser():
3754
expression_parser = cached_parser.expression_parser()
38-
if expression_parser.productions == set(module_ir.PRODUCTIONS) | {
55+
module_ir_productions = set(module_ir.PRODUCTIONS) | {
3956
parser_types.Production(lr1.START_PRIME, (module_ir.EXPRESSION_START_SYMBOL,))
40-
}:
41-
return expression_parser
42-
return make_parser.build_expression_parser()
57+
}
58+
if expression_parser.productions == module_ir_productions:
59+
return ParserAndIsCached(
60+
expression_parser,
61+
(set(), set()),
62+
)
63+
return ParserAndIsCached(
64+
make_parser.build_expression_parser(),
65+
(
66+
expression_parser.productions - module_ir_productions,
67+
module_ir_productions - expression_parser.productions,
68+
),
69+
)
70+
71+
72+
def module_parser_cache_mismatch():
73+
return _load_module_parser().cache_mismatch
4374

4475

4576
def parse_module(tokens):
4677
"""Parses the provided Emboss token list into an Emboss module parse tree."""
47-
return _load_module_parser().parse(tokens)
78+
return _load_module_parser().parser.parse(tokens)
4879

4980

5081
def parse_expression(tokens):
5182
"""Parses the provided Emboss token list into an expression parse tree."""
52-
return _load_expression_parser().parse(tokens)
83+
return _load_expression_parser().parser.parse(tokens)

compiler/util/error.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ def format(self, source_code):
131131
# messages.
132132
severity_colors = {
133133
ERROR: (BRIGHT_RED, BOLD),
134-
WARNING: (BRIGHT_MAGENTA, BOLD),
135-
NOTE: (BRIGHT_BLACK, WHITE),
134+
WARNING: (BRIGHT_YELLOW, BOLD),
135+
NOTE: (WHITE, WHITE),
136136
}
137137

138138
result = []

compiler/util/error_test.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,10 @@ def test_multiline_error(self):
201201
(error.BRIGHT_RED, "error: "), # Severity
202202
(error.BOLD, "Bad thing\n"), # Message
203203
(error.BOLD, "foo.emb:3:4: "), # Location, line 2
204-
(error.BRIGHT_BLACK, "note: "), # "Note" severity, line 2
204+
(error.WHITE, "note: "), # "Note" severity, line 2
205205
(error.WHITE, "Some explanation\n"), # Message, line 2
206206
(error.BOLD, "foo.emb:3:4: "), # Location, line 3
207-
(error.BRIGHT_BLACK, "note: "), # "Note" severity, line 3
207+
(error.WHITE, "note: "), # "Note" severity, line 3
208208
(error.WHITE, "More explanation"), # Message, line 3
209209
],
210210
sourceless_format,
@@ -223,10 +223,10 @@ def test_multiline_error(self):
223223
(error.BRIGHT_RED, "error: "), # Severity
224224
(error.BOLD, "Bad thing\n"), # Message
225225
(error.BOLD, "foo.emb:3:4: "), # Location, line 2
226-
(error.BRIGHT_BLACK, "note: "), # "Note" severity, line 2
226+
(error.WHITE, "note: "), # "Note" severity, line 2
227227
(error.WHITE, "Some explanation\n"), # Message, line 2
228228
(error.BOLD, "foo.emb:3:4: "), # Location, line 3
229-
(error.BRIGHT_BLACK, "note: "), # "Note" severity, line 3
229+
(error.WHITE, "note: "), # "Note" severity, line 3
230230
(error.WHITE, "More explanation\n"), # Message, line 3
231231
(error.WHITE, "abcdefghijklm\n"), # Source snippet
232232
(error.BRIGHT_GREEN, " ^^"), # Column indicator
@@ -252,7 +252,7 @@ def test_warn(self):
252252
self.assertEqual(
253253
[
254254
(error.BOLD, "foo.emb:3:4: "), # Location
255-
(error.BRIGHT_MAGENTA, "warning: "), # Severity
255+
(error.BRIGHT_YELLOW, "warning: "), # Severity
256256
(error.BOLD, "Not good thing\n"), # Message
257257
(error.WHITE, "abcdefghijklm\n"), # Source snippet
258258
(error.BRIGHT_GREEN, " ^^"), # Column indicator
@@ -278,7 +278,7 @@ def test_note(self):
278278
self.assertEqual(
279279
[
280280
(error.BOLD, "foo.emb:3:4: "), # Location
281-
(error.BRIGHT_BLACK, "note: "), # Severity
281+
(error.WHITE, "note: "), # Severity
282282
(error.WHITE, "OK thing\n"), # Message
283283
(error.WHITE, "abcdefghijklm\n"), # Source snippet
284284
(error.BRIGHT_GREEN, " ^^"), # Column indicator
@@ -457,13 +457,12 @@ def test_format_errors(self):
457457
bold = error.BOLD
458458
reset = error.RESET
459459
white = error.WHITE
460-
bright_black = error.BRIGHT_BLACK
461460
bright_green = error.BRIGHT_GREEN
462461
self.assertEqual(
463462
bold
464463
+ "foo.emb:3:4: "
465464
+ reset
466-
+ bright_black
465+
+ white
467466
+ "note: "
468467
+ reset
469468
+ white

0 commit comments

Comments
 (0)