agent-codinglanguage-mapper 1.0.0__py3-none-any.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.
- agent_codinglanguage_mapper/__init__.py +20 -0
- agent_codinglanguage_mapper/__main__.py +4 -0
- agent_codinglanguage_mapper/_version.py +2 -0
- agent_codinglanguage_mapper/adapters/__init__.py +4 -0
- agent_codinglanguage_mapper/adapters/delphi.py +822 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/__init__.py +6 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/comment_builder.py +29 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/consts.py +345 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/grammar.py +460 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/lark_builder.py +2674 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/lark_tokens.py +237 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/lsp_server.py +1832 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/nodes.py +371 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/parser.py +193 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/preprocessor.py +997 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/project_discovery.py +518 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/project_indexer.py +319 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/semantic.py +375 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/semantic_builder.py +1384 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/source_reader.py +17 -0
- agent_codinglanguage_mapper/adapters/delphi_frontend/workspace.py +67 -0
- agent_codinglanguage_mapper/adapters/tree_sitter.py +1722 -0
- agent_codinglanguage_mapper/cli.py +138 -0
- agent_codinglanguage_mapper/discovery.py +1328 -0
- agent_codinglanguage_mapper/indexer.py +1102 -0
- agent_codinglanguage_mapper/integration.py +186 -0
- agent_codinglanguage_mapper/lsp_server.py +413 -0
- agent_codinglanguage_mapper/lsp_service.py +447 -0
- agent_codinglanguage_mapper/mapper.py +596 -0
- agent_codinglanguage_mapper/models.py +101 -0
- agent_codinglanguage_mapper/protocol.py +152 -0
- agent_codinglanguage_mapper/rendering.py +153 -0
- agent_codinglanguage_mapper/templates/opencode/plugins/codebase_map.ts +191 -0
- agent_codinglanguage_mapper/templates/skill/SKILL.md +52 -0
- agent_codinglanguage_mapper/worker.py +29 -0
- agent_codinglanguage_mapper/workspace.py +114 -0
- agent_codinglanguage_mapper-1.0.0.dist-info/METADATA +383 -0
- agent_codinglanguage_mapper-1.0.0.dist-info/RECORD +42 -0
- agent_codinglanguage_mapper-1.0.0.dist-info/WHEEL +5 -0
- agent_codinglanguage_mapper-1.0.0.dist-info/entry_points.txt +2 -0
- agent_codinglanguage_mapper-1.0.0.dist-info/licenses/LICENSE +373 -0
- agent_codinglanguage_mapper-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1384 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Iterable, Optional
|
|
5
|
+
|
|
6
|
+
from .consts import ATTRIBUTE_NAME_STRINGS, AttributeName, SyntaxNodeType
|
|
7
|
+
from .nodes import CompoundSyntaxNode, SyntaxNode, ValuedSyntaxNode
|
|
8
|
+
from .semantic import (
|
|
9
|
+
ArrayTypeRef,
|
|
10
|
+
ClassOfTypeRef,
|
|
11
|
+
ClassTypeRef,
|
|
12
|
+
EnumTypeRef,
|
|
13
|
+
FileTypeRef,
|
|
14
|
+
GenericInstanceTypeRef,
|
|
15
|
+
InterfaceTypeRef,
|
|
16
|
+
Modifier,
|
|
17
|
+
NamedTypeRef,
|
|
18
|
+
PointerTypeRef,
|
|
19
|
+
ProcTypeRef,
|
|
20
|
+
RecordTypeRef,
|
|
21
|
+
ReferenceKind,
|
|
22
|
+
ReferenceTypeRef,
|
|
23
|
+
Scope,
|
|
24
|
+
ScopeKind,
|
|
25
|
+
SetTypeRef,
|
|
26
|
+
SourceRange,
|
|
27
|
+
SubrangeTypeRef,
|
|
28
|
+
Symbol,
|
|
29
|
+
SymbolIndex,
|
|
30
|
+
SymbolKind,
|
|
31
|
+
SymbolReference,
|
|
32
|
+
TypeParameterRef,
|
|
33
|
+
TypeRef,
|
|
34
|
+
UnknownTypeRef,
|
|
35
|
+
Visibility,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class SemanticProblem:
|
|
41
|
+
message: str
|
|
42
|
+
range: SourceRange
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class SemanticModel:
|
|
47
|
+
unit_scope: Scope
|
|
48
|
+
index: SymbolIndex
|
|
49
|
+
problems: list[SemanticProblem] = field(default_factory=list)
|
|
50
|
+
references: list[SymbolReference] = field(default_factory=list)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class SemanticBuilder:
|
|
54
|
+
def __init__(self, *, collect_references: bool = True) -> None:
|
|
55
|
+
self._collect_references_enabled = collect_references
|
|
56
|
+
self._problems: list[SemanticProblem] = []
|
|
57
|
+
self._references: list[SymbolReference] = []
|
|
58
|
+
self._index: SymbolIndex = SymbolIndex()
|
|
59
|
+
self._node_scopes: dict[int, Scope] = {}
|
|
60
|
+
self._builtin_types = {
|
|
61
|
+
'string', 'ansistring', 'widestring', 'unicodestring',
|
|
62
|
+
'char', 'widechar',
|
|
63
|
+
'integer', 'smallint', 'shortint', 'longint', 'int64', 'uint64',
|
|
64
|
+
'byte', 'word', 'cardinal', 'nativeint', 'nativeuint',
|
|
65
|
+
'boolean', 'bytebool', 'wordbool', 'longbool',
|
|
66
|
+
'single', 'double', 'extended', 'currency', 'real', 'real48',
|
|
67
|
+
'variant', 'olevariant', 'pointer', 'pchar', 'tobject', 'tclass',
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
def build(self, root: SyntaxNode, *, index: SymbolIndex | None = None) -> SemanticModel:
|
|
71
|
+
self._reset_state(index=index, clear_scopes=True)
|
|
72
|
+
unit_scope = self.declare(root, index=self._index)
|
|
73
|
+
return self.resolve(root, unit_scope)
|
|
74
|
+
|
|
75
|
+
def declare(
|
|
76
|
+
self,
|
|
77
|
+
root: SyntaxNode,
|
|
78
|
+
*,
|
|
79
|
+
index: SymbolIndex | None = None,
|
|
80
|
+
unit_scope: Scope | None = None,
|
|
81
|
+
reset_state: bool = False,
|
|
82
|
+
) -> Scope:
|
|
83
|
+
if reset_state:
|
|
84
|
+
self._reset_state(index=index, clear_scopes=True)
|
|
85
|
+
elif index is not None:
|
|
86
|
+
self._index = index
|
|
87
|
+
|
|
88
|
+
unit_name = self._attr(root, AttributeName.anName) or 'unit'
|
|
89
|
+
if unit_scope is None:
|
|
90
|
+
unit_scope = Scope(kind=ScopeKind.UNIT, name=unit_name)
|
|
91
|
+
if unit_scope.owner is None:
|
|
92
|
+
unit_symbol = Symbol(
|
|
93
|
+
name=unit_name,
|
|
94
|
+
kind=SymbolKind.UNIT,
|
|
95
|
+
decl_range=self._node_range(root),
|
|
96
|
+
name_range=self._node_range(root),
|
|
97
|
+
scope=unit_scope,
|
|
98
|
+
)
|
|
99
|
+
unit_scope.owner = unit_symbol
|
|
100
|
+
self._define_symbol(unit_scope, unit_symbol)
|
|
101
|
+
|
|
102
|
+
self._declare_symbols(root, unit_scope, Visibility.PUBLIC)
|
|
103
|
+
self._index.register_unit(unit_name, unit_scope)
|
|
104
|
+
return unit_scope
|
|
105
|
+
|
|
106
|
+
def resolve(self, root: SyntaxNode, unit_scope: Scope) -> SemanticModel:
|
|
107
|
+
self._references = []
|
|
108
|
+
self._resolve_type_refs(unit_scope)
|
|
109
|
+
|
|
110
|
+
if self._collect_references_enabled:
|
|
111
|
+
self._collect_references_pass(root, unit_scope, Visibility.PUBLIC)
|
|
112
|
+
|
|
113
|
+
return SemanticModel(
|
|
114
|
+
unit_scope=unit_scope,
|
|
115
|
+
index=self._index,
|
|
116
|
+
problems=list(self._problems),
|
|
117
|
+
references=list(self._references),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def _reset_state(self, *, index: SymbolIndex | None, clear_scopes: bool) -> None:
|
|
121
|
+
self._problems = []
|
|
122
|
+
self._references = []
|
|
123
|
+
if clear_scopes:
|
|
124
|
+
self._node_scopes = {}
|
|
125
|
+
if index is not None:
|
|
126
|
+
self._index = index
|
|
127
|
+
elif self._index is None:
|
|
128
|
+
self._index = SymbolIndex()
|
|
129
|
+
|
|
130
|
+
def _declare_symbols(self, node: SyntaxNode, scope: Scope, visibility: Visibility) -> None:
|
|
131
|
+
if node.typ == SyntaxNodeType.ntUses:
|
|
132
|
+
self._handle_uses(node, scope)
|
|
133
|
+
return
|
|
134
|
+
if node.typ == SyntaxNodeType.ntTypeSection:
|
|
135
|
+
self._handle_type_section(node, scope)
|
|
136
|
+
return
|
|
137
|
+
if node.typ == SyntaxNodeType.ntVariables:
|
|
138
|
+
self._handle_variable_section(node, scope, visibility)
|
|
139
|
+
return
|
|
140
|
+
if node.typ == SyntaxNodeType.ntVariable:
|
|
141
|
+
self._handle_inline_variable(node, scope, visibility)
|
|
142
|
+
return
|
|
143
|
+
if node.typ == SyntaxNodeType.ntConstants:
|
|
144
|
+
self._handle_constant_section(node, scope)
|
|
145
|
+
return
|
|
146
|
+
if node.typ == SyntaxNodeType.ntMethod:
|
|
147
|
+
self._handle_method(node, scope, visibility)
|
|
148
|
+
return
|
|
149
|
+
if node.typ == SyntaxNodeType.ntProperty:
|
|
150
|
+
self._handle_property(node, scope, visibility)
|
|
151
|
+
return
|
|
152
|
+
if node.typ == SyntaxNodeType.ntField:
|
|
153
|
+
self._handle_field(node, scope, visibility)
|
|
154
|
+
return
|
|
155
|
+
if node.typ == SyntaxNodeType.ntLabel:
|
|
156
|
+
self._handle_label(node, scope)
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
for child in node.child_nodes:
|
|
160
|
+
self._declare_symbols(child, scope, visibility)
|
|
161
|
+
|
|
162
|
+
def _handle_uses(self, node: SyntaxNode, scope: Scope) -> None:
|
|
163
|
+
for child in node.child_nodes:
|
|
164
|
+
if child.typ != SyntaxNodeType.ntUnit:
|
|
165
|
+
continue
|
|
166
|
+
name = self._attr(child, AttributeName.anName)
|
|
167
|
+
if not name:
|
|
168
|
+
continue
|
|
169
|
+
imported_scope = self._index.lookup_unit(name)
|
|
170
|
+
if imported_scope is None:
|
|
171
|
+
imported_scope = Scope(kind=ScopeKind.UNIT, name=name)
|
|
172
|
+
self._add_problem(f'Unresolved unit {name}', child)
|
|
173
|
+
scope.add_import(imported_scope)
|
|
174
|
+
|
|
175
|
+
def _handle_type_section(self, node: SyntaxNode, scope: Scope) -> None:
|
|
176
|
+
for child in node.child_nodes:
|
|
177
|
+
if child.typ != SyntaxNodeType.ntTypeDecl:
|
|
178
|
+
continue
|
|
179
|
+
self._handle_type_decl(child, scope)
|
|
180
|
+
|
|
181
|
+
def _handle_type_decl(self, node: SyntaxNode, scope: Scope) -> None:
|
|
182
|
+
name = self._attr(node, AttributeName.anName)
|
|
183
|
+
if not name:
|
|
184
|
+
return
|
|
185
|
+
type_node = node.find_node(SyntaxNodeType.ntType)
|
|
186
|
+
type_ref, kind = self._infer_type_ref_and_kind(name, type_node)
|
|
187
|
+
type_symbol = Symbol(
|
|
188
|
+
name=name,
|
|
189
|
+
kind=kind,
|
|
190
|
+
decl_range=self._node_range(node),
|
|
191
|
+
name_range=self._node_range(node),
|
|
192
|
+
scope=scope,
|
|
193
|
+
type_ref=type_ref,
|
|
194
|
+
)
|
|
195
|
+
type_scope = Scope(kind=ScopeKind.TYPE, name=name, parent=scope, owner=type_symbol)
|
|
196
|
+
type_symbol.member_scope = type_scope
|
|
197
|
+
type_symbol.base_types = self._type_bases(type_node)
|
|
198
|
+
self._define_symbol(scope, type_symbol)
|
|
199
|
+
self._node_scopes[id(node)] = type_scope
|
|
200
|
+
|
|
201
|
+
type_params = node.find_node(SyntaxNodeType.ntTypeParams)
|
|
202
|
+
if type_params is not None:
|
|
203
|
+
self._define_type_parameters(type_params, type_scope)
|
|
204
|
+
|
|
205
|
+
if kind == SymbolKind.ENUM and type_node is not None:
|
|
206
|
+
self._define_enum_values(type_node, scope, type_symbol)
|
|
207
|
+
|
|
208
|
+
if type_node is not None:
|
|
209
|
+
self._visit_type_members(type_node, type_scope)
|
|
210
|
+
|
|
211
|
+
def _define_enum_values(self, type_node: SyntaxNode, scope: Scope, type_symbol: Symbol) -> None:
|
|
212
|
+
for child in type_node.child_nodes:
|
|
213
|
+
if child.typ != SyntaxNodeType.ntEnum:
|
|
214
|
+
continue
|
|
215
|
+
name = self._child_name(child)
|
|
216
|
+
if not name:
|
|
217
|
+
continue
|
|
218
|
+
symbol = Symbol(
|
|
219
|
+
name=name,
|
|
220
|
+
kind=SymbolKind.ENUM_VALUE,
|
|
221
|
+
decl_range=self._node_range(child),
|
|
222
|
+
name_range=self._node_range(child),
|
|
223
|
+
scope=scope,
|
|
224
|
+
type_ref=NamedTypeRef(name=type_symbol.name),
|
|
225
|
+
)
|
|
226
|
+
self._define_symbol(scope, symbol)
|
|
227
|
+
|
|
228
|
+
def _visit_type_members(self, node: SyntaxNode, scope: Scope) -> None:
|
|
229
|
+
visibility = Visibility.PUBLIC
|
|
230
|
+
visibility_map = self._visibility_map()
|
|
231
|
+
for child in node.child_nodes:
|
|
232
|
+
if child.typ in visibility_map:
|
|
233
|
+
visibility = visibility_map[child.typ]
|
|
234
|
+
for member in child.child_nodes:
|
|
235
|
+
self._declare_symbols(member, scope, visibility)
|
|
236
|
+
continue
|
|
237
|
+
self._declare_symbols(child, scope, visibility)
|
|
238
|
+
|
|
239
|
+
def _handle_variable_section(self, node: SyntaxNode, scope: Scope, visibility: Visibility) -> None:
|
|
240
|
+
section_kind = self._attr(node, AttributeName.anKind)
|
|
241
|
+
for child in node.child_nodes:
|
|
242
|
+
if child.typ != SyntaxNodeType.ntVariable:
|
|
243
|
+
continue
|
|
244
|
+
name = self._child_name(child)
|
|
245
|
+
if not name:
|
|
246
|
+
continue
|
|
247
|
+
type_ref = self._type_from_node(child.find_node(SyntaxNodeType.ntType))
|
|
248
|
+
symbol = Symbol(
|
|
249
|
+
name=name,
|
|
250
|
+
kind=SymbolKind.VARIABLE,
|
|
251
|
+
decl_range=self._node_range(child),
|
|
252
|
+
name_range=self._node_range(child),
|
|
253
|
+
scope=scope,
|
|
254
|
+
visibility=visibility,
|
|
255
|
+
type_ref=type_ref,
|
|
256
|
+
)
|
|
257
|
+
if section_kind:
|
|
258
|
+
symbol.attributes['section'] = section_kind
|
|
259
|
+
self._define_symbol(scope, symbol)
|
|
260
|
+
|
|
261
|
+
def _handle_constant_section(self, node: SyntaxNode, scope: Scope) -> None:
|
|
262
|
+
section_kind = self._attr(node, AttributeName.anKind)
|
|
263
|
+
for child in node.child_nodes:
|
|
264
|
+
if child.typ != SyntaxNodeType.ntConstant:
|
|
265
|
+
continue
|
|
266
|
+
name = self._child_name(child)
|
|
267
|
+
if not name:
|
|
268
|
+
continue
|
|
269
|
+
type_ref = self._type_from_node(child.find_node(SyntaxNodeType.ntType))
|
|
270
|
+
symbol = Symbol(
|
|
271
|
+
name=name,
|
|
272
|
+
kind=SymbolKind.CONSTANT,
|
|
273
|
+
decl_range=self._node_range(child),
|
|
274
|
+
name_range=self._node_range(child),
|
|
275
|
+
scope=scope,
|
|
276
|
+
type_ref=type_ref,
|
|
277
|
+
)
|
|
278
|
+
if section_kind:
|
|
279
|
+
symbol.attributes['section'] = section_kind
|
|
280
|
+
self._define_symbol(scope, symbol)
|
|
281
|
+
|
|
282
|
+
def _handle_field(self, node: SyntaxNode, scope: Scope, visibility: Visibility) -> None:
|
|
283
|
+
name = self._child_name(node)
|
|
284
|
+
if not name:
|
|
285
|
+
return
|
|
286
|
+
type_ref = self._type_from_node(node.find_node(SyntaxNodeType.ntType))
|
|
287
|
+
symbol = Symbol(
|
|
288
|
+
name=name,
|
|
289
|
+
kind=SymbolKind.FIELD,
|
|
290
|
+
decl_range=self._node_range(node),
|
|
291
|
+
name_range=self._node_range(node),
|
|
292
|
+
scope=scope,
|
|
293
|
+
visibility=visibility,
|
|
294
|
+
type_ref=type_ref,
|
|
295
|
+
)
|
|
296
|
+
self._define_symbol(scope, symbol)
|
|
297
|
+
|
|
298
|
+
def _handle_inline_variable(self, node: SyntaxNode, scope: Scope, visibility: Visibility) -> None:
|
|
299
|
+
name = self._child_name(node)
|
|
300
|
+
if not name:
|
|
301
|
+
return
|
|
302
|
+
type_ref = self._type_from_node(node.find_node(SyntaxNodeType.ntType))
|
|
303
|
+
if isinstance(type_ref, UnknownTypeRef):
|
|
304
|
+
type_ref = UnknownTypeRef('inferred')
|
|
305
|
+
symbol = Symbol(
|
|
306
|
+
name=name,
|
|
307
|
+
kind=SymbolKind.VARIABLE,
|
|
308
|
+
decl_range=self._node_range(node),
|
|
309
|
+
name_range=self._node_range(node),
|
|
310
|
+
scope=scope,
|
|
311
|
+
visibility=visibility,
|
|
312
|
+
type_ref=type_ref,
|
|
313
|
+
)
|
|
314
|
+
symbol.attributes['section'] = 'inline'
|
|
315
|
+
self._define_symbol(scope, symbol)
|
|
316
|
+
|
|
317
|
+
def _handle_label(self, node: SyntaxNode, scope: Scope) -> None:
|
|
318
|
+
name = self._attr(node, AttributeName.anName)
|
|
319
|
+
if not name and isinstance(node, ValuedSyntaxNode):
|
|
320
|
+
name = node.value
|
|
321
|
+
if not name:
|
|
322
|
+
return
|
|
323
|
+
symbol = Symbol(
|
|
324
|
+
name=name,
|
|
325
|
+
kind=SymbolKind.LABEL,
|
|
326
|
+
decl_range=self._node_range(node),
|
|
327
|
+
name_range=self._node_range(node),
|
|
328
|
+
scope=scope,
|
|
329
|
+
)
|
|
330
|
+
self._define_symbol(scope, symbol)
|
|
331
|
+
|
|
332
|
+
def _handle_method(self, node: SyntaxNode, scope: Scope, visibility: Visibility) -> None:
|
|
333
|
+
name = self._attr(node, AttributeName.anName)
|
|
334
|
+
if not name:
|
|
335
|
+
return
|
|
336
|
+
kind = self._method_kind(node)
|
|
337
|
+
type_ref = self._method_type_ref(node, name)
|
|
338
|
+
symbol = Symbol(
|
|
339
|
+
name=name,
|
|
340
|
+
kind=kind,
|
|
341
|
+
decl_range=self._node_tree_range(node),
|
|
342
|
+
name_range=self._node_range(node),
|
|
343
|
+
scope=scope,
|
|
344
|
+
visibility=visibility,
|
|
345
|
+
type_ref=type_ref,
|
|
346
|
+
modifiers=self._method_modifiers(node),
|
|
347
|
+
attributes=self._symbol_attributes(node),
|
|
348
|
+
)
|
|
349
|
+
routine_scope = Scope(kind=ScopeKind.ROUTINE, name=name, parent=scope, owner=symbol)
|
|
350
|
+
symbol.member_scope = routine_scope
|
|
351
|
+
self._define_symbol(scope, symbol)
|
|
352
|
+
self._node_scopes[id(node)] = routine_scope
|
|
353
|
+
|
|
354
|
+
params = node.find_node(SyntaxNodeType.ntParameters)
|
|
355
|
+
if params is not None:
|
|
356
|
+
self._define_parameters(params, routine_scope)
|
|
357
|
+
|
|
358
|
+
type_params = node.find_node(SyntaxNodeType.ntTypeParams)
|
|
359
|
+
if type_params is not None:
|
|
360
|
+
self._define_type_parameters(type_params, routine_scope)
|
|
361
|
+
|
|
362
|
+
for child in node.child_nodes:
|
|
363
|
+
if child.typ in {SyntaxNodeType.ntParameters, SyntaxNodeType.ntReturnType, SyntaxNodeType.ntTypeParams}:
|
|
364
|
+
continue
|
|
365
|
+
self._declare_symbols(child, routine_scope, visibility)
|
|
366
|
+
|
|
367
|
+
def _handle_property(self, node: SyntaxNode, scope: Scope, visibility: Visibility) -> None:
|
|
368
|
+
name = self._attr(node, AttributeName.anName)
|
|
369
|
+
if not name:
|
|
370
|
+
return
|
|
371
|
+
type_ref = self._type_from_node(node.find_node(SyntaxNodeType.ntType))
|
|
372
|
+
symbol = Symbol(
|
|
373
|
+
name=name,
|
|
374
|
+
kind=SymbolKind.PROPERTY,
|
|
375
|
+
decl_range=self._node_range(node),
|
|
376
|
+
name_range=self._node_range(node),
|
|
377
|
+
scope=scope,
|
|
378
|
+
visibility=visibility,
|
|
379
|
+
type_ref=type_ref,
|
|
380
|
+
attributes=self._symbol_attributes(node),
|
|
381
|
+
)
|
|
382
|
+
self._define_symbol(scope, symbol)
|
|
383
|
+
|
|
384
|
+
def _define_parameters(self, node: SyntaxNode, scope: Scope) -> None:
|
|
385
|
+
for child in node.child_nodes:
|
|
386
|
+
if child.typ != SyntaxNodeType.ntParameter:
|
|
387
|
+
continue
|
|
388
|
+
name = self._child_name(child)
|
|
389
|
+
if not name:
|
|
390
|
+
continue
|
|
391
|
+
type_ref = self._type_from_node(child.find_node(SyntaxNodeType.ntType))
|
|
392
|
+
symbol = Symbol(
|
|
393
|
+
name=name,
|
|
394
|
+
kind=SymbolKind.PARAMETER,
|
|
395
|
+
decl_range=self._node_range(child),
|
|
396
|
+
name_range=self._node_range(child),
|
|
397
|
+
scope=scope,
|
|
398
|
+
type_ref=type_ref,
|
|
399
|
+
)
|
|
400
|
+
kind = self._attr(child, AttributeName.anKind)
|
|
401
|
+
if kind:
|
|
402
|
+
symbol.attributes['modifier'] = kind
|
|
403
|
+
self._define_symbol(scope, symbol)
|
|
404
|
+
|
|
405
|
+
def _define_type_parameters(self, node: SyntaxNode, scope: Scope) -> None:
|
|
406
|
+
for child in node.child_nodes:
|
|
407
|
+
if child.typ != SyntaxNodeType.ntTypeParam:
|
|
408
|
+
continue
|
|
409
|
+
name = self._child_name(child)
|
|
410
|
+
if not name:
|
|
411
|
+
continue
|
|
412
|
+
symbol = Symbol(
|
|
413
|
+
name=name,
|
|
414
|
+
kind=SymbolKind.TYPE_PARAMETER,
|
|
415
|
+
decl_range=self._node_range(child),
|
|
416
|
+
name_range=self._node_range(child),
|
|
417
|
+
scope=scope,
|
|
418
|
+
type_ref=TypeParameterRef(name=name),
|
|
419
|
+
)
|
|
420
|
+
constraints = self._constraint_names(child)
|
|
421
|
+
if constraints:
|
|
422
|
+
symbol.attributes['constraints'] = ', '.join(constraints)
|
|
423
|
+
self._define_symbol(scope, symbol)
|
|
424
|
+
|
|
425
|
+
def _method_kind(self, node: SyntaxNode) -> SymbolKind:
|
|
426
|
+
kind = self._attr(node, AttributeName.anKind)
|
|
427
|
+
if kind == 'function':
|
|
428
|
+
return SymbolKind.FUNCTION
|
|
429
|
+
if kind == 'procedure':
|
|
430
|
+
return SymbolKind.PROCEDURE
|
|
431
|
+
if kind == 'constructor':
|
|
432
|
+
return SymbolKind.CONSTRUCTOR
|
|
433
|
+
if kind == 'destructor':
|
|
434
|
+
return SymbolKind.DESTRUCTOR
|
|
435
|
+
return SymbolKind.METHOD
|
|
436
|
+
|
|
437
|
+
def _method_modifiers(self, node: SyntaxNode) -> set[Modifier]:
|
|
438
|
+
modifiers: set[Modifier] = set()
|
|
439
|
+
if self._attr(node, AttributeName.anClass) == 'true':
|
|
440
|
+
modifiers.add(Modifier.CLASS)
|
|
441
|
+
binding = self._attr(node, AttributeName.anMethodBinding)
|
|
442
|
+
if binding in {'virtual', 'dynamic'}:
|
|
443
|
+
modifiers.add(Modifier.VIRTUAL)
|
|
444
|
+
if binding == 'override':
|
|
445
|
+
modifiers.add(Modifier.OVERRIDE)
|
|
446
|
+
if self._attr(node, AttributeName.anReintroduce) == 'true':
|
|
447
|
+
modifiers.add(Modifier.REINTRODUCE)
|
|
448
|
+
if self._attr(node, AttributeName.anOverload) == 'true':
|
|
449
|
+
modifiers.add(Modifier.OVERLOAD)
|
|
450
|
+
if self._attr(node, AttributeName.anAbstract) == 'true':
|
|
451
|
+
modifiers.add(Modifier.ABSTRACT)
|
|
452
|
+
if self._attr(node, AttributeName.anInline) == 'true':
|
|
453
|
+
modifiers.add(Modifier.INLINE)
|
|
454
|
+
if self._attr(node, AttributeName.anExternal) == 'true':
|
|
455
|
+
modifiers.add(Modifier.EXTERNAL)
|
|
456
|
+
if self._attr(node, AttributeName.anForwarded) == 'true':
|
|
457
|
+
modifiers.add(Modifier.FORWARD)
|
|
458
|
+
if self._attr(node, AttributeName.anDeprecated):
|
|
459
|
+
modifiers.add(Modifier.DEPRECATED)
|
|
460
|
+
if self._attr(node, AttributeName.anNoReturn) == 'true':
|
|
461
|
+
modifiers.add(Modifier.NORETURN)
|
|
462
|
+
if self._attr(node, AttributeName.anStatic) == 'true':
|
|
463
|
+
modifiers.add(Modifier.STATIC)
|
|
464
|
+
if self._attr(node, AttributeName.anFinal) == 'true':
|
|
465
|
+
modifiers.add(Modifier.FINAL)
|
|
466
|
+
if self._attr(node, AttributeName.anSealed) == 'true':
|
|
467
|
+
modifiers.add(Modifier.SEALED)
|
|
468
|
+
return modifiers
|
|
469
|
+
|
|
470
|
+
def _method_type_ref(self, node: SyntaxNode, name: str) -> TypeRef:
|
|
471
|
+
params = node.find_node(SyntaxNodeType.ntParameters)
|
|
472
|
+
param_types = tuple(
|
|
473
|
+
self._type_from_node(p.find_node(SyntaxNodeType.ntType))
|
|
474
|
+
for p in params.child_nodes
|
|
475
|
+
if p.typ == SyntaxNodeType.ntParameter
|
|
476
|
+
) if params else ()
|
|
477
|
+
return_type_node = node.find_node(SyntaxNodeType.ntReturnType)
|
|
478
|
+
return_type = None
|
|
479
|
+
if return_type_node is not None:
|
|
480
|
+
return_type = self._type_from_node(return_type_node.find_node(SyntaxNodeType.ntType))
|
|
481
|
+
return ProcTypeRef(name=name, params=param_types, return_type=return_type)
|
|
482
|
+
|
|
483
|
+
def _infer_type_ref_and_kind(self, name: str, type_node: Optional[SyntaxNode]) -> tuple[TypeRef, SymbolKind]:
|
|
484
|
+
if type_node is None:
|
|
485
|
+
return UnknownTypeRef('missing type'), SymbolKind.TYPE
|
|
486
|
+
type_tag = self._attr(type_node, AttributeName.anType)
|
|
487
|
+
name_tag = self._attr(type_node, AttributeName.anName)
|
|
488
|
+
if type_tag == 'class':
|
|
489
|
+
return ClassTypeRef(name=name), SymbolKind.CLASS
|
|
490
|
+
if type_tag == 'record':
|
|
491
|
+
return RecordTypeRef(name=name), SymbolKind.RECORD
|
|
492
|
+
if type_tag in {'interface', 'dispinterface'}:
|
|
493
|
+
return InterfaceTypeRef(name=name), SymbolKind.INTERFACE
|
|
494
|
+
if name_tag == 'enum':
|
|
495
|
+
members = tuple(self._enum_members(type_node))
|
|
496
|
+
return EnumTypeRef(name=name, members=members), SymbolKind.ENUM
|
|
497
|
+
if type_tag == 'set':
|
|
498
|
+
elem = self._type_from_node(type_node.find_node(SyntaxNodeType.ntType))
|
|
499
|
+
return SetTypeRef(element_type=elem), SymbolKind.TYPE
|
|
500
|
+
if type_tag == 'array':
|
|
501
|
+
return self._type_from_node(type_node), SymbolKind.TYPE
|
|
502
|
+
if type_tag == 'distinct':
|
|
503
|
+
return self._type_from_node(type_node), SymbolKind.TYPE
|
|
504
|
+
if name_tag == 'subrange':
|
|
505
|
+
lower, upper = self._subrange_bounds(type_node)
|
|
506
|
+
return SubrangeTypeRef(lower=lower, upper=upper), SymbolKind.TYPE
|
|
507
|
+
if name_tag:
|
|
508
|
+
return NamedTypeRef(name=name_tag), SymbolKind.TYPE
|
|
509
|
+
return UnknownTypeRef('unresolved type'), SymbolKind.TYPE
|
|
510
|
+
|
|
511
|
+
def _type_bases(self, type_node: Optional[SyntaxNode]) -> tuple[TypeRef, ...]:
|
|
512
|
+
if type_node is None:
|
|
513
|
+
return ()
|
|
514
|
+
bases = []
|
|
515
|
+
for child in type_node.child_nodes:
|
|
516
|
+
if child.typ == SyntaxNodeType.ntType:
|
|
517
|
+
bases.append(self._type_from_node(child))
|
|
518
|
+
return tuple(bases)
|
|
519
|
+
|
|
520
|
+
def _resolve_type_refs(self, scope: Scope) -> None:
|
|
521
|
+
for symbols in scope.symbols.values():
|
|
522
|
+
for symbol in symbols:
|
|
523
|
+
symbol.type_ref = self._resolve_type_ref(symbol.type_ref, scope)
|
|
524
|
+
if symbol.member_scope is not None:
|
|
525
|
+
self._resolve_type_refs(symbol.member_scope)
|
|
526
|
+
|
|
527
|
+
def _resolve_type_ref(self, type_ref: TypeRef, scope: Scope) -> TypeRef:
|
|
528
|
+
if isinstance(type_ref, GenericInstanceTypeRef):
|
|
529
|
+
base = self._resolve_type_ref(type_ref.base, scope)
|
|
530
|
+
args = tuple(self._resolve_type_ref(arg, scope) for arg in type_ref.args)
|
|
531
|
+
if isinstance(base, NamedTypeRef):
|
|
532
|
+
return GenericInstanceTypeRef(base=base, args=args)
|
|
533
|
+
return GenericInstanceTypeRef(base=NamedTypeRef(name=type_ref.base.name), args=args)
|
|
534
|
+
if isinstance(type_ref, ArrayTypeRef):
|
|
535
|
+
elem = self._resolve_type_ref(type_ref.element_type, scope)
|
|
536
|
+
dims = tuple(self._resolve_type_ref(dim, scope) for dim in type_ref.dimensions)
|
|
537
|
+
return ArrayTypeRef(element_type=elem, dimensions=dims, is_dynamic=type_ref.is_dynamic)
|
|
538
|
+
if isinstance(type_ref, SetTypeRef):
|
|
539
|
+
elem = self._resolve_type_ref(type_ref.element_type, scope)
|
|
540
|
+
return SetTypeRef(element_type=elem)
|
|
541
|
+
if isinstance(type_ref, PointerTypeRef):
|
|
542
|
+
return PointerTypeRef(self._resolve_type_ref(type_ref.target, scope))
|
|
543
|
+
if isinstance(type_ref, ClassOfTypeRef):
|
|
544
|
+
return ClassOfTypeRef(self._resolve_type_ref(type_ref.target, scope))
|
|
545
|
+
if isinstance(type_ref, ReferenceTypeRef):
|
|
546
|
+
return ReferenceTypeRef(self._resolve_type_ref(type_ref.target, scope))
|
|
547
|
+
if isinstance(type_ref, FileTypeRef) and type_ref.element_type is not None:
|
|
548
|
+
return FileTypeRef(self._resolve_type_ref(type_ref.element_type, scope))
|
|
549
|
+
if isinstance(type_ref, NamedTypeRef):
|
|
550
|
+
return self._normalize_named_type(type_ref, scope)
|
|
551
|
+
return type_ref
|
|
552
|
+
|
|
553
|
+
def _normalize_named_type(self, type_ref: NamedTypeRef, scope: Scope) -> NamedTypeRef:
|
|
554
|
+
if type_ref.unit_name:
|
|
555
|
+
return type_ref
|
|
556
|
+
if '.' in type_ref.name:
|
|
557
|
+
unit_name, name = self._split_qualified_name(type_ref.name)
|
|
558
|
+
return NamedTypeRef(name=name, unit_name=unit_name)
|
|
559
|
+
resolved = scope.resolve(type_ref.name)
|
|
560
|
+
if resolved:
|
|
561
|
+
symbol = resolved[0]
|
|
562
|
+
unit_scope = self._unit_scope_for_symbol(symbol)
|
|
563
|
+
if unit_scope is not None and unit_scope.name != scope.name:
|
|
564
|
+
return NamedTypeRef(name=type_ref.name, unit_name=unit_scope.name)
|
|
565
|
+
return type_ref
|
|
566
|
+
|
|
567
|
+
def _type_from_node(self, node: Optional[SyntaxNode]) -> TypeRef:
|
|
568
|
+
if node is None:
|
|
569
|
+
return UnknownTypeRef('missing type')
|
|
570
|
+
name = self._attr(node, AttributeName.anName)
|
|
571
|
+
type_tag = self._attr(node, AttributeName.anType)
|
|
572
|
+
if type_tag == 'pointer':
|
|
573
|
+
target = node.find_node(SyntaxNodeType.ntType)
|
|
574
|
+
return PointerTypeRef(self._type_from_node(target))
|
|
575
|
+
if type_tag == 'array':
|
|
576
|
+
element = self._type_from_node(node.find_node(SyntaxNodeType.ntType))
|
|
577
|
+
bounds_node = node.find_node(SyntaxNodeType.ntBounds)
|
|
578
|
+
if bounds_node is None or not bounds_node.child_nodes:
|
|
579
|
+
return ArrayTypeRef(element_type=element, is_dynamic=True)
|
|
580
|
+
dims = tuple(self._bound_type_ref(child) for child in bounds_node.child_nodes)
|
|
581
|
+
return ArrayTypeRef(element_type=element, dimensions=dims, is_dynamic=False)
|
|
582
|
+
if type_tag == 'set':
|
|
583
|
+
elem = self._type_from_node(node.find_node(SyntaxNodeType.ntType))
|
|
584
|
+
return SetTypeRef(element_type=elem)
|
|
585
|
+
if type_tag == 'class of':
|
|
586
|
+
target = node.find_node(SyntaxNodeType.ntType)
|
|
587
|
+
return ClassOfTypeRef(self._type_from_node(target))
|
|
588
|
+
if type_tag == 'reference':
|
|
589
|
+
target = node.find_node(SyntaxNodeType.ntType)
|
|
590
|
+
return ReferenceTypeRef(self._type_from_node(target))
|
|
591
|
+
if type_tag == 'file':
|
|
592
|
+
target = node.find_node(SyntaxNodeType.ntType)
|
|
593
|
+
if target is None:
|
|
594
|
+
return FileTypeRef(None)
|
|
595
|
+
return FileTypeRef(self._type_from_node(target))
|
|
596
|
+
if type_tag == 'packed':
|
|
597
|
+
target = node.find_node(SyntaxNodeType.ntType)
|
|
598
|
+
return self._type_from_node(target)
|
|
599
|
+
if type_tag == 'distinct':
|
|
600
|
+
target = node.find_node(SyntaxNodeType.ntType)
|
|
601
|
+
return self._type_from_node(target)
|
|
602
|
+
if type_tag in {'procedure', 'function'}:
|
|
603
|
+
return self._proc_type_from_node(node, type_tag)
|
|
604
|
+
if name == 'subrange':
|
|
605
|
+
lower, upper = self._subrange_bounds(node)
|
|
606
|
+
return SubrangeTypeRef(lower=lower, upper=upper)
|
|
607
|
+
|
|
608
|
+
type_args_node = node.find_node(SyntaxNodeType.ntTypeArgs)
|
|
609
|
+
if name:
|
|
610
|
+
base = self._type_ref_from_name(name)
|
|
611
|
+
if type_args_node is not None:
|
|
612
|
+
args = tuple(
|
|
613
|
+
self._type_from_node(child)
|
|
614
|
+
for child in type_args_node.child_nodes
|
|
615
|
+
if child.typ == SyntaxNodeType.ntType
|
|
616
|
+
)
|
|
617
|
+
if isinstance(base, NamedTypeRef):
|
|
618
|
+
return GenericInstanceTypeRef(base=base, args=args)
|
|
619
|
+
return base
|
|
620
|
+
return UnknownTypeRef('unresolved type')
|
|
621
|
+
|
|
622
|
+
def _type_ref_from_name(self, name: str) -> TypeRef:
|
|
623
|
+
generic = self._generic_name_parts(name)
|
|
624
|
+
if generic is None:
|
|
625
|
+
return self._named_type_ref(name)
|
|
626
|
+
base_name, arg_names = generic
|
|
627
|
+
base = self._named_type_ref(base_name)
|
|
628
|
+
args = tuple(self._type_ref_from_name(arg_name) for arg_name in arg_names)
|
|
629
|
+
if isinstance(base, NamedTypeRef):
|
|
630
|
+
return GenericInstanceTypeRef(base=base, args=args)
|
|
631
|
+
return self._named_type_ref(name)
|
|
632
|
+
|
|
633
|
+
def _generic_name_parts(self, name: str) -> Optional[tuple[str, tuple[str, ...]]]:
|
|
634
|
+
text = name.strip()
|
|
635
|
+
open_index = text.find('<')
|
|
636
|
+
if open_index <= 0 or not text.endswith('>'):
|
|
637
|
+
return None
|
|
638
|
+
depth = 0
|
|
639
|
+
for index, ch in enumerate(text[open_index:], start=open_index):
|
|
640
|
+
if ch == '<':
|
|
641
|
+
depth += 1
|
|
642
|
+
elif ch == '>':
|
|
643
|
+
depth -= 1
|
|
644
|
+
if depth == 0 and index != len(text) - 1:
|
|
645
|
+
return None
|
|
646
|
+
if depth < 0:
|
|
647
|
+
return None
|
|
648
|
+
if depth != 0:
|
|
649
|
+
return None
|
|
650
|
+
base_name = text[:open_index].strip()
|
|
651
|
+
if not base_name:
|
|
652
|
+
return None
|
|
653
|
+
args = self._split_top_level_type_args(text[open_index + 1 : -1])
|
|
654
|
+
if not args:
|
|
655
|
+
return None
|
|
656
|
+
return base_name, tuple(args)
|
|
657
|
+
|
|
658
|
+
def _split_top_level_type_args(self, text: str) -> list[str]:
|
|
659
|
+
args: list[str] = []
|
|
660
|
+
current: list[str] = []
|
|
661
|
+
angle = 0
|
|
662
|
+
square = 0
|
|
663
|
+
round_ = 0
|
|
664
|
+
in_string = False
|
|
665
|
+
index = 0
|
|
666
|
+
while index < len(text):
|
|
667
|
+
ch = text[index]
|
|
668
|
+
if ch == "'":
|
|
669
|
+
current.append(ch)
|
|
670
|
+
if in_string and index + 1 < len(text) and text[index + 1] == "'":
|
|
671
|
+
current.append(text[index + 1])
|
|
672
|
+
index += 2
|
|
673
|
+
continue
|
|
674
|
+
in_string = not in_string
|
|
675
|
+
index += 1
|
|
676
|
+
continue
|
|
677
|
+
if not in_string:
|
|
678
|
+
if ch == '<':
|
|
679
|
+
angle += 1
|
|
680
|
+
elif ch == '>':
|
|
681
|
+
angle = max(0, angle - 1)
|
|
682
|
+
elif ch == '[':
|
|
683
|
+
square += 1
|
|
684
|
+
elif ch == ']':
|
|
685
|
+
square = max(0, square - 1)
|
|
686
|
+
elif ch == '(':
|
|
687
|
+
round_ += 1
|
|
688
|
+
elif ch == ')':
|
|
689
|
+
round_ = max(0, round_ - 1)
|
|
690
|
+
elif ch == ',' and angle == 0 and square == 0 and round_ == 0:
|
|
691
|
+
arg = ''.join(current).strip()
|
|
692
|
+
if arg:
|
|
693
|
+
args.append(arg)
|
|
694
|
+
current = []
|
|
695
|
+
index += 1
|
|
696
|
+
continue
|
|
697
|
+
current.append(ch)
|
|
698
|
+
index += 1
|
|
699
|
+
arg = ''.join(current).strip()
|
|
700
|
+
if arg:
|
|
701
|
+
args.append(arg)
|
|
702
|
+
return args
|
|
703
|
+
|
|
704
|
+
def _proc_type_from_node(self, node: SyntaxNode, kind: str) -> TypeRef:
|
|
705
|
+
params = node.find_node(SyntaxNodeType.ntParameters)
|
|
706
|
+
param_types = tuple(
|
|
707
|
+
self._type_from_node(p.find_node(SyntaxNodeType.ntType))
|
|
708
|
+
for p in params.child_nodes
|
|
709
|
+
if p.typ == SyntaxNodeType.ntParameter
|
|
710
|
+
) if params else ()
|
|
711
|
+
return_type = None
|
|
712
|
+
return_type_node = node.find_node(SyntaxNodeType.ntReturnType)
|
|
713
|
+
if return_type_node is not None:
|
|
714
|
+
return_type = self._type_from_node(return_type_node.find_node(SyntaxNodeType.ntType))
|
|
715
|
+
return ProcTypeRef(name=kind, params=param_types, return_type=return_type)
|
|
716
|
+
|
|
717
|
+
def _bound_type_ref(self, node: SyntaxNode) -> TypeRef:
|
|
718
|
+
if node.typ == SyntaxNodeType.ntSubrange:
|
|
719
|
+
lower, upper = self._subrange_bounds(node)
|
|
720
|
+
return SubrangeTypeRef(lower=lower, upper=upper)
|
|
721
|
+
text = self._expr_to_text(node)
|
|
722
|
+
if text:
|
|
723
|
+
return NamedTypeRef(name=text)
|
|
724
|
+
return UnknownTypeRef('bound')
|
|
725
|
+
|
|
726
|
+
def _subrange_bounds(self, node: SyntaxNode) -> tuple[str, str]:
|
|
727
|
+
bounds = node.find_node(SyntaxNodeType.ntBounds)
|
|
728
|
+
if bounds is None:
|
|
729
|
+
children = node.child_nodes
|
|
730
|
+
else:
|
|
731
|
+
children = bounds.child_nodes
|
|
732
|
+
values = [self._expr_to_text(child) for child in children if self._expr_to_text(child)]
|
|
733
|
+
if len(values) >= 2:
|
|
734
|
+
return (values[0], values[1])
|
|
735
|
+
return ('', '')
|
|
736
|
+
|
|
737
|
+
def _enum_members(self, node: SyntaxNode) -> Iterable[str]:
|
|
738
|
+
for child in node.child_nodes:
|
|
739
|
+
if child.typ == SyntaxNodeType.ntEnum:
|
|
740
|
+
name = self._child_name(child)
|
|
741
|
+
if name:
|
|
742
|
+
yield name
|
|
743
|
+
|
|
744
|
+
def _collect_references_pass(self, node: SyntaxNode, scope: Scope, visibility: Visibility) -> None:
|
|
745
|
+
if node.typ in {SyntaxNodeType.ntCall, SyntaxNodeType.ntDot, SyntaxNodeType.ntIdentifier}:
|
|
746
|
+
self._collect_expr_references(node, scope)
|
|
747
|
+
return
|
|
748
|
+
if node.typ == SyntaxNodeType.ntUses:
|
|
749
|
+
self._collect_uses_references(node, scope)
|
|
750
|
+
return
|
|
751
|
+
if node.typ == SyntaxNodeType.ntTypeSection:
|
|
752
|
+
for child in node.child_nodes:
|
|
753
|
+
if child.typ == SyntaxNodeType.ntTypeDecl:
|
|
754
|
+
self._collect_type_decl_references(child, scope)
|
|
755
|
+
return
|
|
756
|
+
if node.typ == SyntaxNodeType.ntVariables:
|
|
757
|
+
for child in node.child_nodes:
|
|
758
|
+
if child.typ == SyntaxNodeType.ntVariable:
|
|
759
|
+
self._collect_variable_references(child, scope)
|
|
760
|
+
return
|
|
761
|
+
if node.typ == SyntaxNodeType.ntConstants:
|
|
762
|
+
for child in node.child_nodes:
|
|
763
|
+
if child.typ == SyntaxNodeType.ntConstant:
|
|
764
|
+
self._collect_constant_references(child, scope)
|
|
765
|
+
return
|
|
766
|
+
if node.typ == SyntaxNodeType.ntMethod:
|
|
767
|
+
self._collect_method_references(node, scope, visibility)
|
|
768
|
+
return
|
|
769
|
+
if node.typ == SyntaxNodeType.ntProperty:
|
|
770
|
+
self._collect_property_references(node, scope)
|
|
771
|
+
return
|
|
772
|
+
if node.typ == SyntaxNodeType.ntField:
|
|
773
|
+
self._collect_field_references(node, scope)
|
|
774
|
+
return
|
|
775
|
+
if node.typ == SyntaxNodeType.ntWith:
|
|
776
|
+
self._collect_with_references(node, scope, visibility)
|
|
777
|
+
return
|
|
778
|
+
if node.typ == SyntaxNodeType.ntGoto:
|
|
779
|
+
label_name = self._attr(node, AttributeName.anName)
|
|
780
|
+
self._add_reference(label_name, ReferenceKind.LABEL, node, scope)
|
|
781
|
+
return
|
|
782
|
+
if node.typ in {SyntaxNodeType.ntStatements, SyntaxNodeType.ntStatement}:
|
|
783
|
+
for child in node.child_nodes:
|
|
784
|
+
self._collect_references_pass(child, scope, visibility)
|
|
785
|
+
return
|
|
786
|
+
|
|
787
|
+
for child in node.child_nodes:
|
|
788
|
+
self._collect_references_pass(child, scope, visibility)
|
|
789
|
+
|
|
790
|
+
def _collect_uses_references(self, node: SyntaxNode, scope: Scope) -> None:
|
|
791
|
+
for child in node.child_nodes:
|
|
792
|
+
if child.typ != SyntaxNodeType.ntUnit:
|
|
793
|
+
continue
|
|
794
|
+
name = self._attr(child, AttributeName.anName)
|
|
795
|
+
if name:
|
|
796
|
+
self._add_reference(name, ReferenceKind.UNIT, child, scope)
|
|
797
|
+
|
|
798
|
+
def _collect_type_decl_references(self, node: SyntaxNode, scope: Scope) -> None:
|
|
799
|
+
type_node = node.find_node(SyntaxNodeType.ntType)
|
|
800
|
+
type_scope = self._node_scopes.get(id(node), scope)
|
|
801
|
+
type_params = node.find_node(SyntaxNodeType.ntTypeParams)
|
|
802
|
+
if type_params is not None:
|
|
803
|
+
self._collect_type_param_references(type_params, scope)
|
|
804
|
+
if type_node is not None:
|
|
805
|
+
for child in type_node.child_nodes:
|
|
806
|
+
if child.typ == SyntaxNodeType.ntType:
|
|
807
|
+
self._record_type_reference(child, scope)
|
|
808
|
+
self._collect_type_members_references(type_node, type_scope)
|
|
809
|
+
|
|
810
|
+
def _collect_type_members_references(self, node: SyntaxNode, scope: Scope) -> None:
|
|
811
|
+
visibility = Visibility.PUBLIC
|
|
812
|
+
visibility_map = self._visibility_map()
|
|
813
|
+
for child in node.child_nodes:
|
|
814
|
+
if child.typ in visibility_map:
|
|
815
|
+
visibility = visibility_map[child.typ]
|
|
816
|
+
for member in child.child_nodes:
|
|
817
|
+
self._collect_references_pass(member, scope, visibility)
|
|
818
|
+
continue
|
|
819
|
+
self._collect_references_pass(child, scope, visibility)
|
|
820
|
+
|
|
821
|
+
def _collect_variable_references(self, node: SyntaxNode, scope: Scope) -> None:
|
|
822
|
+
type_node = node.find_node(SyntaxNodeType.ntType)
|
|
823
|
+
if type_node is not None:
|
|
824
|
+
self._record_type_reference(type_node, scope)
|
|
825
|
+
value_node = node.find_node(SyntaxNodeType.ntValue)
|
|
826
|
+
if value_node is not None:
|
|
827
|
+
self._collect_expr_references(value_node, scope)
|
|
828
|
+
|
|
829
|
+
def _collect_constant_references(self, node: SyntaxNode, scope: Scope) -> None:
|
|
830
|
+
type_node = node.find_node(SyntaxNodeType.ntType)
|
|
831
|
+
if type_node is not None:
|
|
832
|
+
self._record_type_reference(type_node, scope)
|
|
833
|
+
value_node = node.find_node(SyntaxNodeType.ntValue)
|
|
834
|
+
if value_node is not None:
|
|
835
|
+
self._collect_expr_references(value_node, scope)
|
|
836
|
+
|
|
837
|
+
def _collect_field_references(self, node: SyntaxNode, scope: Scope) -> None:
|
|
838
|
+
type_node = node.find_node(SyntaxNodeType.ntType)
|
|
839
|
+
if type_node is not None:
|
|
840
|
+
self._record_type_reference(type_node, scope)
|
|
841
|
+
|
|
842
|
+
def _collect_with_references(self, node: SyntaxNode, scope: Scope, visibility: Visibility) -> None:
|
|
843
|
+
expr_nodes: list[SyntaxNode] = []
|
|
844
|
+
body_nodes: list[SyntaxNode] = []
|
|
845
|
+
for child in node.child_nodes:
|
|
846
|
+
if child.typ == SyntaxNodeType.ntExpressions:
|
|
847
|
+
expr_nodes.extend(child.child_nodes)
|
|
848
|
+
else:
|
|
849
|
+
body_nodes.append(child)
|
|
850
|
+
|
|
851
|
+
for expr in expr_nodes:
|
|
852
|
+
self._collect_expr_references(expr, scope)
|
|
853
|
+
|
|
854
|
+
with_scopes: list[Scope] = []
|
|
855
|
+
for expr in expr_nodes:
|
|
856
|
+
with_scopes.extend(self._with_scopes_for_expr(expr, scope))
|
|
857
|
+
|
|
858
|
+
target_scope = scope
|
|
859
|
+
if with_scopes:
|
|
860
|
+
target_scope = Scope(kind=ScopeKind.WITH, name='with', parent=scope)
|
|
861
|
+
for with_scope in with_scopes:
|
|
862
|
+
target_scope.add_with_scope(with_scope)
|
|
863
|
+
|
|
864
|
+
for child in body_nodes:
|
|
865
|
+
self._collect_references_pass(child, target_scope, visibility)
|
|
866
|
+
|
|
867
|
+
def _with_scopes_for_expr(self, node: SyntaxNode, scope: Scope) -> list[Scope]:
|
|
868
|
+
name = self._expr_name(node)
|
|
869
|
+
if not name:
|
|
870
|
+
return []
|
|
871
|
+
symbol = self._resolve_reference(name, ReferenceKind.VALUE, scope)
|
|
872
|
+
if symbol is None:
|
|
873
|
+
return []
|
|
874
|
+
return list(self._iter_member_scopes(symbol, scope))
|
|
875
|
+
|
|
876
|
+
def _collect_method_references(self, node: SyntaxNode, scope: Scope, visibility: Visibility) -> None:
|
|
877
|
+
method_scope = self._node_scopes.get(id(node), scope)
|
|
878
|
+
params = node.find_node(SyntaxNodeType.ntParameters)
|
|
879
|
+
if params is not None:
|
|
880
|
+
for param in params.child_nodes:
|
|
881
|
+
if param.typ != SyntaxNodeType.ntParameter:
|
|
882
|
+
continue
|
|
883
|
+
type_node = param.find_node(SyntaxNodeType.ntType)
|
|
884
|
+
if type_node is not None:
|
|
885
|
+
self._record_type_reference(type_node, method_scope)
|
|
886
|
+
value_node = param.find_node(SyntaxNodeType.ntValue)
|
|
887
|
+
if value_node is not None:
|
|
888
|
+
self._collect_expr_references(value_node, method_scope)
|
|
889
|
+
type_params = node.find_node(SyntaxNodeType.ntTypeParams)
|
|
890
|
+
if type_params is not None:
|
|
891
|
+
self._collect_type_param_references(type_params, method_scope)
|
|
892
|
+
return_type_node = node.find_node(SyntaxNodeType.ntReturnType)
|
|
893
|
+
if return_type_node is not None:
|
|
894
|
+
type_node = return_type_node.find_node(SyntaxNodeType.ntType)
|
|
895
|
+
if type_node is not None:
|
|
896
|
+
self._record_type_reference(type_node, method_scope)
|
|
897
|
+
for child in node.child_nodes:
|
|
898
|
+
if child.typ in {SyntaxNodeType.ntParameters, SyntaxNodeType.ntReturnType, SyntaxNodeType.ntTypeParams}:
|
|
899
|
+
continue
|
|
900
|
+
self._collect_references_pass(child, method_scope, visibility)
|
|
901
|
+
|
|
902
|
+
def _collect_property_references(self, node: SyntaxNode, scope: Scope) -> None:
|
|
903
|
+
type_node = node.find_node(SyntaxNodeType.ntType)
|
|
904
|
+
if type_node is not None:
|
|
905
|
+
self._record_type_reference(type_node, scope)
|
|
906
|
+
params = node.find_node(SyntaxNodeType.ntParameters)
|
|
907
|
+
if params is not None:
|
|
908
|
+
for param in params.child_nodes:
|
|
909
|
+
if param.typ != SyntaxNodeType.ntParameter:
|
|
910
|
+
continue
|
|
911
|
+
type_node = param.find_node(SyntaxNodeType.ntType)
|
|
912
|
+
if type_node is not None:
|
|
913
|
+
self._record_type_reference(type_node, scope)
|
|
914
|
+
for child in node.child_nodes:
|
|
915
|
+
if child.typ in {SyntaxNodeType.ntRead, SyntaxNodeType.ntWrite, SyntaxNodeType.ntImplements}:
|
|
916
|
+
self._collect_expr_references(child, scope)
|
|
917
|
+
if child.typ == SyntaxNodeType.ntUnknown and self._attr(child, AttributeName.anKind) in {'add', 'remove', 'stored'}:
|
|
918
|
+
self._collect_expr_references(child, scope)
|
|
919
|
+
|
|
920
|
+
def _collect_type_param_references(self, node: SyntaxNode, scope: Scope) -> None:
|
|
921
|
+
for child in node.child_nodes:
|
|
922
|
+
if child.typ != SyntaxNodeType.ntTypeParam:
|
|
923
|
+
continue
|
|
924
|
+
constraints = child.find_node(SyntaxNodeType.ntConstraints)
|
|
925
|
+
if constraints is None:
|
|
926
|
+
continue
|
|
927
|
+
for constraint in constraints.child_nodes:
|
|
928
|
+
if constraint.typ == SyntaxNodeType.ntType:
|
|
929
|
+
self._record_type_reference(constraint, scope)
|
|
930
|
+
|
|
931
|
+
def _record_type_reference(self, node: SyntaxNode, scope: Scope) -> None:
|
|
932
|
+
name = self._attr(node, AttributeName.anName)
|
|
933
|
+
if not name:
|
|
934
|
+
return
|
|
935
|
+
self._add_reference(name, ReferenceKind.TYPE, node, scope)
|
|
936
|
+
type_args_node = node.find_node(SyntaxNodeType.ntTypeArgs)
|
|
937
|
+
if type_args_node is not None:
|
|
938
|
+
for child in type_args_node.child_nodes:
|
|
939
|
+
if child.typ == SyntaxNodeType.ntType:
|
|
940
|
+
self._record_type_reference(child, scope)
|
|
941
|
+
|
|
942
|
+
def _collect_expr_references(self, node: SyntaxNode, scope: Scope) -> None:
|
|
943
|
+
if node.typ == SyntaxNodeType.ntCall:
|
|
944
|
+
target = node.child_nodes[0] if node.child_nodes else None
|
|
945
|
+
name = self._expr_name(target) if target is not None else ''
|
|
946
|
+
if name:
|
|
947
|
+
self._add_reference(name, ReferenceKind.CALL, target or node, scope)
|
|
948
|
+
for child in node.child_nodes[1:]:
|
|
949
|
+
self._collect_expr_references(child, scope)
|
|
950
|
+
return
|
|
951
|
+
if node.typ == SyntaxNodeType.ntDot:
|
|
952
|
+
name = self._expr_name(node)
|
|
953
|
+
if name:
|
|
954
|
+
self._add_reference(name, ReferenceKind.VALUE, node, scope)
|
|
955
|
+
return
|
|
956
|
+
if node.typ == SyntaxNodeType.ntIdentifier:
|
|
957
|
+
name = self._attr(node, AttributeName.anName)
|
|
958
|
+
self._add_reference(name, ReferenceKind.VALUE, node, scope)
|
|
959
|
+
return
|
|
960
|
+
|
|
961
|
+
for child in node.child_nodes:
|
|
962
|
+
self._collect_expr_references(child, scope)
|
|
963
|
+
|
|
964
|
+
def _expr_name(self, node: Optional[SyntaxNode]) -> str:
|
|
965
|
+
if node is None:
|
|
966
|
+
return ''
|
|
967
|
+
if node.typ == SyntaxNodeType.ntIdentifier:
|
|
968
|
+
name = self._attr(node, AttributeName.anName)
|
|
969
|
+
generic_args = self._attr(node, AttributeName.anGenericArgs)
|
|
970
|
+
if generic_args:
|
|
971
|
+
return f'{name}{generic_args}'
|
|
972
|
+
return name
|
|
973
|
+
if node.typ == SyntaxNodeType.ntDot and len(node.child_nodes) == 2:
|
|
974
|
+
left = self._expr_name(node.child_nodes[0])
|
|
975
|
+
right = self._expr_name(node.child_nodes[1])
|
|
976
|
+
if left and right:
|
|
977
|
+
return f'{left}.{right}'
|
|
978
|
+
return left or right
|
|
979
|
+
if node.typ == SyntaxNodeType.ntCall and node.child_nodes:
|
|
980
|
+
return self._expr_name(node.child_nodes[0])
|
|
981
|
+
if node.typ == SyntaxNodeType.ntIndexed and node.child_nodes:
|
|
982
|
+
return self._expr_name(node.child_nodes[0])
|
|
983
|
+
return ''
|
|
984
|
+
|
|
985
|
+
def _add_reference(self, name: str, kind: ReferenceKind, node: SyntaxNode, scope: Scope) -> None:
|
|
986
|
+
if not name:
|
|
987
|
+
return
|
|
988
|
+
resolved = self._resolve_reference(name, kind, scope)
|
|
989
|
+
if resolved is None and kind == ReferenceKind.TYPE and not self._is_builtin_type(name):
|
|
990
|
+
self._add_problem(f'Unresolved type {name}', node)
|
|
991
|
+
self._references.append(
|
|
992
|
+
SymbolReference(
|
|
993
|
+
name=name,
|
|
994
|
+
kind=kind,
|
|
995
|
+
ref_range=self._node_range(node),
|
|
996
|
+
scope=scope,
|
|
997
|
+
resolved=resolved,
|
|
998
|
+
)
|
|
999
|
+
)
|
|
1000
|
+
|
|
1001
|
+
def _resolve_reference(self, name: str, kind: ReferenceKind, scope: Scope) -> Optional[Symbol]:
|
|
1002
|
+
parts = self._normalized_reference_parts(name)
|
|
1003
|
+
if not parts:
|
|
1004
|
+
return None
|
|
1005
|
+
if len(parts) > 1:
|
|
1006
|
+
resolved = self._resolve_qualified_reference(parts, scope)
|
|
1007
|
+
if resolved is not None:
|
|
1008
|
+
return resolved
|
|
1009
|
+
symbols = self._index.resolve_qualified('.'.join(parts))
|
|
1010
|
+
return symbols[0] if symbols else None
|
|
1011
|
+
symbols = scope.resolve(parts[0])
|
|
1012
|
+
if symbols:
|
|
1013
|
+
return symbols[0]
|
|
1014
|
+
return None
|
|
1015
|
+
|
|
1016
|
+
def _add_problem(self, message: str, node: SyntaxNode) -> None:
|
|
1017
|
+
self._problems.append(
|
|
1018
|
+
SemanticProblem(
|
|
1019
|
+
message=message,
|
|
1020
|
+
range=self._node_range(node),
|
|
1021
|
+
)
|
|
1022
|
+
)
|
|
1023
|
+
|
|
1024
|
+
def _is_builtin_type(self, name: str) -> bool:
|
|
1025
|
+
base = name.split('.')[-1]
|
|
1026
|
+
base = self._strip_generic_args(base)
|
|
1027
|
+
return base.casefold() in self._builtin_types
|
|
1028
|
+
|
|
1029
|
+
def _normalized_reference_parts(self, name: str) -> list[str]:
|
|
1030
|
+
if not name:
|
|
1031
|
+
return []
|
|
1032
|
+
parts = self._split_reference_parts(name)
|
|
1033
|
+
normalized = [self._strip_generic_args(part) for part in parts]
|
|
1034
|
+
return [part for part in normalized if part]
|
|
1035
|
+
|
|
1036
|
+
def _split_reference_parts(self, name: str) -> list[str]:
|
|
1037
|
+
parts: list[str] = []
|
|
1038
|
+
buf: list[str] = []
|
|
1039
|
+
depth = 0
|
|
1040
|
+
for ch in name:
|
|
1041
|
+
if ch == '<':
|
|
1042
|
+
depth += 1
|
|
1043
|
+
elif ch == '>':
|
|
1044
|
+
if depth:
|
|
1045
|
+
depth -= 1
|
|
1046
|
+
elif ch == '.' and depth == 0:
|
|
1047
|
+
part = ''.join(buf).strip()
|
|
1048
|
+
if part:
|
|
1049
|
+
parts.append(part)
|
|
1050
|
+
buf = []
|
|
1051
|
+
continue
|
|
1052
|
+
buf.append(ch)
|
|
1053
|
+
part = ''.join(buf).strip()
|
|
1054
|
+
if part:
|
|
1055
|
+
parts.append(part)
|
|
1056
|
+
return parts
|
|
1057
|
+
|
|
1058
|
+
def _strip_generic_args(self, name: str) -> str:
|
|
1059
|
+
if '<' in name:
|
|
1060
|
+
return name.split('<', 1)[0]
|
|
1061
|
+
return name
|
|
1062
|
+
|
|
1063
|
+
def _resolve_qualified_reference(self, parts: list[str], scope: Scope) -> Optional[Symbol]:
|
|
1064
|
+
unit_scope, unit_len = self._match_unit_prefix(parts)
|
|
1065
|
+
if unit_scope is not None and unit_len > 0:
|
|
1066
|
+
symbol = self._resolve_scope_chain(unit_scope, parts[unit_len:], allow_imports=False, origin_scope=scope)
|
|
1067
|
+
if symbol is not None:
|
|
1068
|
+
return symbol
|
|
1069
|
+
return self._resolve_scope_chain(scope, parts, allow_imports=True, origin_scope=scope)
|
|
1070
|
+
|
|
1071
|
+
def _match_unit_prefix(self, parts: list[str]) -> tuple[Optional[Scope], int]:
|
|
1072
|
+
if len(parts) < 2:
|
|
1073
|
+
return None, 0
|
|
1074
|
+
for idx in range(len(parts) - 1, 0, -1):
|
|
1075
|
+
unit_name = '.'.join(parts[:idx])
|
|
1076
|
+
unit_scope = self._index.lookup_unit(unit_name)
|
|
1077
|
+
if unit_scope is not None:
|
|
1078
|
+
return unit_scope, idx
|
|
1079
|
+
return None, 0
|
|
1080
|
+
|
|
1081
|
+
def _resolve_scope_chain(
|
|
1082
|
+
self,
|
|
1083
|
+
scope: Scope,
|
|
1084
|
+
parts: list[str],
|
|
1085
|
+
*,
|
|
1086
|
+
allow_imports: bool,
|
|
1087
|
+
origin_scope: Scope,
|
|
1088
|
+
) -> Optional[Symbol]:
|
|
1089
|
+
if not parts:
|
|
1090
|
+
return None
|
|
1091
|
+
symbol = self._resolve_in_scope(scope, parts[0], allow_imports=allow_imports)
|
|
1092
|
+
if symbol is None:
|
|
1093
|
+
return None
|
|
1094
|
+
for part in parts[1:]:
|
|
1095
|
+
member_symbol = self._resolve_member_symbol(symbol, part, origin_scope)
|
|
1096
|
+
if member_symbol is None:
|
|
1097
|
+
return None
|
|
1098
|
+
symbol = member_symbol
|
|
1099
|
+
return symbol
|
|
1100
|
+
|
|
1101
|
+
def _resolve_in_scope(self, scope: Scope, name: str, *, allow_imports: bool) -> Optional[Symbol]:
|
|
1102
|
+
symbols = scope.resolve(name) if allow_imports else scope.lookup_local(name)
|
|
1103
|
+
return symbols[0] if symbols else None
|
|
1104
|
+
|
|
1105
|
+
def _member_scope_for_symbol(self, symbol: Symbol, scope: Scope) -> Optional[Scope]:
|
|
1106
|
+
scopes = list(self._iter_member_scopes(symbol, scope))
|
|
1107
|
+
return scopes[0] if scopes else None
|
|
1108
|
+
|
|
1109
|
+
def _resolve_member_symbol(self, symbol: Symbol, name: str, scope: Scope) -> Optional[Symbol]:
|
|
1110
|
+
for member_scope in self._iter_member_scopes(symbol, scope):
|
|
1111
|
+
members = member_scope.lookup_local(name)
|
|
1112
|
+
if members:
|
|
1113
|
+
return members[0]
|
|
1114
|
+
return None
|
|
1115
|
+
|
|
1116
|
+
def _iter_member_scopes(self, symbol: Symbol, scope: Scope) -> Iterable[Scope]:
|
|
1117
|
+
type_symbol = self._type_owner_for_symbol(symbol, scope)
|
|
1118
|
+
if type_symbol is None:
|
|
1119
|
+
return
|
|
1120
|
+
yield from self._iter_type_member_scopes(type_symbol, scope)
|
|
1121
|
+
|
|
1122
|
+
def _type_owner_for_symbol(self, symbol: Symbol, scope: Scope) -> Optional[Symbol]:
|
|
1123
|
+
if symbol.member_scope is not None and symbol.kind in {
|
|
1124
|
+
SymbolKind.TYPE,
|
|
1125
|
+
SymbolKind.CLASS,
|
|
1126
|
+
SymbolKind.RECORD,
|
|
1127
|
+
SymbolKind.INTERFACE,
|
|
1128
|
+
SymbolKind.ENUM,
|
|
1129
|
+
}:
|
|
1130
|
+
return symbol
|
|
1131
|
+
if symbol.scope.kind == ScopeKind.TYPE and symbol.scope.owner is not None:
|
|
1132
|
+
return symbol.scope.owner
|
|
1133
|
+
return self._type_symbol_from_ref(symbol.type_ref, scope)
|
|
1134
|
+
|
|
1135
|
+
def _iter_type_member_scopes(self, type_symbol: Symbol, scope: Scope) -> Iterable[Scope]:
|
|
1136
|
+
seen: set[int] = set()
|
|
1137
|
+
queue: list[Symbol] = [type_symbol]
|
|
1138
|
+
while queue:
|
|
1139
|
+
current = queue.pop(0)
|
|
1140
|
+
current_id = id(current)
|
|
1141
|
+
if current_id in seen:
|
|
1142
|
+
continue
|
|
1143
|
+
seen.add(current_id)
|
|
1144
|
+
if current.member_scope is not None:
|
|
1145
|
+
yield current.member_scope
|
|
1146
|
+
for base_ref in current.base_types:
|
|
1147
|
+
base_symbol = self._type_symbol_from_ref(base_ref, scope)
|
|
1148
|
+
if base_symbol is not None:
|
|
1149
|
+
queue.append(base_symbol)
|
|
1150
|
+
|
|
1151
|
+
def _type_symbol_from_ref(self, type_ref: TypeRef, scope: Scope) -> Optional[Symbol]:
|
|
1152
|
+
if isinstance(type_ref, GenericInstanceTypeRef):
|
|
1153
|
+
return self._type_symbol_from_ref(type_ref.base, scope)
|
|
1154
|
+
if isinstance(type_ref, NamedTypeRef):
|
|
1155
|
+
if type_ref.unit_name:
|
|
1156
|
+
unit_scope = self._index.lookup_unit(type_ref.unit_name)
|
|
1157
|
+
if unit_scope is not None:
|
|
1158
|
+
symbols = unit_scope.lookup_local(type_ref.name)
|
|
1159
|
+
return symbols[0] if symbols else None
|
|
1160
|
+
if '.' in type_ref.name:
|
|
1161
|
+
symbols = self._index.resolve_qualified(type_ref.name)
|
|
1162
|
+
if symbols:
|
|
1163
|
+
return symbols[0]
|
|
1164
|
+
symbols = scope.resolve(type_ref.name)
|
|
1165
|
+
return symbols[0] if symbols else None
|
|
1166
|
+
return None
|
|
1167
|
+
|
|
1168
|
+
def _define_symbol(self, scope: Scope, symbol: Symbol) -> None:
|
|
1169
|
+
existing = scope.lookup_local(symbol.name)
|
|
1170
|
+
scope.define(symbol)
|
|
1171
|
+
for prev in existing:
|
|
1172
|
+
if self._is_overloadable(prev, symbol):
|
|
1173
|
+
prev.add_overload(symbol)
|
|
1174
|
+
symbol.add_overload(prev)
|
|
1175
|
+
|
|
1176
|
+
def _is_overloadable(self, left: Symbol, right: Symbol) -> bool:
|
|
1177
|
+
overload_kinds = {
|
|
1178
|
+
SymbolKind.METHOD,
|
|
1179
|
+
SymbolKind.FUNCTION,
|
|
1180
|
+
SymbolKind.PROCEDURE,
|
|
1181
|
+
SymbolKind.CONSTRUCTOR,
|
|
1182
|
+
SymbolKind.DESTRUCTOR,
|
|
1183
|
+
}
|
|
1184
|
+
return left.kind in overload_kinds and right.kind in overload_kinds
|
|
1185
|
+
|
|
1186
|
+
def _symbol_attributes(self, node: SyntaxNode) -> dict[str, str]:
|
|
1187
|
+
attrs: dict[str, str] = {}
|
|
1188
|
+
skip = {
|
|
1189
|
+
AttributeName.anName,
|
|
1190
|
+
AttributeName.anKind,
|
|
1191
|
+
AttributeName.anType,
|
|
1192
|
+
AttributeName.anClass,
|
|
1193
|
+
AttributeName.anVisibility,
|
|
1194
|
+
AttributeName.anPath,
|
|
1195
|
+
}
|
|
1196
|
+
for key, value in node.attributes:
|
|
1197
|
+
if key in skip:
|
|
1198
|
+
continue
|
|
1199
|
+
attrs[ATTRIBUTE_NAME_STRINGS[key]] = value
|
|
1200
|
+
return attrs
|
|
1201
|
+
|
|
1202
|
+
def _constraint_names(self, node: SyntaxNode) -> tuple[str, ...]:
|
|
1203
|
+
constraints_node = node.find_node(SyntaxNodeType.ntConstraints)
|
|
1204
|
+
if constraints_node is None:
|
|
1205
|
+
return ()
|
|
1206
|
+
names: list[str] = []
|
|
1207
|
+
for child in constraints_node.child_nodes:
|
|
1208
|
+
if child.typ == SyntaxNodeType.ntClassConstraint:
|
|
1209
|
+
names.append('class')
|
|
1210
|
+
elif child.typ == SyntaxNodeType.ntRecordConstraint:
|
|
1211
|
+
names.append('record')
|
|
1212
|
+
elif child.typ == SyntaxNodeType.ntConstructorConstraint:
|
|
1213
|
+
names.append('constructor')
|
|
1214
|
+
elif child.typ == SyntaxNodeType.ntInterfaceConstraint:
|
|
1215
|
+
names.append('interface')
|
|
1216
|
+
elif child.typ == SyntaxNodeType.ntUnmanagedConstraint:
|
|
1217
|
+
names.append('unmanaged')
|
|
1218
|
+
elif child.typ == SyntaxNodeType.ntType:
|
|
1219
|
+
names.append(self._type_from_node(child).display_name())
|
|
1220
|
+
return tuple(names)
|
|
1221
|
+
|
|
1222
|
+
def _named_type_ref(self, name: str) -> NamedTypeRef:
|
|
1223
|
+
if '.' in name:
|
|
1224
|
+
unit_name, type_name = self._split_qualified_name(name)
|
|
1225
|
+
return NamedTypeRef(name=type_name, unit_name=unit_name)
|
|
1226
|
+
return NamedTypeRef(name=name)
|
|
1227
|
+
|
|
1228
|
+
def _split_qualified_name(self, name: str) -> tuple[str, str]:
|
|
1229
|
+
parts = name.split('.')
|
|
1230
|
+
return ('.'.join(parts[:-1]), parts[-1])
|
|
1231
|
+
|
|
1232
|
+
def _unit_scope_for_symbol(self, symbol: Symbol) -> Optional[Scope]:
|
|
1233
|
+
scope = symbol.scope
|
|
1234
|
+
while scope is not None:
|
|
1235
|
+
if scope.kind == ScopeKind.UNIT:
|
|
1236
|
+
return scope
|
|
1237
|
+
scope = scope.parent
|
|
1238
|
+
return None
|
|
1239
|
+
|
|
1240
|
+
def _attr(self, node: SyntaxNode, name: AttributeName) -> str:
|
|
1241
|
+
return node.get_attribute(name)
|
|
1242
|
+
|
|
1243
|
+
def _child_name(self, node: Optional[SyntaxNode]) -> str:
|
|
1244
|
+
if node is None:
|
|
1245
|
+
return ''
|
|
1246
|
+
if isinstance(node, ValuedSyntaxNode):
|
|
1247
|
+
return node.value
|
|
1248
|
+
name = self._attr(node, AttributeName.anName)
|
|
1249
|
+
if name:
|
|
1250
|
+
return name
|
|
1251
|
+
for child in node.child_nodes:
|
|
1252
|
+
if child.typ == SyntaxNodeType.ntName:
|
|
1253
|
+
if isinstance(child, ValuedSyntaxNode):
|
|
1254
|
+
return child.value
|
|
1255
|
+
return self._attr(child, AttributeName.anName)
|
|
1256
|
+
return ''
|
|
1257
|
+
|
|
1258
|
+
def _expr_to_text(self, node: SyntaxNode) -> str:
|
|
1259
|
+
if isinstance(node, ValuedSyntaxNode):
|
|
1260
|
+
return node.value
|
|
1261
|
+
name = node.get_attribute(AttributeName.anName)
|
|
1262
|
+
if name:
|
|
1263
|
+
return name
|
|
1264
|
+
binary_ops = {
|
|
1265
|
+
SyntaxNodeType.ntAdd: '+',
|
|
1266
|
+
SyntaxNodeType.ntSub: '-',
|
|
1267
|
+
SyntaxNodeType.ntMul: '*',
|
|
1268
|
+
SyntaxNodeType.ntFDiv: '/',
|
|
1269
|
+
SyntaxNodeType.ntDiv: 'div',
|
|
1270
|
+
SyntaxNodeType.ntMod: 'mod',
|
|
1271
|
+
SyntaxNodeType.ntShl: 'shl',
|
|
1272
|
+
SyntaxNodeType.ntShr: 'shr',
|
|
1273
|
+
SyntaxNodeType.ntAnd: 'and',
|
|
1274
|
+
SyntaxNodeType.ntOr: 'or',
|
|
1275
|
+
SyntaxNodeType.ntXor: 'xor',
|
|
1276
|
+
SyntaxNodeType.ntEqual: '=',
|
|
1277
|
+
SyntaxNodeType.ntNotEqual: '<>',
|
|
1278
|
+
SyntaxNodeType.ntLower: '<',
|
|
1279
|
+
SyntaxNodeType.ntLowerEqual: '<=',
|
|
1280
|
+
SyntaxNodeType.ntGreater: '>',
|
|
1281
|
+
SyntaxNodeType.ntGreaterEqual: '>=',
|
|
1282
|
+
SyntaxNodeType.ntIn: 'in',
|
|
1283
|
+
SyntaxNodeType.ntIs: 'is',
|
|
1284
|
+
SyntaxNodeType.ntAs: 'as',
|
|
1285
|
+
SyntaxNodeType.ntNotIn: 'not in',
|
|
1286
|
+
SyntaxNodeType.ntIsNot: 'is not',
|
|
1287
|
+
}
|
|
1288
|
+
if node.typ in binary_ops and len(node.child_nodes) >= 2:
|
|
1289
|
+
left = self._expr_to_text(node.child_nodes[0])
|
|
1290
|
+
right = self._expr_to_text(node.child_nodes[1])
|
|
1291
|
+
if left and right:
|
|
1292
|
+
return f'{left} {binary_ops[node.typ]} {right}'
|
|
1293
|
+
if node.typ == SyntaxNodeType.ntUnaryMinus and node.child_nodes:
|
|
1294
|
+
inner = self._expr_to_text(node.child_nodes[0])
|
|
1295
|
+
return f'-{inner}' if inner else ''
|
|
1296
|
+
if node.typ == SyntaxNodeType.ntNot and node.child_nodes:
|
|
1297
|
+
inner = self._expr_to_text(node.child_nodes[0])
|
|
1298
|
+
return f'not {inner}' if inner else ''
|
|
1299
|
+
if node.typ in {SyntaxNodeType.ntAddr, SyntaxNodeType.ntDeref} and node.child_nodes:
|
|
1300
|
+
inner = self._expr_to_text(node.child_nodes[0])
|
|
1301
|
+
if not inner:
|
|
1302
|
+
return ''
|
|
1303
|
+
return f'@{inner}' if node.typ == SyntaxNodeType.ntAddr else f'^{inner}'
|
|
1304
|
+
if node.typ == SyntaxNodeType.ntCall and node.child_nodes:
|
|
1305
|
+
callee = self._expr_to_text(node.child_nodes[0])
|
|
1306
|
+
args_node = node.find_node(SyntaxNodeType.ntArguments)
|
|
1307
|
+
args = []
|
|
1308
|
+
if args_node is not None:
|
|
1309
|
+
for child in args_node.child_nodes:
|
|
1310
|
+
text = self._expr_to_text(child)
|
|
1311
|
+
if text:
|
|
1312
|
+
args.append(text)
|
|
1313
|
+
return f'{callee}({", ".join(args)})' if callee else ''
|
|
1314
|
+
if node.typ == SyntaxNodeType.ntNamedArgument and node.child_nodes:
|
|
1315
|
+
arg_name = self._attr(node, AttributeName.anName)
|
|
1316
|
+
value = self._expr_to_text(node.child_nodes[0])
|
|
1317
|
+
if arg_name and value:
|
|
1318
|
+
return f'{arg_name}: {value}'
|
|
1319
|
+
if node.typ == SyntaxNodeType.ntPositionalArgument and node.child_nodes:
|
|
1320
|
+
return self._expr_to_text(node.child_nodes[0])
|
|
1321
|
+
if node.typ == SyntaxNodeType.ntDot and len(node.child_nodes) >= 2:
|
|
1322
|
+
left = self._expr_to_text(node.child_nodes[0])
|
|
1323
|
+
right = self._expr_to_text(node.child_nodes[1])
|
|
1324
|
+
if left and right:
|
|
1325
|
+
return f'{left}.{right}'
|
|
1326
|
+
if node.typ == SyntaxNodeType.ntIndexed and node.child_nodes:
|
|
1327
|
+
base = self._expr_to_text(node.child_nodes[0])
|
|
1328
|
+
exprs_node = node.find_node(SyntaxNodeType.ntExpressions)
|
|
1329
|
+
parts = []
|
|
1330
|
+
if exprs_node is not None:
|
|
1331
|
+
for child in exprs_node.child_nodes:
|
|
1332
|
+
text = self._expr_to_text(child)
|
|
1333
|
+
if text:
|
|
1334
|
+
parts.append(text)
|
|
1335
|
+
return f'{base}[{", ".join(parts)}]' if base else ''
|
|
1336
|
+
if node.typ == SyntaxNodeType.ntExpression and self._attr(node, AttributeName.anKind) == 'format':
|
|
1337
|
+
parts = []
|
|
1338
|
+
for child in node.child_nodes:
|
|
1339
|
+
text = self._expr_to_text(child)
|
|
1340
|
+
if text:
|
|
1341
|
+
parts.append(text)
|
|
1342
|
+
return ':'.join(parts)
|
|
1343
|
+
return ''
|
|
1344
|
+
|
|
1345
|
+
def _node_range(self, node: SyntaxNode) -> SourceRange:
|
|
1346
|
+
if isinstance(node, CompoundSyntaxNode):
|
|
1347
|
+
return SourceRange(
|
|
1348
|
+
file_name=node.file_name,
|
|
1349
|
+
start_line=node.line,
|
|
1350
|
+
start_col=node.col,
|
|
1351
|
+
end_line=node.end_line,
|
|
1352
|
+
end_col=node.end_col,
|
|
1353
|
+
)
|
|
1354
|
+
return SourceRange(
|
|
1355
|
+
file_name=node.file_name,
|
|
1356
|
+
start_line=node.line,
|
|
1357
|
+
start_col=node.col,
|
|
1358
|
+
end_line=node.line,
|
|
1359
|
+
end_col=node.col,
|
|
1360
|
+
)
|
|
1361
|
+
|
|
1362
|
+
def _node_tree_range(self, node: SyntaxNode) -> SourceRange:
|
|
1363
|
+
result = self._node_range(node)
|
|
1364
|
+
for child in node.child_nodes:
|
|
1365
|
+
child_range = self._node_tree_range(child)
|
|
1366
|
+
if (child_range.end_line, child_range.end_col) > (result.end_line, result.end_col):
|
|
1367
|
+
result = SourceRange(
|
|
1368
|
+
file_name=result.file_name,
|
|
1369
|
+
start_line=result.start_line,
|
|
1370
|
+
start_col=result.start_col,
|
|
1371
|
+
end_line=child_range.end_line,
|
|
1372
|
+
end_col=child_range.end_col,
|
|
1373
|
+
)
|
|
1374
|
+
return result
|
|
1375
|
+
|
|
1376
|
+
def _visibility_map(self) -> dict[SyntaxNodeType, Visibility]:
|
|
1377
|
+
return {
|
|
1378
|
+
SyntaxNodeType.ntPrivate: Visibility.PRIVATE,
|
|
1379
|
+
SyntaxNodeType.ntProtected: Visibility.PROTECTED,
|
|
1380
|
+
SyntaxNodeType.ntPublic: Visibility.PUBLIC,
|
|
1381
|
+
SyntaxNodeType.ntPublished: Visibility.PUBLISHED,
|
|
1382
|
+
SyntaxNodeType.ntStrictPrivate: Visibility.STRICT_PRIVATE,
|
|
1383
|
+
SyntaxNodeType.ntStrictProtected: Visibility.STRICT_PROTECTED,
|
|
1384
|
+
}
|