summaryrefslogtreecommitdiffstats
path: root/Tools/peg_generator/pegen/grammar.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/peg_generator/pegen/grammar.py')
-rw-r--r--Tools/peg_generator/pegen/grammar.py141
1 files changed, 10 insertions, 131 deletions
diff --git a/Tools/peg_generator/pegen/grammar.py b/Tools/peg_generator/pegen/grammar.py
index 66fd5b3..fa47b98 100644
--- a/Tools/peg_generator/pegen/grammar.py
+++ b/Tools/peg_generator/pegen/grammar.py
@@ -2,6 +2,7 @@ from __future__ import annotations
from abc import abstractmethod
from typing import (
+ TYPE_CHECKING,
AbstractSet,
Any,
Dict,
@@ -11,11 +12,9 @@ from typing import (
Optional,
Set,
Tuple,
- TYPE_CHECKING,
Union,
)
-
if TYPE_CHECKING:
from pegen.parser_generator import ParserGenerator
@@ -31,7 +30,7 @@ class GrammarVisitor:
visitor = getattr(self, method, self.generic_visit)
return visitor(node, *args, **kwargs)
- def generic_visit(self, node: Iterable[Any], *args: Any, **kwargs: Any) -> None:
+ def generic_visit(self, node: Iterable[Any], *args: Any, **kwargs: Any) -> Any:
"""Called if no explicit visitor function exists for a node."""
for value in node:
if isinstance(value, list):
@@ -73,8 +72,6 @@ class Rule:
self.type = type
self.rhs = rhs
self.memo = bool(memo)
- self.visited = False
- self.nullable = False
self.left_recursive = False
self.leader = False
@@ -101,17 +98,6 @@ class Rule:
def __iter__(self) -> Iterator[Rhs]:
yield self.rhs
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- if self.visited:
- # A left-recursive rule is considered non-nullable.
- return False
- self.visited = True
- self.nullable = self.rhs.nullable_visit(rules)
- return self.nullable
-
- def initial_names(self) -> AbstractSet[str]:
- return self.rhs.initial_names()
-
def flatten(self) -> Rhs:
# If it's a single parenthesized group, flatten it.
rhs = self.rhs
@@ -124,10 +110,6 @@ class Rule:
rhs = rhs.alts[0].items[0].item.rhs
return rhs
- def collect_todo(self, gen: ParserGenerator) -> None:
- rhs = self.flatten()
- rhs.collect_todo(gen)
-
class Leaf:
def __init__(self, value: str):
@@ -140,14 +122,6 @@ class Leaf:
if False:
yield
- @abstractmethod
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- raise NotImplementedError
-
- @abstractmethod
- def initial_names(self) -> AbstractSet[str]:
- raise NotImplementedError
-
class NameLeaf(Leaf):
"""The value is the name."""
@@ -160,15 +134,6 @@ class NameLeaf(Leaf):
def __repr__(self) -> str:
return f"NameLeaf({self.value!r})"
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- if self.value in rules:
- return rules[self.value].nullable_visit(rules)
- # Token or unknown; never empty.
- return False
-
- def initial_names(self) -> AbstractSet[str]:
- return {self.value}
-
class StringLeaf(Leaf):
"""The value is a string literal, including quotes."""
@@ -176,13 +141,6 @@ class StringLeaf(Leaf):
def __repr__(self) -> str:
return f"StringLeaf({self.value!r})"
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- # The string token '' is considered empty.
- return not self.value
-
- def initial_names(self) -> AbstractSet[str]:
- return set()
-
class Rhs:
def __init__(self, alts: List[Alt]):
@@ -198,21 +156,14 @@ class Rhs:
def __iter__(self) -> Iterator[List[Alt]]:
yield self.alts
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- for alt in self.alts:
- if alt.nullable_visit(rules):
- return True
- return False
-
- def initial_names(self) -> AbstractSet[str]:
- names: Set[str] = set()
- for alt in self.alts:
- names |= alt.initial_names()
- return names
-
- def collect_todo(self, gen: ParserGenerator) -> None:
- for alt in self.alts:
- alt.collect_todo(gen)
+ @property
+ def can_be_inlined(self) -> bool:
+ if len(self.alts) != 1 or len(self.alts[0].items) != 1:
+ return False
+ # If the alternative has an action we cannot inline
+ if getattr(self.alts[0], "action", None) is not None:
+ return False
+ return True
class Alt:
@@ -239,31 +190,12 @@ class Alt:
def __iter__(self) -> Iterator[List[NamedItem]]:
yield self.items
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- for item in self.items:
- if not item.nullable_visit(rules):
- return False
- return True
-
- def initial_names(self) -> AbstractSet[str]:
- names: Set[str] = set()
- for item in self.items:
- names |= item.initial_names()
- if not item.nullable:
- break
- return names
-
- def collect_todo(self, gen: ParserGenerator) -> None:
- for item in self.items:
- item.collect_todo(gen)
-
class NamedItem:
def __init__(self, name: Optional[str], item: Item, type: Optional[str] = None):
self.name = name
self.item = item
self.type = type
- self.nullable = False
def __str__(self) -> str:
if not SIMPLE_STR and self.name:
@@ -277,16 +209,6 @@ class NamedItem:
def __iter__(self) -> Iterator[Item]:
yield self.item
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- self.nullable = self.item.nullable_visit(rules)
- return self.nullable
-
- def initial_names(self) -> AbstractSet[str]:
- return self.item.initial_names()
-
- def collect_todo(self, gen: ParserGenerator) -> None:
- gen.callmakervisitor.visit(self.item)
-
class Forced:
def __init__(self, node: Plain):
@@ -298,12 +220,6 @@ class Forced:
def __iter__(self) -> Iterator[Plain]:
yield self.node
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- return True
-
- def initial_names(self) -> AbstractSet[str]:
- return set()
-
class Lookahead:
def __init__(self, node: Plain, sign: str):
@@ -316,12 +232,6 @@ class Lookahead:
def __iter__(self) -> Iterator[Plain]:
yield self.node
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- return True
-
- def initial_names(self) -> AbstractSet[str]:
- return set()
-
class PositiveLookahead(Lookahead):
def __init__(self, node: Plain):
@@ -357,12 +267,6 @@ class Opt:
def __iter__(self) -> Iterator[Item]:
yield self.node
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- return True
-
- def initial_names(self) -> AbstractSet[str]:
- return self.node.initial_names()
-
class Repeat:
"""Shared base class for x* and x+."""
@@ -371,16 +275,9 @@ class Repeat:
self.node = node
self.memo: Optional[Tuple[Optional[str], str]] = None
- @abstractmethod
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- raise NotImplementedError
-
def __iter__(self) -> Iterator[Plain]:
yield self.node
- def initial_names(self) -> AbstractSet[str]:
- return self.node.initial_names()
-
class Repeat0(Repeat):
def __str__(self) -> str:
@@ -394,9 +291,6 @@ class Repeat0(Repeat):
def __repr__(self) -> str:
return f"Repeat0({self.node!r})"
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- return True
-
class Repeat1(Repeat):
def __str__(self) -> str:
@@ -410,9 +304,6 @@ class Repeat1(Repeat):
def __repr__(self) -> str:
return f"Repeat1({self.node!r})"
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- return False
-
class Gather(Repeat):
def __init__(self, separator: Plain, node: Plain):
@@ -425,9 +316,6 @@ class Gather(Repeat):
def __repr__(self) -> str:
return f"Gather({self.separator!r}, {self.node!r})"
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- return False
-
class Group:
def __init__(self, rhs: Rhs):
@@ -442,12 +330,6 @@ class Group:
def __iter__(self) -> Iterator[Rhs]:
yield self.rhs
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- return self.rhs.nullable_visit(rules)
-
- def initial_names(self) -> AbstractSet[str]:
- return self.rhs.initial_names()
-
class Cut:
def __init__(self) -> None:
@@ -468,9 +350,6 @@ class Cut:
return NotImplemented
return True
- def nullable_visit(self, rules: Dict[str, Rule]) -> bool:
- return True
-
def initial_names(self) -> AbstractSet[str]:
return set()