From 2fd85be9236f79025358248064f5f4b480897533 Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Mon, 3 Nov 2025 11:11:43 +0100 Subject: [PATCH] Tag --- Doc/CompileStages.md | 57 ++++++++++++++++++++++++++++++++++++++++++++ Doc/FMX-Styles 1.md | 43 +++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 Doc/CompileStages.md create mode 100644 Doc/FMX-Styles 1.md diff --git a/Doc/CompileStages.md b/Doc/CompileStages.md new file mode 100644 index 0000000..31fa39b --- /dev/null +++ b/Doc/CompileStages.md @@ -0,0 +1,57 @@ +# Projektplan: Refactoring der Compiler-Phasen + +*Datum: 01.11.2025 16:30* + +## Motivation + +Der aktuelle Compiler-Monolith (`TAstBinder`) wurde erfolgreich in logische Phasen aufgeteilt (Expand, Bind, TypeCheck, Lower, TCO). Dabei ist ein schwerwiegendes technisches Problem aufgetreten: + +Die `TAstTransformer`-Basisklasse (in `Myc.Ast.Visitor.pas`) zerstört die spezialisierten `TBound...Node`-Typen während der Transformation. Wenn eine spätere Phase (z.B. `TAstLowerer`) einen Baum transformiert, werden die `TBoundFunctionCallNode`s (aus Phase 2) fälschlicherweise in `TFunctionCallNode`s (Basis-Typ) zurückverwandelt. Dies führt zu Abstürzen beim `as`-Casting in der nachfolgenden Phase (`TAstTCO`). + +## Ziel + +Das System muss stabilisiert werden, indem der Typverlust im `TAstTransformer` behoben wird. Es gibt zwei konkurrierende Architekturen, um dieses Ziel zu erreichen. + +## Ergebnis: Lösungs-Pfade + +### Pfad 1: Pragmatische Lösung (Virtuelles Rebuild) + +Dieser Ansatz repariert den `TAstTransformer`, behält aber die bestehende (unsaubere) Datenstruktur bei. + +* **Strategie:** Wir behalten die "Gott-Objekt"-Knoten (`TBound...Node`), die Daten aus allen Phasen enthalten (`Address`, `StaticType`, `IsTailCall`). Wir reparieren den `TAstTransformer` (in `Myc.Ast.Visitor.pas`), indem wir virtuelle `Rebuild...`-Methoden (z.B. `RebuildFunctionCall`) einführen. +* **Implementierung:** Die `Visit...`-Methoden des Transformers rufen nicht mehr `TAst.FunctionCall` auf, sondern `Self.RebuildFunctionCall`. Alle unsere Phasen (Binder, Lowerer, TCO) überschreiben diese `Rebuild...`-Methoden und stellen sicher, dass der korrekte `TBound...Node`-Typ (unter Beibehaltung der Metadaten) neu erstellt wird. +* **Pro:** + * **Schnell:** Behebt den Absturz mit minimalem Eingriff. + * **Wenig Code:** Die Phasen müssen weiterhin nur die `Visit...`-Methoden überschreiben, die sie tatsächlich interessieren. +* **Contra:** + * **Architektur:** Die Datenstruktur bleibt "schmutzig". Implementierungsdetails bluten weiterhin durch (z.B. muss der `TAstBinder` (Phase 2) das Feld `IsTailCall` (Phase 5) initialisieren). + +### Pfad 2: Saubere Architektur (Staged Data Layers) + +Dieser Ansatz definiert für jede Phase eine eigene, unveränderliche Datenstruktur. + +* **Strategie:** Wir verwerfen den `TAstTransformer`. Jede Compiler-Phase (Binder, TypeChecker, ...) wird ein reiner `IAstVisitor`. +* **Implementierung:** + 1. `TAstBinder` (Phase 2) konsumiert `IAstNode` und produziert `IBoundNode` (enthält *nur* `Address`, `IsBoxed`). + 2. `TTypeChecker` (Phase 3) konsumiert `IBoundNode` und produziert `ITypedNode` (enthält *zusätzlich* `StaticType`). + 3. (usw. für Lowering und TCO) + * Die neuen Knoten (`TBoundNode`, `TTypedNode`) nutzen Aggregation und das `implements`-Schlüsselwort, um die Basis-Schnittstellen (z.B. `IIdentifierNode`) an den aggregierten Knoten der Vor-Phase zu delegieren. +* **Pro:** + * **Architektur:** Typsicher und sauber. Keine "blutenden" Implementierungsdetails. Daten sind zwischen den Phasen unveränderlich (immutable). + * **Robust:** Die Fehlerklasse (`as`-Cast-Fehler) wird eliminiert. +* **Contra:** + * **Aufwand:** Ein massives Refactoring. + * **Boilerplate:** Jede Phase (Binder, TypeChecker, ...) muss *alle* 20+ `Visit...`-Methoden implementieren, um den Baum von Typ `A` in Typ `B` zu überführen, selbst wenn 19 davon nur "Durchreicher" sind. + +## TODO (Nächste Schritte für Pfad 1) + +Gemäß deiner Entscheidung probieren wir **Pfad 1**. + +1. **`Myc.Ast.Visitor.pas` (`TAstTransformer`)**: + * `VisitFunctionCall`, `VisitLambdaExpression`, `VisitVariableDeclaration` und `VisitRecordLiteral` (die Knoten, die `TBound...`-Typen haben) so umbauen, dass sie `virtual Rebuild...`-Methoden aufrufen. +2. **`Myc.Ast.Binding.pas` (`TAstBinder`)**: + * `Rebuild...`-Methoden überschreiben, um `TBound...Node`-Instanzen zu erzeugen (und `IsTailCall=False` zu setzen). +3. **`Myc.Ast.Lowering.pas` (`TAstLowerer`)**: + * `Rebuild...`-Methoden überschreiben, um `TBound...Node`-Instanzen zu erhalten (und `IsTailCall` vom Original zu kopieren). +4. **`Myc.Ast.Compiler.TCO.pas` (`TAstTCO`)**: + * `RebuildFunctionCall` überschreiben, um den `IsTailCall`-Status basierend auf dem `FIsTailStack` korrekt zu setzen. \ No newline at end of file diff --git a/Doc/FMX-Styles 1.md b/Doc/FMX-Styles 1.md new file mode 100644 index 0000000..393a91d --- /dev/null +++ b/Doc/FMX-Styles 1.md @@ -0,0 +1,43 @@ + +## 📝 Projektplan: Refactoring der AST-Visualisierung (Architekturfokus) + +**Datum und Uhrzeit:** 03.11.2025 09:02:21 + +### 💡 Motivation: Entkopplung und Skalierbarkeit + +Die **aktuelle Implementierung** des AST Visualisierers in FireMonkey basiert auf einem Design mit **starker Kopplung** zwischen der **semantischen Logik** (Layout-Anordnung) und der **visuellen Darstellung** (Farben, Rahmen). Dies äußert sich in: + +1. **Visuelle Inflexibilität:** Die `TAuraNode.Paint`-Methode verwendet **Custom Drawing**, was die zentrale Steuerung visueller Eigenschaften (z.B. für einen Dark Mode oder Branding) über FMX Style-Dateien unmöglich macht. +2. **Architektonische Starrheit:** Die Ableitung einer FMX-Control-Klasse (`TAuraXxxNode`) für jeden AST-Knotentyp ist ein Verstoß gegen das **Open/Closed Principle** und macht die Einführung neuer Knotentypen unnötig aufwendig. + +Ziel des Refactorings ist die Trennung dieser Bedenken, um ein robustes, skalierbares System zu schaffen. + +--- + +### 🏛️ Architektur: Strategisches Schichtenmodell + +Die neue Architektur ersetzt die Vererbung durch **Komposition** und verteilt die Verantwortung auf drei Schichten: + +#### 1. FMX Style Aggregation (Visuelle Schicht) + +Diese Schicht übernimmt die komplette **visuelle Gestaltung** des äußeren Rahmens. + +* **`TAuraNode` (Control Shell):** Dient als generisches FMX-Control-Grundgerüst. Es erbt von `TStyledControl` und verwendet ein **Style-Lookup** basierend auf dem AST-Knotentyp (`constantstyle`, `ifexpressionstyle`, etc.). +* **Visuelle Eigenschaften:** Eigenschaften wie `BackgroundColor`, `BorderWidth` etc. sind nicht länger Felder in `TAuraNode`. Stattdessen werden sie über die **FMX Style Accessoren** (`GetStyleProperty`/`SetStyleProperty`) direkt in der geladenen FMX Style-Datei gespeichert und gelesen. +* **Style-Bindung:** Die `ApplyStyle`-Methode findet das primäre Style-Element (`TRectangle` mit `StyleName='background'`) und wendet die Style-Eigenschaften (Farbe, Dicke, Radius) auf dieses Element an, wodurch das Custom Drawing in `Paint` obsolet wird. + +--- + +#### 2. Logik-Aggregation (`INodeViewModel` / Semantische Schicht) + +Dieses Aggregat kapselt die gesamte Knoten-spezifische Logik (was einen `if`-Knoten von einem `lambda`-Knoten unterscheidet). + +* **`INodeViewModel`:** Das zentrale **Strategie-Interface**. Es definiert die Schnittstellen **`Setup(HostNode, ...)`** zur Erstellung des Layouts und **`CreateAst(HostNode)`** zur Rekonstruktion des AST-Knotens aus dem visuellen Zustand. +* **`TNodeViewModelRegistry`:** Eine Factory-Klasse, die zur Laufzeit das korrekte `INodeViewModel`-Objekt (z.B. `TIfExpressionViewModel`) basierend auf dem `TAstNodeKind` des aktuellen Knotens instanziiert. +* **`TNodeViewModelBase`:** Bietet Helfer-Methoden (`AddLabel`, `AddExpr` mit Rekursion), die es der `Setup`-Methode ermöglichen, das semantische Layout (z.B. die vertikale Anordnung von "if", "then" und "else" Labels und Kind-Knoten) zu erstellen, ohne FMX-Interna zu duplizieren. + +--- + +#### 3. Ergebnis (Zusammenfassung) + +Die Architektur trennt die **statische visuelle Gestaltung** (FMX Style) von der **dynamischen Layout-Logik** (`INodeViewModel`). Die generische Klasse `TAuraNode` wird zum Host, der die visuelle Schicht steuert und die Layout-Erstellung an die Logik-Schicht delegiert.