diff options
Diffstat (limited to 'Tools/peg_generator/pegen/grammar.py')
-rw-r--r-- | Tools/peg_generator/pegen/grammar.py | 141 |
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() |