]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-124889: Rework Python generator cache (#125816)
authorMikhail Efimov <efimov.mikhail@gmail.com>
Tue, 22 Oct 2024 08:42:56 +0000 (11:42 +0300)
committerGitHub <noreply@github.com>
Tue, 22 Oct 2024 08:42:56 +0000 (09:42 +0100)
Tools/peg_generator/pegen/python_generator.py

index 588d3d3f6ef8f82f7283f0ae9fc7a1bb9ef20a7e..7057135a9061f6345ef6cabc169b33abdb9d8c0b 100644 (file)
@@ -1,6 +1,6 @@
 import os.path
 import token
-from typing import IO, Any, Dict, Optional, Sequence, Set, Text, Tuple
+from typing import IO, Any, Callable, Dict, Optional, Sequence, Set, Text, Tuple
 
 from pegen import grammar
 from pegen.grammar import (
@@ -93,7 +93,7 @@ class InvalidNodeVisitor(GrammarVisitor):
 class PythonCallMakerVisitor(GrammarVisitor):
     def __init__(self, parser_generator: ParserGenerator):
         self.gen = parser_generator
-        self.cache: Dict[Any, Any] = {}
+        self.cache: Dict[str, Tuple[str, str]] = {}
 
     def visit_NameLeaf(self, node: NameLeaf) -> Tuple[Optional[str], str]:
         name = node.value
@@ -110,16 +110,6 @@ class PythonCallMakerVisitor(GrammarVisitor):
     def visit_StringLeaf(self, node: StringLeaf) -> Tuple[str, str]:
         return "literal", f"self.expect({node.value})"
 
-    def visit_Rhs(self, node: Rhs) -> Tuple[Optional[str], str]:
-        if node in self.cache:
-            return self.cache[node]
-        if len(node.alts) == 1 and len(node.alts[0].items) == 1:
-            self.cache[node] = self.visit(node.alts[0].items[0])
-        else:
-            name = self.gen.artificial_rule_from_rhs(node)
-            self.cache[node] = name, f"self.{name}()"
-        return self.cache[node]
-
     def visit_NamedItem(self, node: NamedItem) -> Tuple[Optional[str], str]:
         name, call = self.visit(node.item)
         if node.name:
@@ -151,26 +141,57 @@ class PythonCallMakerVisitor(GrammarVisitor):
         else:
             return "opt", f"{call},"
 
+    def _generate_artificial_rule_call(
+        self,
+        node: Any,
+        prefix: str,
+        call_by_name_func: Callable[[str], str],
+        rule_generation_func: Callable[[], str],
+    ) -> Tuple[str, str]:
+        node_str = f"{node}"
+        key = f"{prefix}_{node_str}"
+        if key in self.cache:
+            return self.cache[key]
+
+        name = rule_generation_func()
+        call = call_by_name_func(name)
+        self.cache[key] = name, call
+        return self.cache[key]
+
+    def visit_Rhs(self, node: Rhs) -> Tuple[str, str]:
+        if len(node.alts) == 1 and len(node.alts[0].items) == 1:
+            return self.visit(node.alts[0].items[0])
+
+        return self._generate_artificial_rule_call(
+            node,
+            "rhs",
+            lambda name: f"self.{name}()",
+            lambda: self.gen.artificial_rule_from_rhs(node),
+        )
+
     def visit_Repeat0(self, node: Repeat0) -> Tuple[str, str]:
-        if node in self.cache:
-            return self.cache[node]
-        name = self.gen.artificial_rule_from_repeat(node.node, False)
-        self.cache[node] = name, f"self.{name}(),"  # Also a trailing comma!
-        return self.cache[node]
+        return self._generate_artificial_rule_call(
+            node,
+            "repeat0",
+            lambda name: f"self.{name}(),",  # Also a trailing comma!
+            lambda: self.gen.artificial_rule_from_repeat(node.node, is_repeat1=False),
+        )
 
     def visit_Repeat1(self, node: Repeat1) -> Tuple[str, str]:
-        if node in self.cache:
-            return self.cache[node]
-        name = self.gen.artificial_rule_from_repeat(node.node, True)
-        self.cache[node] = name, f"self.{name}()"  # But no trailing comma here!
-        return self.cache[node]
+        return self._generate_artificial_rule_call(
+            node,
+            "repeat1",
+            lambda name: f"self.{name}()",  # But no trailing comma here!
+            lambda: self.gen.artificial_rule_from_repeat(node.node, is_repeat1=True),
+        )
 
     def visit_Gather(self, node: Gather) -> Tuple[str, str]:
-        if node in self.cache:
-            return self.cache[node]
-        name = self.gen.artificial_rule_from_gather(node)
-        self.cache[node] = name, f"self.{name}()"  # No trailing comma here either!
-        return self.cache[node]
+        return self._generate_artificial_rule_call(
+            node,
+            "gather",
+            lambda name: f"self.{name}()",  # No trailing comma here either!
+            lambda: self.gen.artificial_rule_from_gather(node),
+        )
 
     def visit_Group(self, node: Group) -> Tuple[Optional[str], str]:
         return self.visit(node.rhs)