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.
Files changed (42) hide show
  1. agent_codinglanguage_mapper/__init__.py +20 -0
  2. agent_codinglanguage_mapper/__main__.py +4 -0
  3. agent_codinglanguage_mapper/_version.py +2 -0
  4. agent_codinglanguage_mapper/adapters/__init__.py +4 -0
  5. agent_codinglanguage_mapper/adapters/delphi.py +822 -0
  6. agent_codinglanguage_mapper/adapters/delphi_frontend/__init__.py +6 -0
  7. agent_codinglanguage_mapper/adapters/delphi_frontend/comment_builder.py +29 -0
  8. agent_codinglanguage_mapper/adapters/delphi_frontend/consts.py +345 -0
  9. agent_codinglanguage_mapper/adapters/delphi_frontend/grammar.py +460 -0
  10. agent_codinglanguage_mapper/adapters/delphi_frontend/lark_builder.py +2674 -0
  11. agent_codinglanguage_mapper/adapters/delphi_frontend/lark_tokens.py +237 -0
  12. agent_codinglanguage_mapper/adapters/delphi_frontend/lsp_server.py +1832 -0
  13. agent_codinglanguage_mapper/adapters/delphi_frontend/nodes.py +371 -0
  14. agent_codinglanguage_mapper/adapters/delphi_frontend/parser.py +193 -0
  15. agent_codinglanguage_mapper/adapters/delphi_frontend/preprocessor.py +997 -0
  16. agent_codinglanguage_mapper/adapters/delphi_frontend/project_discovery.py +518 -0
  17. agent_codinglanguage_mapper/adapters/delphi_frontend/project_indexer.py +319 -0
  18. agent_codinglanguage_mapper/adapters/delphi_frontend/semantic.py +375 -0
  19. agent_codinglanguage_mapper/adapters/delphi_frontend/semantic_builder.py +1384 -0
  20. agent_codinglanguage_mapper/adapters/delphi_frontend/source_reader.py +17 -0
  21. agent_codinglanguage_mapper/adapters/delphi_frontend/workspace.py +67 -0
  22. agent_codinglanguage_mapper/adapters/tree_sitter.py +1722 -0
  23. agent_codinglanguage_mapper/cli.py +138 -0
  24. agent_codinglanguage_mapper/discovery.py +1328 -0
  25. agent_codinglanguage_mapper/indexer.py +1102 -0
  26. agent_codinglanguage_mapper/integration.py +186 -0
  27. agent_codinglanguage_mapper/lsp_server.py +413 -0
  28. agent_codinglanguage_mapper/lsp_service.py +447 -0
  29. agent_codinglanguage_mapper/mapper.py +596 -0
  30. agent_codinglanguage_mapper/models.py +101 -0
  31. agent_codinglanguage_mapper/protocol.py +152 -0
  32. agent_codinglanguage_mapper/rendering.py +153 -0
  33. agent_codinglanguage_mapper/templates/opencode/plugins/codebase_map.ts +191 -0
  34. agent_codinglanguage_mapper/templates/skill/SKILL.md +52 -0
  35. agent_codinglanguage_mapper/worker.py +29 -0
  36. agent_codinglanguage_mapper/workspace.py +114 -0
  37. agent_codinglanguage_mapper-1.0.0.dist-info/METADATA +383 -0
  38. agent_codinglanguage_mapper-1.0.0.dist-info/RECORD +42 -0
  39. agent_codinglanguage_mapper-1.0.0.dist-info/WHEEL +5 -0
  40. agent_codinglanguage_mapper-1.0.0.dist-info/entry_points.txt +2 -0
  41. agent_codinglanguage_mapper-1.0.0.dist-info/licenses/LICENSE +373 -0
  42. 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
+ }