|
8 | 8 | import re |
9 | 9 | from contextlib import contextmanager |
10 | 10 | from dataclasses import dataclass, field |
11 | | -from typing import Any, ContextManager, Iterable, Iterator, TypeVar, overload |
| 11 | +from typing import Any, Callable, ContextManager, Iterable, Iterator, TypeVar, overload |
12 | 12 |
|
13 | 13 | from .error import InvalidSyntax, UnexpectedEOF, UnexpectedToken |
14 | 14 | from .location import SourceLocation, set_location |
@@ -68,6 +68,9 @@ class TokenStream: |
68 | 68 | >>> stream.source |
69 | 69 | 'hello world' |
70 | 70 |
|
| 71 | + token_handler |
| 72 | + A callback for modifying tokens before they're emitted. |
| 73 | +
|
71 | 74 | syntax_rules |
72 | 75 | A tuple of ``(token_type, pattern)`` pairs that define the recognizable tokens. |
73 | 76 |
|
@@ -140,6 +143,7 @@ class TokenStream: |
140 | 143 | """ |
141 | 144 |
|
142 | 145 | source: str |
| 146 | + token_handler: Callable[[Token], Token] | None = extra_field(default=None) |
143 | 147 | syntax_rules: SyntaxRules = extra_field(default=()) |
144 | 148 | regex: re.Pattern[str] = extra_field() |
145 | 149 |
|
@@ -482,6 +486,9 @@ def emit_token(self, token_type: str, value: str = "") -> Token: |
482 | 486 | end_location=SourceLocation(end_pos, end_lineno, end_colno), |
483 | 487 | ) |
484 | 488 |
|
| 489 | + if self.token_handler: |
| 490 | + token = self.token_handler(token) |
| 491 | + |
485 | 492 | self.location = token.end_location |
486 | 493 | self.tokens.append(token) |
487 | 494 |
|
|
0 commit comments