TatSu takes a grammar in a variation of EBNF as input, and outputs a memoizing PEG/Packrat parser in Python.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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.
Foundation exception classes that provide common functionality for all TatSu errors.
class TatSuException(Exception):
"""Base exception for all TatSu errors."""
class ParseException(TatSuException):
"""
Base parsing exception with position information.
Attributes:
- message: str, error description
- line: int, line number where error occurred
- col: int, column number where error occurred
- pos: int, character position in input
- context: parsing context information
"""Errors that occur during grammar parsing and compilation phase, before any input parsing begins.
class GrammarError(ParseException):
"""
Grammar definition and compilation errors.
Raised when:
- Grammar has invalid EBNF syntax
- Rule definitions are malformed
- Semantic inconsistencies in grammar
- Circular dependencies in rules
"""
class SemanticError(ParseException):
"""
Semantic analysis and action errors.
Raised when:
- Semantic action methods are malformed
- Type inconsistencies in semantic processing
- Missing semantic actions for required rules
"""
class CodegenError(ParseException):
"""
Code generation errors.
Raised when:
- Generated code would be invalid Python
- Template processing fails
- Output file cannot be written
"""
class MissingSemanticFor(SemanticError):
"""
Missing semantic action for a specific rule.
Raised when semantic actions object doesn't provide
required method for a grammar rule.
"""Errors that occur during input text parsing, providing detailed position and context information.
class FailedParse(ParseException):
"""
Base parse failure with position information.
All parse failures include:
- Exact position where parsing failed
- Expected vs actual content
- Rule context and call stack
- Recovery suggestions when possible
"""
class FailedToken(FailedParse):
"""
Expected token not found.
Raised when:
- Literal string token doesn't match input
- Case-sensitive token matching fails
- End of input reached when token expected
"""
class FailedPattern(FailedParse):
"""
Regular expression pattern match failed.
Raised when:
- Regex pattern doesn't match at current position
- Pattern matches empty string when non-empty expected
- Invalid regex in grammar definition
"""
class FailedKeyword(FailedParse):
"""
Keyword match failed.
Raised when:
- Keyword token doesn't match input
- Keyword conflicts with identifier
- Keyword followed by invalid character
"""
class FailedSemantics(FailedParse):
"""
Semantic action execution failed.
Raised when:
- Semantic action method raises exception
- Semantic action returns invalid result type
- Custom validation in semantic action fails
"""
class FailedKeywordSemantics(FailedSemantics):
"""
Keyword semantic action failed.
Specialized semantic failure for keyword processing,
often indicating grammar design issues.
"""Errors related to grammar structure and control flow during parsing.
class FailedRef(FailedParse):
"""
Rule reference resolution failed.
Raised when:
- Referenced rule doesn't exist in grammar
- Circular rule dependency detected
- Rule invocation stack overflow
"""
class FailedChoice(FailedParse):
"""
No choice alternative matched.
Raised when:
- All alternatives in choice expression fail
- Ordered choice doesn't find valid alternative
- Priority conflicts in choices
"""
class FailedCut(FailedParse):
"""
Cut point failed, prevents backtracking.
Raised after cut point when:
- Parsing fails beyond commit point
- No backtracking possible to earlier alternatives
- Parse recovery not available
"""
class FailedLookahead(FailedParse):
"""
Lookahead assertion failed.
Raised when:
- Positive lookahead doesn't match expected pattern
- Negative lookahead matches forbidden pattern
- Lookahead assertion at end of input
"""
class FailedLeftRecursion(FailedParse):
"""
Left recursion handling issue.
Raised when:
- Left-recursive rule cannot be resolved
- Infinite recursion detected
- Left-recursion algorithm fails
"""
class FailedExpectingEndOfText(FailedParse):
"""
Expected end of input but found more text.
Raised when:
- Parse completes but input remains
- Start rule matches but doesn't consume all input
- Trailing whitespace or comments not handled
"""Internal control flow exceptions, typically not seen by end users.
class OptionSucceeded(ParseException):
"""
Internal: option succeeded.
Used internally for optional element control flow.
Should not be raised to user code.
"""
class NoParseInfo(ParseException):
"""
Parse info not available.
Raised when:
- ParseInfo requested but not enabled
- Parse context doesn't contain position data
- Information not available for generated code
"""import tatsu
from tatsu.exceptions import ParseException, GrammarError
# Handle grammar compilation errors
try:
model = tatsu.compile("invalid grammar {")
except GrammarError as e:
print(f"Grammar error at line {e.line}: {e}")
# Fix grammar and retry
# Handle parse failures
try:
result = tatsu.parse("expr = number;", "not_a_number")
except ParseException as e:
print(f"Parse failed at position {e.pos} (line {e.line}, col {e.col}): {e}")
# Provide user feedback or attempt recoveryfrom tatsu.exceptions import FailedParse
try:
result = model.parse(user_input)
except FailedParse as e:
# Detailed error reporting
error_info = {
'message': str(e),
'position': e.pos,
'line': e.line,
'column': e.col,
'expected': getattr(e, 'expected', None),
'found': getattr(e, 'found', None)
}
# Show error context
lines = user_input.split('\n')
if e.line <= len(lines):
error_line = lines[e.line - 1]
print(f"Error on line {e.line}: {error_line}")
print(f"{'':>{e.col-1}}^ {e}")from tatsu.exceptions import FailedSemantics
from tatsu.semantics import ModelBuilderSemantics
class SafeSemantics(ModelBuilderSemantics):
def number(self, ast):
try:
return int(ast)
except ValueError as e:
# Convert to TatSu exception for consistent handling
raise FailedSemantics(f"Invalid number format: {ast}") from e
def division(self, ast):
left, _, right = ast
if right == 0:
raise FailedSemantics("Division by zero not allowed")
return left / right
try:
result = model.parse("10 / 0", semantics=SafeSemantics())
except FailedSemantics as e:
print(f"Semantic error: {e}")import logging
from tatsu.exceptions import ParseException, GrammarError
def safe_parse(grammar, input_text, **kwargs):
"""Production-ready parsing with comprehensive error handling."""
try:
model = tatsu.compile(grammar)
return {'success': True, 'result': model.parse(input_text, **kwargs)}
except GrammarError as e:
logging.error(f"Grammar compilation failed: {e}")
return {
'success': False,
'error': 'Invalid grammar definition',
'details': str(e)
}
except ParseException as e:
logging.warning(f"Parse failed: {e}")
return {
'success': False,
'error': 'Parse failure',
'position': {
'line': e.line,
'column': e.col,
'offset': e.pos
},
'message': str(e)
}
except Exception as e:
logging.exception("Unexpected error during parsing")
return {
'success': False,
'error': 'Unexpected error',
'details': str(e)
}
# Usage
result = safe_parse(my_grammar, user_input)
if result['success']:
process_ast(result['result'])
else:
show_error_to_user(result['error'], result.get('position'))def parse_with_recovery(model, input_text, max_attempts=3):
"""Attempt parsing with simple error recovery."""
for attempt in range(max_attempts):
try:
return model.parse(input_text)
except FailedToken as e:
if attempt < max_attempts - 1:
# Try skipping problematic character
pos = e.pos
input_text = input_text[:pos] + input_text[pos+1:]
print(f"Attempt {attempt + 1}: Skipping character at position {pos}")
else:
raise
except FailedExpectingEndOfText as e:
# Input parsed successfully but has trailing content
return e.ast # Return partial parse if available
raise ParseException("Parse recovery failed after maximum attempts")Install with Tessl CLI
npx tessl i tessl/pypi-tatsu