Files
TerminalBasic/PLAN.md
Chili Palmer 7e6fa6ea88 Phase 0: Referenzdokumente, Fehlerkatalog, Testkorpus, Ratatui-Spike
Entscheidungen festgehalten: TBVM bestaetigt und eingebettet in die
Executables; durchgaengig UTF-8 statt CP437 (dokumentierte Abweichung).

- docs/: Sprachreferenz, Forms-Referenz, Dateiformate, TBVM-Design
- tb-runtime::errors: klassischer Laufzeitfehler-Katalog (implementiert)
- tb-ui::screen: 80x25-Unicode-Zellenpuffer mit 16-Farben-Abbildung,
  Scrollbereich (VIEW PRINT), Letterboxing; Ratatui-Widget + Tests
- Spike: cargo run -p tb-ui --example spike (Farben, Unicode, Tasten, Maus)
- tests/compat/: erste Referenzprogramme mit byte-genauer Sollausgabe

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-01 16:36:45 +02:00

12 KiB
Raw Blame History

PLAN — Terminal Basic

Arbeitsplan für die Re-Implementierung des DOS-BASIC-Dialekts (1992) in Rust. Dieses Dokument wird fortgeschrieben: erledigte Punkte werden abgehakt, Entscheidungen mit Datum und Begründung festgehalten.

Konvention: [ ] offen · [x] erledigt · [~] in Arbeit


Leitplanken

  • Referenzverhalten schlägt Eleganz. Bei Zweifeln zählt das beobachtbare Verhalten des Vorbilds (inkl. Fehlercodes, Rundung, Formatierung), nicht das, was „richtiger" wäre. Abweichungen werden dokumentiert.
  • Markenrecht: Der Name des Vorbilds wird in Code, Doku und Artefakten nicht verwendet. Wir sprechen vom „Vorbild" bzw. „dem Dialekt".
  • Jede Phase endet mit lauffähigen Tests gegen eine wachsende Kompatibilitäts-Testsuite (Verzeichnis tests/compat, geplant).

Phase 0 — Exploration und Grundsatzentscheidungen

0.1 Sprach- und Bibliotheksreferenz rekonstruieren

  • [~] Sprachreferenz zusammentragen: Anweisungen, Funktionen, Operatoren, Typsystem (INTEGER, LONG, SINGLE, DOUBLE, STRING, CURRENCY, feste Strings, TYPE…END TYPE), Typ-Suffixe (% & ! # $ @), DEFINT-Familie, Sichtbarkeitsregeln (SHARED, COMMON, STATIC) → Grundgerüst in docs/sprachreferenz.md; Detailfragen (exaktes Verhalten) werden dort als TODO markiert
  • [~] Forms-/Steuerelemente-Referenz: Steuerelementtypen, Eigenschaften, Methoden, Ereignisse, Standardwerte, Fokus- und Z-Reihenfolge → Grundgerüst in docs/forms-referenz.md
  • [~] Dateiformate dokumentieren: Quelltext (.BAS), Formulare (.FRM, Textformat mit VERSION/Begin…End-Blöcken), Projekt (.MAK) → docs/dateiformate.md
  • Laufzeitfehler-Katalog (Codes + Meldungstexte) erfasst und als tb_runtime::errors implementiert (inkl. Tests)
  • [~] Testkorpus aufbauen: kleine Referenzprogramme, deren erwartete Ausgabe dokumentiert ist → erste Programme in tests/compat/, Harness folgt mit Phase 2 (tbdosc run + Ausgabevergleich)

0.2 VM-/Runtime-Entscheidung (Aufstellung der Optionen)

Anforderungen an die Ausführungsschicht: BASIC-Fehlersemantik (ON ERROR GOTO/RESUME mit ERR/ERL), GOSUB/RETURN, unterbrechbare Ausführung (Debugger-Einzelschritt, Strg+Untbr, ereignisgesteuerte Forms-Hauptschleife), dynamische Strings/Arrays mit BASIC-Semantik, serialisierbares Kompilat, gute Fehlerortung (Zeile/Spalte).

Option Vorteile Nachteile Eignung
1. Eigene Bytecode-VM in Rust („TBVM") Volle Kontrolle über Semantik (Fehlerbehandlung, GOSUB, Events, Suspend/Resume); Bytecode als .tbc serialisierbar; Debugger-Integration trivial (Zeileninfo im Bytecode); keine Fremdabhängigkeit Eigenaufwand für VM, GC/Refcounting für Strings/Arrays; „nur" Interpreter-Geschwindigkeit Empfohlen — Interpreter-Tempo genügt für 80×25-Programme bei Weitem
2. Tree-Walking-Interpreter Schnellster Weg zu ersten laufenden Programmen; ideal zum Validieren der Semantik Langsam; Debugger/Resume-Semantik unsauber; wäre später Wegwerfcode Optional als Bootstrap in Phase 1, dann ersetzen
3. WebAssembly-Ziel (wasmtime/wasmer) Ausgereifte VMs mit JIT (Cranelift); portables, standardisiertes Kompilat; Sandbox; theoretisch Browser-Ausführung BASIC-Semantik passt schlecht: ON ERROR/RESUME, GOSUB und unterbrechbare Ausführung müssen aufwendig transformiert werden (Relooper/State-Machine); Strings/Arrays komplett selbst verwalten; Debugging über zwei Ebenen; schwere Abhängigkeit Später als zweites Backend denkbar (gleiche IR), nicht als Start
4. Cranelift direkt (JIT auf nativen Code) Native Geschwindigkeit; Rust-eigenes Projekt, gut eingebettet Gleiche Semantik-Transformationsprobleme wie WASM; kein portables Kompilat; JIT auf allen drei Plattformen pflegen Nur falls Performance je Thema wird — unwahrscheinlich
5. LLVM-AOT (inkwell) Maximale Performance, echte Executables Sehr schwere Toolchain-Abhängigkeit (LLVM-Build je Plattform); lange Kompilierzeiten; Debugger/Edit-Run-Zyklus der IDE leidet massiv Ungeeignet für dieses Projekt
6. Transpilation auf fremde Skript-VM (Lua via mlua/piccolo) Ausgereifte VM mit GC geschenkt Semantik-Mismatch (Zahlentypen, Fehler-/Eventmodell, 1-basierte vs. BASIC-Arrays mit OPTION BASE); Fehlerortung und Debugger bilden schlecht ab Ungeeignet
7. Transpilation nach Rust (AOT) Native Binaries, keine VM Kein Interpretermodus → IDE-Kernfeatures (Direktfenster, Start ohne Build-Wartezeit, Debugger) praktisch unmöglich; Rust-Toolchain als Laufzeitvoraussetzung Ungeeignet als Primärziel

Entscheidung (2026-09-01, bestätigt): Eigene Stack-basierte Bytecode-VM (Option 1, TBVM), sowohl in der Entwicklungsphase als auch eingebettet in die Executables (tbdos-IDE und von tbdosc erzeugte Programme), damit der schnelle Edit-Run-Turnaround überall identisch ist. Die IR/Bytecode-Schicht wird sauber vom Interpreter getrennt, sodass später ein zweites Backend (WASM via Cranelift, Option 3) ergänzt werden kann, ohne das Frontend anzufassen. Für die Ausführungsgeschwindigkeit typischer Terminal-Programme ist ein Interpreter mehr als ausreichend; entscheidend sind Debugger-Fähigkeit, exakte Fehlersemantik und der schnelle Edit-Run-Zyklus der IDE.

  • Optionen aufstellen und bewerten (siehe Tabelle)
  • [~] Bytecode-Grobdesign: Stack-Maschine, Konstantenpool, Zeilentabelle für Diagnostik/Debugger, Aufrufkonventionen (SUB/FUNCTION vs. GOSUB) → Entwurf in docs/tbvm-design.md
  • [~] Speichermodell für Werte: Tagged Enum (kein NaN-Boxing); Refcounting für Strings/Arrays (kein Zyklenrisiko im Dialekt → Rc genügt) → Entwurf in docs/tbvm-design.md

0.3 Ratatui-/Terminal-Spike

Entscheidung (2026-09-01): Keine CP437-Emulation — der Textbildschirm ist durchgängig UTF-8/Unicode. Strings sind Unicode-Text, CHR$/ASC arbeiten auf Codepoints. Das ist eine bewusste Abweichung vom Vorbild und wird in der Sprachreferenz unter „Abweichungen" dokumentiert.

  • 80×25-Zellenpuffer (Zeichen + Farbattribut) als eigenes Widget rendern; kleinere Terminals: Hinweis „Terminal zu klein", größere: zentriert (Letterboxing) → tb-ui::screen, Demo: cargo run -p tb-ui --example spike
  • 16-Farben-Palette (Vordergrund 015, Hintergrund 07) auf ANSI-Indexfarben abgebildet; Blink-Attribut vorerst ignoriert (offen)
  • [~] Maus-Ereignisse (crossterm) und Sondertasten (F1F12, Alt-Kombis) im Spike sichtbar gemacht; systematischer Test unter Windows Terminal, gnome-terminal, iTerm2 steht aus
  • Ereignisschleifen-Architektur: Terminal-Events → Event-Queue → VM-Ticks

Phase 1 — Sprach-Frontend (tb-frontend)

  • Lexer inkl. Typ-Suffixe, Zeilennummern/Labels, REM/'-Kommentare, case-insensitive Keywords
  • AST für Module, Prozeduren, Anweisungen, Ausdrücke, Deklarationen
  • Parser (zeilenorientiert, fehlertolerant — die IDE prüft pro Zeile)
  • Semantik: Symboltabellen, implizite Deklaration, DEFINT-Regeln, Typprüfung und -konvertierung, OPTION EXPLICIT/OPTION BASE, Array-Dimensionierung (statisch/dynamisch, REDIM)
  • Diagnostik mit exakten Positionen und den Meldungstexten des Vorbilds
  • Meilenstein: kompletter Testkorpus parst und wird typgeprüft

Phase 2 — Bytecode und VM (tb-vm)

  • Bytecode-Format und Serialisierung (.tbc)
  • Codegenerator AST → Bytecode
  • Interpreter: Ausdrücke, Kontrollfluss (IF, SELECT CASE, Schleifen, GOTO/GOSUB), Prozeduraufrufe, BYREF-Semantik
  • Fehlerbehandlung: ON ERROR GOTO/RESUME, ERR/ERL, Fehlerkaskaden
  • Unterbrechbarkeit: Tick-Grenzen, Breakpoints, Einzelschritt, Variableninspektion (Grundlage für IDE-Debugger)
  • Meilenstein: Konsolen-Testkorpus läuft mit korrekter Ausgabe (tbdosc run)

Phase 3 — Laufzeitbibliothek (tb-runtime) und Bildschirm (tb-ui::screen)

  • Strings: LEFT$, MID$ (auch als Anweisung), INSTR, STR$/VAL, SPACE$, STRING$, LTRIM$/RTRIM$, UCASE$/LCASE$
  • Zahlenformatierung: PRINT-Zonen, PRINT USING (vollständig), Banker's Rounding, CINT/CLNG/CSNG/CDBL/CCUR
  • Mathematik: RND/RANDOMIZE (kompatibler PRNG!), trigonometrische Funktionen, Integer-Überlaufverhalten (Fehler 6)
  • Datei-E/A: OPEN (sequenziell/random/binär), INPUT#/LINE INPUT#, PRINT#/WRITE#, GET/PUT mit Record-Typen, EOF/LOF/SEEK, Pfadsemantik plattformübergreifend
  • Bildschirm: PRINT, LOCATE, COLOR, CLS, INPUT, INKEY$, CSRLIN/POS, WIDTH, VIEW PRINT auf dem Zellenpuffer
  • Meilenstein: klassische Konsolenprogramme laufen unverändert

Phase 4 — Forms-Engine (tb-ui::forms)

  • Formular-Modell: Eigenschaften, Lade-/Entladezyklus, SHOW/HIDE (modal/nicht-modal)
  • Steuerelemente: CommandButton, TextBox, ListBox, ComboBox, CheckBox, OptionButton, Frame, Label, HScrollBar/VScrollBar, PictureBox (Text), Timer — mit allen Eigenschaften/Methoden/Ereignissen des Vorbilds
  • Menüsystem (Menüleiste, Shortcuts, Access Keys)
  • Fokus-/Tab-Reihenfolge, Access-Keys, Maussteuerung
  • .FRM-Dateiformat lesen/schreiben (Kompatibilität zu Originaldateien)
  • Ereignisdispatch: Event-Queue ↔ VM (Ereignisprozeduren Name_Ereignis)
  • Meilenstein: Beispiel-Formularprogramme aus dem Testkorpus laufen

Phase 5 — IDE (tb-ide)

  • IDE-Rahmen: Menüleiste, MDI-artige Fensterverwaltung, Statuszeile, klassisches Farbschema
  • Editor: Syntaxprüfung/-normalisierung pro Zeile (Keywords groß, Leerzeichen), Suchen/Ersetzen, Hilfe-Verweise
  • Projektverwaltung (.MAK): mehrere Module/Formulare
  • Formular-Designer: Steuerelemente platzieren/verschieben/skalieren, Eigenschaftenfenster
  • Ausführen aus der IDE: Start/Unterbrechen/Fortsetzen/Neustart
  • Debugger: Breakpoints, Einzelschritt/Prozedurschritt, Direktfenster, Überwachungsausdrücke
  • Meilenstein: Programm komplett in der IDE schreiben, gestalten, debuggen und ausführen

Phase 6 — Kompatibilität, Politur, Distribution

  • Kompatibilitäts-Testsuite ausbauen (Snapshot-Tests der Bildschirmausgabe)
  • Plattformtests: Windows Terminal, Linux (mind. 2 Emulatoren), macOS
  • Performance-Pass über die VM (nur falls nötig)
  • tbdosc build → binäres Ergebnis: .tbc-Bytecode bzw. eigenständig ausführbares Programm (Bytecode + eingebetteter Runner)
  • Dokumentation: Sprachreferenz, Migrationshinweise, Beispielprogramme
  • CI (GitHub Actions: Build + Tests auf allen drei Plattformen), Releases

Offene Fragen

  • Umgang mit CURRENCY (@): als i64-Festkomma (×10 000) — klären, ob das Vorbild ihn überhaupt in allen Kontexten unterstützt
  • ISAM-Dateiunterstützung des Vorbilds: nachbilden oder als Nicht-Ziel erklären?
  • PEEK/POKE/CALL INTERRUPT u. ä. Hardware-Nähe: sinnvolle Teilmenge emulieren (z. B. Bildschirmspeicher B800) oder Laufzeitfehler?
  • Unicode-Zeichen mit Darstellungsbreite ≠ 1 (Emoji, CJK): das Zellenmodell ist strikt 1 Zeichen = 1 Zelle. Breite Zeichen ablehnen (Fehler 5), ersetzen oder 2 Zellen belegen?
  • GET/PUT mit Record-Typen unter UTF-8: feste Strings (STRING * n) waren im Vorbild n Bytes — bei uns n Zeichen. Binärlayout der Records festlegen (Vorschlag: UTF-8 mit Padding auf feste Bytelänge? Oder UTF-32?)
  • Blink-Attribut (COLOR mit Vordergrund 1631): ignorieren, als „hell" darstellen oder echtes Terminal-Blink nutzen (nicht überall unterstützt)?
  • Lizenzwahl (MIT im Rahmen angenommen — bestätigen)