1 from __future__ import annotations
2
3 from typing import (
4 AbstractSet,
5 Any,
6 Iterable,
7 Iterator,
8 List,
9 Optional,
10 Tuple,
11 Union,
12 )
13
14
15 class ESC[4;38;5;81mGrammarError(ESC[4;38;5;149mException):
16 pass
17
18
19 class ESC[4;38;5;81mGrammarVisitor:
20 def visit(self, node: Any, *args: Any, **kwargs: Any) -> Any:
21 """Visit a node."""
22 method = "visit_" + node.__class__.__name__
23 visitor = getattr(self, method, self.generic_visit)
24 return visitor(node, *args, **kwargs)
25
26 def generic_visit(self, node: Iterable[Any], *args: Any, **kwargs: Any) -> Any:
27 """Called if no explicit visitor function exists for a node."""
28 for value in node:
29 if isinstance(value, list):
30 for item in value:
31 self.visit(item, *args, **kwargs)
32 else:
33 self.visit(value, *args, **kwargs)
34
35
36 class ESC[4;38;5;81mGrammar:
37 def __init__(self, rules: Iterable[Rule], metas: Iterable[Tuple[str, Optional[str]]]):
38 self.rules = {rule.name: rule for rule in rules}
39 self.metas = dict(metas)
40
41 def __str__(self) -> str:
42 return "\n".join(str(rule) for name, rule in self.rules.items())
43
44 def __repr__(self) -> str:
45 lines = ["Grammar("]
46 lines.append(" [")
47 for rule in self.rules.values():
48 lines.append(f" {repr(rule)},")
49 lines.append(" ],")
50 lines.append(" {repr(list(self.metas.items()))}")
51 lines.append(")")
52 return "\n".join(lines)
53
54 def __iter__(self) -> Iterator[Rule]:
55 yield from self.rules.values()
56
57
58 # Global flag whether we want actions in __str__() -- default off.
59 SIMPLE_STR = True
60
61
62 class ESC[4;38;5;81mRule:
63 def __init__(self, name: str, type: Optional[str], rhs: Rhs, memo: Optional[object] = None):
64 self.name = name
65 self.type = type
66 self.rhs = rhs
67 self.memo = bool(memo)
68 self.left_recursive = False
69 self.leader = False
70
71 def is_loop(self) -> bool:
72 return self.name.startswith("_loop")
73
74 def is_gather(self) -> bool:
75 return self.name.startswith("_gather")
76
77 def __str__(self) -> str:
78 if SIMPLE_STR or self.type is None:
79 res = f"{self.name}: {self.rhs}"
80 else:
81 res = f"{self.name}[{self.type}]: {self.rhs}"
82 if len(res) < 88:
83 return res
84 lines = [res.split(":")[0] + ":"]
85 lines += [f" | {alt}" for alt in self.rhs.alts]
86 return "\n".join(lines)
87
88 def __repr__(self) -> str:
89 return f"Rule({self.name!r}, {self.type!r}, {self.rhs!r})"
90
91 def __iter__(self) -> Iterator[Rhs]:
92 yield self.rhs
93
94 def flatten(self) -> Rhs:
95 # If it's a single parenthesized group, flatten it.
96 rhs = self.rhs
97 if (
98 not self.is_loop()
99 and len(rhs.alts) == 1
100 and len(rhs.alts[0].items) == 1
101 and isinstance(rhs.alts[0].items[0].item, Group)
102 ):
103 rhs = rhs.alts[0].items[0].item.rhs
104 return rhs
105
106
107 class ESC[4;38;5;81mLeaf:
108 def __init__(self, value: str):
109 self.value = value
110
111 def __str__(self) -> str:
112 return self.value
113
114 def __iter__(self) -> Iterable[str]:
115 if False:
116 yield
117
118
119 class ESC[4;38;5;81mNameLeaf(ESC[4;38;5;149mLeaf):
120 """The value is the name."""
121
122 def __str__(self) -> str:
123 if self.value == "ENDMARKER":
124 return "$"
125 return super().__str__()
126
127 def __repr__(self) -> str:
128 return f"NameLeaf({self.value!r})"
129
130
131 class ESC[4;38;5;81mStringLeaf(ESC[4;38;5;149mLeaf):
132 """The value is a string literal, including quotes."""
133
134 def __repr__(self) -> str:
135 return f"StringLeaf({self.value!r})"
136
137
138 class ESC[4;38;5;81mRhs:
139 def __init__(self, alts: List[Alt]):
140 self.alts = alts
141 self.memo: Optional[Tuple[Optional[str], str]] = None
142
143 def __str__(self) -> str:
144 return " | ".join(str(alt) for alt in self.alts)
145
146 def __repr__(self) -> str:
147 return f"Rhs({self.alts!r})"
148
149 def __iter__(self) -> Iterator[List[Alt]]:
150 yield self.alts
151
152 @property
153 def can_be_inlined(self) -> bool:
154 if len(self.alts) != 1 or len(self.alts[0].items) != 1:
155 return False
156 # If the alternative has an action we cannot inline
157 if getattr(self.alts[0], "action", None) is not None:
158 return False
159 return True
160
161
162 class ESC[4;38;5;81mAlt:
163 def __init__(self, items: List[NamedItem], *, icut: int = -1, action: Optional[str] = None):
164 self.items = items
165 self.icut = icut
166 self.action = action
167
168 def __str__(self) -> str:
169 core = " ".join(str(item) for item in self.items)
170 if not SIMPLE_STR and self.action:
171 return f"{core} {{ {self.action} }}"
172 else:
173 return core
174
175 def __repr__(self) -> str:
176 args = [repr(self.items)]
177 if self.icut >= 0:
178 args.append(f"icut={self.icut}")
179 if self.action:
180 args.append(f"action={self.action!r}")
181 return f"Alt({', '.join(args)})"
182
183 def __iter__(self) -> Iterator[List[NamedItem]]:
184 yield self.items
185
186
187 class ESC[4;38;5;81mNamedItem:
188 def __init__(self, name: Optional[str], item: Item, type: Optional[str] = None):
189 self.name = name
190 self.item = item
191 self.type = type
192
193 def __str__(self) -> str:
194 if not SIMPLE_STR and self.name:
195 return f"{self.name}={self.item}"
196 else:
197 return str(self.item)
198
199 def __repr__(self) -> str:
200 return f"NamedItem({self.name!r}, {self.item!r})"
201
202 def __iter__(self) -> Iterator[Item]:
203 yield self.item
204
205
206 class ESC[4;38;5;81mForced:
207 def __init__(self, node: Plain):
208 self.node = node
209
210 def __str__(self) -> str:
211 return f"&&{self.node}"
212
213 def __iter__(self) -> Iterator[Plain]:
214 yield self.node
215
216
217 class ESC[4;38;5;81mLookahead:
218 def __init__(self, node: Plain, sign: str):
219 self.node = node
220 self.sign = sign
221
222 def __str__(self) -> str:
223 return f"{self.sign}{self.node}"
224
225 def __iter__(self) -> Iterator[Plain]:
226 yield self.node
227
228
229 class ESC[4;38;5;81mPositiveLookahead(ESC[4;38;5;149mLookahead):
230 def __init__(self, node: Plain):
231 super().__init__(node, "&")
232
233 def __repr__(self) -> str:
234 return f"PositiveLookahead({self.node!r})"
235
236
237 class ESC[4;38;5;81mNegativeLookahead(ESC[4;38;5;149mLookahead):
238 def __init__(self, node: Plain):
239 super().__init__(node, "!")
240
241 def __repr__(self) -> str:
242 return f"NegativeLookahead({self.node!r})"
243
244
245 class ESC[4;38;5;81mOpt:
246 def __init__(self, node: Item):
247 self.node = node
248
249 def __str__(self) -> str:
250 s = str(self.node)
251 # TODO: Decide whether to use [X] or X? based on type of X
252 if " " in s:
253 return f"[{s}]"
254 else:
255 return f"{s}?"
256
257 def __repr__(self) -> str:
258 return f"Opt({self.node!r})"
259
260 def __iter__(self) -> Iterator[Item]:
261 yield self.node
262
263
264 class ESC[4;38;5;81mRepeat:
265 """Shared base class for x* and x+."""
266
267 def __init__(self, node: Plain):
268 self.node = node
269 self.memo: Optional[Tuple[Optional[str], str]] = None
270
271 def __iter__(self) -> Iterator[Plain]:
272 yield self.node
273
274
275 class ESC[4;38;5;81mRepeat0(ESC[4;38;5;149mRepeat):
276 def __str__(self) -> str:
277 s = str(self.node)
278 # TODO: Decide whether to use (X)* or X* based on type of X
279 if " " in s:
280 return f"({s})*"
281 else:
282 return f"{s}*"
283
284 def __repr__(self) -> str:
285 return f"Repeat0({self.node!r})"
286
287
288 class ESC[4;38;5;81mRepeat1(ESC[4;38;5;149mRepeat):
289 def __str__(self) -> str:
290 s = str(self.node)
291 # TODO: Decide whether to use (X)+ or X+ based on type of X
292 if " " in s:
293 return f"({s})+"
294 else:
295 return f"{s}+"
296
297 def __repr__(self) -> str:
298 return f"Repeat1({self.node!r})"
299
300
301 class ESC[4;38;5;81mGather(ESC[4;38;5;149mRepeat):
302 def __init__(self, separator: Plain, node: Plain):
303 self.separator = separator
304 self.node = node
305
306 def __str__(self) -> str:
307 return f"{self.separator!s}.{self.node!s}+"
308
309 def __repr__(self) -> str:
310 return f"Gather({self.separator!r}, {self.node!r})"
311
312
313 class ESC[4;38;5;81mGroup:
314 def __init__(self, rhs: Rhs):
315 self.rhs = rhs
316
317 def __str__(self) -> str:
318 return f"({self.rhs})"
319
320 def __repr__(self) -> str:
321 return f"Group({self.rhs!r})"
322
323 def __iter__(self) -> Iterator[Rhs]:
324 yield self.rhs
325
326
327 class ESC[4;38;5;81mCut:
328 def __init__(self) -> None:
329 pass
330
331 def __repr__(self) -> str:
332 return f"Cut()"
333
334 def __str__(self) -> str:
335 return f"~"
336
337 def __iter__(self) -> Iterator[Tuple[str, str]]:
338 if False:
339 yield
340
341 def __eq__(self, other: object) -> bool:
342 if not isinstance(other, Cut):
343 return NotImplemented
344 return True
345
346 def initial_names(self) -> AbstractSet[str]:
347 return set()
348
349
350 Plain = Union[Leaf, Group]
351 Item = Union[Plain, Opt, Repeat, Forced, Lookahead, Rhs, Cut]
352 RuleName = Tuple[str, str]
353 MetaTuple = Tuple[str, Optional[str]]
354 MetaList = List[MetaTuple]
355 RuleList = List[Rule]
356 NamedItemList = List[NamedItem]
357 LookaheadOrCut = Union[Lookahead, Cut]