Phase 3 (Kern): Laufzeitbibliothek, Bildschirm und Datei-E/A

Setzt den OpenSpec-Change phase-3-runtime-bildschirm um (77/77 Aufgaben).
Abdeckung laut Inventar: 195 implementiert, 37 offen, 53 Non-Feature.

Vollstaendigkeits-Inventar
- docs/inventar.md mit 285 Eintraegen aus den Themenlisten von
  bas7advr.hlp und qb45advr.hlp, je mit Status und Fundstelle
- crates/tb-frontend/tests/inventar.rs haelt die Tabelle in beide
  Richtungen gegen den Code; der Abdeckungsstand kann nicht veralten

Bruchschritt (Puffer, Host, Korpus)
- Cell/TextScreen ziehen ratatui-frei nach tb-runtime::screen; tb-ui
  behaelt Farbabbildung, Widget und den neuen Terminal-Host
- Host wechselt vom Zeichenstrom auf Anzeige des Zellenpuffers plus
  Ereignisse (Taste, Groessenaenderung, Abbruch)
- Korpusvergleich auf getrimmten Bildschirm-Snapshot; die acht
  bestehenden Sollausgaben blieben dabei unveraendert

Groessenunabhaengigkeit
- 80x25 ist nirgends mehr eine feste Grenze; Groessenaenderungen waehrend
  der Ausfuehrung werden zugestellt (Inhalt oben links erhalten, Cursor
  und VIEW PRINT geklemmt)
- Korpusnachweis: dasselbe Programm bei 80x25 und 120x40 mit je eigener
  Sollausgabe, plus ein Programm mit Groessenwechsel mitten im Lauf

Bibliothek
- Breite Unicode-Zeichen belegen zwei Zellen (Cursor, POS, Randumbruch)
- Bildschirm: CLS, COLOR, LOCATE, WIDTH, VIEW PRINT, SCREEN, CSRLIN, POS
- Tastatur: INKEY$, INPUT$, Funktionstasten-Makros (KEY n / LIST / ON)
- PRINT USING, LPRINT USING, FORMAT$, SetFormatCC
- Mathematik mit kompatiblem PRNG (gleiche Saat, gleiche Folge)
- Datum und Zeit mit Serienwerten ab 1899
- Finanzmathematik: FV#, PV#, Pmt#, IPmt#, PPmt#, NPer#, Rate#, NPV#,
  IRR#, MIRR#, SLN#, SYD#, DDB#
- Datei-E/A: sequenziell, RANDOM (Recordpuffer und UDT-Variablen),
  BINARY, FIELD/LSET/RSET, Statusfunktionen, Dateisystem, MK$/CV
- System: ENVIRON, FRE, CLEAR, TRON/TROFF, STACK, ERDEV, ERR-Anweisung

Altlasten aus Phase 2
- ON ERROR GOTO auf Modulebene ist aus Prozeduren ansprechbar
  (prozeduruebergreifender Fixup im Codegenerator)
- DATA behaelt seinen Rohtext (Gross-/Kleinschreibung, innerer Leerraum)
- Die vier TODO-verify-Zellen der Konvertierungsmatrix sind aufgeloest

Vom Inventar aufgedeckte Fehler
- Zwoelf Non-Features wies der Compiler entgegen der Phase-1-Spec nicht
  ab (CALLS, SSEG, POINT, VIEW, COM, PEN, STRIG, STICK, die
  String*-Routinen, LINE und OPEN "COMn:") -- geschlossen
- Drei Gruppen fehlten im urspruenglichen Umfang: Finanzmathematik,
  Record-Konvertierung, Rest der Dateisystemfunktionen
- bas7advr.hlp allein ist keine vollstaendige Quelle; das Inventar
  bildet die Vereinigung mit qb45advr.hlp

Neue Changes
- phase-3-isam: schliesst Phase 3 ab (Speicherschicht redb)
- phase-3-ortszeit: zieht die UTC-Abweichung zurueck

Neue Abhaengigkeit: unicode-width.
Dokumentiert: sprachreferenz.md und tbvm-design.md sind TODO-frei,
docs/bibliothek.md neu, PLAN.md fortgeschrieben.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-04 06:54:19 +02:00
parent a6f005d023
commit 52ccbb5848
94 changed files with 10421 additions and 792 deletions

View File

@@ -235,10 +235,97 @@ pub enum Builtin {
PrintTab,
PrintSpc,
PrintNewline,
PrintUsing,
FormatS,
SetFormatCc,
// Bildschirm (Anweisungen)
Cls,
Color,
Locate,
Width,
ViewPrint,
ScreenStmt,
KeyAssign,
KeyList,
KeyDisplay,
// Bildschirm (Funktionen)
Csrlin,
PosFn,
ScreenFn,
// Tastatur
InkeyS,
InputS,
// System
EnvironS,
EnvironSet,
Fre,
Clear,
Tron,
Troff,
StackFn,
StackStmt,
Erdev,
ErdevS,
// Datei-E/A
Open,
Close,
CloseAll,
PrintZiel,
WriteFile,
EofF,
LofF,
LocF,
SeekF,
SeekStmt,
Freefile,
Fileattr,
LockStmt,
Kill,
NameStmt,
Files,
Chdir,
Chdrive,
Mkdir,
Rmdir,
CurdirS,
DirS,
Lpos,
ShellStmt,
ShellFn,
MkS,
CvF,
// Finanzmathematik
Fv,
Pv,
Pmt,
NPer,
IPmt,
PPmt,
Rate,
Npv,
Irr,
Mirr,
Sln,
Syd,
Ddb,
// Sonstiges
Timer,
DateS,
TimeS,
DateSet,
TimeSet,
Now,
DateSerial,
TimeSerial,
DateValue,
TimeValue,
DayF,
MonthF,
YearF,
WeekdayF,
HourF,
MinuteF,
SecondF,
CommandS,
Doevents,
Sleep,
@@ -365,7 +452,29 @@ pub enum HStmtKind {
/// Endet die Anweisung mit `;`/`,` (kein Zeilenumbruch)?
trailing: bool,
},
/// `FIELD #n, laenge AS var$, …` — Recordpuffer in Felder aufteilen.
Field {
file: HExpr,
fields: Vec<(HExpr, HPlace)>,
},
/// `LSET`/`RSET` — links- bzw. rechtsbündig zuweisen; ist das Ziel ein
/// `FIELD`-Feld, wirkt die Zuweisung zugleich auf den Recordpuffer.
LsetRset {
rset: bool,
target: HPlace,
value: HExpr,
},
/// `GET`/`PUT` auf einer Datei: Datensatz- bzw. Bytenummer und Ziel-
/// bzw. Quellvariable. Ohne Variable wirkt der Recordpuffer.
GetPut {
put: bool,
file: HExpr,
recnum: Option<HExpr>,
var: Option<HPlace>,
},
Input {
/// `INPUT #n` — Quelle ist eine Datei statt der Tastatur.
file: Option<HExpr>,
line_mode: bool,
prompt: Option<String>,
/// Fragezeichen nach dem Prompt (`;`-Form).
@@ -425,6 +534,8 @@ pub enum HStmtKind {
Resume(HResume),
/// `ERROR n`.
RaiseError(HExpr),
/// `ERR = n` — Fehlercode setzen, ohne einen Fehler auszulösen.
SetErr(HExpr),
Read(Vec<HPlace>),
/// Ziel als Index in `HirModule::data` (0 = Anfang).
Restore(u32),