Skip to content

Commit 3f61113

Browse files
author
whitequark
committedMay 8, 2015
Make default error reporting rule work again.
1 parent a470d6b commit 3f61113

File tree

1 file changed

+51
-40
lines changed

1 file changed

+51
-40
lines changed
 

Diff for: ‎pyparser/parser.py

+51-40
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,7 @@
4646

4747
# Generic LL parsing combinators
4848
class Unmatched:
49-
def __init__(self, diagnostic=None):
50-
self.diagnostic = diagnostic
51-
52-
def __repr__(self):
53-
if self.diagnostic:
54-
return "<can't parse: %s>" % repr(self.diagnostic)
55-
else:
56-
return "<can't parse>"
49+
pass
5750

5851
unmatched = Unmatched()
5952

@@ -67,7 +60,7 @@ def decorator(inner_rule):
6760
if cases == 1:
6861
def rule(*args, **kwargs):
6962
result = inner_rule(*args, **kwargs)
70-
if not isinstance(result, Unmatched):
63+
if result is not unmatched:
7164
rule.covered[0] = True
7265
return result
7366
else:
@@ -93,7 +86,7 @@ def decorator(mapper):
9386
@llrule(loc, inner_rule.expected)
9487
def outer_rule(parser):
9588
result = inner_rule(parser)
96-
if isinstance(result, Unmatched):
89+
if result is unmatched:
9790
return result
9891
if isinstance(result, tuple):
9992
return mapper(parser, *result)
@@ -121,7 +114,7 @@ def Loc(kind, loc=None):
121114
@llrule(loc, lambda parser: [kind])
122115
def rule(parser):
123116
result = parser._accept(kind)
124-
if isinstance(result, Unmatched):
117+
if result is unmatched:
125118
return result
126119
return result.loc
127120
return rule
@@ -138,19 +131,23 @@ def Expect(inner_rule, loc=None):
138131
@llrule(loc, inner_rule.expected)
139132
def rule(parser):
140133
result = inner_rule(parser)
141-
if isinstance(result, Unmatched):
142-
expected = inner_rule.expected(parser)
134+
if result is unmatched:
135+
expected = reduce(list.__add__, [rule.expected(parser) for rule in parser._errrules])
136+
expected = list(sorted(set(expected)))
137+
143138
if len(expected) > 1:
144139
expected = ' or '.join([', '.join(expected[0:-1]), expected[-1]])
145140
elif len(expected) == 1:
146141
expected = expected[0]
147142
else:
148143
expected = '(impossible)'
144+
145+
error_tok = parser._tokens[parser._errindex]
149146
error = diagnostic.Diagnostic(
150147
"error", "unexpected {actual}: expected {expected}",
151-
{'actual': parser.token.kind, 'expected': expected},
152-
parser.token.loc)
153-
return Unmatched(diagnostic.DiagnosticException(error))
148+
{'actual': error_tok.kind, 'expected': expected},
149+
error_tok.loc)
150+
raise diagnostic.DiagnosticException(error)
154151
return result
155152
return rule
156153

@@ -162,13 +159,13 @@ def Seq(first_rule, *rest_of_rules, **kwargs):
162159
@llrule(kwargs.get('loc', None), first_rule.expected)
163160
def rule(parser):
164161
result = first_rule(parser)
165-
if isinstance(result, Unmatched):
162+
if result is unmatched:
166163
return result
167164

168165
results = [result]
169166
for rule in rest_of_rules:
170167
result = rule(parser)
171-
if isinstance(result, Unmatched):
168+
if result is unmatched:
172169
return result
173170
results.append(result)
174171
return tuple(results)
@@ -198,8 +195,8 @@ def rule(parser):
198195
data = parser._save()
199196
for idx, inner_rule in enumerate(inner_rules):
200197
result = inner_rule(parser)
201-
if isinstance(result, Unmatched):
202-
parser._restore(data)
198+
if result is unmatched:
199+
parser._restore(data, rule=inner_rule)
203200
else:
204201
rule.covered[idx] = True
205202
return result
@@ -210,8 +207,8 @@ def rule(parser):
210207
data = parser._save()
211208
for inner_rule in inner_rules:
212209
result = inner_rule(parser)
213-
if isinstance(result, Unmatched):
214-
parser._restore(data)
210+
if result is unmatched:
211+
parser._restore(data, rule=inner_rule)
215212
else:
216213
return result
217214
return unmatched
@@ -232,8 +229,8 @@ def rule(parser):
232229
while True:
233230
data = parser._save()
234231
result = inner_rule(parser)
235-
if isinstance(result, Unmatched):
236-
parser._restore(data)
232+
if result is unmatched:
233+
parser._restore(data, rule=inner_rule)
237234
return results
238235
results.append(result)
239236
return rule
@@ -246,15 +243,15 @@ def Plus(inner_rule, loc=None):
246243
@llrule(loc, inner_rule.expected)
247244
def rule(parser):
248245
result = inner_rule(parser)
249-
if isinstance(result, Unmatched):
246+
if result is unmatched:
250247
return result
251248

252249
results = [result]
253250
while True:
254251
data = parser._save()
255252
result = inner_rule(parser)
256-
if isinstance(result, Unmatched):
257-
parser._restore(data)
253+
if result is unmatched:
254+
parser._restore(data, rule=inner_rule)
258255
return results
259256
results.append(result)
260257
return rule
@@ -280,19 +277,19 @@ def rule(parser):
280277

281278
if leading:
282279
result = inner_rule(parser)
283-
if isinstance(result, Unmatched):
280+
if result is unmatched:
284281
return result
285282
else:
286283
results.append(result)
287284

288285
while True:
289286
result = separator_rule(parser)
290-
if isinstance(result, Unmatched):
287+
if result is unmatched:
291288
results.trailing_comma = None
292289
return results
293290

294291
result_1 = inner_rule(parser)
295-
if isinstance(result_1, Unmatched):
292+
if result_1 is unmatched:
296293
results.trailing_comma = result
297294
return results
298295
else:
@@ -305,7 +302,7 @@ def Newline(loc=None):
305302
@llrule(loc, lambda parser: ['newline'])
306303
def rule(parser):
307304
result = parser._accept('newline')
308-
if isinstance(result, Unmatched):
305+
if result is unmatched:
309306
return result
310307
return []
311308
return rule
@@ -352,18 +349,32 @@ class Parser:
352349

353350
# Generic LL parsing methods
354351
def __init__(self, lexer):
355-
self.lexer = lexer
356-
self._tokens = []
357-
self._index = -1
352+
self.lexer = lexer
353+
self._tokens = []
354+
self._index = -1
355+
self._errindex = -1
356+
self._errrules = []
358357
self._advance()
359358

360359
def _save(self):
361360
return self._index
362361

363-
def _restore(self, data):
362+
def _restore(self, data, rule):
364363
self._index = data
365364
self._token = self._tokens[self._index]
366365

366+
if self._index > self._errindex:
367+
# We have advanced since last error
368+
self._errindex = self._index
369+
self._errrules = [rule]
370+
elif self._index == self._errindex:
371+
# We're at the same place as last error
372+
self._errrules.append(rule)
373+
else:
374+
# We've backtracked far and are now just failing the
375+
# whole parse
376+
pass
377+
367378
def _advance(self):
368379
self._index += 1
369380
if self._index == len(self._tokens):
@@ -404,22 +415,22 @@ def add_flags(self, flags):
404415
if 'print_function' in flags:
405416
self.lexer.print_function = True
406417

407-
@action(Alt(Newline(),
408-
Rule('simple_stmt'),
409-
SeqN(0, Rule('compound_stmt'), Newline())))
418+
@action(Expect(Alt(Newline(),
419+
Rule('simple_stmt'),
420+
SeqN(0, Rule('compound_stmt'), Newline()))))
410421
def single_input(self, body):
411422
"""single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE"""
412423
loc = None if body == [] else body[0].loc
413424
return ast.Interactive(body=body, loc=loc)
414425

415-
@action(SeqN(0, Star(Alt(Newline(), Rule('stmt'))), Tok('eof')))
426+
@action(Expect(SeqN(0, Star(Alt(Newline(), Rule('stmt'))), Tok('eof'))))
416427
def file_input(parser, body):
417428
"""file_input: (NEWLINE | stmt)* ENDMARKER"""
418429
body = reduce(list.__add__, body, [])
419430
loc = None if body == [] else body[0].loc
420431
return ast.Module(body=body, loc=loc)
421432

422-
@action(SeqN(0, Rule('testlist'), Star(Tok('newline')), Tok('eof')))
433+
@action(Expect(SeqN(0, Rule('testlist'), Star(Tok('newline')), Tok('eof'))))
423434
def eval_input(self, expr):
424435
"""eval_input: testlist NEWLINE* ENDMARKER"""
425436
return ast.Expression(body=[expr], loc=expr.loc)

0 commit comments

Comments
 (0)
Please sign in to comment.