]> git.madduck.net Git - etc/vim.git/blobdiff - src/blib2to3/pytree.py

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Fix comments getting removed from inside parenthesized strings (#3909)
[etc/vim.git] / src / blib2to3 / pytree.py
index 7843467e0129d2c3f281ffab3ff76da7d53001f3..2a0cd6d196a3410536b4e9a07d5ded47d6c90b54 100644 (file)
@@ -10,22 +10,21 @@ even the comments and whitespace between tokens.
 There's also a pattern matching implementation here.
 """
 
 There's also a pattern matching implementation here.
 """
 
-# mypy: allow-untyped-defs
+# mypy: allow-untyped-defs, allow-incomplete-defs
 
 from typing import (
     Any,
 
 from typing import (
     Any,
-    Callable,
     Dict,
     Dict,
+    Iterable,
     Iterator,
     List,
     Optional,
     Iterator,
     List,
     Optional,
-    Text,
+    Set,
     Tuple,
     TypeVar,
     Union,
     Tuple,
     TypeVar,
     Union,
-    Set,
-    Iterable,
 )
 )
+
 from blib2to3.pgen2.grammar import Grammar
 
 __author__ = "Guido van Rossum <guido@python.org>"
 from blib2to3.pgen2.grammar import Grammar
 
 __author__ = "Guido van Rossum <guido@python.org>"
@@ -35,10 +34,10 @@ from io import StringIO
 
 HUGE: int = 0x7FFFFFFF  # maximum repeat count, default max
 
 
 HUGE: int = 0x7FFFFFFF  # maximum repeat count, default max
 
-_type_reprs: Dict[int, Union[Text, int]] = {}
+_type_reprs: Dict[int, Union[str, int]] = {}
 
 
 
 
-def type_repr(type_num: int) -> Union[Text, int]:
+def type_repr(type_num: int) -> Union[str, int]:
     global _type_reprs
     if not _type_reprs:
         from .pygram import python_symbols
     global _type_reprs
     if not _type_reprs:
         from .pygram import python_symbols
@@ -52,15 +51,14 @@ def type_repr(type_num: int) -> Union[Text, int]:
     return _type_reprs.setdefault(type_num, type_num)
 
 
     return _type_reprs.setdefault(type_num, type_num)
 
 
-_P = TypeVar("_P")
+_P = TypeVar("_P", bound="Base")
 
 NL = Union["Node", "Leaf"]
 
 NL = Union["Node", "Leaf"]
-Context = Tuple[Text, Tuple[int, int]]
-RawNode = Tuple[int, Optional[Text], Optional[Context], Optional[List[NL]]]
+Context = Tuple[str, Tuple[int, int]]
+RawNode = Tuple[int, Optional[str], Optional[Context], Optional[List[NL]]]
 
 
 
 
-class Base(object):
-
+class Base:
     """
     Abstract base class for Node and Leaf.
 
     """
     Abstract base class for Node and Leaf.
 
@@ -92,10 +90,8 @@ class Base(object):
             return NotImplemented
         return self._eq(other)
 
             return NotImplemented
         return self._eq(other)
 
-    __hash__ = None  # type: Any  # For Py3 compatibility.
-
     @property
     @property
-    def prefix(self) -> Text:
+    def prefix(self) -> str:
         raise NotImplementedError
 
     def _eq(self: _P, other: _P) -> bool:
         raise NotImplementedError
 
     def _eq(self: _P, other: _P) -> bool:
@@ -109,6 +105,9 @@ class Base(object):
         """
         raise NotImplementedError
 
         """
         raise NotImplementedError
 
+    def __deepcopy__(self: _P, memo: Any) -> _P:
+        return self.clone()
+
     def clone(self: _P) -> _P:
         """
         Return a cloned (deep) copy of self.
     def clone(self: _P) -> _P:
         """
         Return a cloned (deep) copy of self.
@@ -225,7 +224,7 @@ class Base(object):
             return 0
         return 1 + self.parent.depth()
 
             return 0
         return 1 + self.parent.depth()
 
-    def get_suffix(self) -> Text:
+    def get_suffix(self) -> str:
         """
         Return the string immediately following the invocant node. This is
         effectively equivalent to node.next_sibling.prefix
         """
         Return the string immediately following the invocant node. This is
         effectively equivalent to node.next_sibling.prefix
@@ -238,18 +237,17 @@ class Base(object):
 
 
 class Node(Base):
 
 
 class Node(Base):
-
     """Concrete implementation for interior nodes."""
 
     fixers_applied: Optional[List[Any]]
     """Concrete implementation for interior nodes."""
 
     fixers_applied: Optional[List[Any]]
-    used_names: Optional[Set[Text]]
+    used_names: Optional[Set[str]]
 
     def __init__(
         self,
         type: int,
         children: List[NL],
         context: Optional[Any] = None,
 
     def __init__(
         self,
         type: int,
         children: List[NL],
         context: Optional[Any] = None,
-        prefix: Optional[Text] = None,
+        prefix: Optional[str] = None,
         fixers_applied: Optional[List[Any]] = None,
     ) -> None:
         """
         fixers_applied: Optional[List[Any]] = None,
     ) -> None:
         """
@@ -274,16 +272,16 @@ class Node(Base):
         else:
             self.fixers_applied = None
 
         else:
             self.fixers_applied = None
 
-    def __repr__(self) -> Text:
+    def __repr__(self) -> str:
         """Return a canonical string representation."""
         assert self.type is not None
         """Return a canonical string representation."""
         assert self.type is not None
-        return "%s(%s, %r)" % (
+        return "{}({}, {!r})".format(
             self.__class__.__name__,
             type_repr(self.type),
             self.children,
         )
 
             self.__class__.__name__,
             type_repr(self.type),
             self.children,
         )
 
-    def __str__(self) -> Text:
+    def __str__(self) -> str:
         """
         Return a pretty string representation.
 
         """
         Return a pretty string representation.
 
@@ -291,7 +289,7 @@ class Node(Base):
         """
         return "".join(map(str, self.children))
 
         """
         return "".join(map(str, self.children))
 
-    def _eq(self, other) -> bool:
+    def _eq(self, other: Base) -> bool:
         """Compare two nodes for equality."""
         return (self.type, self.children) == (other.type, other.children)
 
         """Compare two nodes for equality."""
         return (self.type, self.children) == (other.type, other.children)
 
@@ -317,7 +315,7 @@ class Node(Base):
             yield from child.pre_order()
 
     @property
             yield from child.pre_order()
 
     @property
-    def prefix(self) -> Text:
+    def prefix(self) -> str:
         """
         The whitespace and comments preceding this node in the input.
         """
         """
         The whitespace and comments preceding this node in the input.
         """
@@ -326,7 +324,7 @@ class Node(Base):
         return self.children[0].prefix
 
     @prefix.setter
         return self.children[0].prefix
 
     @prefix.setter
-    def prefix(self, prefix) -> None:
+    def prefix(self, prefix: str) -> None:
         if self.children:
             self.children[0].prefix = prefix
 
         if self.children:
             self.children[0].prefix = prefix
 
@@ -379,26 +377,32 @@ class Node(Base):
 
 
 class Leaf(Base):
 
 
 class Leaf(Base):
-
     """Concrete implementation for leaf nodes."""
 
     # Default values for instance variables
     """Concrete implementation for leaf nodes."""
 
     # Default values for instance variables
-    value: Text
+    value: str
     fixers_applied: List[Any]
     bracket_depth: int
     fixers_applied: List[Any]
     bracket_depth: int
-    opening_bracket: "Leaf"
-    used_names: Optional[Set[Text]]
+    # Changed later in brackets.py
+    opening_bracket: Optional["Leaf"] = None
+    used_names: Optional[Set[str]]
     _prefix = ""  # Whitespace and comments preceding this token in the input
     lineno: int = 0  # Line where this token starts in the input
     column: int = 0  # Column where this token starts in the input
     _prefix = ""  # Whitespace and comments preceding this token in the input
     lineno: int = 0  # Line where this token starts in the input
     column: int = 0  # Column where this token starts in the input
+    # If not None, this Leaf is created by converting a block of fmt off/skip
+    # code, and `fmt_pass_converted_first_leaf` points to the first Leaf in the
+    # converted code.
+    fmt_pass_converted_first_leaf: Optional["Leaf"] = None
 
     def __init__(
         self,
         type: int,
 
     def __init__(
         self,
         type: int,
-        value: Text,
+        value: str,
         context: Optional[Context] = None,
         context: Optional[Context] = None,
-        prefix: Optional[Text] = None,
+        prefix: Optional[str] = None,
         fixers_applied: List[Any] = [],
         fixers_applied: List[Any] = [],
+        opening_bracket: Optional["Leaf"] = None,
+        fmt_pass_converted_first_leaf: Optional["Leaf"] = None,
     ) -> None:
         """
         Initializer.
     ) -> None:
         """
         Initializer.
@@ -416,27 +420,29 @@ class Leaf(Base):
             self._prefix = prefix
         self.fixers_applied: Optional[List[Any]] = fixers_applied[:]
         self.children = []
             self._prefix = prefix
         self.fixers_applied: Optional[List[Any]] = fixers_applied[:]
         self.children = []
+        self.opening_bracket = opening_bracket
+        self.fmt_pass_converted_first_leaf = fmt_pass_converted_first_leaf
 
     def __repr__(self) -> str:
         """Return a canonical string representation."""
         from .pgen2.token import tok_name
 
         assert self.type is not None
 
     def __repr__(self) -> str:
         """Return a canonical string representation."""
         from .pgen2.token import tok_name
 
         assert self.type is not None
-        return "%s(%s, %r)" % (
+        return "{}({}, {!r})".format(
             self.__class__.__name__,
             tok_name.get(self.type, self.type),
             self.value,
         )
 
             self.__class__.__name__,
             tok_name.get(self.type, self.type),
             self.value,
         )
 
-    def __str__(self) -> Text:
+    def __str__(self) -> str:
         """
         Return a pretty string representation.
 
         This reproduces the input source exactly.
         """
         """
         Return a pretty string representation.
 
         This reproduces the input source exactly.
         """
-        return self.prefix + str(self.value)
+        return self._prefix + str(self.value)
 
 
-    def _eq(self, other) -> bool:
+    def _eq(self, other: "Leaf") -> bool:
         """Compare two nodes for equality."""
         return (self.type, self.value) == (other.type, other.value)
 
         """Compare two nodes for equality."""
         return (self.type, self.value) == (other.type, other.value)
 
@@ -462,14 +468,14 @@ class Leaf(Base):
         yield self
 
     @property
         yield self
 
     @property
-    def prefix(self) -> Text:
+    def prefix(self) -> str:
         """
         The whitespace and comments preceding this token in the input.
         """
         return self._prefix
 
     @prefix.setter
         """
         The whitespace and comments preceding this token in the input.
         """
         return self._prefix
 
     @prefix.setter
-    def prefix(self, prefix) -> None:
+    def prefix(self, prefix: str) -> None:
         self.changed()
         self._prefix = prefix
 
         self.changed()
         self._prefix = prefix
 
@@ -494,11 +500,10 @@ def convert(gr: Grammar, raw_node: RawNode) -> NL:
         return Leaf(type, value or "", context=context)
 
 
         return Leaf(type, value or "", context=context)
 
 
-_Results = Dict[Text, NL]
-
+_Results = Dict[str, NL]
 
 
-class BasePattern(object):
 
 
+class BasePattern:
     """
     A pattern is a tree matching pattern.
 
     """
     A pattern is a tree matching pattern.
 
@@ -517,19 +522,19 @@ class BasePattern(object):
     type: Optional[int]
     type = None  # Node type (token if < 256, symbol if >= 256)
     content: Any = None  # Optional content matching pattern
     type: Optional[int]
     type = None  # Node type (token if < 256, symbol if >= 256)
     content: Any = None  # Optional content matching pattern
-    name: Optional[Text] = None  # Optional name used to store match in results dict
+    name: Optional[str] = None  # Optional name used to store match in results dict
 
     def __new__(cls, *args, **kwds):
         """Constructor that prevents BasePattern from being instantiated."""
         assert cls is not BasePattern, "Cannot instantiate BasePattern"
         return object.__new__(cls)
 
 
     def __new__(cls, *args, **kwds):
         """Constructor that prevents BasePattern from being instantiated."""
         assert cls is not BasePattern, "Cannot instantiate BasePattern"
         return object.__new__(cls)
 
-    def __repr__(self) -> Text:
+    def __repr__(self) -> str:
         assert self.type is not None
         args = [type_repr(self.type), self.content, self.name]
         while args and args[-1] is None:
             del args[-1]
         assert self.type is not None
         args = [type_repr(self.type), self.content, self.name]
         while args and args[-1] is None:
             del args[-1]
-        return "%s(%s)" % (self.__class__.__name__, ", ".join(map(repr, args)))
+        return "{}({})".format(self.__class__.__name__, ", ".join(map(repr, args)))
 
     def _submatch(self, node, results=None) -> bool:
         raise NotImplementedError
 
     def _submatch(self, node, results=None) -> bool:
         raise NotImplementedError
@@ -593,8 +598,8 @@ class LeafPattern(BasePattern):
     def __init__(
         self,
         type: Optional[int] = None,
     def __init__(
         self,
         type: Optional[int] = None,
-        content: Optional[Text] = None,
-        name: Optional[Text] = None,
+        content: Optional[str] = None,
+        name: Optional[str] = None,
     ) -> None:
         """
         Initializer.  Takes optional type, content, and name.
     ) -> None:
         """
         Initializer.  Takes optional type, content, and name.
@@ -615,7 +620,7 @@ class LeafPattern(BasePattern):
         self.content = content
         self.name = name
 
         self.content = content
         self.name = name
 
-    def match(self, node: NL, results=None):
+    def match(self, node: NL, results=None) -> bool:
         """Override match() to insist on a leaf node."""
         if not isinstance(node, Leaf):
             return False
         """Override match() to insist on a leaf node."""
         if not isinstance(node, Leaf):
             return False
@@ -638,14 +643,13 @@ class LeafPattern(BasePattern):
 
 
 class NodePattern(BasePattern):
 
 
 class NodePattern(BasePattern):
-
     wildcards: bool = False
 
     def __init__(
         self,
         type: Optional[int] = None,
     wildcards: bool = False
 
     def __init__(
         self,
         type: Optional[int] = None,
-        content: Optional[Iterable[Text]] = None,
-        name: Optional[Text] = None,
+        content: Optional[Iterable[str]] = None,
+        name: Optional[str] = None,
     ) -> None:
         """
         Initializer.  Takes optional type, content, and name.
     ) -> None:
         """
         Initializer.  Takes optional type, content, and name.
@@ -669,10 +673,13 @@ class NodePattern(BasePattern):
             newcontent = list(content)
             for i, item in enumerate(newcontent):
                 assert isinstance(item, BasePattern), (i, item)
             newcontent = list(content)
             for i, item in enumerate(newcontent):
                 assert isinstance(item, BasePattern), (i, item)
-                if isinstance(item, WildcardPattern):
-                    self.wildcards = True
+                # I don't even think this code is used anywhere, but it does cause
+                # unreachable errors from mypy. This function's signature does look
+                # odd though *shrug*.
+                if isinstance(item, WildcardPattern):  # type: ignore[unreachable]
+                    self.wildcards = True  # type: ignore[unreachable]
         self.type = type
         self.type = type
-        self.content = newcontent
+        self.content = newcontent  # TODO: this is unbound when content is None
         self.name = name
 
     def _submatch(self, node, results=None) -> bool:
         self.name = name
 
     def _submatch(self, node, results=None) -> bool:
@@ -704,7 +711,6 @@ class NodePattern(BasePattern):
 
 
 class WildcardPattern(BasePattern):
 
 
 class WildcardPattern(BasePattern):
-
     """
     A wildcard pattern can match zero or more nodes.
 
     """
     A wildcard pattern can match zero or more nodes.
 
@@ -722,10 +728,10 @@ class WildcardPattern(BasePattern):
 
     def __init__(
         self,
 
     def __init__(
         self,
-        content: Optional[Text] = None,
+        content: Optional[str] = None,
         min: int = 0,
         max: int = HUGE,
         min: int = 0,
         max: int = HUGE,
-        name: Optional[Text] = None,
+        name: Optional[str] = None,
     ) -> None:
         """
         Initializer.
     ) -> None:
         """
         Initializer.
@@ -914,7 +920,7 @@ class WildcardPattern(BasePattern):
 
 
 class NegatedPattern(BasePattern):
 
 
 class NegatedPattern(BasePattern):
-    def __init__(self, content: Optional[Any] = None) -> None:
+    def __init__(self, content: Optional[BasePattern] = None) -> None:
         """
         Initializer.
 
         """
         Initializer.
 
@@ -935,7 +941,7 @@ class NegatedPattern(BasePattern):
         # We only match an empty sequence of nodes in its entirety
         return len(nodes) == 0
 
         # We only match an empty sequence of nodes in its entirety
         return len(nodes) == 0
 
-    def generate_matches(self, nodes) -> Iterator[Tuple[int, _Results]]:
+    def generate_matches(self, nodes: List[NL]) -> Iterator[Tuple[int, _Results]]:
         if self.content is None:
             # Return a match if there is an empty sequence
             if len(nodes) == 0:
         if self.content is None:
             # Return a match if there is an empty sequence
             if len(nodes) == 0:
@@ -975,6 +981,3 @@ def generate_matches(
                     r.update(r0)
                     r.update(r1)
                     yield c0 + c1, r
                     r.update(r0)
                     r.update(r1)
                     yield c0 + c1, r
-
-
-_Convert = Callable[[Grammar, RawNode], Any]