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