python-delphi-lsp 3.6.0__cp310-abi3-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- delphi_lsp/__init__.py +184 -0
- delphi_lsp/_version.py +1 -0
- delphi_lsp/agent_cache.py +1574 -0
- delphi_lsp/agent_cli.py +902 -0
- delphi_lsp/agent_context.py +3907 -0
- delphi_lsp/agent_cpg.py +349 -0
- delphi_lsp/agent_cpg_builder.py +666 -0
- delphi_lsp/agent_layers.py +1410 -0
- delphi_lsp/agent_metrics.py +526 -0
- delphi_lsp/agent_protocol.py +445 -0
- delphi_lsp/agent_relations.py +1881 -0
- delphi_lsp/agent_templates.py +614 -0
- delphi_lsp/agent_wiki.py +2853 -0
- delphi_lsp/agent_workspace.py +860 -0
- delphi_lsp/ast_serialize.py +126 -0
- delphi_lsp/binary.py +250 -0
- delphi_lsp/comment_builder.py +28 -0
- delphi_lsp/consts.py +345 -0
- delphi_lsp/delphi_lsp_native.pyd +0 -0
- delphi_lsp/delphiast_lexer.py +399 -0
- delphi_lsp/delphiast_parser.py +2189 -0
- delphi_lsp/delphiast_tokens.py +41 -0
- delphi_lsp/grammar.py +459 -0
- delphi_lsp/incremental.py +1139 -0
- delphi_lsp/lark_builder.py +2684 -0
- delphi_lsp/lark_tokens.py +236 -0
- delphi_lsp/lexical_scanner.py +30 -0
- delphi_lsp/lsp_server.py +6698 -0
- delphi_lsp/metrics.py +1452 -0
- delphi_lsp/native_bridge.py +300 -0
- delphi_lsp/navigation_cache.py +189 -0
- delphi_lsp/nodes.py +462 -0
- delphi_lsp/parallel_outline.py +662 -0
- delphi_lsp/parse_artifacts.py +969 -0
- delphi_lsp/parser.py +342 -0
- delphi_lsp/parser_backend.py +139 -0
- delphi_lsp/preprocessor.py +1122 -0
- delphi_lsp/progress.py +26 -0
- delphi_lsp/project_config.py +285 -0
- delphi_lsp/project_discovery.py +932 -0
- delphi_lsp/project_indexer.py +470 -0
- delphi_lsp/py.typed +1 -0
- delphi_lsp/response_cache.py +465 -0
- delphi_lsp/semantic.py +394 -0
- delphi_lsp/semantic_builder.py +2302 -0
- delphi_lsp/source_reader.py +17 -0
- delphi_lsp/wiki_external_sort.py +392 -0
- delphi_lsp/wiki_memory.py +548 -0
- delphi_lsp/workspace.py +83 -0
- delphi_lsp/writer.py +73 -0
- python_delphi_lsp-3.6.0.dist-info/METADATA +766 -0
- python_delphi_lsp-3.6.0.dist-info/RECORD +56 -0
- python_delphi_lsp-3.6.0.dist-info/WHEEL +4 -0
- python_delphi_lsp-3.6.0.dist-info/entry_points.txt +3 -0
- python_delphi_lsp-3.6.0.dist-info/licenses/LICENSE +373 -0
- python_delphi_lsp-3.6.0.dist-info/sboms/python-delphi-lsp.cyclonedx.json +770 -0
delphi_lsp/nodes.py
ADDED
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Iterable, Sequence
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from .consts import AttributeName, SyntaxNodeType
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ParserException(Exception):
|
|
12
|
+
def __init__(self, line: int, col: int, file_name: str, message: str) -> None:
|
|
13
|
+
super().__init__(message)
|
|
14
|
+
self.file_name = file_name
|
|
15
|
+
self.line = line
|
|
16
|
+
self.col = col
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SyntaxTreeException(ParserException):
|
|
20
|
+
def __init__(self, line: int, col: int, file_name: str, message: str, syntax_tree: SyntaxNode) -> None:
|
|
21
|
+
super().__init__(line, col, file_name, message)
|
|
22
|
+
self.syntax_tree = syntax_tree
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SyntaxNode:
|
|
26
|
+
__slots__ = (
|
|
27
|
+
"_attributes",
|
|
28
|
+
"_child_loader",
|
|
29
|
+
"_child_nodes",
|
|
30
|
+
"_col",
|
|
31
|
+
"_file_name",
|
|
32
|
+
"_incremental_source_positions_normalized",
|
|
33
|
+
"_line",
|
|
34
|
+
"_parent_node",
|
|
35
|
+
"_position_anchor",
|
|
36
|
+
"_source_positions",
|
|
37
|
+
"_token_end_col",
|
|
38
|
+
"_token_end_line",
|
|
39
|
+
"_typ",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
def __init__(self, typ: SyntaxNodeType) -> None:
|
|
43
|
+
self._typ = typ
|
|
44
|
+
self._col = 0
|
|
45
|
+
self._line = 0
|
|
46
|
+
self._file_name = ''
|
|
47
|
+
self._attributes: list[tuple[AttributeName, str]] = []
|
|
48
|
+
self._child_nodes: list[SyntaxNode] = []
|
|
49
|
+
self._child_loader: Callable[[], list[SyntaxNode]] | None = None
|
|
50
|
+
self._parent_node: SyntaxNode | None = None
|
|
51
|
+
self._source_positions: tuple[tuple[int, int], ...] = ()
|
|
52
|
+
self._position_anchor: Any = None
|
|
53
|
+
self._incremental_source_positions_normalized = False
|
|
54
|
+
self._token_end_line = 0
|
|
55
|
+
self._token_end_col = 0
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def typ(self) -> SyntaxNodeType:
|
|
59
|
+
return self._typ
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def col(self) -> int:
|
|
63
|
+
return self._col
|
|
64
|
+
|
|
65
|
+
@col.setter
|
|
66
|
+
def col(self, value: int) -> None:
|
|
67
|
+
self._col = value
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def line(self) -> int:
|
|
71
|
+
return self._line
|
|
72
|
+
|
|
73
|
+
@line.setter
|
|
74
|
+
def line(self, value: int) -> None:
|
|
75
|
+
self._line = value
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def file_name(self) -> str:
|
|
79
|
+
return self._file_name
|
|
80
|
+
|
|
81
|
+
@file_name.setter
|
|
82
|
+
def file_name(self, value: str) -> None:
|
|
83
|
+
self._file_name = value
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def attributes(self) -> list[tuple[AttributeName, str]]:
|
|
87
|
+
return self._attributes
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def child_nodes(self) -> list[SyntaxNode]:
|
|
91
|
+
self._materialize_children()
|
|
92
|
+
return self._child_nodes
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def has_attributes(self) -> bool:
|
|
96
|
+
return len(self._attributes) > 0
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def has_children(self) -> bool:
|
|
100
|
+
return self._child_loader is not None or len(self._child_nodes) > 0
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def parent_node(self) -> SyntaxNode | None:
|
|
104
|
+
return self._parent_node
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def source_positions(self) -> tuple[tuple[int, int], ...]:
|
|
108
|
+
"""Positions for compact source text characters plus its end position."""
|
|
109
|
+
if self._position_anchor is not None:
|
|
110
|
+
return self._position_anchor.positions
|
|
111
|
+
return self._source_positions
|
|
112
|
+
|
|
113
|
+
@source_positions.setter
|
|
114
|
+
def source_positions(self, value: Iterable[tuple[int, int]]) -> None:
|
|
115
|
+
self._position_anchor = None
|
|
116
|
+
self._source_positions = tuple(value)
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def token_end_line(self) -> int:
|
|
120
|
+
return self._token_end_line
|
|
121
|
+
|
|
122
|
+
@token_end_line.setter
|
|
123
|
+
def token_end_line(self, value: int) -> None:
|
|
124
|
+
self._token_end_line = value
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def token_end_col(self) -> int:
|
|
128
|
+
return self._token_end_col
|
|
129
|
+
|
|
130
|
+
@token_end_col.setter
|
|
131
|
+
def token_end_col(self, value: int) -> None:
|
|
132
|
+
self._token_end_col = value
|
|
133
|
+
|
|
134
|
+
def assign_position_from(self, node: SyntaxNode) -> None:
|
|
135
|
+
self._col = node.col
|
|
136
|
+
self._line = node.line
|
|
137
|
+
self._file_name = node.file_name
|
|
138
|
+
self._position_anchor = node._position_anchor
|
|
139
|
+
self._source_positions = node._source_positions
|
|
140
|
+
self._token_end_line = node.token_end_line
|
|
141
|
+
self._token_end_col = node.token_end_col
|
|
142
|
+
|
|
143
|
+
def clone(self) -> SyntaxNode:
|
|
144
|
+
self._materialize_children()
|
|
145
|
+
clone_node = self.__class__(self._typ)
|
|
146
|
+
clone_node._col = self._col
|
|
147
|
+
clone_node._line = self._line
|
|
148
|
+
clone_node._file_name = self._file_name
|
|
149
|
+
clone_node._attributes = list(self._attributes)
|
|
150
|
+
clone_node._position_anchor = self._position_anchor
|
|
151
|
+
clone_node._source_positions = self._source_positions
|
|
152
|
+
clone_node._token_end_line = self._token_end_line
|
|
153
|
+
clone_node._token_end_col = self._token_end_col
|
|
154
|
+
clone_node._child_nodes = [child.clone() for child in self._child_nodes]
|
|
155
|
+
for child in clone_node._child_nodes:
|
|
156
|
+
child._parent_node = clone_node
|
|
157
|
+
return clone_node
|
|
158
|
+
|
|
159
|
+
def get_attribute(self, key: AttributeName) -> str:
|
|
160
|
+
for attr_key, attr_value in self._attributes:
|
|
161
|
+
if attr_key == key:
|
|
162
|
+
return attr_value
|
|
163
|
+
return ''
|
|
164
|
+
|
|
165
|
+
def has_attribute(self, key: AttributeName) -> bool:
|
|
166
|
+
return any(attr_key == key for attr_key, _ in self._attributes)
|
|
167
|
+
|
|
168
|
+
def set_attribute(self, key: AttributeName, value: str) -> None:
|
|
169
|
+
for index, (attr_key, _) in enumerate(self._attributes):
|
|
170
|
+
if attr_key == key:
|
|
171
|
+
self._attributes[index] = (key, value)
|
|
172
|
+
return
|
|
173
|
+
self._attributes.append((key, value))
|
|
174
|
+
|
|
175
|
+
def clear_attributes(self) -> None:
|
|
176
|
+
self._attributes = []
|
|
177
|
+
|
|
178
|
+
def add_child(self, node_or_type: SyntaxNode | SyntaxNodeType) -> SyntaxNode:
|
|
179
|
+
self._materialize_children()
|
|
180
|
+
if isinstance(node_or_type, SyntaxNodeType):
|
|
181
|
+
node = SyntaxNode(node_or_type)
|
|
182
|
+
else:
|
|
183
|
+
node = node_or_type
|
|
184
|
+
if node is None:
|
|
185
|
+
raise ValueError('node must not be None')
|
|
186
|
+
self._child_nodes.append(node)
|
|
187
|
+
node._parent_node = self
|
|
188
|
+
return node
|
|
189
|
+
|
|
190
|
+
def extract_child(self, node: SyntaxNode) -> None:
|
|
191
|
+
self._materialize_children()
|
|
192
|
+
try:
|
|
193
|
+
index = self._child_nodes.index(node)
|
|
194
|
+
except ValueError:
|
|
195
|
+
return
|
|
196
|
+
self._child_nodes.pop(index)
|
|
197
|
+
node._parent_node = None
|
|
198
|
+
|
|
199
|
+
def delete_child(self, node: SyntaxNode) -> None:
|
|
200
|
+
self.extract_child(node)
|
|
201
|
+
|
|
202
|
+
def find_node(self, typ_or_path: SyntaxNodeType | Sequence[SyntaxNodeType]) -> SyntaxNode | None:
|
|
203
|
+
self._materialize_children()
|
|
204
|
+
if isinstance(typ_or_path, SyntaxNodeType):
|
|
205
|
+
for child in self._child_nodes:
|
|
206
|
+
if child.typ == typ_or_path:
|
|
207
|
+
return child
|
|
208
|
+
return None
|
|
209
|
+
|
|
210
|
+
types_path = list(typ_or_path)
|
|
211
|
+
if not types_path:
|
|
212
|
+
return None
|
|
213
|
+
if types_path[-1] == SyntaxNodeType.ntUnknown:
|
|
214
|
+
return None
|
|
215
|
+
return self._find_node_recursively(self, types_path, 0)
|
|
216
|
+
|
|
217
|
+
def _set_child_loader(self, loader: Callable[[], list[SyntaxNode]]) -> None:
|
|
218
|
+
if self._child_nodes:
|
|
219
|
+
raise ValueError('cannot defer children after materialization')
|
|
220
|
+
self._child_loader = loader
|
|
221
|
+
|
|
222
|
+
def _materialize_children(self) -> None:
|
|
223
|
+
loader = self._child_loader
|
|
224
|
+
if loader is None:
|
|
225
|
+
return
|
|
226
|
+
self._child_loader = None
|
|
227
|
+
children: list[SyntaxNode] | None = None
|
|
228
|
+
try:
|
|
229
|
+
children = loader()
|
|
230
|
+
finally:
|
|
231
|
+
if children is None:
|
|
232
|
+
self._child_loader = loader
|
|
233
|
+
assert children is not None
|
|
234
|
+
self._child_nodes.extend(children)
|
|
235
|
+
for child in children:
|
|
236
|
+
child._parent_node = self
|
|
237
|
+
|
|
238
|
+
def _find_node_recursively(
|
|
239
|
+
self,
|
|
240
|
+
node: SyntaxNode,
|
|
241
|
+
types_path: Sequence[SyntaxNodeType],
|
|
242
|
+
type_index: int,
|
|
243
|
+
) -> SyntaxNode | None:
|
|
244
|
+
for child in node.child_nodes:
|
|
245
|
+
if types_path[type_index] in (child.typ, SyntaxNodeType.ntUnknown):
|
|
246
|
+
if type_index < len(types_path) - 1:
|
|
247
|
+
found = self._find_node_recursively(child, types_path, type_index + 1)
|
|
248
|
+
else:
|
|
249
|
+
found = child
|
|
250
|
+
if found is not None:
|
|
251
|
+
return found
|
|
252
|
+
return None
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class CompoundSyntaxNode(SyntaxNode):
|
|
256
|
+
__slots__ = ("end_col", "end_line")
|
|
257
|
+
|
|
258
|
+
def __init__(self, typ: SyntaxNodeType) -> None:
|
|
259
|
+
super().__init__(typ)
|
|
260
|
+
self.end_col = 0
|
|
261
|
+
self.end_line = 0
|
|
262
|
+
|
|
263
|
+
def clone(self) -> SyntaxNode:
|
|
264
|
+
clone_node = super().clone()
|
|
265
|
+
clone_node.end_col = self.end_col
|
|
266
|
+
clone_node.end_line = self.end_line
|
|
267
|
+
return clone_node
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class ValuedSyntaxNode(SyntaxNode):
|
|
271
|
+
__slots__ = ("value",)
|
|
272
|
+
|
|
273
|
+
def __init__(self, typ: SyntaxNodeType) -> None:
|
|
274
|
+
super().__init__(typ)
|
|
275
|
+
self.value = ''
|
|
276
|
+
|
|
277
|
+
def clone(self) -> SyntaxNode:
|
|
278
|
+
clone_node = super().clone()
|
|
279
|
+
clone_node.value = self.value
|
|
280
|
+
return clone_node
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class CommentNode(SyntaxNode):
|
|
284
|
+
__slots__ = ("text",)
|
|
285
|
+
|
|
286
|
+
def __init__(self, typ: SyntaxNodeType) -> None:
|
|
287
|
+
super().__init__(typ)
|
|
288
|
+
self.text = ''
|
|
289
|
+
|
|
290
|
+
def clone(self) -> SyntaxNode:
|
|
291
|
+
clone_node = super().clone()
|
|
292
|
+
clone_node.text = self.text
|
|
293
|
+
return clone_node
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class OperatorKind(Enum):
|
|
297
|
+
UNARY = 'unary'
|
|
298
|
+
BINARY = 'binary'
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
class OperatorAssoc(Enum):
|
|
302
|
+
LEFT = 'left'
|
|
303
|
+
RIGHT = 'right'
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
@dataclass(frozen=True)
|
|
307
|
+
class OperatorInfo:
|
|
308
|
+
typ: SyntaxNodeType
|
|
309
|
+
priority: int
|
|
310
|
+
kind: OperatorKind
|
|
311
|
+
assoc: OperatorAssoc
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
_OPERATOR_INFO = (
|
|
315
|
+
OperatorInfo(SyntaxNodeType.ntAddr, 1, OperatorKind.UNARY, OperatorAssoc.RIGHT),
|
|
316
|
+
OperatorInfo(SyntaxNodeType.ntDeref, 1, OperatorKind.UNARY, OperatorAssoc.LEFT),
|
|
317
|
+
OperatorInfo(SyntaxNodeType.ntGeneric, 1, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
318
|
+
OperatorInfo(SyntaxNodeType.ntIndexed, 1, OperatorKind.UNARY, OperatorAssoc.LEFT),
|
|
319
|
+
OperatorInfo(SyntaxNodeType.ntDot, 2, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
320
|
+
OperatorInfo(SyntaxNodeType.ntCall, 3, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
321
|
+
OperatorInfo(SyntaxNodeType.ntUnaryMinus, 5, OperatorKind.UNARY, OperatorAssoc.RIGHT),
|
|
322
|
+
OperatorInfo(SyntaxNodeType.ntNot, 6, OperatorKind.UNARY, OperatorAssoc.RIGHT),
|
|
323
|
+
OperatorInfo(SyntaxNodeType.ntMul, 7, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
324
|
+
OperatorInfo(SyntaxNodeType.ntFDiv, 7, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
325
|
+
OperatorInfo(SyntaxNodeType.ntDiv, 7, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
326
|
+
OperatorInfo(SyntaxNodeType.ntMod, 7, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
327
|
+
OperatorInfo(SyntaxNodeType.ntAnd, 7, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
328
|
+
OperatorInfo(SyntaxNodeType.ntShl, 7, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
329
|
+
OperatorInfo(SyntaxNodeType.ntShr, 7, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
330
|
+
OperatorInfo(SyntaxNodeType.ntAs, 7, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
331
|
+
OperatorInfo(SyntaxNodeType.ntAdd, 8, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
332
|
+
OperatorInfo(SyntaxNodeType.ntSub, 8, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
333
|
+
OperatorInfo(SyntaxNodeType.ntOr, 8, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
334
|
+
OperatorInfo(SyntaxNodeType.ntXor, 8, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
335
|
+
OperatorInfo(SyntaxNodeType.ntEqual, 9, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
336
|
+
OperatorInfo(SyntaxNodeType.ntNotEqual, 9, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
337
|
+
OperatorInfo(SyntaxNodeType.ntLower, 9, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
338
|
+
OperatorInfo(SyntaxNodeType.ntGreater, 9, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
339
|
+
OperatorInfo(SyntaxNodeType.ntLowerEqual, 9, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
340
|
+
OperatorInfo(SyntaxNodeType.ntGreaterEqual, 9, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
341
|
+
OperatorInfo(SyntaxNodeType.ntIn, 9, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
342
|
+
OperatorInfo(SyntaxNodeType.ntIs, 9, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
343
|
+
OperatorInfo(SyntaxNodeType.ntNotIn, 9, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
344
|
+
OperatorInfo(SyntaxNodeType.ntIsNot, 9, OperatorKind.BINARY, OperatorAssoc.RIGHT),
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
_OPERATORS = {info.typ: info for info in _OPERATOR_INFO}
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _is_round_close(typ: SyntaxNodeType) -> bool:
|
|
351
|
+
return typ == SyntaxNodeType.ntRoundClose
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _is_round_open(typ: SyntaxNodeType) -> bool:
|
|
355
|
+
return typ == SyntaxNodeType.ntRoundOpen
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def is_operator(typ: SyntaxNodeType) -> bool:
|
|
359
|
+
return typ in _OPERATORS
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def operator_info(typ: SyntaxNodeType) -> OperatorInfo:
|
|
363
|
+
return _OPERATORS[typ]
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def expr_to_reverse_notation(expr: Iterable[SyntaxNode]) -> list[SyntaxNode]:
|
|
367
|
+
output: list[SyntaxNode] = []
|
|
368
|
+
stack: list[SyntaxNode] = []
|
|
369
|
+
for node in expr:
|
|
370
|
+
if is_operator(node.typ):
|
|
371
|
+
while stack and is_operator(stack[-1].typ):
|
|
372
|
+
current = operator_info(node.typ)
|
|
373
|
+
top = operator_info(stack[-1].typ)
|
|
374
|
+
if (
|
|
375
|
+
(current.assoc == OperatorAssoc.LEFT and current.priority >= top.priority)
|
|
376
|
+
or (current.assoc == OperatorAssoc.RIGHT and current.priority > top.priority)
|
|
377
|
+
):
|
|
378
|
+
output.append(stack.pop())
|
|
379
|
+
else:
|
|
380
|
+
break
|
|
381
|
+
stack.append(node)
|
|
382
|
+
elif _is_round_open(node.typ):
|
|
383
|
+
stack.append(node)
|
|
384
|
+
elif _is_round_close(node.typ):
|
|
385
|
+
while stack and not _is_round_open(stack[-1].typ):
|
|
386
|
+
output.append(stack.pop())
|
|
387
|
+
if stack:
|
|
388
|
+
stack.pop()
|
|
389
|
+
if stack and is_operator(stack[-1].typ):
|
|
390
|
+
output.append(stack.pop())
|
|
391
|
+
else:
|
|
392
|
+
output.append(node)
|
|
393
|
+
while stack:
|
|
394
|
+
output.append(stack.pop())
|
|
395
|
+
return output
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def node_list_to_tree(expr: Iterable[SyntaxNode], root: SyntaxNode) -> None:
|
|
399
|
+
stack: list[SyntaxNode] = []
|
|
400
|
+
for node in expr:
|
|
401
|
+
if is_operator(node.typ):
|
|
402
|
+
info = operator_info(node.typ)
|
|
403
|
+
if info.kind == OperatorKind.UNARY:
|
|
404
|
+
node.add_child(stack.pop())
|
|
405
|
+
else:
|
|
406
|
+
second = stack.pop()
|
|
407
|
+
node.add_child(stack.pop())
|
|
408
|
+
node.add_child(second)
|
|
409
|
+
stack.append(node)
|
|
410
|
+
root.add_child(stack.pop())
|
|
411
|
+
if stack:
|
|
412
|
+
raise ValueError('expression stack not empty after parsing')
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def prepare_expr(expr_nodes: Iterable[SyntaxNode]) -> list[SyntaxNode]:
|
|
416
|
+
prepared: list[SyntaxNode] = []
|
|
417
|
+
prev_node: SyntaxNode | None = None
|
|
418
|
+
for node in expr_nodes:
|
|
419
|
+
if node.typ == SyntaxNodeType.ntCall:
|
|
420
|
+
continue
|
|
421
|
+
|
|
422
|
+
if prev_node is not None and _is_round_open(node.typ):
|
|
423
|
+
if not is_operator(prev_node.typ) and not _is_round_open(prev_node.typ):
|
|
424
|
+
prepared.append(create_node_with_parents_position(SyntaxNodeType.ntCall, node.parent_node))
|
|
425
|
+
if (
|
|
426
|
+
is_operator(prev_node.typ)
|
|
427
|
+
and operator_info(prev_node.typ).kind == OperatorKind.UNARY
|
|
428
|
+
and operator_info(prev_node.typ).assoc == OperatorAssoc.LEFT
|
|
429
|
+
):
|
|
430
|
+
prepared.append(create_node_with_parents_position(SyntaxNodeType.ntCall, node.parent_node))
|
|
431
|
+
|
|
432
|
+
if prev_node is not None and node.typ == SyntaxNodeType.ntTypeArgs:
|
|
433
|
+
if not is_operator(prev_node.typ) and prev_node.typ != SyntaxNodeType.ntTypeArgs:
|
|
434
|
+
prepared.append(create_node_with_parents_position(SyntaxNodeType.ntGeneric, node.parent_node))
|
|
435
|
+
if (
|
|
436
|
+
is_operator(prev_node.typ)
|
|
437
|
+
and operator_info(prev_node.typ).kind == OperatorKind.UNARY
|
|
438
|
+
and operator_info(prev_node.typ).assoc == OperatorAssoc.LEFT
|
|
439
|
+
):
|
|
440
|
+
prepared.append(create_node_with_parents_position(SyntaxNodeType.ntGeneric, node.parent_node))
|
|
441
|
+
|
|
442
|
+
if node.typ != SyntaxNodeType.ntAlignmentParam:
|
|
443
|
+
prepared.append(node.clone())
|
|
444
|
+
prev_node = node
|
|
445
|
+
|
|
446
|
+
return prepared
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def create_node_with_parents_position(node_type: SyntaxNodeType, parent_node: SyntaxNode | None) -> SyntaxNode:
|
|
450
|
+
node = SyntaxNode(node_type)
|
|
451
|
+
if parent_node is not None:
|
|
452
|
+
node.assign_position_from(parent_node)
|
|
453
|
+
return node
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def raw_node_list_to_tree(raw_parent_node: SyntaxNode, raw_node_list: Iterable[SyntaxNode], new_root: SyntaxNode) -> None:
|
|
457
|
+
try:
|
|
458
|
+
prepared = prepare_expr(raw_node_list)
|
|
459
|
+
reverse = expr_to_reverse_notation(prepared)
|
|
460
|
+
node_list_to_tree(reverse, new_root)
|
|
461
|
+
except Exception as exc: # pragma: no cover - parity with Pascal error handling
|
|
462
|
+
raise ParserException(new_root.line, new_root.col, new_root.file_name, str(exc)) from exc
|