94fc6bf56d
This commit introduces support for AST macros and templates, enabling users to define and use custom, reusable components within the visual DSL. Key changes include: - A new `MacroRegistry` to manage macro definitions. - A `MacroExpander` to process macro calls and expand templates. - A `MacroEvaluator` trait for evaluating expressions during expansion. - The `Expansion` node in `BoundKind` to preserve the original macro call and its expanded form for debugging. - Updates to the `Binder`, `Dumper`, and `UpvalueAnalyzer` to handle the new macro constructs. - New examples demonstrating various macro functionalities like `unless`, splicing, and nested macros.
49 lines
2.9 KiB
Markdown
49 lines
2.9 KiB
Markdown
# AST Macros & Templates (Portierung von Delphi nach Rust)
|
|
|
|
Dieses Dokument beschreibt die Architektur und Nomenklatur für das Makro- und Template-System im Rust-AST-Compiler.
|
|
|
|
## 1. Motivation: Warum Makros in einer visuellen DSL?
|
|
|
|
In einer visuellen DSL dienen Makros als **Benutzerdefinierte Komponenten**. Ein User baut einen Graphen (den Body), definiert Eingänge (Placeholder) und deklariert dieses Template unter einem Namen. Bei der Kompilierung wird dieses Template an den Aufrufstellen "expandiert".
|
|
|
|
**Vorteile:**
|
|
- **Abstraktion:** Komplexe Logik wird hinter einem einzigen Block in der UI versteckt.
|
|
- **Wiederverwendbarkeit:** Einmal deklarierte Finanz-Indikatoren können überall eingesetzt werden.
|
|
- **Kompilierzeit-Optimierung:** Strukturelle Transformationen (z.B. Loop-Unrolling) können über Makros abgebildet werden.
|
|
|
|
## 2. Nomenklatur (Visuelle Ebene statt Lisp-Ebene)
|
|
|
|
Um die Kluft zwischen Text-Logik (Lisp) und visueller Logik zu schließen, wurde folgende Nomenklatur gewählt:
|
|
|
|
| Konzept | Name in Rust | Funktion |
|
|
| :--- | :--- | :--- |
|
|
| `akMacroDefinition` | `MacroDecl` | Deklariert ein benanntes Template als Compiler-Erweiterung. |
|
|
| `akQuasiquote` | `Template` | Ein Rahmen (Sub-Graph), in dem Placeholder ersetzt werden können. |
|
|
| `akUnquote` | `Placeholder` | Ein "Loch" oder "Input-Pin" innerhalb eines Templates. |
|
|
| `akUnquoteSplicing` | `Splice` | Ein spezialisierter Placeholder, der Inhalte "auspackt" und verschmilzt. |
|
|
| `akMacroExpansion` | `Expansion` | Ein Hybrid-Knoten, der den Original-Aufruf und das Ergebnis speichert. |
|
|
|
|
## 3. Semantik von "Splice" (Die Verschmelzung)
|
|
|
|
Ein `Splice(X)`-Knoten löst die äußere Hülle von $X$ auf und fügt dessen Elemente direkt in den Ziel-Container ein.
|
|
|
|
### 3.1 Striktes Verhalten (Entscheidung)
|
|
|
|
In dieser Implementierung gilt ein **striktes** Splicing. Das bedeutet, dass $X$ zur Kompilierzeit als Container erkannt werden muss.
|
|
|
|
- **In Sequenzen (Tuple / Block):**
|
|
- $X$ muss ein `Tuple` oder ein `Block` sein.
|
|
- Die Elemente von $X$ werden flach in die Ziel-Sequenz eingefügt.
|
|
- **In Records (Map):**
|
|
- $X$ muss eine `Map` sein.
|
|
- Die Key-Value-Paare von $X$ werden mit der Ziel-Map verschmolzen (Merging).
|
|
- **Fehlverhalten:** Falls $X$ kein unterstützter Container ist (z.B. eine Konstante oder ein If-Ausdruck), bricht der Compiler mit einem Fehler ab. Dies verhindert logische Inkonsistenzen im Makro-Design.
|
|
|
|
## 4. Transparenz & Debugging (Der Expansion-Knoten)
|
|
|
|
Der `Expansion`-Knoten ist das Herzstück für ein sauberes User-Erlebnis:
|
|
|
|
1. **Origin-Tracking:** Er behält die `Identity` (Span/NodeId) des ursprünglichen Aufrufs.
|
|
2. **Transparenz:** Die UI kann im Fehlerfall auf den High-Level-Block verweisen, während der Compiler den hocheffizienten, expandierten Code sieht.
|
|
3. **Visualisierung:** Er ermöglicht ein "Aufklappen" von Makro-Blöcken in der GUI, um die innere Funktionsweise des expandierten Codes zu inspizieren.
|