From dcca22c78f60daba88bd4af700e278e9dcf1a655 Mon Sep 17 00:00:00 2001 From: Olaf Monien Date: Wed, 11 Feb 2026 00:17:29 +0100 Subject: [PATCH] Delphi-Konzept: Reale tree-sitter-pascal AST-Typen, Integration Guide, erweiterte Fixtures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- Delphi/Docs/01-Implementation-Plan.md | 98 ++++++++---- Delphi/Docs/02-Capture-Convention.md | 120 ++++++++++----- Delphi/Docs/03-AST-Referenz.md | 139 +++++++++++++++++ Delphi/Docs/03-TreeSitter-Query-Sketches.md | 119 --------------- Delphi/Docs/04-Checklist.md | 81 ++++++---- Delphi/Docs/05-NodeKind-Mapping.md | 67 +++++++++ Delphi/Docs/06-Integration-Guide.md | 142 ++++++++++++++++++ Delphi/README.md | 47 ++++-- .../Scaffold/src/languages/pascal/README.md | 15 -- .../Scaffold/src/languages/pascal/language.ts | 29 ---- .../src/languages/pascal/queries/edges.scm | 38 ----- .../src/languages/pascal/queries/nodes.scm | 61 -------- Delphi/fixtures/UAuth.pas | 47 +++++- Delphi/fixtures/UTypes.pas | 75 +++++++++ Delphi/resolution/UnitResolution.md | 45 ++++-- 15 files changed, 739 insertions(+), 384 deletions(-) create mode 100644 Delphi/Docs/03-AST-Referenz.md delete mode 100644 Delphi/Docs/03-TreeSitter-Query-Sketches.md create mode 100644 Delphi/Docs/05-NodeKind-Mapping.md create mode 100644 Delphi/Docs/06-Integration-Guide.md delete mode 100644 Delphi/Scaffold/src/languages/pascal/README.md delete mode 100644 Delphi/Scaffold/src/languages/pascal/language.ts delete mode 100644 Delphi/Scaffold/src/languages/pascal/queries/edges.scm delete mode 100644 Delphi/Scaffold/src/languages/pascal/queries/nodes.scm create mode 100644 Delphi/fixtures/UTypes.pas diff --git a/Delphi/Docs/01-Implementation-Plan.md b/Delphi/Docs/01-Implementation-Plan.md index e8a985d..ecd1a25 100644 --- a/Delphi/Docs/01-Implementation-Plan.md +++ b/Delphi/Docs/01-Implementation-Plan.md @@ -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 index` indexiert Delphi/Pascal-Dateien ohne Crash +- `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 diff --git a/Delphi/Docs/02-Capture-Convention.md b/Delphi/Docs/02-Capture-Convention.md index 4538748..e4a1b01 100644 --- a/Delphi/Docs/02-Capture-Convention.md +++ b/Delphi/Docs/02-Capture-Convention.md @@ -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. diff --git a/Delphi/Docs/03-AST-Referenz.md b/Delphi/Docs/03-AST-Referenz.md new file mode 100644 index 0000000..35c30b7 --- /dev/null +++ b/Delphi/Docs/03-AST-Referenz.md @@ -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` | + diff --git a/Delphi/Docs/03-TreeSitter-Query-Sketches.md b/Delphi/Docs/03-TreeSitter-Query-Sketches.md deleted file mode 100644 index e73021e..0000000 --- a/Delphi/Docs/03-TreeSitter-Query-Sketches.md +++ /dev/null @@ -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. diff --git a/Delphi/Docs/04-Checklist.md b/Delphi/Docs/04-Checklist.md index ff8a5cb..496fa78 100644 --- a/Delphi/Docs/04-Checklist.md +++ b/Delphi/Docs/04-Checklist.md @@ -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. diff --git a/Delphi/Docs/05-NodeKind-Mapping.md b/Delphi/Docs/05-NodeKind-Mapping.md new file mode 100644 index 0000000..b84cfed --- /dev/null +++ b/Delphi/Docs/05-NodeKind-Mapping.md @@ -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) | + diff --git a/Delphi/Docs/06-Integration-Guide.md b/Delphi/Docs/06-Integration-Guide.md new file mode 100644 index 0000000..44f8d2f --- /dev/null +++ b/Delphi/Docs/06-Integration-Guide.md @@ -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 = { + // ...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 = { + // ...bestehende Mappings... + '.liquid': 'liquid', + '.svelte': 'svelte', + '.pas': 'pascal', // ← NEU + '.dpr': 'pascal', // ← NEU + '.dpk': 'pascal', // ← NEU + '.lpr': 'pascal', // ← NEU +}; +``` + +### getLanguageDisplayName(): + +```typescript +const names: Record = { + // ...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. + diff --git a/Delphi/README.md b/Delphi/README.md index a6e2057..1089b79 100644 --- a/Delphi/README.md +++ b/Delphi/README.md @@ -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` diff --git a/Delphi/Scaffold/src/languages/pascal/README.md b/Delphi/Scaffold/src/languages/pascal/README.md deleted file mode 100644 index a6e966f..0000000 --- a/Delphi/Scaffold/src/languages/pascal/README.md +++ /dev/null @@ -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`). diff --git a/Delphi/Scaffold/src/languages/pascal/language.ts b/Delphi/Scaffold/src/languages/pascal/language.ts deleted file mode 100644 index 47a7574..0000000 --- a/Delphi/Scaffold/src/languages/pascal/language.ts +++ /dev/null @@ -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 - } -}; diff --git a/Delphi/Scaffold/src/languages/pascal/queries/edges.scm b/Delphi/Scaffold/src/languages/pascal/queries/edges.scm deleted file mode 100644 index ac14ffe..0000000 --- a/Delphi/Scaffold/src/languages/pascal/queries/edges.scm +++ /dev/null @@ -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") diff --git a/Delphi/Scaffold/src/languages/pascal/queries/nodes.scm b/Delphi/Scaffold/src/languages/pascal/queries/nodes.scm deleted file mode 100644 index 76db826..0000000 --- a/Delphi/Scaffold/src/languages/pascal/queries/nodes.scm +++ /dev/null @@ -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") diff --git a/Delphi/fixtures/UAuth.pas b/Delphi/fixtures/UAuth.pas index 6d89521..51a8425 100644 --- a/Delphi/fixtures/UAuth.pas +++ b/Delphi/fixtures/UAuth.pas @@ -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; diff --git a/Delphi/fixtures/UTypes.pas b/Delphi/fixtures/UTypes.pas new file mode 100644 index 0000000..4458d31 --- /dev/null +++ b/Delphi/fixtures/UTypes.pas @@ -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. + diff --git a/Delphi/resolution/UnitResolution.md b/Delphi/resolution/UnitResolution.md index d960eab..3e71ce6 100644 --- a/Delphi/resolution/UnitResolution.md +++ b/Delphi/resolution/UnitResolution.md @@ -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