docs
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
# Projektplan: Refactoring auf First-Class List Nodes
|
||||
|
||||
**Datum:** 29.11.2025 16:43
|
||||
|
||||
## 1. Motivation
|
||||
Aktuell werden Listen von Elementen im AST (z. B. Parameter in `Lambda`, Argumente in `Call`, Felder in `RecordLiteral`) als native Arrays (`TArray<T>`) innerhalb des Eltern-Knotens gespeichert. Dies führt zu signifikanten Problemen bei der Entwicklung des Projectional Editors:
|
||||
|
||||
1. **Fehlende Adressierbarkeit:** Eine Liste als `TArray` hat keine Identität (`IAstIdentity`) und keine Position. Sie kann im Editor nicht als Ganzes selektiert, fokussiert oder hervorgehoben werden.
|
||||
2. **Das "Leere-Liste"-Problem:** Wenn eine Liste leer ist, gibt es keinen visuellen Anker (wie einen Platzhalter zwischen Klammern), den der Benutzer anklicken kann, um das erste Element einzufügen.
|
||||
3. **Inkonsistente UI-Logik:** Jeder Handler (`LambdaHandler`, `CallHandler`, etc.) muss derzeit selbstständig Logik für Klammern `()`, Trennzeichen `,` und Layout implementieren. Dies führt zu Code-Duplizierung.
|
||||
4. **Komplexe Manipulation:** Operationen wie "Verschiebe Argument 2 an Position 1" oder "Lösche alle Parameter" sind schwierig umzusetzen, da die Logik fest im Eltern-Knoten verdrahtet ist und nicht an einen generischen Listen-Handler delegiert werden kann.
|
||||
5. **Record-Felder:** Aktuell sind Key-Value-Paare (`TRecordFieldLiteral`) reine Records, keine AST-Nodes. Sie können daher nicht einzeln selektiert oder per Drag & Drop verschoben werden.
|
||||
|
||||
Um einen robusten, wartbaren Editor zu gewährleisten, muss das Prinzip **"Alles, was sichtbar und manipulierbar ist, muss ein AST-Knoten sein"** konsequent angewendet werden.
|
||||
|
||||
## 2. Ziel
|
||||
Umbau der AST-Struktur und der Editor-Handler, um Listen und Record-Felder als eigenständige Knoten zu etablieren.
|
||||
|
||||
### Kernaufgaben:
|
||||
1. **AST-Erweiterung (`Myc.Ast.Nodes`):**
|
||||
* Einführung eines generischen Interfaces `INodeList<T: IAstNode>`.
|
||||
* Einführung spezifischer Listen-Typen zur Wahrung der Typsicherheit: `IParameterList`, `IArgumentList`, `IRecordFieldList`.
|
||||
* Einführung von `IRecordFieldNode` als Wrapper für Key-Value-Paare.
|
||||
* Erweiterung des `TAstNodeKind` Enums.
|
||||
|
||||
2. **Anpassung der Factories & Visitor (`Myc.Ast` & `Myc.Ast.Visitor`):**
|
||||
* Update der Factory-Methoden (z.B. `TAst.LambdaExpr`), um Listen-Nodes statt Arrays zu akzeptieren.
|
||||
* Erweiterung des `IAstVisitor` um Methoden für die neuen Knotentypen.
|
||||
|
||||
3. **Generischer UI-Handler (`Myc.Fmx.AstEditor.Handlers`):**
|
||||
* Implementierung von `TNodeListHandler<T>`, der das Rendering von Listen (Start-Zeichen, Trennzeichen, End-Zeichen, Layout) zentralisiert.
|
||||
* Implementierung der `IEditableNodeHandler`-Logik im Listen-Handler (Hinzufügen neuer Elemente).
|
||||
|
||||
4. **Refactoring existierender Handler:**
|
||||
* Vereinfachung von `TLambdaExpressionNodeHandler`, `TFunctionCallNodeHandler` und `TRecordLiteralNodeHandler` durch Delegation an den neuen `TNodeListHandler`.
|
||||
|
||||
## 3. Ergebnis
|
||||
* **Architektonische Konsistenz:** Der AST spiegelt die logische Struktur der Sprache und die visuelle Struktur des Editors 1:1 wider.
|
||||
* **Reduzierte Komplexität:** UI-Logik für Listen existiert nur noch einmal zentral im `TNodeListHandler`.
|
||||
* **Erweiterte Funktionalität:** Listen können nun selektiert, kopiert und geleert werden. Leere Listen sind durch ihre Klammern als Drop-Target für neue Elemente nutzbar.
|
||||
* **Typsicherheit:** Trotz generischer Implementierung im Editor bleibt die semantische Unterscheidung (Parameter vs. Argumente) im AST und Compiler erhalten.
|
||||
|
||||
## 4. Nächster Schritt
|
||||
Implementierung der Änderungen in `Myc.Ast.Nodes` (Definition der Interfaces `INodeList`, `IParameterList`, `IArgumentList`, `IRecordFieldList`, `IRecordFieldNode`) und Anpassung der `TAstNodeKind` Enumeration.
|
||||
@@ -0,0 +1,111 @@
|
||||
|
||||
# Architekturkonzept: Hybrid Projectional Financial Editor
|
||||
|
||||
## 1. Motivation und Zielsetzung
|
||||
Entwicklung einer Entwicklungsumgebung für Finanzanalysen (Backtesting, Indikatoren), die die Vorteile zweier Welten vereint:
|
||||
1. **Visuelle Programmierung (Blöcke):** Für die grobe Architektur, den Datenfluss und die Übersichtlichkeit. Vermeidet Syntaxfehler bei komplexen Verschachtelungen.
|
||||
2. **Textuelle Programmierung (S-Expressions):** Für mathematische Formeln und Detail-Logik. Ermöglicht schnelle Eingabe und präzises Editieren für Experten.
|
||||
|
||||
Das System verhält sich **reaktiv** (wie "Strudel" für Musik): Änderungen am Code oder an Parametern führen sofort zur Neuberechnung und Aktualisierung der Charts ("Live Coding").
|
||||
|
||||
---
|
||||
|
||||
## 2. Kern-Architektur (MVC)
|
||||
|
||||
Die Anwendung folgt strikt dem Model-View-Controller Muster, um Rendering von Logik zu trennen.
|
||||
|
||||
### Model (Der AST & Environment)
|
||||
* **Immutable AST:** Der Abstract Syntax Tree besteht aus unveränderlichen Interfaces (`IAstNode`). Jede Änderung erzeugt einen neuen Teilbaum.
|
||||
* **Environment (`TAstEnvironment`):** Hält den Laufzeit-Zustand (Variablen, definierte Makros) und führt den Code aus.
|
||||
* **Domain:** Spezialisierte Datentypen für Finanzen (`ISeries` für Zeitreihen, `TDecimal` für Währung).
|
||||
|
||||
### View (`TWorkspace` & `TEditorFrame`)
|
||||
* **Aufgabe:** Rein visuelle Darstellung. Kennt keine Logik, nur `TControl`-Hierarchien.
|
||||
* **Rendering:** Zeichnet Blöcke, Verbindungen und visuelle Container.
|
||||
* **Input:** Leitet Maus- und Tastatur-Events (Drag & Drop) an den Controller weiter.
|
||||
|
||||
### Controller (`TAstEditorController`)
|
||||
* **Aufgabe:** Das "Gehirn". Synchronisiert AST und View.
|
||||
* **Zustandsverwaltung:** Hält den aktuellen validen AST (`FCurrentAst`).
|
||||
* **Undo/Redo:** Speichert Snapshots des ASTs auf einem Stack (Memento Pattern).
|
||||
* **Reaktivität:** Feuert `OnChange` bei jeder Modifikation, um die Ausführungspipeline anzustoßen.
|
||||
|
||||
---
|
||||
|
||||
## 3. Der Hybride Editor-Ansatz
|
||||
|
||||
Das System entscheidet dynamisch, wie ein AST-Knoten dargestellt wird ("Smart Nodes").
|
||||
|
||||
### A. Die Makro-Ebene (Visuell)
|
||||
Strukturelle Elemente werden als grafische Blöcke dargestellt:
|
||||
* **Control Flow:** `If`, `Loop`, `Block` (do...end).
|
||||
* **Definitionen:** `VarDecl`, `MacroDef`.
|
||||
* **High-Level Funktionen:** `LoadCSV`, `Chart`, `Strategy`.
|
||||
|
||||
**Vorteil:** Der Benutzer erkennt die Topologie der Strategie auf einen Blick ("Code Folding" durch Visualisierung).
|
||||
|
||||
### B. Die Mikro-Ebene (Textuell / S-Expressions)
|
||||
Mathematische Ausdrücke und Parameter werden als Text (Lisp-artige Syntax) dargestellt und editiert.
|
||||
* Beispiel: Statt eines Baums aus 5 Boxen sieht der User ein Label: `(> Close (SMA Close 20))`.
|
||||
|
||||
### C. Drill-Down Editing (In-Place)
|
||||
Der innovative Kern des Editors. Wenn ein User einen Knoten bearbeitet (Doppelklick), öffnet sich ein Texteditor über dem Knoten.
|
||||
|
||||
1. **Shallow Printing:** Der Editor zeigt nicht den gesamten tiefen Baum als Text, sondern nutzt **Platzhalter** (`#ID`) für komplexe Unter-Knoten.
|
||||
* AST: `If(Condition, ThenBlock, ElseBlock)`
|
||||
* Text: `(if #1 #2 #3)`
|
||||
2. **Kontext:** Der Controller speichert in einem `TEditContext`, welcher AST-Knoten hinter `#1` steckt.
|
||||
3. **Navigation:** Der User kann `#1` mit dem Cursor ansteuern und per Shortcut (z.B. `Ctrl+Space`) "in-place" expandieren.
|
||||
* Text wird zu: `(if (> Close #4) #2 #3)`
|
||||
4. **Commit:** Beim Bestätigen (Enter) wird der Text geparst (`TAstParser`). Die Platzhalter werden durch die originalen, unveränderten AST-Knoten aus dem Kontext ersetzt.
|
||||
|
||||
**Vorteil:** Maximale Effizienz. Man editiert nur das, was man ändern will. Der Rest des Baumes bleibt vor versehentlichen Syntaxfehlern geschützt.
|
||||
|
||||
---
|
||||
|
||||
## 4. Reaktivität & Live Coding
|
||||
|
||||
Das System kompiliert und führt den Code permanent aus, nicht erst auf Knopfdruck.
|
||||
|
||||
### Reactive Pipeline
|
||||
1. **Änderung:** User zieht einen Block oder ändert eine Zahl.
|
||||
2. **Controller:** Baut neuen AST -> `OnChange`.
|
||||
3. **Runner:** Führt `FEnv.Run(NewAst)` aus.
|
||||
4. **UI Update:** Charts und Indikatoren werden neu gezeichnet.
|
||||
|
||||
### Number Scrubbing
|
||||
Benutzer können Zahlenwerte (Konstanten) mit der Maus "ziehen" (drücken + ziehen).
|
||||
* Der Controller aktualisiert den AST "live" (hochfrequent).
|
||||
* Der Chart verändert sich flüssig während der Mausbewegung.
|
||||
* Ermöglicht intuitives Finden von Parametern (z.B. "Welche SMA-Länge passt visuell am besten?").
|
||||
|
||||
### Code as UI (Widgets)
|
||||
Der Code kann UI-Elemente zurückgeben, die im REPL-Output gerendert werden.
|
||||
* `var len := Slider("Period", 10, 200)` erzeugt einen Schieberegler.
|
||||
* Bewegt man den Regler, wird das Skript mit dem neuen Wert für `len` erneut ausgeführt.
|
||||
|
||||
---
|
||||
|
||||
## 5. Technische Komponenten (Zusammenfassung)
|
||||
|
||||
| Komponente | Verantwortung |
|
||||
| :--- | :--- |
|
||||
| **`TAstPrettyPrinter`** | Wandelt AST-Knoten in S-Expressions (`(func arg1 arg2)`). Unterstützt "Shallow Printing" mit Platzhaltern. |
|
||||
| **`TAstParser`** | Wandelt S-Expressions zurück in AST-Knoten. Löst Platzhalter (`#ID`) über den `TEditContext` auf. |
|
||||
| **`TEditContext`** | Hält die Referenzen zwischen Text-Tokens (`#1`) und echten `IAstNode`-Instanzen während des Editierens. |
|
||||
| **`TRtlRegistry`** | Registriert Finanzfunktionen (`SMA`, `RSI`) und UI-Widgets (`Slider`, `Chart`). |
|
||||
| **`TAstEditorController`** | Orchestriert Edit-Vorgänge. Führt "Path Copying" durch, um den immutablen Baum nach einem Text-Edit zu aktualisieren. |
|
||||
|
||||
---
|
||||
|
||||
## 6. User Workflow Beispiel
|
||||
|
||||
1. **Struktur bauen:** User zieht `LoadCSV`, `VarDecl` (für SMA) und `Chart` als Blöcke in den Workspace.
|
||||
2. **Logik verfeinern:** User doppelklickt auf den Parameter des SMA.
|
||||
3. **Text Edit:** Ein kleines Popup erscheint. User tippt `(* 20 2)`.
|
||||
4. **Commit:** Aus dem Text wird ein Multiplikations-Knoten. Der Block zeigt nun `40` (oder die Formel).
|
||||
5. **Analyse:** Der Chart zeigt sofort den SMA(40).
|
||||
6. **Tuning:** User klickt auf die `20` im Text/Label, zieht die Maus nach rechts. Die Zahl steigt auf `25`. Der Chart aktualisiert sich in Echtzeit.
|
||||
7. **Refactoring:** User merkt, er braucht Logik. Er klickt auf den SMA-Block und drückt `Ctrl+Space` (Wrap in...). Wählt `If`.
|
||||
* Der SMA ist nun das "Then"-Kind eines neuen If-Blocks.
|
||||
* Die Struktur wurde geändert, ohne Text kopieren zu müssen.
|
||||
Reference in New Issue
Block a user