CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-parsy

Easy-to-use parser combinators for parsing in pure Python

Pending
Overview
Eval results
Files

utilities.mddocs/

Utility Functions

Helper functions and constants that support parsy's parsing operations. These utilities provide common functionality used throughout the parsing library.

Capabilities

Position Information

Get line and column information for positions in input streams.

def line_info_at(stream, index):
    """
    Get line and column information for a position in the stream.
    
    Args:
        stream: Input string to analyze
        index: Position index in the stream
        
    Returns:
        tuple: (line, column) where both are 0-indexed
        
    Raises:
        ValueError: If index is greater than stream length
    """

Identity Function

No-operation function that returns its argument unchanged.

noop: function
"""Identity function (lambda x: x) used as default transform parameter."""

Usage Examples

Position Tracking

from parsy import line_info_at

# Get position information
text = "line1\nline2\nline3"
position = 8  # After "line1\nli"

line, col = line_info_at(text, position)
print(f"Position {position} is at line {line}, column {col}")
# Output: Position 8 is at line 1, column 2

# Use in error reporting
def parse_with_position_info(parser, text):
    try:
        return parser.parse(text)
    except ParseError as e:
        line, col = line_info_at(text, e.index)
        print(f"Parse error at line {line}, column {col}: {e}")
        raise

# Track positions during parsing
@generate
def positioned_content():
    start_info = yield line_info
    content = yield regex(r'[^\n]+')
    end_info = yield line_info
    return {
        'content': content,
        'start': start_info,
        'end': end_info
    }

Transform Functions

from parsy import string, noop

# Using noop as identity transform
case_sensitive = string('Hello', transform=noop)
result = case_sensitive.parse('Hello')  # Returns 'Hello'

# Custom transform functions
case_insensitive = string('Hello', transform=str.lower)
result = case_insensitive.parse('HELLO')  # Returns 'Hello'

# Transform function for normalization
def normalize_whitespace(s):
    return ' '.join(s.split())

normalized_string = string('hello    world', transform=normalize_whitespace)
result = normalized_string.parse('hello world')  # Returns 'hello    world'

Position-Aware Error Handling

from parsy import generate, string, regex, ParseError, line_info_at

class DetailedParseError(Exception):
    def __init__(self, message, line, column, context=""):
        self.message = message
        self.line = line
        self.column = column
        self.context = context
        super().__init__(f"{message} at line {line}, column {column}")

def enhanced_parse(parser, text):
    """Parse with enhanced error reporting."""
    try:
        return parser.parse(text)
    except ParseError as e:
        line, col = line_info_at(text, e.index)
        
        # Get context around error position
        lines = text.split('\n')
        if line < len(lines):
            context = lines[line]
            pointer = ' ' * col + '^'
            context_display = f"{context}\n{pointer}"
        else:
            context_display = ""
        
        raise DetailedParseError(
            str(e),
            line + 1,  # Convert to 1-indexed for human reading
            col + 1,   # Convert to 1-indexed for human reading
            context_display
        )

# Usage example
@generate
def simple_assignment():
    var_name = yield regex(r'[a-zA-Z_][a-zA-Z0-9_]*')
    yield string('=')
    value = yield regex(r'\d+').map(int)
    return (var_name, value)

try:
    result = enhanced_parse(simple_assignment, 'x = abc')
except DetailedParseError as e:
    print(f"Error: {e}")
    print(f"Context:\n{e.context}")

Line Information Utilities

from parsy import line_info, generate, string, any_char

# Create a parser that tracks line information
@generate
def line_tracking_parser():
    content = []
    
    while True:
        # Try to get current position
        pos = yield line_info
        
        # Try to get next character
        try:
            char = yield any_char
            content.append((char, pos))
        except:
            break
    
    return content

# Parse with line tracking
text = "a\nb\nc"
result = line_tracking_parser.parse_partial(text)
# Returns [('a', (0, 0)), ('\n', (0, 1)), ('b', (1, 0)), ('\n', (1, 1)), ('c', (2, 0))]

Install with Tessl CLI

npx tessl i tessl/pypi-parsy

docs

basic-parsers.md

combinators.md

core-parser.md

index.md

predefined-parsers.md

utilities.md

tile.json