Files
RustAst/docs/CompileStages.md
T
Michael Schimmel 494bf554d2 Old Docs added
2026-02-20 10:09:22 +01:00

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 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.