0
# Exception Handling
1
2
Comprehensive exception hierarchy for handling grammar compilation errors, parse failures, and semantic processing issues. TatSu provides detailed error information including position data, context, and recovery suggestions.
3
4
## Capabilities
5
6
### Base Exception Classes
7
8
Foundation exception classes that provide common functionality for all TatSu errors.
9
10
```python { .api }
11
class TatSuException(Exception):
12
"""Base exception for all TatSu errors."""
13
14
class ParseException(TatSuException):
15
"""
16
Base parsing exception with position information.
17
18
Attributes:
19
- message: str, error description
20
- line: int, line number where error occurred
21
- col: int, column number where error occurred
22
- pos: int, character position in input
23
- context: parsing context information
24
"""
25
```
26
27
### Grammar Compilation Errors
28
29
Errors that occur during grammar parsing and compilation phase, before any input parsing begins.
30
31
```python { .api }
32
class GrammarError(ParseException):
33
"""
34
Grammar definition and compilation errors.
35
36
Raised when:
37
- Grammar has invalid EBNF syntax
38
- Rule definitions are malformed
39
- Semantic inconsistencies in grammar
40
- Circular dependencies in rules
41
"""
42
43
class SemanticError(ParseException):
44
"""
45
Semantic analysis and action errors.
46
47
Raised when:
48
- Semantic action methods are malformed
49
- Type inconsistencies in semantic processing
50
- Missing semantic actions for required rules
51
"""
52
53
class CodegenError(ParseException):
54
"""
55
Code generation errors.
56
57
Raised when:
58
- Generated code would be invalid Python
59
- Template processing fails
60
- Output file cannot be written
61
"""
62
63
class MissingSemanticFor(SemanticError):
64
"""
65
Missing semantic action for a specific rule.
66
67
Raised when semantic actions object doesn't provide
68
required method for a grammar rule.
69
"""
70
```
71
72
### Parse Failure Exceptions
73
74
Errors that occur during input text parsing, providing detailed position and context information.
75
76
```python { .api }
77
class FailedParse(ParseException):
78
"""
79
Base parse failure with position information.
80
81
All parse failures include:
82
- Exact position where parsing failed
83
- Expected vs actual content
84
- Rule context and call stack
85
- Recovery suggestions when possible
86
"""
87
88
class FailedToken(FailedParse):
89
"""
90
Expected token not found.
91
92
Raised when:
93
- Literal string token doesn't match input
94
- Case-sensitive token matching fails
95
- End of input reached when token expected
96
"""
97
98
class FailedPattern(FailedParse):
99
"""
100
Regular expression pattern match failed.
101
102
Raised when:
103
- Regex pattern doesn't match at current position
104
- Pattern matches empty string when non-empty expected
105
- Invalid regex in grammar definition
106
"""
107
108
class FailedKeyword(FailedParse):
109
"""
110
Keyword match failed.
111
112
Raised when:
113
- Keyword token doesn't match input
114
- Keyword conflicts with identifier
115
- Keyword followed by invalid character
116
"""
117
118
class FailedSemantics(FailedParse):
119
"""
120
Semantic action execution failed.
121
122
Raised when:
123
- Semantic action method raises exception
124
- Semantic action returns invalid result type
125
- Custom validation in semantic action fails
126
"""
127
128
class FailedKeywordSemantics(FailedSemantics):
129
"""
130
Keyword semantic action failed.
131
132
Specialized semantic failure for keyword processing,
133
often indicating grammar design issues.
134
"""
135
```
136
137
### Structural Parse Failures
138
139
Errors related to grammar structure and control flow during parsing.
140
141
```python { .api }
142
class FailedRef(FailedParse):
143
"""
144
Rule reference resolution failed.
145
146
Raised when:
147
- Referenced rule doesn't exist in grammar
148
- Circular rule dependency detected
149
- Rule invocation stack overflow
150
"""
151
152
class FailedChoice(FailedParse):
153
"""
154
No choice alternative matched.
155
156
Raised when:
157
- All alternatives in choice expression fail
158
- Ordered choice doesn't find valid alternative
159
- Priority conflicts in choices
160
"""
161
162
class FailedCut(FailedParse):
163
"""
164
Cut point failed, prevents backtracking.
165
166
Raised after cut point when:
167
- Parsing fails beyond commit point
168
- No backtracking possible to earlier alternatives
169
- Parse recovery not available
170
"""
171
172
class FailedLookahead(FailedParse):
173
"""
174
Lookahead assertion failed.
175
176
Raised when:
177
- Positive lookahead doesn't match expected pattern
178
- Negative lookahead matches forbidden pattern
179
- Lookahead assertion at end of input
180
"""
181
182
class FailedLeftRecursion(FailedParse):
183
"""
184
Left recursion handling issue.
185
186
Raised when:
187
- Left-recursive rule cannot be resolved
188
- Infinite recursion detected
189
- Left-recursion algorithm fails
190
"""
191
192
class FailedExpectingEndOfText(FailedParse):
193
"""
194
Expected end of input but found more text.
195
196
Raised when:
197
- Parse completes but input remains
198
- Start rule matches but doesn't consume all input
199
- Trailing whitespace or comments not handled
200
"""
201
```
202
203
### Special Control Exceptions
204
205
Internal control flow exceptions, typically not seen by end users.
206
207
```python { .api }
208
class OptionSucceeded(ParseException):
209
"""
210
Internal: option succeeded.
211
212
Used internally for optional element control flow.
213
Should not be raised to user code.
214
"""
215
216
class NoParseInfo(ParseException):
217
"""
218
Parse info not available.
219
220
Raised when:
221
- ParseInfo requested but not enabled
222
- Parse context doesn't contain position data
223
- Information not available for generated code
224
"""
225
```
226
227
## Error Handling Patterns
228
229
### Basic Exception Handling
230
231
```python
232
import tatsu
233
from tatsu.exceptions import ParseException, GrammarError
234
235
# Handle grammar compilation errors
236
try:
237
model = tatsu.compile("invalid grammar {")
238
except GrammarError as e:
239
print(f"Grammar error at line {e.line}: {e}")
240
# Fix grammar and retry
241
242
# Handle parse failures
243
try:
244
result = tatsu.parse("expr = number;", "not_a_number")
245
except ParseException as e:
246
print(f"Parse failed at position {e.pos} (line {e.line}, col {e.col}): {e}")
247
# Provide user feedback or attempt recovery
248
```
249
250
### Detailed Error Information
251
252
```python
253
from tatsu.exceptions import FailedParse
254
255
try:
256
result = model.parse(user_input)
257
except FailedParse as e:
258
# Detailed error reporting
259
error_info = {
260
'message': str(e),
261
'position': e.pos,
262
'line': e.line,
263
'column': e.col,
264
'expected': getattr(e, 'expected', None),
265
'found': getattr(e, 'found', None)
266
}
267
268
# Show error context
269
lines = user_input.split('\n')
270
if e.line <= len(lines):
271
error_line = lines[e.line - 1]
272
print(f"Error on line {e.line}: {error_line}")
273
print(f"{'':>{e.col-1}}^ {e}")
274
```
275
276
### Semantic Action Error Handling
277
278
```python
279
from tatsu.exceptions import FailedSemantics
280
from tatsu.semantics import ModelBuilderSemantics
281
282
class SafeSemantics(ModelBuilderSemantics):
283
def number(self, ast):
284
try:
285
return int(ast)
286
except ValueError as e:
287
# Convert to TatSu exception for consistent handling
288
raise FailedSemantics(f"Invalid number format: {ast}") from e
289
290
def division(self, ast):
291
left, _, right = ast
292
if right == 0:
293
raise FailedSemantics("Division by zero not allowed")
294
return left / right
295
296
try:
297
result = model.parse("10 / 0", semantics=SafeSemantics())
298
except FailedSemantics as e:
299
print(f"Semantic error: {e}")
300
```
301
302
### Production Error Handling
303
304
```python
305
import logging
306
from tatsu.exceptions import ParseException, GrammarError
307
308
def safe_parse(grammar, input_text, **kwargs):
309
"""Production-ready parsing with comprehensive error handling."""
310
try:
311
model = tatsu.compile(grammar)
312
return {'success': True, 'result': model.parse(input_text, **kwargs)}
313
314
except GrammarError as e:
315
logging.error(f"Grammar compilation failed: {e}")
316
return {
317
'success': False,
318
'error': 'Invalid grammar definition',
319
'details': str(e)
320
}
321
322
except ParseException as e:
323
logging.warning(f"Parse failed: {e}")
324
return {
325
'success': False,
326
'error': 'Parse failure',
327
'position': {
328
'line': e.line,
329
'column': e.col,
330
'offset': e.pos
331
},
332
'message': str(e)
333
}
334
335
except Exception as e:
336
logging.exception("Unexpected error during parsing")
337
return {
338
'success': False,
339
'error': 'Unexpected error',
340
'details': str(e)
341
}
342
343
# Usage
344
result = safe_parse(my_grammar, user_input)
345
if result['success']:
346
process_ast(result['result'])
347
else:
348
show_error_to_user(result['error'], result.get('position'))
349
```
350
351
### Error Recovery Strategies
352
353
```python
354
def parse_with_recovery(model, input_text, max_attempts=3):
355
"""Attempt parsing with simple error recovery."""
356
357
for attempt in range(max_attempts):
358
try:
359
return model.parse(input_text)
360
361
except FailedToken as e:
362
if attempt < max_attempts - 1:
363
# Try skipping problematic character
364
pos = e.pos
365
input_text = input_text[:pos] + input_text[pos+1:]
366
print(f"Attempt {attempt + 1}: Skipping character at position {pos}")
367
else:
368
raise
369
370
except FailedExpectingEndOfText as e:
371
# Input parsed successfully but has trailing content
372
return e.ast # Return partial parse if available
373
374
raise ParseException("Parse recovery failed after maximum attempts")
375
```