dbrownell-parserlib 0.7.0__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/PKG-INFO +1 -1
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/pyproject.toml +1 -1
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/__init__.py +8 -0
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/antlr/antlr_visitor_mixins.py +4 -2
- dbrownell_parserlib-0.8.0/src/dbrownell_ParserLib/expression.py +288 -0
- dbrownell_parserlib-0.8.0/src/dbrownell_ParserLib/terminal_expression.py +21 -0
- dbrownell_parserlib-0.8.0/src/dbrownell_ParserLib/visitors.py +160 -0
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/README.md +0 -0
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/antlr/__init__.py +0 -0
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/antlr/antlr_parser.py +0 -0
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/antlr/build_antlr_grammar/__init__.py +0 -0
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/antlr/build_antlr_grammar/antlr-4.13.2-complete.jar +0 -0
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/errors.py +0 -0
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/location.py +0 -0
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/py.typed +0 -0
- {dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/region.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dbrownell-parserlib"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.8.0"
|
|
4
4
|
# ^^^^^
|
|
5
5
|
# Wheel names will be generated according to this value. Do not manually modify this value; instead
|
|
6
6
|
# update it according to committed changes by running this command from the root of the repository:
|
|
@@ -12,8 +12,11 @@ from dbrownell_ParserLib.antlr import (
|
|
|
12
12
|
SignificantWhitespaceAntlrVisitorMixin,
|
|
13
13
|
)
|
|
14
14
|
from dbrownell_ParserLib.errors import Error, PythonError
|
|
15
|
+
from dbrownell_ParserLib.expression import Expression
|
|
15
16
|
from dbrownell_ParserLib.location import Location
|
|
16
17
|
from dbrownell_ParserLib.region import Region
|
|
18
|
+
from dbrownell_ParserLib.terminal_expression import TerminalExpression
|
|
19
|
+
from dbrownell_ParserLib.visitors import ExpressionVisitor, ExpressionVisitorHelper, VisitResult
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
# ----------------------------------------------------------------------
|
|
@@ -24,11 +27,16 @@ __all__ = [
|
|
|
24
27
|
"BuildAntlrGrammar",
|
|
25
28
|
"CreateAntlrParser",
|
|
26
29
|
"Error",
|
|
30
|
+
"Expression",
|
|
31
|
+
"ExpressionVisitor",
|
|
32
|
+
"ExpressionVisitorHelper",
|
|
27
33
|
"InsignificantWhitespaceAntlrVisitorMixin",
|
|
28
34
|
"Location",
|
|
29
35
|
"PythonError",
|
|
30
36
|
"Region",
|
|
31
37
|
"SignificantWhitespaceAntlrVisitorMixin",
|
|
38
|
+
"TerminalExpression",
|
|
39
|
+
"VisitResult",
|
|
32
40
|
"__version__",
|
|
33
41
|
]
|
|
34
42
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Various ANTLR visitor mixins that can be used to add functionality to the generated visitor classes."""
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
-
from typing import cast, TYPE_CHECKING
|
|
4
|
+
from typing import cast, override, TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
import antlr4
|
|
7
7
|
|
|
@@ -70,6 +70,7 @@ class InsignificantWhitespaceAntlrVisitorMixin(AntlrVisitorMixinBase):
|
|
|
70
70
|
"""Mixin that adds functionality used for grammars that ignore insignificant whitespace."""
|
|
71
71
|
|
|
72
72
|
# ----------------------------------------------------------------------
|
|
73
|
+
@override
|
|
73
74
|
def CreateRegion(
|
|
74
75
|
self,
|
|
75
76
|
ctx: antlr4.ParserRuleContext,
|
|
@@ -106,7 +107,8 @@ class SignificantWhitespaceAntlrVisitorMixin(AntlrVisitorMixinBase):
|
|
|
106
107
|
self._newline_token_string = newline_token_string
|
|
107
108
|
|
|
108
109
|
# ----------------------------------------------------------------------
|
|
109
|
-
|
|
110
|
+
@override
|
|
111
|
+
def CreateRegion(
|
|
110
112
|
self,
|
|
111
113
|
ctx: antlr4.ParserRuleContext,
|
|
112
114
|
) -> Region:
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# noqa: D100
|
|
2
|
+
from collections.abc import Generator, Iterable
|
|
3
|
+
from contextlib import contextmanager
|
|
4
|
+
from dataclasses import dataclass, field, fields, InitVar
|
|
5
|
+
from typing import Self, TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from dbrownell_Common.Types import extension, override
|
|
8
|
+
|
|
9
|
+
from dbrownell_ParserLib.visitors import ExpressionVisitor, ExpressionVisitorHelper, VisitResult
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
|
|
14
|
+
from dbrownell_ParserLib.region import Region
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# ----------------------------------------------------------------------
|
|
18
|
+
@dataclass(eq=False)
|
|
19
|
+
class Expression:
|
|
20
|
+
"""Abstract base class for all expressions encountered during the parsing process."""
|
|
21
|
+
|
|
22
|
+
# ----------------------------------------------------------------------
|
|
23
|
+
# |
|
|
24
|
+
# | Public Data
|
|
25
|
+
# |
|
|
26
|
+
# ----------------------------------------------------------------------
|
|
27
|
+
region__: Region
|
|
28
|
+
finalize: InitVar[bool] = field(kw_only=True, default=True)
|
|
29
|
+
|
|
30
|
+
parent__: Expression | None = field(init=False)
|
|
31
|
+
|
|
32
|
+
_unique_id: tuple[object, ...] | None = field(init=False)
|
|
33
|
+
_disabled: bool = field(init=False)
|
|
34
|
+
|
|
35
|
+
_finalize_func: Callable[[], None] = field(init=False)
|
|
36
|
+
|
|
37
|
+
# ----------------------------------------------------------------------
|
|
38
|
+
# |
|
|
39
|
+
# | Public Methods
|
|
40
|
+
# |
|
|
41
|
+
# ----------------------------------------------------------------------
|
|
42
|
+
def __post_init__(
|
|
43
|
+
self,
|
|
44
|
+
finalize: bool,
|
|
45
|
+
) -> None:
|
|
46
|
+
self.parent__ = None
|
|
47
|
+
|
|
48
|
+
self._unique_id = None
|
|
49
|
+
self._disabled = False
|
|
50
|
+
|
|
51
|
+
# ----------------------------------------------------------------------
|
|
52
|
+
def Finalize() -> None:
|
|
53
|
+
visitor = _UniqueIdVisitor(self)
|
|
54
|
+
|
|
55
|
+
self.Accept(visitor)
|
|
56
|
+
|
|
57
|
+
self._unique_id = visitor.unique_id
|
|
58
|
+
|
|
59
|
+
# ----------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
self._finalize_func = Finalize
|
|
62
|
+
|
|
63
|
+
if finalize:
|
|
64
|
+
self._Finalize()
|
|
65
|
+
|
|
66
|
+
# ----------------------------------------------------------------------
|
|
67
|
+
@property
|
|
68
|
+
def unique_id__(self) -> tuple[object, ...]:
|
|
69
|
+
"""A unique identifier for this expression, which can be used for caching and other purposes."""
|
|
70
|
+
|
|
71
|
+
assert self._unique_id is not None
|
|
72
|
+
return self._unique_id
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def is_disabled__(self) -> bool:
|
|
76
|
+
"""Whether this expression is disabled, which can be used for caching and other purposes."""
|
|
77
|
+
|
|
78
|
+
return self._disabled
|
|
79
|
+
|
|
80
|
+
# ----------------------------------------------------------------------
|
|
81
|
+
def __hash__(self) -> int:
|
|
82
|
+
return hash(self.unique_id__)
|
|
83
|
+
|
|
84
|
+
# ----------------------------------------------------------------------
|
|
85
|
+
def __eq__(self, other: object) -> bool:
|
|
86
|
+
if not isinstance(other, Expression):
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
return self.unique_id__ == other.unique_id__
|
|
90
|
+
|
|
91
|
+
# ----------------------------------------------------------------------
|
|
92
|
+
def __ne__(self, other: object) -> bool:
|
|
93
|
+
if not isinstance(other, Expression):
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
return self.unique_id__ != other.unique_id__
|
|
97
|
+
|
|
98
|
+
# ----------------------------------------------------------------------
|
|
99
|
+
def Clone(self, **kwargs) -> Self:
|
|
100
|
+
"""Create a copy of this expression, optionally overriding some of its fields."""
|
|
101
|
+
|
|
102
|
+
for field_value in fields(self.__class__):
|
|
103
|
+
if field_value.init and field_value.name != "finalize" and field_value.name not in kwargs:
|
|
104
|
+
kwargs[field_value.name] = getattr(self, field_value.name)
|
|
105
|
+
|
|
106
|
+
return self.__class__(**kwargs)
|
|
107
|
+
|
|
108
|
+
# ----------------------------------------------------------------------
|
|
109
|
+
def Disable(self) -> None:
|
|
110
|
+
"""Disable this expression so that it doesn't participate in visitation."""
|
|
111
|
+
|
|
112
|
+
assert self.is_disabled__ is False
|
|
113
|
+
self._disabled = True
|
|
114
|
+
|
|
115
|
+
# ----------------------------------------------------------------------
|
|
116
|
+
def Accept( # noqa: C901
|
|
117
|
+
self,
|
|
118
|
+
visitor: ExpressionVisitor,
|
|
119
|
+
*,
|
|
120
|
+
include_disabled: bool = False,
|
|
121
|
+
) -> VisitResult:
|
|
122
|
+
"""Accept a visitor for visitation of this expression and its children (if any)."""
|
|
123
|
+
|
|
124
|
+
if self.is_disabled__ and not include_disabled:
|
|
125
|
+
return VisitResult.Continue
|
|
126
|
+
|
|
127
|
+
with visitor.OnExpression(self) as expression_visit_result:
|
|
128
|
+
if expression_visit_result & VisitResult.Terminate:
|
|
129
|
+
return expression_visit_result
|
|
130
|
+
|
|
131
|
+
if expression_visit_result & VisitResult.SkipAll:
|
|
132
|
+
return VisitResult.Continue
|
|
133
|
+
|
|
134
|
+
method_name = f"On{self.__class__.__name__}"
|
|
135
|
+
|
|
136
|
+
method = getattr(visitor, method_name, None)
|
|
137
|
+
assert method is not None, method_name
|
|
138
|
+
|
|
139
|
+
with method(self) as method_visit_result:
|
|
140
|
+
if method_visit_result & VisitResult.Terminate:
|
|
141
|
+
return method_visit_result
|
|
142
|
+
|
|
143
|
+
# Details
|
|
144
|
+
if not method_visit_result & VisitResult.SkipDetails:
|
|
145
|
+
all_details = list(self._GenerateAcceptDetails())
|
|
146
|
+
|
|
147
|
+
if all_details:
|
|
148
|
+
with visitor.OnExpressionDetails(self) as details_visit_result:
|
|
149
|
+
if details_visit_result & VisitResult.Terminate:
|
|
150
|
+
return details_visit_result
|
|
151
|
+
|
|
152
|
+
if not details_visit_result & VisitResult.SkipDetails:
|
|
153
|
+
method_name_prefix = f"On{self.__class__.__name__}__"
|
|
154
|
+
|
|
155
|
+
for detail_name, detail_value in all_details:
|
|
156
|
+
method_name = f"{method_name_prefix}{detail_name}"
|
|
157
|
+
|
|
158
|
+
method = getattr(visitor, method_name, None)
|
|
159
|
+
assert method is not None, method_name
|
|
160
|
+
|
|
161
|
+
detail_visit_result = method(
|
|
162
|
+
detail_value, include_disabled=include_disabled
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if detail_visit_result & VisitResult.Terminate:
|
|
166
|
+
return detail_visit_result
|
|
167
|
+
|
|
168
|
+
if detail_visit_result & VisitResult.SkipDetails:
|
|
169
|
+
break
|
|
170
|
+
|
|
171
|
+
# Children
|
|
172
|
+
if not method_visit_result & VisitResult.SkipChildren:
|
|
173
|
+
children_result = self._GetAcceptChildren()
|
|
174
|
+
|
|
175
|
+
if children_result:
|
|
176
|
+
children_name, children = children_result
|
|
177
|
+
|
|
178
|
+
with visitor.OnExpressionChildren(
|
|
179
|
+
self,
|
|
180
|
+
children_name,
|
|
181
|
+
children,
|
|
182
|
+
) as children_visit_result:
|
|
183
|
+
if children_visit_result & VisitResult.Terminate:
|
|
184
|
+
return children_visit_result
|
|
185
|
+
|
|
186
|
+
if not children_visit_result & VisitResult.SkipChildren:
|
|
187
|
+
for child in children:
|
|
188
|
+
child_accept_result = child.Accept(
|
|
189
|
+
visitor, include_disabled=include_disabled
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
if child_accept_result & VisitResult.Terminate:
|
|
193
|
+
return child_accept_result
|
|
194
|
+
|
|
195
|
+
if child_accept_result & VisitResult.SkipChildren:
|
|
196
|
+
break
|
|
197
|
+
|
|
198
|
+
return VisitResult.Continue
|
|
199
|
+
|
|
200
|
+
# ----------------------------------------------------------------------
|
|
201
|
+
# |
|
|
202
|
+
# | Protected Types
|
|
203
|
+
# |
|
|
204
|
+
# ----------------------------------------------------------------------
|
|
205
|
+
_GenerateAcceptDetailsResultType = Generator[tuple[str, list[Self]]]
|
|
206
|
+
_GetAcceptChildrenResultType = tuple[str, Iterable[Self]] | None
|
|
207
|
+
|
|
208
|
+
# ----------------------------------------------------------------------
|
|
209
|
+
# |
|
|
210
|
+
# | Protected Methods
|
|
211
|
+
# |
|
|
212
|
+
# ----------------------------------------------------------------------
|
|
213
|
+
def _Finalize(self) -> None:
|
|
214
|
+
self._finalize_func()
|
|
215
|
+
|
|
216
|
+
# ----------------------------------------------------------------------
|
|
217
|
+
# |
|
|
218
|
+
# | Private Methods
|
|
219
|
+
# |
|
|
220
|
+
# ----------------------------------------------------------------------
|
|
221
|
+
@extension
|
|
222
|
+
def _GetTerminalUniqueId(self) -> tuple[object, ...]:
|
|
223
|
+
"""Get a unique identifier for this expression that doesn't include any of its children."""
|
|
224
|
+
|
|
225
|
+
msg = "This functionality should be implemented by a terminal expression (i.e. an expression that doesn't have any children)."
|
|
226
|
+
raise Exception(msg)
|
|
227
|
+
|
|
228
|
+
# ----------------------------------------------------------------------
|
|
229
|
+
@extension
|
|
230
|
+
def _GenerateAcceptDetails(self) -> _GenerateAcceptDetailsResultType:
|
|
231
|
+
# Nothing by default
|
|
232
|
+
if False:
|
|
233
|
+
yield
|
|
234
|
+
|
|
235
|
+
# ----------------------------------------------------------------------
|
|
236
|
+
@extension
|
|
237
|
+
def _GetAcceptChildren(self) -> _GetAcceptChildrenResultType:
|
|
238
|
+
# Nothing by default
|
|
239
|
+
return None
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# ----------------------------------------------------------------------
|
|
243
|
+
# |
|
|
244
|
+
# | Private Types
|
|
245
|
+
# |
|
|
246
|
+
# ----------------------------------------------------------------------
|
|
247
|
+
class _UniqueIdVisitor(ExpressionVisitorHelper):
|
|
248
|
+
# ----------------------------------------------------------------------
|
|
249
|
+
def __init__(
|
|
250
|
+
self,
|
|
251
|
+
root_expression: Expression,
|
|
252
|
+
) -> None:
|
|
253
|
+
self._target_expression = root_expression
|
|
254
|
+
|
|
255
|
+
self._child_unique_ids: list[tuple[object, ...]] = []
|
|
256
|
+
self._result: tuple[object, ...] | None = None
|
|
257
|
+
|
|
258
|
+
# ----------------------------------------------------------------------
|
|
259
|
+
@property
|
|
260
|
+
def unique_id(self) -> tuple[object, ...]:
|
|
261
|
+
assert self._result is not None
|
|
262
|
+
return self._result
|
|
263
|
+
|
|
264
|
+
# ----------------------------------------------------------------------
|
|
265
|
+
@override
|
|
266
|
+
@contextmanager
|
|
267
|
+
def OnExpression(
|
|
268
|
+
self,
|
|
269
|
+
expression: Expression,
|
|
270
|
+
) -> Generator[VisitResult]:
|
|
271
|
+
if expression is self._target_expression:
|
|
272
|
+
yield VisitResult.Continue
|
|
273
|
+
|
|
274
|
+
if not self._child_unique_ids:
|
|
275
|
+
result = expression._GetTerminalUniqueId() # noqa: SLF001
|
|
276
|
+
else:
|
|
277
|
+
result = tuple(self._child_unique_ids)
|
|
278
|
+
|
|
279
|
+
assert self._result is None
|
|
280
|
+
self._result = (type(expression).__name__, *result)
|
|
281
|
+
|
|
282
|
+
return
|
|
283
|
+
|
|
284
|
+
self._child_unique_ids.append(expression.unique_id__)
|
|
285
|
+
|
|
286
|
+
# Do not parse the children of this expression as its unique id already takes that information
|
|
287
|
+
# into account.
|
|
288
|
+
yield VisitResult.SkipChildren
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# noqa: D100
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import override
|
|
4
|
+
|
|
5
|
+
from dbrownell_ParserLib.expression import Expression
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# ----------------------------------------------------------------------
|
|
9
|
+
@dataclass(eq=False)
|
|
10
|
+
class TerminalExpression[T](Expression):
|
|
11
|
+
"""Expression with a single value member, typically used with leaves in an abstract syntax tree."""
|
|
12
|
+
|
|
13
|
+
# ----------------------------------------------------------------------
|
|
14
|
+
value: T
|
|
15
|
+
|
|
16
|
+
# ----------------------------------------------------------------------
|
|
17
|
+
# ----------------------------------------------------------------------
|
|
18
|
+
# ----------------------------------------------------------------------
|
|
19
|
+
@override
|
|
20
|
+
def _GetTerminalUniqueId(self) -> tuple[object, ...]:
|
|
21
|
+
return (self.value,)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Contains types related to Expression visitation."""
|
|
2
|
+
|
|
3
|
+
import types
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
from enum import auto, Flag
|
|
8
|
+
from typing import override, TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from collections.abc import Generator, Iterable
|
|
12
|
+
|
|
13
|
+
from dbrownell_ParserLib.expression import Expression
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ----------------------------------------------------------------------
|
|
17
|
+
class VisitResult(Flag):
|
|
18
|
+
"""Result returned during visitation that controls the flow of the visitation process."""
|
|
19
|
+
|
|
20
|
+
Continue = 0
|
|
21
|
+
"""Continue visiting the rest of the expressions as normal."""
|
|
22
|
+
|
|
23
|
+
SkipDetails = auto()
|
|
24
|
+
"""Skip visiting the details of this expression, but continue visiting the rest of the expressions as normal."""
|
|
25
|
+
|
|
26
|
+
SkipChildren = auto()
|
|
27
|
+
"""Skip visiting the children of this expression, but continue visiting the rest of the expressions as normal."""
|
|
28
|
+
|
|
29
|
+
Terminate = auto()
|
|
30
|
+
"""Terminate the visitation process immediately."""
|
|
31
|
+
|
|
32
|
+
# Amalgamations
|
|
33
|
+
SkipAll = SkipDetails | SkipChildren
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ----------------------------------------------------------------------
|
|
37
|
+
class ExpressionVisitor(ABC):
|
|
38
|
+
"""Abstract base class for a visitor that accepts Expressions."""
|
|
39
|
+
|
|
40
|
+
# ----------------------------------------------------------------------
|
|
41
|
+
@abstractmethod
|
|
42
|
+
@contextmanager
|
|
43
|
+
def OnExpression(
|
|
44
|
+
self,
|
|
45
|
+
expression: Expression,
|
|
46
|
+
) -> Generator[VisitResult]:
|
|
47
|
+
"""Call for every expression."""
|
|
48
|
+
|
|
49
|
+
raise NotImplementedError("Abstract method") # noqa: EM101 # pragma: no cover
|
|
50
|
+
|
|
51
|
+
# ----------------------------------------------------------------------
|
|
52
|
+
@abstractmethod
|
|
53
|
+
@contextmanager
|
|
54
|
+
def OnExpressionDetails(
|
|
55
|
+
self,
|
|
56
|
+
expression: Expression,
|
|
57
|
+
) -> Generator[VisitResult]:
|
|
58
|
+
"""Call when visiting the details of an expression."""
|
|
59
|
+
|
|
60
|
+
raise NotImplementedError("Abstract method") # noqa: EM101 # pragma: no cover
|
|
61
|
+
|
|
62
|
+
# ----------------------------------------------------------------------
|
|
63
|
+
@abstractmethod
|
|
64
|
+
@contextmanager
|
|
65
|
+
def OnExpressionChildren(
|
|
66
|
+
self,
|
|
67
|
+
expression: Expression,
|
|
68
|
+
children_name: str,
|
|
69
|
+
children: Iterable[Expression],
|
|
70
|
+
) -> Generator[VisitResult]:
|
|
71
|
+
"""Call when visiting the children of an expression."""
|
|
72
|
+
|
|
73
|
+
raise NotImplementedError("Abstract method") # noqa: EM101 # pragma: no cover
|
|
74
|
+
|
|
75
|
+
# ----------------------------------------------------------------------
|
|
76
|
+
# Derived classes should implement the following methods:
|
|
77
|
+
#
|
|
78
|
+
# @contextmanager
|
|
79
|
+
# def On<Expression Name>(self, expression: <Expression Name>) -> Generator[VisitResult]:
|
|
80
|
+
# ...
|
|
81
|
+
#
|
|
82
|
+
# def On<Expression Name>__<Detail Name>(self, expression_or_expressions: <Expression Name> | list[<Expression Name>], include_disabled: bool) -> VisitResult:
|
|
83
|
+
# ...
|
|
84
|
+
#
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# ----------------------------------------------------------------------
|
|
88
|
+
class ExpressionVisitorHelper(ExpressionVisitor):
|
|
89
|
+
"""Base class that makes writing custom visitors easier by providing default behavior for visitation methods."""
|
|
90
|
+
|
|
91
|
+
# ----------------------------------------------------------------------
|
|
92
|
+
@override
|
|
93
|
+
@contextmanager
|
|
94
|
+
def OnExpression(
|
|
95
|
+
self,
|
|
96
|
+
expression: Expression,
|
|
97
|
+
) -> Generator[VisitResult]:
|
|
98
|
+
yield VisitResult.Continue
|
|
99
|
+
|
|
100
|
+
# ----------------------------------------------------------------------
|
|
101
|
+
@override
|
|
102
|
+
@contextmanager
|
|
103
|
+
def OnExpressionDetails(
|
|
104
|
+
self,
|
|
105
|
+
expression: Expression,
|
|
106
|
+
) -> Generator[VisitResult]:
|
|
107
|
+
yield VisitResult.Continue
|
|
108
|
+
|
|
109
|
+
# ----------------------------------------------------------------------
|
|
110
|
+
@override
|
|
111
|
+
@contextmanager
|
|
112
|
+
def OnExpressionChildren(
|
|
113
|
+
self,
|
|
114
|
+
expression: Expression,
|
|
115
|
+
children_name: str,
|
|
116
|
+
children: Iterable[Expression],
|
|
117
|
+
) -> Generator[VisitResult]:
|
|
118
|
+
yield VisitResult.Continue
|
|
119
|
+
|
|
120
|
+
# ----------------------------------------------------------------------
|
|
121
|
+
def __getattr__(
|
|
122
|
+
self,
|
|
123
|
+
method_name: str,
|
|
124
|
+
) -> object:
|
|
125
|
+
if method_name.endswith("Expression"):
|
|
126
|
+
return self.__class__._DefaultExpressionMethod # noqa: SLF001
|
|
127
|
+
|
|
128
|
+
index = method_name.find("Expression__")
|
|
129
|
+
if index != -1 and index + len("Expression__") + 1 < len(method_name):
|
|
130
|
+
return types.MethodType(self.__class__._DefaultDetailMethod, self) # noqa: SLF001
|
|
131
|
+
|
|
132
|
+
raise AttributeError(method_name)
|
|
133
|
+
|
|
134
|
+
# ----------------------------------------------------------------------
|
|
135
|
+
# ----------------------------------------------------------------------
|
|
136
|
+
# ----------------------------------------------------------------------
|
|
137
|
+
@staticmethod
|
|
138
|
+
@contextmanager
|
|
139
|
+
def _DefaultExpressionMethod(*args, **kwargs) -> Generator[VisitResult]: # noqa: ARG004
|
|
140
|
+
yield VisitResult.Continue
|
|
141
|
+
|
|
142
|
+
# ----------------------------------------------------------------------
|
|
143
|
+
def _DefaultDetailMethod(
|
|
144
|
+
self,
|
|
145
|
+
expression_or_expressions: Expression | list[Expression],
|
|
146
|
+
*,
|
|
147
|
+
include_disabled: bool,
|
|
148
|
+
) -> VisitResult:
|
|
149
|
+
expressions: list[Expression] = ( # ty: ignore[invalid-assignment]
|
|
150
|
+
expression_or_expressions
|
|
151
|
+
if isinstance(expression_or_expressions, list)
|
|
152
|
+
else [expression_or_expressions]
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
for expression in expressions:
|
|
156
|
+
result = expression.Accept(self, include_disabled=include_disabled)
|
|
157
|
+
if result & VisitResult.Terminate:
|
|
158
|
+
return result
|
|
159
|
+
|
|
160
|
+
return VisitResult.Continue
|
|
File without changes
|
{dbrownell_parserlib-0.7.0 → dbrownell_parserlib-0.8.0}/src/dbrownell_ParserLib/antlr/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|