]>
crepu.dev Git - config.git/blob - djavu-asus/emacs/elpy/rpc-venv/lib/python3.11/site-packages/parso/tree.py
e5298711ead793683b7054190819a6d58167ef41
1 from abc
import abstractmethod
, abstractproperty
2 from typing
import List
, Optional
, Tuple
, Union
4 from parso
.utils
import split_lines
7 def search_ancestor(node
: 'NodeOrLeaf', *node_types
: str) -> 'Optional[BaseNode]':
9 Recursively looks at the parents of a node and returns the first found node
10 that matches ``node_types``. Returns ``None`` if no matching node is found.
12 This function is deprecated, use :meth:`NodeOrLeaf.search_ancestor` instead.
14 :param node: The ancestors of this node will be checked.
15 :param node_types: type names that are searched for.
19 if n
.type in node_types
:
27 The base class for nodes and leaves.
29 __slots__
= ('parent',)
32 The type is a string that typically matches the types of the grammar file.
34 parent
: 'Optional[BaseNode]'
36 The parent :class:`BaseNode` of this node or leaf.
37 None if this is the root node.
40 def get_root_node(self
):
42 Returns the root node of a parser tree. The returned node doesn't have
43 a parent node like all the other nodes/leaves.
46 while scope
.parent
is not None:
50 def get_next_sibling(self
):
52 Returns the node immediately following this node in this parent's
53 children list. If this node does not have a next sibling, it is None
59 # Can't use index(); we need to test by identity
60 for i
, child
in enumerate(parent
.children
):
63 return self
.parent
.children
[i
+ 1]
67 def get_previous_sibling(self
):
69 Returns the node immediately preceding this node in this parent's
70 children list. If this node does not have a previous sibling, it is
77 # Can't use index(); we need to test by identity
78 for i
, child
in enumerate(parent
.children
):
82 return self
.parent
.children
[i
- 1]
84 def get_previous_leaf(self
):
86 Returns the previous leaf in the parser tree.
87 Returns `None` if this is the first element in the parser tree.
89 if self
.parent
is None:
94 c
= node
.parent
.children
98 if node
.parent
is None:
106 node
= node
.children
[-1]
107 except AttributeError: # A Leaf doesn't have children.
110 def get_next_leaf(self
):
112 Returns the next leaf in the parser tree.
113 Returns None if this is the last element in the parser tree.
115 if self
.parent
is None:
120 c
= node
.parent
.children
124 if node
.parent
is None:
132 node
= node
.children
[0]
133 except AttributeError: # A Leaf doesn't have children.
137 def start_pos(self
) -> Tuple
[int, int]:
139 Returns the starting position of the prefix as a tuple, e.g. `(3, 4)`.
141 :return tuple of int: (line, column)
145 def end_pos(self
) -> Tuple
[int, int]:
147 Returns the end position of the prefix as a tuple, e.g. `(3, 4)`.
149 :return tuple of int: (line, column)
153 def get_start_pos_of_prefix(self
):
155 Returns the start_pos of the prefix. This means basically it returns
156 the end_pos of the last prefix. The `get_start_pos_of_prefix()` of the
157 prefix `+` in `2 + 1` would be `(1, 1)`, while the start_pos is
160 :return tuple of int: (line, column)
164 def get_first_leaf(self
):
166 Returns the first leaf of a node or itself if this is a leaf.
170 def get_last_leaf(self
):
172 Returns the last leaf of a node or itself if this is a leaf.
176 def get_code(self
, include_prefix
=True):
178 Returns the code that was the input for the parser for this node.
180 :param include_prefix: Removes the prefix (whitespace and comments) of
184 def search_ancestor(self
, *node_types
: str) -> 'Optional[BaseNode]':
186 Recursively looks at the parents of this node or leaf and returns the
187 first found node that matches ``node_types``. Returns ``None`` if no
188 matching node is found.
190 :param node_types: type names that are searched for.
193 while node
is not None:
194 if node
.type in node_types
:
199 def dump(self
, *, indent
: Optional
[Union
[int, str]] = 4) -> str:
201 Returns a formatted dump of the parser tree rooted at this node or leaf. This is
202 mainly useful for debugging purposes.
204 The ``indent`` parameter is interpreted in a similar way as :py:func:`ast.dump`.
205 If ``indent`` is a non-negative integer or string, then the tree will be
206 pretty-printed with that indent level. An indent level of 0, negative, or ``""``
207 will only insert newlines. ``None`` selects the single line representation.
208 Using a positive integer indent indents that many spaces per level. If
209 ``indent`` is a string (such as ``"\\t"``), that string is used to indent each
212 :param indent: Indentation style as described above. The default indentation is
213 4 spaces, which yields a pretty-printed dump.
216 >>> print(parso.parse("lambda x, y: x + y").dump())
219 Keyword('lambda', (1, 0)),
221 Name('x', (1, 7), prefix=' '),
222 Operator(',', (1, 8)),
225 Name('y', (1, 10), prefix=' '),
227 Operator(':', (1, 11)),
228 PythonNode('arith_expr', [
229 Name('x', (1, 13), prefix=' '),
230 Operator('+', (1, 15), prefix=' '),
231 Name('y', (1, 17), prefix=' '),
234 EndMarker('', (1, 18)),
240 elif isinstance(indent
, int):
242 indent_string
= ' ' * indent
243 elif isinstance(indent
, str):
245 indent_string
= indent
247 raise TypeError(f
"expect 'indent' to be int, str or None, got {indent!r}")
249 def _format_dump(node
: NodeOrLeaf
, indent
: str = '', top_level
: bool = True) -> str:
251 node_type
= type(node
).__name
__
252 if isinstance(node
, Leaf
):
253 result
+= f
'{indent}{node_type}('
254 if isinstance(node
, ErrorLeaf
):
255 result
+= f
'{node.token_type!r}, '
256 elif isinstance(node
, TypedLeaf
):
257 result
+= f
'{node.type!r}, '
258 result
+= f
'{node.value!r}, {node.start_pos!r}'
260 result
+= f
', prefix={node.prefix!r}'
262 elif isinstance(node
, BaseNode
):
263 result
+= f
'{indent}{node_type}('
264 if isinstance(node
, Node
):
265 result
+= f
'{node.type!r}, '
269 for child
in node
.children
:
270 result
+= _format_dump(child
, indent
=indent
+ indent_string
, top_level
=False)
271 result
+= f
'{indent}])'
272 else: # pragma: no cover
273 # We shouldn't ever reach here, unless:
274 # - `NodeOrLeaf` is incorrectly subclassed else where
275 # - or a node's children list contains invalid nodes or leafs
276 # Both are unexpected internal errors.
277 raise TypeError(f
'unsupported node encountered: {node!r}')
285 return _format_dump(self
)
288 class Leaf(NodeOrLeaf
):
290 Leafs are basically tokens with a better API. Leafs exactly know where they
291 were defined and what text preceeds them.
293 __slots__
= ('value', 'line', 'column', 'prefix')
296 def __init__(self
, value
: str, start_pos
: Tuple
[int, int], prefix
: str = '') -> None:
299 :py:func:`str` The value of the current token.
301 self
.start_pos
= start_pos
304 :py:func:`str` Typically a mixture of whitespace and comments. Stuff
305 that is syntactically irrelevant for the syntax tree.
307 self
.parent
: Optional
[BaseNode
] = None
309 The parent :class:`BaseNode` of this leaf.
313 def start_pos(self
) -> Tuple
[int, int]:
314 return self
.line
, self
.column
317 def start_pos(self
, value
: Tuple
[int, int]) -> None:
319 self
.column
= value
[1]
321 def get_start_pos_of_prefix(self
):
322 previous_leaf
= self
.get_previous_leaf()
323 if previous_leaf
is None:
324 lines
= split_lines(self
.prefix
)
325 # + 1 is needed because split_lines always returns at least [''].
326 return self
.line
- len(lines
) + 1, 0 # It's the first leaf.
327 return previous_leaf
.end_pos
329 def get_first_leaf(self
):
332 def get_last_leaf(self
):
335 def get_code(self
, include_prefix
=True):
337 return self
.prefix
+ self
.value
342 def end_pos(self
) -> Tuple
[int, int]:
343 lines
= split_lines(self
.value
)
344 end_pos_line
= self
.line
+ len(lines
) - 1
345 # Check for multiline token
346 if self
.line
== end_pos_line
:
347 end_pos_column
= self
.column
+ len(lines
[-1])
349 end_pos_column
= len(lines
[-1])
350 return end_pos_line
, end_pos_column
356 return "<%s: %s>" % (type(self
).__name
__, value
)
359 class TypedLeaf(Leaf
):
360 __slots__
= ('type',)
362 def __init__(self
, type, value
, start_pos
, prefix
=''):
363 super().__init
__(value
, start_pos
, prefix
)
367 class BaseNode(NodeOrLeaf
):
369 The super class for all nodes.
370 A node has children, a type and possibly a parent node.
372 __slots__
= ('children',)
374 def __init__(self
, children
: List
[NodeOrLeaf
]) -> None:
375 self
.children
= children
377 A list of :class:`NodeOrLeaf` child nodes.
379 self
.parent
: Optional
[BaseNode
] = None
381 The parent :class:`BaseNode` of this node.
382 None if this is the root node.
384 for child
in children
:
388 def start_pos(self
) -> Tuple
[int, int]:
389 return self
.children
[0].start_pos
391 def get_start_pos_of_prefix(self
):
392 return self
.children
[0].get_start_pos_of_prefix()
395 def end_pos(self
) -> Tuple
[int, int]:
396 return self
.children
[-1].end_pos
398 def _get_code_for_children(self
, children
, include_prefix
):
400 return "".join(c
.get_code() for c
in children
)
402 first
= children
[0].get_code(include_prefix
=False)
403 return first
+ "".join(c
.get_code() for c
in children
[1:])
405 def get_code(self
, include_prefix
=True):
406 return self
._get
_code
_for
_children
(self
.children
, include_prefix
)
408 def get_leaf_for_position(self
, position
, include_prefixes
=False):
410 Get the :py:class:`parso.tree.Leaf` at ``position``
412 :param tuple position: A position tuple, row, column. Rows start from 1
413 :param bool include_prefixes: If ``False``, ``None`` will be returned if ``position`` falls
414 on whitespace or comments before a leaf
415 :return: :py:class:`parso.tree.Leaf` at ``position``, or ``None``
417 def binary_search(lower
, upper
):
419 element
= self
.children
[lower
]
420 if not include_prefixes
and position
< element
.start_pos
:
423 # In case we have prefixes, a leaf always matches
425 return element
.get_leaf_for_position(position
, include_prefixes
)
426 except AttributeError:
429 index
= int((lower
+ upper
) / 2)
430 element
= self
.children
[index
]
431 if position
<= element
.end_pos
:
432 return binary_search(lower
, index
)
434 return binary_search(index
+ 1, upper
)
436 if not ((1, 0) <= position
<= self
.children
[-1].end_pos
):
437 raise ValueError('Please provide a position that exists within this node.')
438 return binary_search(0, len(self
.children
) - 1)
440 def get_first_leaf(self
):
441 return self
.children
[0].get_first_leaf()
443 def get_last_leaf(self
):
444 return self
.children
[-1].get_last_leaf()
447 code
= self
.get_code().replace('\n', ' ').replace('\r', ' ').strip()
448 return "<%s: %s@%s,%s>" % \
449 (type(self
).__name
__, code
, self
.start_pos
[0], self
.start_pos
[1])
452 class Node(BaseNode
):
453 """Concrete implementation for interior nodes."""
454 __slots__
= ('type',)
456 def __init__(self
, type, children
):
457 super().__init
__(children
)
461 return "%s(%s, %r)" % (self
.__class
__.__name
__, self
.type, self
.children
)
464 class ErrorNode(BaseNode
):
466 A node that contains valid nodes/leaves that we're follow by a token that
467 was invalid. This basically means that the leaf after this node is where
468 Python would mark a syntax error.
474 class ErrorLeaf(Leaf
):
476 A leaf that is either completely invalid in a language (like `$` in Python)
477 or is invalid at that position. Like the star in `1 +* 1`.
479 __slots__
= ('token_type',)
482 def __init__(self
, token_type
, value
, start_pos
, prefix
=''):
483 super().__init
__(value
, start_pos
, prefix
)
484 self
.token_type
= token_type
487 return "<%s: %s:%s, %s>" % \
488 (type(self
).__name
__, self
.token_type
, repr(self
.value
), self
.start_pos
)