Delphi-Konzept: Reale tree-sitter-pascal AST-Typen, Integration Guide, erweiterte Fixtures

- Alle Docs auf verifizierte AST-Knotentypen aktualisiert (declClass, declIntf, declProc, etc.)
- Scaffold/ entfernt und durch konkreten Integration Guide ersetzt (06-Integration-Guide.md)
- Neue Docs: AST-Referenz (03), NodeKind-Mapping (05), Integration Guide (06)
- Checklist um bekannte Einschränkungen erweitert (with-Statements, .dfm/.fmx, Generics)
- UAuth.pas erweitert: Sichtbarkeitsbereiche, Felder, Properties, Constructor/Destructor
- UTypes.pas neu: Enums, Records, Type-Aliase, Konstanten, Class Methods, verschachtelte Typen
- UnitResolution.md mit konkreten AST-Strukturen aktualisiert
- README.md an neue Architektur-Beschreibung angepasst
This commit is contained in:
Olaf Monien
2026-02-11 00:17:29 +01:00
parent 645fd71e45
commit dcca22c78f
15 changed files with 739 additions and 384 deletions
+71 -25
View File
@@ -2,53 +2,96 @@
## 0) Prämissen
- CodeGraph extrahiert **Nodes** und **Edges** über **tree-sitter** und language-spezifische **Queries (`.scm`)**.
- CodeGraph extrahiert **Nodes** und **Edges** über **tree-sitter** und eine `LanguageExtractor`-Konfiguration pro Sprache in `src/extraction/tree-sitter.ts`.
- Sprachen werden zentral in drei Dateien registriert: `grammars.ts`, `types.ts`, und `tree-sitter.ts`.
- Danach folgt **Reference Resolution** (Calls → Definitionen, imports → Dateien, inheritance, framework patterns).
- **Grammar:** [`tree-sitter-pascal`](https://github.com/Isopod/tree-sitter-pascal) (unterstützt Delphi, FreePascal und Standard-Pascal).
## 1) Parser / Grammar
Empfohlen: `tree-sitter-pascal` (unterstützt Delphi + FreePascal).
npm-Paket: `tree-sitter-pascal`
**Konkrete AST-Knoten (Auswahl):**
| tree-sitter-pascal Typ | Beschreibung |
|---|---|
| `unit`, `program`, `library` | Top-Level-Module |
| `moduleName` | Name des Moduls (Kind-Knoten von `unit`/`program`/`library`) |
| `declClass` | Klassen, Records, Objects (enthält `kClass`/`kRecord`/`kObject`) |
| `declIntf` | Interfaces (`kInterface`/`kDispInterface`) |
| `declProc` | Procedures, Functions, Methods, Constructors, Destructors |
| `declProp` | Properties |
| `declField` | Felder in Klassen/Records |
| `declEnum` | Aufzählungstypen |
| `declEnumValue` | Einzelne Enum-Werte |
| `declType` | Type-Deklarationen (enthält `declClass`/`declIntf`/`declEnum`/etc.) |
| `declUses` | `uses`-Klauseln (imports) |
| `declConst` | Konstanten-Deklarationen |
| `declSection` | Sichtbarkeitsbereiche (`kPrivate`/`kPublic`/`kProtected`/`kPublished`) |
| `declHelper` | Class/Record Helpers |
| `declExports` | exports-Klauseln |
| `defProc` | Implementations-Body einer Prozedur/Funktion |
| `exprCall` | Funktionsaufrufe |
| `exprDot` | Qualifizierte Zugriffe (`Obj.Method`) |
| `declArgs` | Parameterliste |
| `declArg` | Einzelner Parameter |
**Tasks:**
- Dependency hinzufügen (wie bei bestehenden Sprachen).
- Language-Loader/Registry erweitern: `languageId = "pascal"` (oder `"delphi"`, aber konsistent).
- `tree-sitter-pascal` als npm-Dependency hinzufügen
- Grammar-Loader in `src/extraction/grammars.ts` registrieren: `pascal: () => require('tree-sitter-pascal')`
- Extension-Mapping und Language-Typ anlegen (siehe Integration Guide)
## 2) File-Erkennung
Extensions (MVP):
- `.pas` (Units)
- `.dpr` (Program)
- `.dpk` (Package)
- `.dpr` (Delphi Program)
- `.dpk` (Delphi Package)
- `.lpr` (Lazarus Program)
Optional:
- `.inc` (Include-Fragmente) erst später oder nur, wenn Parser tolerant genug ist.
Optional (Phase 2):
- `.inc` (Include-Fragmente) erst später, da Parser möglicherweise keinen vollständigen AST liefert.
## 3) Queries (MVP)
## 3) Extraktion (MVP)
### 3.1 Nodes
Extrahiere mindestens:
- Unit/Program/Package Name
- Klassen / Interfaces / Records
- Procedures/Functions
- Methoden (class/instance)
| Delphi-Konzept | tree-sitter Typ | → CodeGraph `NodeKind` |
|---|---|---|
| Unit / Program / Library | `unit` / `program` / `library` | `module` |
| Klasse / Record / Object | `declClass` | `class` |
| Interface | `declIntf` | `interface` |
| Procedure / Function (top-level) | `declProc` (mit `kProcedure`/`kFunction`) | `function` |
| Methode / Constructor / Destructor | `declProc` (mit `kConstructor`/`kDestructor`, oder innerhalb `declClass`) | `method` |
| Property | `declProp` | `property` |
| Feld | `declField` | `field` |
| Enum | `declEnum` | `enum` |
| Enum-Wert | `declEnumValue` | `enum_member` |
| Type-Alias | `declType` (einfache Alias-Formen) | `type_alias` |
| Konstante | `declConst` | `constant` |
| Uses-Klausel | `declUses` | `import` |
### 3.2 Edges
Extrahiere mindestens:
- `uses` (import/dependency)
- `extends` (Basisklasse)
- `implements` (Interface-Implementierungen)
- `calls` (Identifier + optional Qualifier)
| Beziehung | Erkennung | → CodeGraph `EdgeKind` |
|---|---|---|
| `uses X, Y;` | `declUses` → Kind-Knoten `identifier` | `imports` |
| Klassen-Vererbung | `declClass``parent` Feld → erster `typeref` | `extends` |
| Interface-Implementierung | `declClass``parent` Feld → weitere `typeref`s | `implements` |
| Funktionsaufruf | `exprCall` | `calls` |
| Qualifizierter Aufruf | `exprDot` als Elternteil von `exprCall` | `calls` |
| Enthaltensein | Parent-Child im AST (z.B. `declClass``declProc`) | `contains` |
| Instanziierung | `exprCall` mit `TClassName.Create` | `instantiates` |
## 4) Reference Resolution (MVP)
### 4.1 Unit-Auflösung (`uses`)
- Index-Phase: Map `UnitName -> fileId` (aus Units/Programs/Packages)
- Index-Phase: Map `unitName fileId` (aus `moduleName` Knoten in `unit`/`program`/`library`)
- Resolution: Bei `uses Foo, Bar;` Edges auf Ziel-Units setzen.
- Spezialfälle (später): `Foo in 'path\Foo.pas'` (DPR/DPK), Namespaces (`System.SysUtils`).
- Spezialfälle (Phase 2): `Foo in 'path\Foo.pas'` (DPR/DPK), Namespaces (`System.SysUtils`).
### 4.2 Call-Auflösung (best effort)
- Extraktion: `callName`, optional `qualifier` (`Obj.DoIt`, `TMyClass.DoIt`)
- Extraktion: Name aus `exprCall`, Qualifier aus `exprDot`
- Heuristik-Reihenfolge:
1. lokale Procs/Funcs in der gleichen Unit
2. Methoden in der gleichen Klasse
@@ -59,14 +102,17 @@ Extrahiere mindestens:
- Fixtures aus `fixtures/` in die Test-Suite aufnehmen
- Assertions:
- Node-Anzahl + zentrale Namen
- `uses`-Edges
- Node-Anzahl + zentrale Namen prüfen
- `uses`-Edges (imports)
- `extends`/`implements`-Edges
- einfache Call-Edges
- Sichtbarkeiten (public/private/protected)
- Properties, Felder, Enums
## 6) Definition of Done
- `codegraph index` indexiert Delphi/Pascal-Dateien ohne Crash
- `codegraph_search` findet Klassen/Methoden
- `codegraph_search` findet Klassen/Methoden/Properties
- `codegraph_callers/callees` liefert sinnvolle Ergebnisse für einfache Fälle
- `uses`-Graph stimmt (Unit-Abhängigkeiten)
- Sichtbarkeiten werden korrekt extrahiert
+82 -38
View File
@@ -1,53 +1,97 @@
# Capture Convention (wie die `.scm` Queries an CodeGraph andocken)
# Capture Convention: Wie Pascal/Delphi an CodeGraph andockt
Da wir hier nur ein ZIP-Konzept liefern (ohne den CodeGraph-Source lokal auszulesen), ist das wichtigste: **du musst die Captures so benennen, wie CodeGraph sie in den bestehenden Sprachen bereits erwartet**.
## Architektur-Übersicht
## Vorgehen
CodeGraph verwendet **keine** `.scm`-Query-Dateien für die Extraktion. Stattdessen wird die Logik über ein `LanguageExtractor`-Objekt in `src/extraction/tree-sitter.ts` definiert. Dieses Objekt mappt tree-sitter AST-Knotentypen auf die interne Verarbeitungslogik.
1. Öffne im CodeGraph-Repo eine bestehende Sprache (z.B. Go/Rust/Java).
2. Suche nach `.scm` Dateien und schaue:
- welche Capture-Namen verwendet werden
- wie Node-Kind/Edge-Kind gesetzt werden (oft via `#set!`)
3. Übertrage exakt dieses Schema auf Pascal.
### Zentrale Dateien für die Integration
## Empfohlene semantische Einteilung
| Datei | Änderung |
|---|---|
| `src/extraction/grammars.ts` | Grammar-Loader, Extension-Mapping, Display-Name |
| `src/types.ts` | `Language`-Union-Type, `DEFAULT_CONFIG.include` Patterns |
| `src/extraction/tree-sitter.ts` | `EXTRACTORS`-Map mit `LanguageExtractor`-Konfiguration |
Unabhängig von den konkreten Capture-Namen sollte jedes Query-Match folgende Informationen liefern:
## LanguageExtractor-Interface
### Für Nodes
- **kind**: `unit | program | package | class | interface | record | function | procedure | method | property | field | type | enum | variable`
- **name**: Symbolname
- **container** (optional): z.B. Klassenname für Methoden
- **signature** (optional): Parameter/Returntype, falls leicht verfügbar
- **range**: Start/Ende im File (Line/Column)
Die Konfiguration definiert, welche AST-Knotentypen welcher Semantik entsprechen:
### Für Edges
- **kind**: `imports | calls | extends | implements | contains | returns_type`
- **from**: Node-ID der Quelle (oder "current scope")
- **to**: Zielsymbol (Name) oder Ziel-Node-ID, wenn schon auflösbar
- **raw**: Originaltext (hilft Resolvern)
```typescript
interface LanguageExtractor {
functionTypes: string[]; // Top-Level Funktionen/Prozeduren
classTypes: string[]; // Klassen, Records, Objects
methodTypes: string[]; // Methoden, Konstruktoren, Destruktoren
interfaceTypes: string[]; // Interfaces
structTypes: string[]; // Structs (in Delphi: leer)
enumTypes: string[]; // Enums
typeAliasTypes: string[]; // Type-Aliase
importTypes: string[]; // uses-Klauseln
callTypes: string[]; // Funktionsaufrufe
variableTypes: string[]; // Variable/Feld-Deklarationen
nameField: string; // AST-Feld für den Namen
bodyField: string; // AST-Feld für den Body
paramsField: string; // AST-Feld für Parameter
returnField?: string; // AST-Feld für Rückgabetyp
getSignature?: (node, source) => string | undefined;
getVisibility?: (node) => 'public' | 'private' | 'protected' | 'internal' | undefined;
isExported?: (node, source) => boolean;
isStatic?: (node) => boolean;
isConst?: (node) => boolean;
}
```
## Minimaler Capture-Satz (Pseudo)
## Konkrete Zuordnung für Pascal/Delphi
> **Wichtig:** Diese Namen sind **Platzhalter**. Bitte auf das CodeGraph-interne Schema mappen.
| LanguageExtractor-Feld | tree-sitter-pascal Typ(en) | Anmerkung |
|---|---|---|
| `functionTypes` | `['declProc']` | Top-Level, gefiltert nach Kontext (kein Parent `declClass`) |
| `classTypes` | `['declClass']` | Enthält class, record, object |
| `methodTypes` | `['declProc']` | Innerhalb `declClass`, inkl. constructor/destructor |
| `interfaceTypes` | `['declIntf']` | interface, dispinterface |
| `structTypes` | `[]` | Records werden über `declClass` (mit `kRecord`) abgedeckt |
| `enumTypes` | `['declEnum']` | Innerhalb von `declType` |
| `typeAliasTypes` | `['declType']` | Einfache `type X = Y` Deklarationen |
| `importTypes` | `['declUses']` | `uses`-Klauseln |
| `callTypes` | `['exprCall']` | Funktions-/Methodenaufrufe |
| `variableTypes` | `['declField', 'declConst']` | Felder und Konstanten |
| `nameField` | `'name'` | `declProc`, `declConst`, `declField`, `declEnumValue` haben `name`-Feld |
| `bodyField` | `'body'` | Nur bei `defProc` (Implementierungen) |
| `paramsField` | `'args'` | `declProc` hat `args`-Feld (`declArgs`) |
| `returnField` | `'type'` | `declProc` hat optionales `type`-Feld |
- `@cg.node` mit Properties:
- `(#set! cg.kind "class")`
- `(#set! cg.name @nameCapture)` oder per separate captures
## Delphi-spezifische Herausforderungen
- `@cg.edge` mit Properties:
- `(#set! cg.kind "calls")`
- Zielsymbol als Capture: `@cg.target`
### declProc: Funktion oder Methode?
Wenn CodeGraph statt `#set!` eine feste Capture-Nomenklatur nutzt (z.B. `@definition.function`), dann übernimm exakt diese.
`declProc` wird sowohl für Top-Level-Funktionen als auch für Methoden verwendet. Die Unterscheidung erfolgt über den Kontext:
- **Top-Level**: Parent ist `interface` (der Unit-interface-Abschnitt) oder `implementation`
- **Methode**: Parent ist `declClass` oder `declIntf`
- **Kind-Unterscheidung**: Enthält `kProcedure`, `kFunction`, `kConstructor`, oder `kDestructor`
## Delphi-spezifische Stolperfallen
### Sichtbarkeit über declSection
- `procedure Foo;` vs `function Foo: Integer;`
- `class procedure` / `class function`
- `constructor` / `destructor`
- `property` (kann wie Feld wirken, ist aber call-ähnlich)
- `with`-Statements (Call-Qualifier wird verschleiert)
- Namespaces: `System.SysUtils`
Delphi gruppiert Mitglieder in Sichtbarkeitsbereichen:
```
declClass → declSection (kPublic) → declProc, declField, declProp
→ declSection (kPrivate) → declField
```
Die `getVisibility`-Funktion muss den nächsten `declSection`-Vorfahren inspizieren.
Für MVP: **nicht perfekt auflösen**, aber **zuverlässig extrahieren**.
### Vererbung und Interface-Implementierung
`declClass` hat ein `parent`-Feld mit einer Liste von `typeref`-Knoten:
- Der **erste** `typeref` ist typischerweise die Basisklasse (`extends`)
- Weitere `typeref`s sind implementierte Interfaces (`implements`)
### `with`-Statements (Phase 2)
`with`-Statements erzeugen einen impliziten Scope, der Call-Qualifier verschleiert:
```delphi
with MyObj do
DoSomething; // ist eigentlich MyObj.DoSomething
```
Im MVP wird dies **nicht** aufgelöst Calls innerhalb von `with` werden ohne Qualifier extrahiert.
### Namespaces
Delphi-Unit-Namen können Punkte enthalten (`System.SysUtils`). Der `moduleName`-Knoten enthält den vollständigen Namen. Die Resolution muss sowohl exakte Matches als auch Suffix-Matches unterstützen.
+139
View File
@@ -0,0 +1,139 @@
# AST-Referenz: tree-sitter-pascal (verifiziert)
Dieses Dokument zeigt die **tatsächlichen** AST-Knotentypen aus der [`tree-sitter-pascal`](https://github.com/Isopod/tree-sitter-pascal) Grammar, verifiziert anhand der `node-types.json` des Pakets.
> **Hinweis:** CodeGraph nutzt keine `.scm`-Dateien zur Extraktion, sondern ein `LanguageExtractor`-Objekt in TypeScript. Die hier dokumentierten AST-Strukturen zeigen, wie der Parser Delphi-Code als Baum darstellt.
## A) Top-Level Module
### unit
```
(unit (kUnit) (moduleName (identifier)) (interface ...) (implementation ...) (kEndDot))
```
### program
```
(program (kProgram) (moduleName (identifier)) ...body...)
```
### library
```
(library (kLibrary) (moduleName (identifier)) ...body...)
```
## B) Deklarationen
### declClass (Klassen, Records, Objects)
```
(declType
name: (identifier) ← "TMyClass"
value: (type (declClass
(kClass) ← oder (kRecord), (kObject)
parent: ((typeref) (typeref) ...) ← Basisklasse + Interfaces
(declSection (kPublic) ← Sichtbarkeit
(declProc ...) ← Methoden
(declField ...) ← Felder
(declProp ...) ← Properties
)
(kEnd))))
```
### declIntf (Interfaces)
```
(declType
name: (identifier) ← "IMyInterface"
value: (type (declIntf
(kInterface)
parent: ((typeref) ...) ← Basis-Interface
guid: (guid ...) ← optionale GUID
(declProc ...) (declProp ...)
(kEnd))))
```
### declProc (Procedures, Functions, Methods, Constructors, Destructors)
```
(declProc
(kFunction) ← oder kProcedure, kConstructor, kDestructor
name: (identifier) ← "MyMethod"
args: (declArgs (declArg name: (identifier) type: (type ...)))
type: (type ...) ← Rückgabetyp (nur bei functions)
attribute: (procAttribute ...)) ← z.B. override, virtual, static
```
**Unterscheidung Funktion vs. Methode:**
- Top-Level: `declProc` als Kind von `interface`/`implementation`
- Methode: `declProc` als Kind von `declClass` oder `declIntf`
- Statisch: enthält `kClass` Kind-Knoten (`class procedure`)
### declProp (Properties)
```
(declProp (kProperty) name: (identifier) type: (type ...) (kRead) (identifier) (kWrite) (identifier))
```
### declField (Felder)
```
(declField name: (identifier) type: (type ...))
```
### declEnum (Enums)
```
(declEnum (declEnumValue name: (identifier)) (declEnumValue name: (identifier)) ...)
```
### declUses (uses-Klauseln)
```
(declUses (kUses) (identifier) (identifier) ...)
```
Optional mit Pfadangabe: `(kIn) (literalString)` für `uses Foo in 'path/Foo.pas'`
### declConst (Konstanten)
```
(declConst name: (identifier) type: (type ...) defaultValue: (defaultValue ...))
```
## C) Ausdrücke
### exprCall (Funktionsaufruf)
```
(exprCall (identifier) ...args...) ← WriteLn(...)
```
### exprDot (qualifizierter Zugriff)
```
(exprDot lhs: (identifier) operator: (kDot) rhs: (exprCall (identifier) ...)) ← Svc.Login(...)
(exprDot lhs: (identifier) operator: (kDot) rhs: (identifier)) ← TAuthService.Create
```
## D) Sichtbarkeit (declSection)
```
(declSection (kPublic)) ← oder kPrivate, kProtected, kPublished, kStrict
```
Gilt für alle nachfolgenden Deklarationen bis zum nächsten `declSection` oder `kEnd`.
## E) Vererbung (parent-Feld von declClass)
Das `parent`-Feld enthält eine Liste von `typeref`-Knoten:
- **Erster** `typeref` = Basisklasse → EdgeKind `extends`
- **Weitere** `typeref`s = Interfaces → EdgeKind `implements`
```
(declClass (kClass) parent: ((typeref (identifier "TInterfacedObject")) (typeref (identifier "ITokenValidator"))) ...)
```
## F) Zusammenfassung: Relevante Knoten für CodeGraph
| AST-Knotentyp | Feld `name` | Weitere wichtige Felder |
|---|---|---|
| `unit`/`program`/`library` | Kind: `moduleName` | `interface`, `implementation` |
| `declClass` | via Parent `declType` | `parent` (Vererbung), `declSection` |
| `declIntf` | via Parent `declType` | `parent`, `guid` |
| `declProc` | `name` | `args`, `type`, `attribute` |
| `declProp` | `name` | `type` |
| `declField` | `name` | `type` |
| `declEnum` | — | Kind: `declEnumValue` |
| `declEnumValue` | `name` | `value` |
| `declConst` | `name` | `type`, `defaultValue` |
| `declUses` | — | Kind: `identifier` |
| `exprCall` | — | Kind: `identifier` (callee) |
| `exprDot` | — | `lhs`, `rhs` |
-119
View File
@@ -1,119 +0,0 @@
# Tree-sitter Query Skizzen (Pascal/Delphi)
Diese Skizzen sind bewusst so geschrieben, dass du sie schnell an die **konkreten Node-Namen** von `tree-sitter-pascal` und die **Capture-Konvention** von CodeGraph anpassen kannst.
> Praxis-Tipp: Nutze `tree-sitter parse` bzw. Editor-Tools (z.B. Neovim `:InspectTree`) um die exakten Node-Typen im AST zu sehen.
## A) Nodes
### 1) Unit / Program / Package
- Match: `unit`/`program`/`library`/`package` header
- Extrahiere Name
Skizze:
```scm
; (unit_header name: (identifier) @NAME) @NODE
; (#set! "kind" "unit")
; (program_header name: (identifier) @NAME) @NODE
; (#set! "kind" "program")
```
### 2) Klassen / Interfaces / Records
Skizze:
```scm
; (type_declaration
; (type_definition
; name: (identifier) @TYPE_NAME
; value: (class_type) @CLASS
; )
; )
; (type_definition name: (identifier) @TYPE_NAME value: (interface_type) @IFACE)
; (type_definition name: (identifier) @TYPE_NAME value: (record_type) @REC)
```
### 3) Procs/Funcs (top-level)
```scm
; (procedure_declaration name: (identifier) @NAME) @NODE
; (#set! "kind" "procedure")
; (function_declaration name: (identifier) @NAME) @NODE
; (#set! "kind" "function")
```
### 4) Methoden
Je nach Grammar sind Methoden oft als procedure/function nodes innerhalb eines `class_body` oder `visibility_section` enthalten.
```scm
; (method_declaration name: (identifier) @NAME) @NODE
; (#set! "kind" "method")
; optional: capture class name via ancestor match (wenn CodeGraph das unterstützt)
```
## B) Edges
### 1) uses (imports/dependencies)
```scm
; (uses_clause (qualified_identifier) @UNIT_NAME) @EDGE
; (#set! "kind" "imports")
```
### 2) extends (Basisklasse)
```scm
; (class_type
; base_class: (qualified_identifier) @BASE
; ) @EDGE
; (#set! "kind" "extends")
```
### 3) implements (Interfaces)
```scm
; (class_type
; implements: (interface_list (qualified_identifier) @IFACE)
; ) @EDGE
; (#set! "kind" "implements")
```
### 4) calls (Call-Graph)
Du willst in Delphi mindestens folgende Formen sehen:
- `Foo()`
- `Obj.Foo()`
- `TMyClass.Foo()`
Skizze:
```scm
; (call_expression
; function: (identifier) @CALLEE
; ) @EDGE
; (#set! "kind" "calls")
; (call_expression
; function: (qualified_identifier
; qualifier: (identifier) @QUAL
; name: (identifier) @CALLEE)
; ) @EDGE
; (#set! "kind" "calls")
```
## C) MVP: „Contains“-Edges
Optional, aber oft sehr nützlich: Datei/Unit enthält Klassen/Procs.
```scm
; (type_definition name: (identifier) @CHILD) @EDGE
; (#set! "kind" "contains")
```
Das ist abhängig davon, wie CodeGraph containment modelliert.
+55 -26
View File
@@ -1,32 +1,61 @@
# Checklist: Pascal/Delphi Support in CodeGraph
## A) Plumbing
- [ ] tree-sitter grammar dependency (Pascal)
- [ ] Language registry: `pascal` hinzufügen
- [ ] Extension mapping: `.pas .dpr .dpk .lpr` (optional `.inc`)
- [ ] Queries laden (nodes + edges)
## A) Plumbing (Infrastruktur)
- [ ] `npm install tree-sitter-pascal` als Dependency
- [ ] `src/types.ts`: `'pascal'` zum `Language` Union-Type hinzufügen
- [ ] `src/types.ts`: `DEFAULT_CONFIG.include` um `'**/*.pas'`, `'**/*.dpr'`, `'**/*.dpk'`, `'**/*.lpr'` erweitern
- [ ] `src/extraction/grammars.ts`: Grammar-Loader `pascal: () => require('tree-sitter-pascal')`
- [ ] `src/extraction/grammars.ts`: Extension-Mapping `.pas`, `.dpr`, `.dpk`, `.lpr``'pascal'`
- [ ] `src/extraction/grammars.ts`: Display-Name `pascal: 'Pascal / Delphi'`
- [ ] `src/extraction/tree-sitter.ts`: `LanguageExtractor` für `pascal` in `EXTRACTORS` Map
## B) Extraction
- [ ] Unit/Program/Package Nodes
- [ ] Class/Interface/Record Nodes
- [ ] Procedure/Function Nodes
- [ ] Method Nodes
- [ ] uses -> imports edges
- [ ] extends edges
- [ ] implements edges
- [ ] calls edges (best-effort)
## B) Node-Extraktion
- [ ] `unit` / `program` / `library` → NodeKind `module`
- [ ] `declClass` → NodeKind `class` (inkl. record, object)
- [ ] `declIntf` → NodeKind `interface`
- [ ] `declProc` (top-level) → NodeKind `function`
- [ ] `declProc` (in Klasse) → NodeKind `method` (inkl. constructor/destructor)
- [ ] `declProp` → NodeKind `property`
- [ ] `declField` → NodeKind `field`
- [ ] `declEnum` → NodeKind `enum`
- [ ] `declEnumValue` → NodeKind `enum_member`
- [ ] `declConst` → NodeKind `constant`
- [ ] `declType` (einfach) → NodeKind `type_alias`
## C) Resolution
- [ ] unitName -> file/node mapping
- [ ] resolve `uses X;` to unit node
- [ ] resolve `X in 'path'` (DPR/DPK) (Phase 2)
- [ ] call resolution baseline (same file + class)
## C) Edge-Extraktion
- [ ] `declUses` → EdgeKind `imports`
- [ ] `declClass.parent[0]` → EdgeKind `extends`
- [ ] `declClass.parent[1..]` → EdgeKind `implements`
- [ ] `exprCall` → EdgeKind `calls`
- [ ] `exprDot` + `exprCall` → EdgeKind `calls` (qualifiziert)
- [ ] `TClass.Create` → EdgeKind `instantiates`
- [ ] Parent-Child Containment → EdgeKind `contains`
## D) Testing
- [ ] add fixtures to tests
- [ ] assert extracted nodes
- [ ] assert imports/extends/implements/calls
## D) Sichtbarkeit & Attribute
- [ ] `getVisibility`: `declSection` → public/private/protected
- [ ] `isStatic`: `kClass` in `declProc` → true
- [ ] `getSignature`: Parameter + Rückgabetyp extrahieren
## E) Polishing
- [ ] expose language in `Supported Languages` docs
- [ ] update CLI help / config validation
## E) Resolution
- [ ] `moduleName``unitName → fileId` Mapping
- [ ] `uses X;` → Unit-Node auflösen
- [ ] `uses X in 'path'` → Datei direkt auflösen (Phase 2)
- [ ] Call-Resolution: gleiche Unit → gleiche Klasse → uses-Units → global
## F) Testing
- [ ] Fixtures in Test-Suite aufnehmen (`UAuth.pas`, `App.dpr`, `UTypes.pas`)
- [ ] Nodes: Anzahl + Namen verifizieren
- [ ] Edges: imports/extends/implements/calls prüfen
- [ ] Sichtbarkeiten prüfen
- [ ] Properties, Enums, Konstanten prüfen
## G) Polishing
- [ ] Language in Supported-Languages-Dokumentation aufnehmen
- [ ] CLI-Hilfe / Config-Validierung aktualisieren
## H) Bekannte Einschränkungen (für spätere Phasen)
- [ ] **`with`-Statements** (Phase 2): Verschleiern den Qualifier bei Aufrufen. Im MVP werden Calls innerhalb von `with`-Blöcken ohne Qualifier extrahiert.
- [ ] **`.dfm`/`.fmx` Form-Dateien** (Zukunft): Enthalten Komponenten-Deklarationen und Event-Verknüpfungen. Aktuell nicht unterstützt.
- [ ] **`.inc` Include-Dateien** (Optional): Enthalten Code-Fragmente, die per `{$I filename}` eingebunden werden. Parser liefert möglicherweise keinen vollständigen AST.
- [ ] **Class Helpers / Record Helpers** (Phase 2): `declHelper`-Knoten erweitern existierende Typen. Erfordert spezielle Resolution-Logik.
- [ ] **Generics** (Phase 2): `typerefTpl` und `genericTpl` für generische Typen.
+67
View File
@@ -0,0 +1,67 @@
# NodeKind Mapping: Delphi → CodeGraph
Dieses Dokument zeigt die explizite Zuordnung von Delphi/Pascal-Konzepten zu den bestehenden CodeGraph `NodeKind`- und `EdgeKind`-Werten.
> **Ergebnis:** Alle Delphi-Konzepte lassen sich auf existierende `NodeKind`-Werte abbilden. Es werden **keine neuen** Kinds benötigt.
## Node-Mapping
| Delphi-Konzept | tree-sitter Typ | CodeGraph `NodeKind` | Anmerkungen |
|---|---|---|---|
| Unit | `unit` + `moduleName` | `module` | Kompilierungseinheit, vergleichbar mit Modulen |
| Program | `program` + `moduleName` | `module` | Ausführbarer Einstiegspunkt |
| Library | `library` + `moduleName` | `module` | DLL/shared library |
| Klasse | `declClass` (mit `kClass`) | `class` | Standard-Klasse |
| Record | `declClass` (mit `kRecord`) | `class` | Value-Type, aber strukturell wie Klasse |
| Object | `declClass` (mit `kObject`) | `class` | Legacy, wie Klasse behandeln |
| Interface | `declIntf` (mit `kInterface`) | `interface` | — |
| DispInterface | `declIntf` (mit `kDispInterface`) | `interface` | COM-spezifisch |
| Procedure (top-level) | `declProc` (mit `kProcedure`) | `function` | Ohne Rückgabetyp |
| Function (top-level) | `declProc` (mit `kFunction`) | `function` | Mit Rückgabetyp |
| Methode | `declProc` in `declClass` | `method` | Instance-Methode |
| Constructor | `declProc` (mit `kConstructor`) | `method` | Spezielle Methode |
| Destructor | `declProc` (mit `kDestructor`) | `method` | Spezielle Methode |
| Class Method | `declProc` (mit `kClass`) | `method` | Statisch, `isStatic = true` |
| Property | `declProp` | `property` | Mit Getter/Setter |
| Feld | `declField` | `field` | — |
| Enum | `declEnum` | `enum` | — |
| Enum-Wert | `declEnumValue` | `enum_member` | — |
| Type-Alias | `declType` (einfach) | `type_alias` | `type TMyInt = Integer;` |
| Konstante | `declConst` | `constant` | — |
| Uses-Eintrag | `declUses``identifier` | `import` | Pro Unit-Name ein Import-Node |
## Edge-Mapping
| Delphi-Beziehung | Erkennung | CodeGraph `EdgeKind` |
|---|---|---|
| `uses X;` | `declUses` → Kind `identifier` | `imports` |
| Basisklasse | `declClass.parent[0]` (erster `typeref`) | `extends` |
| Interface-Impl. | `declClass.parent[1..]` (weitere `typeref`s) | `implements` |
| Funktionsaufruf | `exprCall` | `calls` |
| Qualifizierter Aufruf | `exprDot``exprCall` | `calls` |
| `TClass.Create` | `exprDot` mit `.Create` Suffix | `instantiates` |
| Unit enthält Klasse | AST Parent-Child | `contains` |
| Klasse enthält Methode | AST Parent-Child | `contains` |
## Nicht abgebildete Konzepte (Phase 2+)
| Konzept | Grund |
|---|---|
| `with`-Statement | Kein eigener EdgeKind nötig; erschwert nur die Call-Qualifizierung |
| Class Helper | Kein eigener NodeKind; als `class` mit speziellem Bezug zum erweiterten Typ |
| `.dfm`/`.fmx` Komponenten | Kein Code im Pascal-Sinne; erfordert eigenen Parser |
| `exports`-Klauseln | `declExports` → könnte als `export` NodeKind abgebildet werden |
| Generics | `typerefTpl` → beeinflusst Typ-Referenzen, nicht den NodeKind |
## Sichtbarkeit
| Delphi-Keyword | CodeGraph Visibility |
|---|---|
| `published` | `public` (CodeGraph kennt kein `published`) |
| `public` | `public` |
| `protected` | `protected` |
| `private` | `private` |
| `strict private` | `private` |
| `strict protected` | `protected` |
| (keine Angabe) | `public` (Default in Delphi-Klassen) |
+142
View File
@@ -0,0 +1,142 @@
# Integration Guide: Konkrete Code-Änderungen
Dieses Dokument zeigt die **exakten Änderungen** an den CodeGraph-Quelldateien, die für Pascal/Delphi-Support nötig sind.
## 1) Dependency installieren
```bash
npm install tree-sitter-pascal
```
## 2) `src/types.ts` — Language-Typ erweitern
```typescript
// Zum Language Union-Type hinzufügen (nach 'liquid'):
export type Language =
| 'typescript'
// ...bestehende Sprachen...
| 'liquid'
| 'pascal' // ← NEU
| 'unknown';
```
**DEFAULT_CONFIG.include** erweitern:
```typescript
include: [
// ...bestehende Patterns...
// Liquid (Shopify themes)
'**/*.liquid',
// Pascal / Delphi ← NEU
'**/*.pas',
'**/*.dpr',
'**/*.dpk',
'**/*.lpr',
],
```
## 3) `src/extraction/grammars.ts` — Grammar registrieren
### grammarLoaders Map:
```typescript
const grammarLoaders: Record<GrammarLanguage, GrammarLoader> = {
// ...bestehende Loader...
dart: () => {
return require('@sengac/tree-sitter-dart');
},
pascal: () => { // ← NEU
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('tree-sitter-pascal');
},
};
```
### EXTENSION_MAP:
```typescript
export const EXTENSION_MAP: Record<string, Language> = {
// ...bestehende Mappings...
'.liquid': 'liquid',
'.svelte': 'svelte',
'.pas': 'pascal', // ← NEU
'.dpr': 'pascal', // ← NEU
'.dpk': 'pascal', // ← NEU
'.lpr': 'pascal', // ← NEU
};
```
### getLanguageDisplayName():
```typescript
const names: Record<Language, string> = {
// ...bestehende Namen...
liquid: 'Liquid',
pascal: 'Pascal / Delphi', // ← NEU
unknown: 'Unknown',
};
```
## 4) `src/extraction/tree-sitter.ts` — LanguageExtractor
```typescript
pascal: {
functionTypes: ['declProc'], // Top-Level Funktionen/Prozeduren
classTypes: ['declClass'], // Klassen, Records, Objects
methodTypes: ['declProc'], // Methoden (in Klasse), Konstruktoren, Destruktoren
interfaceTypes: ['declIntf'], // Interfaces
structTypes: [], // Records über declClass abgedeckt
enumTypes: ['declEnum'], // Aufzählungen
typeAliasTypes: ['declType'], // Type-Aliase
importTypes: ['declUses'], // uses-Klauseln
callTypes: ['exprCall'], // Funktionsaufrufe
variableTypes: ['declField', 'declConst'], // Felder und Konstanten
nameField: 'name',
bodyField: 'body', // nur bei defProc (Implementierung)
paramsField: 'args', // declArgs
returnField: 'type',
getSignature: (node, source) => {
const args = getChildByField(node, 'args');
const returnType = getChildByField(node, 'type');
if (!args) return undefined;
const argsText = getNodeText(args, source);
return returnType
? getNodeText(returnType, source) + ' ' + argsText
: argsText;
},
getVisibility: (node) => {
// Suche den nächsten declSection-Vorfahren
let current = node.parent;
while (current) {
if (current.type === 'declSection') {
for (let i = 0; i < current.childCount; i++) {
const child = current.child(i);
if (child?.type === 'kPublic' || child?.type === 'kPublished')
return 'public';
if (child?.type === 'kPrivate') return 'private';
if (child?.type === 'kProtected') return 'protected';
}
}
current = current.parent;
}
return undefined;
},
isStatic: (node) => {
// class procedure / class function
for (let i = 0; i < node.childCount; i++) {
if (node.child(i)?.type === 'kClass') return true;
}
return false;
},
isConst: (node) => {
return node.type === 'declConst';
},
},
```
## Hinweise
- `declProc` wird sowohl für `functionTypes` als auch `methodTypes` verwendet. CodeGraph unterscheidet anhand des AST-Kontexts (Parent ist `declClass` → method, sonst → function).
- Die `getVisibility`-Funktion traversiert aufwärts zum `declSection`-Knoten.
- Records werden als `class` behandelt, da `declClass` mit `kRecord` Kind-Knoten beides abdeckt.
+31 -16
View File
@@ -1,25 +1,40 @@
# CodeGraph Pascal/Delphi Support (Fork-Konzept)
# CodeGraph Pascal/Delphi Support Konzept & Bauplan
Dieses ZIP ist **kein fertiger CodeGraph-Fork**, sondern ein **umsetzbarer Bauplan** inklusive Query-Skizzen, Scaffold-Dateistruktur, Test-Fixtures und einer Checkliste.
Dieses Verzeichnis enthält einen **umsetzbaren Bauplan** für Pascal/Delphi-Support in CodeGraph. Es basiert auf der tatsächlichen CodeGraph-Architektur und den verifizierten AST-Knotentypen von [`tree-sitter-pascal`](https://github.com/Isopod/tree-sitter-pascal).
Ziel: CodeGraph soll **Pascal/Delphi**-Dateien indexieren und daraus **Nodes** (Units, Klassen, Methoden, …) sowie **Edges** (uses/imports, calls, extends, implements, …) extrahieren.
**Ziel:** CodeGraph soll **Pascal/Delphi**-Dateien indexieren und daraus **Nodes** (Units, Klassen, Methoden, Properties, Enums, …) sowie **Edges** (uses/imports, calls, extends, implements, …) extrahieren.
## Inhalt
- `Docs/` Konzept, Capture-Konventionen, Implementations-Schritte
- `Scaffold/` vorgeschlagene Ordner/Dateien für `src/languages/pascal/` inkl. `.scm` Queries
- `fixtures/` kleine Delphi-Beispieldateien zum Testen der Extraktion
- `resolution/` Resolver-Heuristiken (Unit-Mapping, Call-Resolution)
| Verzeichnis / Datei | Beschreibung |
|---|---|
| `Docs/01-Implementation-Plan.md` | Implementierungs-Roadmap mit konkreten AST-Typen |
| `Docs/02-Capture-Convention.md` | Wie Pascal an CodeGraphs `LanguageExtractor`-Interface andockt |
| `Docs/03-AST-Referenz.md` | Verifizierte AST-Knotentypen aus tree-sitter-pascal |
| `Docs/04-Checklist.md` | Umsetzungs-Checkliste mit bekannten Einschränkungen |
| `Docs/05-NodeKind-Mapping.md` | Explizite Zuordnung Delphi → CodeGraph NodeKind/EdgeKind |
| `Docs/06-Integration-Guide.md` | Konkrete Code-Diffs für `grammars.ts`, `types.ts`, `tree-sitter.ts` |
| `fixtures/` | Delphi-Beispieldateien zum Testen der Extraktion |
| `resolution/` | Resolver-Heuristiken (Unit-Mapping, Call-Resolution) |
## Architektur-Übersicht
CodeGraph verwendet **keine** per-Sprache Plugin-Verzeichnisse. Die Integration erfolgt zentral in drei Dateien:
1. **`src/types.ts`** — `Language` Union-Type und `DEFAULT_CONFIG.include` Patterns
2. **`src/extraction/grammars.ts`** — Grammar-Loader, Extension-Mapping, Display-Name
3. **`src/extraction/tree-sitter.ts`** — `LanguageExtractor`-Konfiguration in der `EXTRACTORS` Map
## Wie du damit arbeitest
1. **Im CodeGraph-Repo** die bestehende Struktur für eine Sprache ansehen (z.B. `src/languages/go` oder `src/languages/java`).
2. Dieses ZIP als Vorlage nehmen und **1:1** in deinen Fork übertragen:
- `src/languages/pascal/**`
- Extension-Mapping (`.pas`, `.dpr`, `.dpk`, `.lpr`, optional `.inc`)
- Language-Registry erweitern
3. Queries (`.scm`) auf die **Capture-Namen** mappen, die CodeGraph intern erwartet.
4. Resolver erweitern (mindestens `uses` → Unit-File, einfache Call-Auflösung).
5. Fixtures in die Tests aufnehmen.
1. **Integration Guide lesen** (`Docs/06-Integration-Guide.md`) — enthält die exakten Code-Änderungen
2. **`npm install tree-sitter-pascal`** als Dependency hinzufügen
3. **Änderungen in den drei Dateien** vornehmen (types.ts, grammars.ts, tree-sitter.ts)
4. **Resolver erweitern** (mindestens `uses` → Unit-File, einfache Call-Auflösung)
5. **Fixtures in die Tests aufnehmen** und Assertions hinzufügen
> Hinweis: Tree-sitter ist die Grundlage. Für Pascal/Delphi bietet sich `tree-sitter-pascal` an (Delphi + FreePascal).
## Grammar
Verwendet wird: [`tree-sitter-pascal`](https://github.com/Isopod/tree-sitter-pascal) (npm: `tree-sitter-pascal`)
- Unterstützt: Delphi, FreePascal, Standard-Pascal
- Dateierweiterungen: `.pas`, `.dpr`, `.dpk`, `.lpr`
@@ -1,15 +0,0 @@
# Pascal / Delphi Language Module (Scaffold)
Diese Dateien sind als **Startpunkt** für einen CodeGraph-Fork gedacht.
## Strukturvorschlag
- `language.ts` registriert Parser, Extensions, Query-Files
- `queries/nodes.scm` Node-Extraktion
- `queries/edges.scm` Edge-Extraktion
- `queries/comments.scm` (optional) Docstrings/Kommentare
## Wichtig
Die Capture-Namen in den `.scm` Dateien sind **Platzhalter**.
Passe sie so an, dass sie zum internen Schema von CodeGraph passen (siehe `Docs/02-Capture-Convention.md`).
@@ -1,29 +0,0 @@
/**
* Pascal / Delphi language registration scaffold for CodeGraph.
*
* NOTE: This is intentionally pseudo-code / a template.
* You must adapt it to the actual CodeGraph codebase structure.
*/
export const pascalLanguage = {
id: 'pascal',
displayName: 'Pascal / Delphi',
// MVP extensions
extensions: ['.pas', '.dpr', '.dpk', '.lpr'],
// Suggested tree-sitter grammar package name (verify in your fork)
// parser: require('tree-sitter-pascal'),
// Queries used by the extractor
queries: {
nodes: __dirname + '/queries/nodes.scm',
edges: __dirname + '/queries/edges.scm',
// comments: __dirname + '/queries/comments.scm',
},
// Optional language-specific settings
options: {
// includeFiles: ['**/*.inc'] // only if you decide to support includes
}
};
@@ -1,38 +0,0 @@
; Pascal/Delphi edge extraction queries (SCAFFOLD)
; -----------------------------------------------
; IMPORTANT: Replace capture names with the exact ones CodeGraph expects.
; === uses (imports) ===
; (uses_clause (qualified_identifier) @cg.target) @cg.edge
; (#set! cg.kind "imports")
; === class inheritance ===
; (class_type
; base_class: (qualified_identifier) @cg.target
; ) @cg.edge
; (#set! cg.kind "extends")
; === implements interfaces ===
; (class_type
; implements: (interface_list (qualified_identifier) @cg.target)
; ) @cg.edge
; (#set! cg.kind "implements")
; === call graph (best-effort) ===
; (call_expression function: (identifier) @cg.target) @cg.edge
; (#set! cg.kind "calls")
; Qualified calls: Obj.Foo(), TMyClass.Bar()
; (call_expression
; function: (qualified_identifier
; qualifier: (identifier) @cg.qualifier
; name: (identifier) @cg.target)
; ) @cg.edge
; (#set! cg.kind "calls")
@@ -1,61 +0,0 @@
; Pascal/Delphi node extraction queries (SCAFFOLD)
; -------------------------------------------------
; IMPORTANT: Replace capture names with the exact ones CodeGraph expects.
; Use existing languages as reference.
; === Unit / Program / Library / Package ===
; (unit_header name: (identifier) @cg.name) @cg.node
; (#set! cg.kind "unit")
; (program_header name: (identifier) @cg.name) @cg.node
; (#set! cg.kind "program")
; (library_header name: (identifier) @cg.name) @cg.node
; (#set! cg.kind "library")
; (package_header name: (identifier) @cg.name) @cg.node
; (#set! cg.kind "package")
; === Types: class / interface / record ===
; (type_definition
; name: (identifier) @cg.name
; value: (class_type)
; ) @cg.node
; (#set! cg.kind "class")
; (type_definition
; name: (identifier) @cg.name
; value: (interface_type)
; ) @cg.node
; (#set! cg.kind "interface")
; (type_definition
; name: (identifier) @cg.name
; value: (record_type)
; ) @cg.node
; (#set! cg.kind "record")
; === Top-level procedures/functions ===
; (procedure_declaration name: (identifier) @cg.name) @cg.node
; (#set! cg.kind "procedure")
; (function_declaration name: (identifier) @cg.name) @cg.node
; (#set! cg.kind "function")
; === Methods (depending on grammar) ===
; (method_declaration name: (identifier) @cg.name) @cg.node
; (#set! cg.kind "method")
; Constructors / Destructors (optional)
; (constructor_declaration name: (identifier) @cg.name) @cg.node
; (#set! cg.kind "constructor")
;
; (destructor_declaration name: (identifier) @cg.name) @cg.node
; (#set! cg.kind "destructor")
+46 -1
View File
@@ -1,3 +1,7 @@
/// Unit UAuth: Authentication-Service mit Interface-Implementierung.
/// Testet: uses, interface (mit GUID), Klasse mit Vererbung + Interface,
/// Sichtbarkeitsbereiche (private/public), Felder, Properties,
/// Methoden, Constructor, Destructor, Funktionsaufrufe.
unit UAuth;
interface
@@ -7,19 +11,56 @@ uses
System.Classes;
type
/// Interface für Token-Validierung
ITokenValidator = interface
['{11111111-1111-1111-1111-111111111111}']
function Validate(const AToken: string): Boolean;
end;
/// Auth-Service mit Token-Validierung
TAuthService = class(TInterfacedObject, ITokenValidator)
private
FToken: string;
FLoginCount: Integer;
procedure IncLoginCount;
protected
function GetToken: string;
public
constructor Create;
destructor Destroy; override;
function Validate(const AToken: string): Boolean;
function Login(const AUser, APass: string): string;
property Token: string read GetToken;
property LoginCount: Integer read FLoginCount;
end;
implementation
{ TAuthService }
constructor TAuthService.Create;
begin
inherited Create;
FToken := '';
FLoginCount := 0;
end;
destructor TAuthService.Destroy;
begin
FToken := '';
inherited Destroy;
end;
procedure TAuthService.IncLoginCount;
begin
Inc(FLoginCount);
end;
function TAuthService.GetToken: string;
begin
Result := FToken;
end;
function TAuthService.Validate(const AToken: string): Boolean;
begin
Result := AToken <> '';
@@ -27,8 +68,12 @@ end;
function TAuthService.Login(const AUser, APass: string): string;
begin
IncLoginCount;
if Validate(AUser + ':' + APass) then
Result := 'ok'
begin
FToken := AUser;
Result := 'ok';
end
else
Result := '';
end;
+75
View File
@@ -0,0 +1,75 @@
/// Unit UTypes: Delphi-Typsystem-Fixture.
/// Testet: Enums, Records (mit Feldern), Type-Aliase,
/// Konstanten, verschachtelte Typen, Class-Methoden (static).
unit UTypes;
interface
uses
System.SysUtils;
const
C_MAX_RETRIES = 3;
C_DEFAULT_NAME = 'Guest';
type
/// Enum: Benutzerrolle
TUserRole = (urAdmin, urEditor, urViewer);
/// Record: Punkt mit X/Y-Koordinaten
TPoint2D = record
X: Double;
Y: Double;
end;
/// Type-Alias
TUserName = string;
/// Klasse mit class method (static), verschachteltem Typ und Enum-Verwendung
TUserInfo = class
public
type
/// Verschachtelter Record innerhalb der Klasse
TAddress = record
Street: string;
City: string;
Zip: string;
end;
private
FName: TUserName;
FRole: TUserRole;
FAddress: TAddress;
public
constructor Create(const AName: TUserName; ARole: TUserRole);
function GetDisplayName: string;
class function CreateAdmin(const AName: TUserName): TUserInfo; static;
property Name: TUserName read FName write FName;
property Role: TUserRole read FRole;
property Address: TAddress read FAddress write FAddress;
end;
implementation
{ TUserInfo }
constructor TUserInfo.Create(const AName: TUserName; ARole: TUserRole);
begin
FName := AName;
FRole := ARole;
end;
function TUserInfo.GetDisplayName: string;
begin
if FRole = urAdmin then
Result := '[Admin] ' + FName
else
Result := FName;
end;
class function TUserInfo.CreateAdmin(const AName: TUserName): TUserInfo;
begin
Result := TUserInfo.Create(AName, urAdmin);
end;
end.
+30 -15
View File
@@ -2,29 +2,44 @@
## Input
- Extracted edges of kind `imports` from `uses` clauses.
- Extracted nodes of kind `unit|program|package|library` with their names.
- Extrahierte Edges vom Typ `imports` aus `declUses`-Knoten.
- Extrahierte Nodes vom Typ `module` aus `unit`/`program`/`library` (Name aus `moduleName`-Kind-Knoten).
## AST-Struktur
```
(declUses
(kUses)
(identifier "System.SysUtils") ← Unit-Name
(identifier "UAuth") ← Unit-Name
(kIn) (literalString "'UAuth.pas'") ← optionaler Pfad
)
```
## MVP Algorithm
1. Build `unitName -> nodeId` map for all indexed files.
2. For each `imports` edge with target name `X`:
- try exact match `X`
- try case-insensitive match
- try namespace normalization:
- `System.SysUtils` may correspond to unit `SysUtils` (optional heuristic)
3. If resolved: store `edge.to_node_id = targetNodeId`.
4. If not resolved: keep `edge.to_symbol = X` so search still works.
1. Build `unitName nodeId` Map für alle indexierten Dateien (aus `moduleName`-Knoten).
2. Für jeden `imports`-Edge mit Zielname `X`:
- Exakter Match auf `X`
- Case-insensitiver Match (Delphi ist case-insensitive)
- Namespace-Normalisierung:
- `System.SysUtils` → versuche auch `SysUtils` (letzter Segment)
- Dateiname-basierter Fallback: `X``X.pas` in den indexierten Dateien suchen
3. Falls aufgelöst: `edge.to_node_id = targetNodeId`
4. Falls nicht aufgelöst: `edge.to_symbol = X` beibehalten (Suche funktioniert trotzdem)
## DPR/DPK "in 'path'" cases (Phase 2)
## DPR/DPK `in 'path'` (Phase 2)
In Delphi project files you can have:
In Delphi-Projektdateien kann ein expliziter Pfad angegeben werden:
```
```delphi
uses
Foo in 'src/Foo.pas',
Bar in 'Bar.pas';
```
Enhancement:
- Parse optional path literal and resolve directly to file.
Im AST erkennbar durch `(kIn) (literalString)` nach dem `(identifier)`.
**Enhancement:**
- `literalString` extrahieren und direkt zur Datei auflösen
- Pfad relativ zur DPR/DPK-Datei interpretieren