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.
2.9 KiB
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):
Xmuss einTupleoder einBlocksein.- Die Elemente von
Xwerden flach in die Ziel-Sequenz eingefügt.
- In Records (Map):
Xmuss eineMapsein.- Die Key-Value-Paare von
Xwerden mit der Ziel-Map verschmolzen (Merging).
- Fehlverhalten: Falls
Xkein 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:
- Origin-Tracking: Er behält die
Identity(Span/NodeId) des ursprünglichen Aufrufs. - Transparenz: Die UI kann im Fehlerfall auf den High-Level-Block verweisen, während der Compiler den hocheffizienten, expandierten Code sieht.
- Visualisierung: Er ermöglicht ein "Aufklappen" von Makro-Blöcken in der GUI, um die innere Funktionsweise des expandierten Codes zu inspizieren.