4.2 KiB
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 TBoundFunctionCallNodes (aus Phase 2) fälschlicherweise in TFunctionCallNodes (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 denTAstTransformer(inMyc.Ast.Visitor.pas), indem wir virtuelleRebuild...-Methoden (z.B.RebuildFunctionCall) einführen. - Implementierung: Die
Visit...-Methoden des Transformers rufen nicht mehrTAst.FunctionCallauf, sondernSelf.RebuildFunctionCall. Alle unsere Phasen (Binder, Lowerer, TCO) überschreiben dieseRebuild...-Methoden und stellen sicher, dass der korrekteTBound...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 FeldIsTailCall(Phase 5) initialisieren).
- Architektur: Die Datenstruktur bleibt "schmutzig". Implementierungsdetails bluten weiterhin durch (z.B. muss der
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 reinerIAstVisitor. - Implementierung:
TAstBinder(Phase 2) konsumiertIAstNodeund produziertIBoundNode(enthält nurAddress,IsBoxed).TTypeChecker(Phase 3) konsumiertIBoundNodeund produziertITypedNode(enthält zusätzlichStaticType).- (usw. für Lowering und TCO)
- Die neuen Knoten (
TBoundNode,TTypedNode) nutzen Aggregation und dasimplements-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 TypAin TypBzu überführen, selbst wenn 19 davon nur "Durchreicher" sind.
TODO (Nächste Schritte für Pfad 1)
Gemäß deiner Entscheidung probieren wir Pfad 1.
Myc.Ast.Visitor.pas(TAstTransformer):VisitFunctionCall,VisitLambdaExpression,VisitVariableDeclarationundVisitRecordLiteral(die Knoten, dieTBound...-Typen haben) so umbauen, dass sievirtual Rebuild...-Methoden aufrufen.
Myc.Ast.Binding.pas(TAstBinder):Rebuild...-Methoden überschreiben, umTBound...Node-Instanzen zu erzeugen (undIsTailCall=Falsezu setzen).
Myc.Ast.Lowering.pas(TAstLowerer):Rebuild...-Methoden überschreiben, umTBound...Node-Instanzen zu erhalten (undIsTailCallvom Original zu kopieren).
Myc.Ast.Compiler.TCO.pas(TAstTCO):RebuildFunctionCallüberschreiben, um denIsTailCall-Status basierend auf demFIsTailStackkorrekt zu setzen.