0
# Core Parsing Primitives
1
2
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.
3
4
## Capabilities
5
6
### Parser Class
7
8
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.
9
10
```python { .api }
11
class Parser:
12
"""
13
A Parser wraps a function to do parsing work.
14
The wrapped function takes (text, index) and returns Value.success() or Value.failure().
15
"""
16
17
def __init__(self, fn):
18
"""
19
Create a parser from a parsing function.
20
21
Args:
22
fn: Function that takes (text: str, index: int) -> Value
23
"""
24
25
def __call__(self, text, index):
26
"""
27
Call the wrapped parsing function directly.
28
29
Args:
30
text (str): Text to parse
31
index (int): Starting position
32
33
Returns:
34
Value: Success or failure result
35
"""
36
37
def parse(self, text):
38
"""
39
Parse a given string completely.
40
41
Args:
42
text (str): String to parse
43
44
Returns:
45
Parsed value on success
46
47
Raises:
48
ParseError: If parsing fails
49
"""
50
51
def parse_partial(self, text):
52
"""
53
Parse the longest possible prefix of a string.
54
55
Args:
56
text (str): String to parse
57
58
Returns:
59
tuple: (parsed_value, remaining_text)
60
61
Raises:
62
ParseError: If parsing fails
63
"""
64
65
def parse_strict(self, text):
66
"""
67
Parse entire string with no remaining text allowed.
68
69
Args:
70
text (str): String to parse completely
71
72
Returns:
73
Parsed value on success
74
75
Raises:
76
ParseError: If parsing fails or text remains
77
"""
78
```
79
80
### Value Type
81
82
Result container that represents the outcome of a parsing operation, containing success/failure status, position information, parsed value, and error expectations.
83
84
```python { .api }
85
class Value:
86
"""
87
Represents the result of a parsing operation.
88
89
Attributes:
90
status (bool): True for success, False for failure
91
index (int): Position after parsing
92
value: Parsed value (None on failure)
93
expected (str): Expected input description (for failures)
94
"""
95
96
@staticmethod
97
def success(index, actual):
98
"""
99
Create a successful parsing result.
100
101
Args:
102
index (int): Position after consuming input
103
actual: The parsed value
104
105
Returns:
106
Value: Success result
107
"""
108
109
@staticmethod
110
def failure(index, expected):
111
"""
112
Create a failed parsing result.
113
114
Args:
115
index (int): Position where parsing failed
116
expected (str): Description of what was expected
117
118
Returns:
119
Value: Failure result
120
"""
121
122
def aggregate(self, other=None):
123
"""
124
Combine results from sequential parsers.
125
126
Args:
127
other (Value, optional): Other parsing result to combine
128
129
Returns:
130
Value: Combined result with concatenated values
131
"""
132
```
133
134
### Parse Error
135
136
Comprehensive error reporting with source location information, including line and column numbers for debugging complex parsing failures.
137
138
```python { .api }
139
class ParseError(RuntimeError):
140
"""
141
Parser error with detailed location information.
142
143
Attributes:
144
expected (str): What the parser expected to find
145
text (str): Original input text being parsed
146
index (int): Position where error occurred
147
"""
148
149
def __init__(self, expected, text, index):
150
"""
151
Create a parsing error.
152
153
Args:
154
expected (str): Description of expected input
155
text (str): The text being parsed
156
index (int): Character position of the error
157
"""
158
159
@staticmethod
160
def loc_info(text, index):
161
"""
162
Calculate line and column from text position.
163
164
Args:
165
text (str): Source text
166
index (int): Character position
167
168
Returns:
169
tuple: (line_number, column_number) both 0-based
170
171
Raises:
172
ValueError: If index is beyond text length
173
"""
174
175
def loc(self):
176
"""
177
Get formatted location string for this error.
178
179
Returns:
180
str: Location in format "line:column" or error description
181
"""
182
183
def __str__(self):
184
"""
185
Get string representation of the error.
186
187
Returns:
188
str: Error message with expected input and location
189
190
Note:
191
The original implementation contains a typo: it returns
192
"excepted X at Y" instead of "expected X at Y".
193
"""
194
```
195
196
### Utility Exports
197
198
Standard library utilities exported for convenience when building parsers.
199
200
```python { .api }
201
# From collections module
202
namedtuple: type
203
"""
204
Factory function for creating tuple subclasses with named fields.
205
Exported for creating custom result types in parsers.
206
"""
207
208
# From functools module
209
wraps: function
210
"""
211
Decorator to preserve function metadata when creating wrapper functions.
212
Exported for use in custom parser decorators.
213
"""
214
215
# Standard library module
216
re: module
217
"""
218
Regular expression module for pattern matching.
219
Used internally by regex() parser and available for custom parsers.
220
"""
221
```
222
223
## Usage Examples
224
225
### Basic Parser Creation
226
227
```python
228
from parsec import Parser, Value
229
230
# Create a parser that matches single character 'x'
231
def x_parser_fn(text, index):
232
if index < len(text) and text[index] == 'x':
233
return Value.success(index + 1, 'x')
234
else:
235
return Value.failure(index, 'character x')
236
237
x_parser = Parser(x_parser_fn)
238
239
# Use the parser
240
result = x_parser.parse("xyz") # Returns 'x'
241
```
242
243
### Error Handling
244
245
```python
246
from parsec import ParseError, string
247
248
parser = string("hello")
249
250
try:
251
result = parser.parse("world")
252
except ParseError as e:
253
print(f"Expected: {e.expected}") # Expected: hello
254
print(f"At position: {e.index}") # At position: 0
255
print(f"Location: {e.loc()}") # Location: 0:0
256
```
257
258
### Using Different Parse Methods
259
260
```python
261
from parsec import string, many, letter
262
263
parser = many(letter())
264
265
# parse() - consume what it can, ignore rest
266
result = parser.parse("abc123") # Returns ['a', 'b', 'c']
267
268
# parse_partial() - return both result and remaining text
269
result, remaining = parser.parse_partial("abc123")
270
# result: ['a', 'b', 'c'], remaining: "123"
271
272
# parse_strict() - entire input must be consumed
273
try:
274
result = parser.parse_strict("abc123") # Raises ParseError
275
except ParseError:
276
print("Text remaining after parsing")
277
```