Coverage for src/renaissance/syntax_tree/text_segment.py: 100%
21 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-15 10:34 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-15 10:34 +0000
1# Copyright (C) 2024-2026 TNO
2#
3# Licensed under the terms specified in the LICENSE file in the root directory
4# of this repository, also available at:
5# https://github.com/TNO/Renaissance.Py/blob/main/LICENSE
7"""Protocol defining a text segment: a consecutive piece of text within a larger text."""
9from typing import Protocol, runtime_checkable
12@runtime_checkable
13class TextSegment(Protocol):
14 """Protocol for anything that represents a text segment.
16 A text segment is a consecutive piece, a.k.a. a slice, within a text.
17 Any consecutive piece of text qualifies;
18 it need not correspond to a single syntactic construct.
19 Instances include comments, whitespace (incl. empty lines), syntax nodes,
20 combinations thereof, such as a syntax node together with its associated trivia,
21 and even a regular expression match, which has no relation to a syntax tree at all.
23 Read-only access is enforced "as much as possible" by
24 exposing only @property getters in the protocol.
26 A concrete implementation of this protocol can make some of the properties lazy by using
27 functools.cached_property or manual memoized attributes,
28 such that it only triggers computation the first time it's needed.
29 For example, start_line and start_column can be computed from start_offset and full_text,
30 but only when they are first accessed.
31 Furthermore, a concrete implementation can also make a line-start-offset table once per document
32 and reuse it for every node in that document,
33 turning each node's line/column lookup into an O(log lines) binary search.
34 """
36 @property
37 def full_text(self) -> str:
38 """The full text that contains the text segment."""
39 ...
41 @property
42 def location(self) -> str:
43 """The location of the full text that contains the text segment.
45 For example, when text originates from disk the location is a file path.
46 """
47 ...
49 @property
50 def start_offset(self) -> int:
51 """Start offset of text segment.
53 start_offset is an integer in [0, len(full_text)].
54 """
55 ...
57 @property
58 def start_line(self) -> int:
59 """Start line of text segment - 0 based."""
60 ...
62 @property
63 def start_column(self) -> int:
64 """Start column of text segment - 0 based."""
65 ...
67 @property
68 def end_offset(self) -> int:
69 """Exclusive end offset of text segment.
71 end_offset is an integer in [0, len(full_text)].
72 """
73 ...
75 @property
76 def end_line(self) -> int:
77 """End line of text segment - 0 based."""
78 ...
80 @property
81 def end_column(self) -> int:
82 """End column of text segment - 0 based."""
83 ...
85 @property
86 def text_segment(self) -> str:
87 """The text segment is a slice of the full text.
89 The text segment is represented by the half-open interval [self.start_offset, self.end_offset).
91 The returned text segment is equal to self.full_text[self.start_offset:self.end_offset].
92 """
93 ...