A universal Python parser combinator library inspired by Parsec library of Haskell
—
The fundamental classes and types that form the foundation of all parsing operations. These include the main Parser class that wraps parsing functions, the Value type for representing parsing results, and comprehensive error reporting with source location information.
The core parser combinator class that wraps parsing functions and provides the foundation for all parsing operations. Every parser is an instance of this class.
class Parser:
"""
A Parser wraps a function to do parsing work.
The wrapped function takes (text, index) and returns Value.success() or Value.failure().
"""
def __init__(self, fn):
"""
Create a parser from a parsing function.
Args:
fn: Function that takes (text: str, index: int) -> Value
"""
def __call__(self, text, index):
"""
Call the wrapped parsing function directly.
Args:
text (str): Text to parse
index (int): Starting position
Returns:
Value: Success or failure result
"""
def parse(self, text):
"""
Parse a given string completely.
Args:
text (str): String to parse
Returns:
Parsed value on success
Raises:
ParseError: If parsing fails
"""
def parse_partial(self, text):
"""
Parse the longest possible prefix of a string.
Args:
text (str): String to parse
Returns:
tuple: (parsed_value, remaining_text)
Raises:
ParseError: If parsing fails
"""
def parse_strict(self, text):
"""
Parse entire string with no remaining text allowed.
Args:
text (str): String to parse completely
Returns:
Parsed value on success
Raises:
ParseError: If parsing fails or text remains
"""Result container that represents the outcome of a parsing operation, containing success/failure status, position information, parsed value, and error expectations.
class Value:
"""
Represents the result of a parsing operation.
Attributes:
status (bool): True for success, False for failure
index (int): Position after parsing
value: Parsed value (None on failure)
expected (str): Expected input description (for failures)
"""
@staticmethod
def success(index, actual):
"""
Create a successful parsing result.
Args:
index (int): Position after consuming input
actual: The parsed value
Returns:
Value: Success result
"""
@staticmethod
def failure(index, expected):
"""
Create a failed parsing result.
Args:
index (int): Position where parsing failed
expected (str): Description of what was expected
Returns:
Value: Failure result
"""
def aggregate(self, other=None):
"""
Combine results from sequential parsers.
Args:
other (Value, optional): Other parsing result to combine
Returns:
Value: Combined result with concatenated values
"""Comprehensive error reporting with source location information, including line and column numbers for debugging complex parsing failures.
class ParseError(RuntimeError):
"""
Parser error with detailed location information.
Attributes:
expected (str): What the parser expected to find
text (str): Original input text being parsed
index (int): Position where error occurred
"""
def __init__(self, expected, text, index):
"""
Create a parsing error.
Args:
expected (str): Description of expected input
text (str): The text being parsed
index (int): Character position of the error
"""
@staticmethod
def loc_info(text, index):
"""
Calculate line and column from text position.
Args:
text (str): Source text
index (int): Character position
Returns:
tuple: (line_number, column_number) both 0-based
Raises:
ValueError: If index is beyond text length
"""
def loc(self):
"""
Get formatted location string for this error.
Returns:
str: Location in format "line:column" or error description
"""
def __str__(self):
"""
Get string representation of the error.
Returns:
str: Error message with expected input and location
Note:
The original implementation contains a typo: it returns
"excepted X at Y" instead of "expected X at Y".
"""Standard library utilities exported for convenience when building parsers.
# From collections module
namedtuple: type
"""
Factory function for creating tuple subclasses with named fields.
Exported for creating custom result types in parsers.
"""
# From functools module
wraps: function
"""
Decorator to preserve function metadata when creating wrapper functions.
Exported for use in custom parser decorators.
"""
# Standard library module
re: module
"""
Regular expression module for pattern matching.
Used internally by regex() parser and available for custom parsers.
"""from parsec import Parser, Value
# Create a parser that matches single character 'x'
def x_parser_fn(text, index):
if index < len(text) and text[index] == 'x':
return Value.success(index + 1, 'x')
else:
return Value.failure(index, 'character x')
x_parser = Parser(x_parser_fn)
# Use the parser
result = x_parser.parse("xyz") # Returns 'x'from parsec import ParseError, string
parser = string("hello")
try:
result = parser.parse("world")
except ParseError as e:
print(f"Expected: {e.expected}") # Expected: hello
print(f"At position: {e.index}") # At position: 0
print(f"Location: {e.loc()}") # Location: 0:0from parsec import string, many, letter
parser = many(letter())
# parse() - consume what it can, ignore rest
result = parser.parse("abc123") # Returns ['a', 'b', 'c']
# parse_partial() - return both result and remaining text
result, remaining = parser.parse_partial("abc123")
# result: ['a', 'b', 'c'], remaining: "123"
# parse_strict() - entire input must be consumed
try:
result = parser.parse_strict("abc123") # Raises ParseError
except ParseError:
print("Text remaining after parsing")Install with Tessl CLI
npx tessl i tessl/pypi-parsec