5.5 KiB
Context
SourceUnit::parse erhält Segmentherkunft. tb-vm/src/project.rs::compile_project parst heute alle Module, löst Exportdeklarationen und Konstanten auf, senkt sie erneut ab und verknüpft alles. Es gibt keinen inkrementellen Cache und keine Editor-Normalisierung. Das bestehende Budget steht in bytecode-kompilat und docs/tbvm-design.md. Dokumente und UI stammen aus 01/02.
Goals / Non-Goals
Goals: Text und Diagnose identisch zur bestehenden Sprache; nur tatsächlich betroffene Module erneut übersetzen; Quellorte bis zur Diagnose erhalten.
Non-Goals: LSP, fremder Editorprozess, neuer BASIC-Parser, Rope ohne gemessenen Bedarf, teure Optimierung oder Live-Patching einer laufenden VM.
Decisions
- Ein dokumentbezogener Textpuffer mit Edit-Operationen reicht zunächst. Cursor/Selektion werden an Unicode-Grenzen geführt; Bildschirmspalten verwenden die vorhandene Unicode-Breitenlogik. Zusammengesetzte Aktionen (Paste, Replace All, Normalisierung, Prozedurerzeugung) sind eine Undo-Einheit. Die Zwischenablage ist IDE-intern verlässlich; ein späterer Betriebssystemadapter ist keine Voraussetzung für CUA-Kopieren zwischen IDE-Fenstern.
- Normierung nutzt Tokenarten und Quellspannen des vorhandenen Frontends, keinen Regex-Ersatz auf dem gesamten Text. Nur eindeutig erkannte Keywords/Trennräume werden geändert; Strings, Kommentare, DATA und Typ-Suffixe bleiben erhalten. Token-/AST-Vergleich der Vorher-/Nachher-Programme prüft Semantikerhalt. Unvollständige Konstrukte werden durch den bestehenden Parserkontext als unfertig markiert, nicht mit einem zweiten permissiven Parser ausgeführt. Line Leave aktualisiert den betroffenen Modulstand; ein noch unvollständiges Modul bleibt nicht startbar.
- Prozedurwahl zeigt Modulrumpf und SUB/FUNCTION-Einträge. Shift+F2 öffnet die Auswahl, Ctrl+F2 kehrt zur vorherigen Codeposition zurück. Die in der Spec konkretisierten Ctrl+Q-Chords sind Projektvorgaben für die in der Referenz nur allgemein genannte WordStar-Familie. Suchdialoge arbeiten zunächst auf dem aktiven Dokument oder dessen Auswahl; Projektweitsuche ist kein Phase-5-Punkt. Auswahl-Suche und F3 nutzen denselben Suchzustand.
- Generierte DECLARE-Zeilen liegen in einem eindeutig kommentierten IDE-Bereich und werden signaturbasiert gepflegt. Vorhandene explizite passende Deklarationen gewinnen; widersprüchliche Handdeklarationen werden diagnostiziert. Der Speicherhook schreibt niemals einen nur teilweise aktualisierten deklarativen Vorspann. Unfertiger oder fehlerhafter Quelltext bleibt ausdrücklich speicherbar: dann wird die automatische DECLARE-Pflege vollständig übersprungen und erklärt, während der eingegebene Text unverändert als Entwurf gespeichert wird. DEFtype-Übernahme verwendet die am Erzeugungsort gültigen Vorgaben und erzeugt keine doppelten Header. FRM-Code benutzt denselben Hook.
- Ein Cache innerhalb des vorhandenen Projektcompilers speichert Parsing und unverkettete Modulprodukte. Schlüssel umfassen Dokument-/Include-Inhalte, Modulidentität, Compilerkonfiguration, importierte öffentliche Vertragsinhalte und Forms-Metadaten. Abhängigkeiten folgen tatsächlicher Namensauflösung einschließlich CONST, TYPE, COMMON, DECLARE und Formularnamen. Private Rumpfänderungen invalidieren keine unabhängigen Module; Exportänderungen invalidieren transitive Verbraucher. Unsichere oder zuvor fehlerhafte Abhängigkeitsauflösung führt konservativ zur betroffenen vollständigen Neuauflösung, nicht zu einem vermeintlich gültigen alten Ergebnis.
- Der vorhandene Linker verknüpft gecachte unverkettete Produkte neu und remappt alle Slot-, Typ-, Prozedur-, String-, DATA-, Objekt- und Quell-IDs. Bereits verknüpfte Produkte werden nicht durch Feldpatches wiederverwendet. Der bisherige Vollcompile bleibt als Vergleichspfad und CLI-Einstieg erhalten. Kein dauerhaftes Cache-Dateiformat.
- Jede Diagnose und jedes Ergebnis gehört zu einem vollständigen Projektrevisionssatz. Start akzeptiert nur den aktuellen Satz; Compilefehler machen einen alten Erfolg nicht aktuell. Editieren während Break erzeugt eine neue Revision; die Laufentscheidung liegt bei 04. Ein einzelner UI-Prozess kann zunächst synchron auf Line Leave kompilieren, solange das bestehende Budget eingehalten wird; Hintergrund-Compiler und Cancellation werden nicht vorsorglich gebaut.
- Tests vergleichen Voll-/Cachepfad für private Änderungen, Includes, transitive Konstanten, Typ-/COMMON-Änderungen, Entfernen/Umordnen von Modulen und Forms-Arrayänderungen. Zähler belegen Wiederverwendung; Benchmarks messen inklusive Invalidierung/Link mit dem vorhandenen Referenzprojekt. Keine fragile Millisekunden-Assertion in normalen Debug-CI-Tests.
Risks / Trade-offs
- Verdeckte Deklarationsabhängigkeit → Export-/Importsignaturen aus realer Auflösung, Differentialtests gegen frischen Compile; bei Zweifeln sicher neu auflösen.
- Fehlerdialog beim unfertigen Block → zwischen unvollständig und eindeutig ungültig unterscheiden; Abbrechen lässt den Text stehen.
- Textnormalisierung verändert Programme → geschützte Tokenklassen und Idempotenz-/Semantiktests, bei uneindeutigem Fragment keine Normalisierung.
- Einfacher Textpuffer wird teuer → erst bei verfehltem Referenzbudget eine andere Datenstruktur erwägen.
Migration Plan
Vollcompiler als Referenz beibehalten, Cache optional dazuschalten und mit denselben Quellen vergleichen. Generierte DECLARE-Blöcke sind normale BASIC-Kommentare und Deklarationen; Quellen bleiben mit der CLI lesbar. Cacheverlust bedeutet nur Neuübersetzung.