OpenSpec: phase-3-runtime-bildschirm archiviert, Delta-Specs gesynct

Zwei neue Capabilities in den Hauptspecs:
- datei-eio: Dateiverwaltung, drei Zugriffsarten, UTF-32-Festtextfelder,
  Recordkonvertierung, Sperren, Dateisystem-Anweisungen
- sprachinventar: das Vollstaendigkeits-Inventar als pruefbares Artefakt

Fortgeschrieben: textbildschirm (Doppelzellen, Groessenunabhaengigkeit,
Bildschirmanweisungen), konsolen-basisbibliothek (Host-Neuschnitt, volle
String-/Format-/Datums-/Finanzbibliothek), kompat-testkorpus
(Snapshot-Vergleich, Nachweis der Groessenunabhaengigkeit),
sprach-frontend (Signaturpflicht, ON-ERROR-Scoping, DATA-Rohtext).

Bilanz: +32 Anforderungen, 6 geaendert, 1 ersetzt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-04 06:55:02 +02:00
parent 52ccbb5848
commit d0461bea34
17 changed files with 700 additions and 40 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-03

View File

@@ -0,0 +1,287 @@
## Context
Siehe proposal.md — Why. Technisch entscheidend ist der Ist-Zustand
dreier Stellen:
- `tb-ui::screen::TextScreen` (385 Zeilen) trägt die Bildschirmsemantik
bereits vollständig: `cls`, `set_color`, `locate`, `csrlin`, `pos`,
`view_print`, `cell`, `print`, `scroll_up`, `resize`. Ratatui kommt
darin an genau zwei Stellen vor: `basic_color()` (4 Zeilen) und
`impl Widget for &TextScreen` (~35 Zeilen).
- `tb-runtime::host::Host` ist ein Stream-Trait (`write(&str)`,
`read_line()`). `tb-runtime` und `tb-ui` sind beide Blätter im
Abhängigkeitsgraphen und treffen sich erst in `tb-cli`/`tb-ide`.
- Rund 50 dokumentierte Elemente besitzen im Frontend eine Signatur in
`builtin_fn`/`builtin_stmt`, senken aber auf `HStmtKind::Unsupported`
bzw. `HExpr::Unsupported` ab → Opcode `0x05` → Laufzeitfehler 73.
Zwei Entscheidungen vom 2026-09-03 rahmen die Arbeit: Das Windowing wird
— wie beim Vorbild — vom erzeugten Programm mitgebracht und nicht von der
IDE, sodass Forms und `PRINT` in denselben Zellenpuffer zeichnen. Die
Forms-Engine selbst bleibt dabei am von PLAN.md vorgesehenen Ort
`tb-ui::forms`.
## Goals / Non-Goals
**Goals:**
- Der Zellenpuffer liegt dort, wo sowohl die Laufzeitbibliothek als auch
die spätere Forms-Engine in `tb-ui` ihn erreichen, ohne dass die
Ausführungsschicht eine Terminal-Bibliothek zieht.
- Bildschirmverhalten ist ohne Terminal automatisiert prüfbar.
- Die Abdeckung misst sich selbst statt gepflegt zu werden.
- Die Umstellung der acht bestehenden Golden Files geschieht in einem
nachvollziehbaren, einmaligen Schritt.
**Non-Goals:**
- Optimierung der Bildschirmausgabe (Diff-Minimierung, Teilaktualisierung)
— erst wenn Messungen sie verlangen.
- Ein Rendering-Backend jenseits des Terminals.
- Die Forms-Engine selbst (Phase 4, `tb-ui::forms`); dieser Change
liefert ihr nur die Zeichenfläche.
## Decisions
### D1: Zellenpuffer nach `tb-runtime::screen`, ratatui-frei
`Cell` und `TextScreen` ziehen unverändert nach `tb-runtime::screen`.
`basic_color()` und `impl Widget` bleiben in `tb-ui` und arbeiten künftig
auf dem Runtime-Typ.
*Warum:* `PRINT`, `LOCATE`, `CLS`, `COLOR`, `CSRLIN`, `POS` und die
Funktionsform von `SCREEN` sind Elemente der Laufzeitbibliothek. Sie
müssen den Puffer erreichen, ohne dass `tb-runtime` eine
Terminal-Bibliothek zieht — sonst braucht jeder VM- und Bibliothekstest
ein Terminal. Das trägt die Entscheidung allein.
*Verhältnis zur Forms-Engine:* Forms bleibt laut PLAN.md in
`tb-ui::forms` (Entscheidung 2026-09-03). Das passt zur Richtung: `tb-ui`
hängt künftig an `tb-runtime` und zeichnet von oben in denselben Puffer
wie `PRINT` — ein `MSGBOX` über einer Konsolenausgabe überdeckt deren
Zellen und gibt sie beim Schließen zurück. Läge der Puffer weiterhin in
`tb-ui`, wäre genau diese gemeinsame Fläche für die Bibliothek
unerreichbar. Umgekehrt entsteht kein Zyklus: die Ausführungsschicht
erreicht die Forms-Engine über die Host-Schnittstelle (D2), die sie
selbst deklariert und `tb-ui` implementiert.
*Alternativen:*
- `tb-runtime` hängt an `tb-ui`: null Doppelung, aber ratatui und
crossterm landen in jedem VM-Test. Verworfen.
- Semantik bleibt in `tb-ui`, jeder Host führt einen eigenen Puffer:
dieselbe Scroll-/Umbruch-/Doppelzellenlogik dreimal. Verworfen.
*Aufwand:* Der Umzug ist mechanisch — betroffen sind der `use`-Block, die
zwei ratatui-Stellen und die Modulzuordnung. Die Semantik selbst wird
nicht angefasst; erweitert wird sie nur um die Doppelzellen (D4).
### D2: `Host` wird Bildschirm- statt Stream-Schnittstelle
`write`/`read_line` weichen einer Schnittstelle, die den Zellenpuffer zur
Anzeige übergibt und Ereignisse (Tastendruck, Größenänderung, Abbruch)
zurückliefert. Die Bibliothek schreibt nicht mehr in den Host, sondern in
den Puffer; der Host stellt dar.
*Warum:* `LOCATE 5,10`, `COLOR 14,1`, `CSRLIN` und besonders
`SCREEN(r,c)` — das ein Zeichen vom Bildschirm *zurückliest* — sind über
einen Zeichenstrom nicht ausdrückbar. Das ist ein Zwang, keine Präferenz.
*Wann dargestellt wird:* Der Host wird an denselben Tick-Grenzen
aufgerufen, an denen die VM heute schon die Abbruchprüfung macht, sowie
vor jeder blockierenden Eingabe. Kein zusätzlicher Mechanismus.
*Blockieren bleibt erlaubt* (Entscheidung D3 aus Phase 2 bleibt gültig):
`INPUT` und `INPUT$` blockieren im Host. Erst die Ereignisschleife der
Phase 4 bringt kooperative Zustellpunkte.
*Alternativen:*
- Stream-Host behalten und Bildschirmwirkungen als ANSI-Escapes
hindurchreichen: `CSRLIN`/`POS`/`SCREEN()` bräuchten trotzdem einen
Schattenpuffer, und der Capture-Host müsste ANSI parsen. Verworfen.
### D3: Korpusvergleich als getrimmter Snapshot
Die `.out`-Datei hält das Textbild des Puffers bis zur letzten belegten
Zeile und Spalte. Eine zweite Ebene mit Farbattributen kommt nur hinzu,
wenn das Programm `COLOR` verwendet.
*Warum getrimmt:* Ein voller 80×25-Snapshot für `hello.bas` wären 2000
Zeichen für zwei Zeichen Signal, und jeder Diff zeigte Rauschen. Getrimmt
bleiben die bestehenden acht Sollausgaben inhaltlich fast unverändert —
`PRINT`-only-Programme ergeben dasselbe Textbild wie bisher der Stream.
*Warum Attribute optional:* Programme ohne `COLOR` erzeugen sonst eine
zweite Ebene aus lauter identischen Werten.
*Umstellung:* Die acht Golden Files werden einmalig neu erzeugt und der
Diff wird geprüft — erwartet wird, dass sich nur Zeilen ändern, die
vorher auf `\r`/Umbruchverhalten beruhten. Ein unerwarteter Diff ist ein
Befund, kein Anpassungsgrund.
*Alternativen:*
- Zwei Harnesses (Stream für Alt-Tests, Snapshot für neue): dauerhaft
doppelte Infrastruktur für einen einmaligen Umstellungsschmerz.
Verworfen.
- Voller Snapshot: siehe oben. Verworfen.
### D4: Doppelzellen über Darstellungsbreite
Breite Zeichen belegen zwei Zellen: die erste trägt das Zeichen, die
zweite ist als Fortsetzung markiert. Neue Abhängigkeit `unicode-width`
in `tb-runtime`.
*Warum eine Abhängigkeit:* Die Breitentabelle folgt einem
Unicode-Annex und ändert sich mit jeder Unicode-Version; sie
nachzubauen hieße, sie dauerhaft nachzupflegen.
*Konsequenzen, die die Spec festhält:* Cursor rückt um zwei Spalten vor;
`POS` zählt die Anfangsspalte; ein breites Zeichen in der letzten Spalte
wird vollständig umgebrochen und die Spalte bleibt leer; `LOCATE` auf
eine Fortsetzungszelle wirkt auf den Zeichenanfang. Beim Überschreiben
einer Hälfte muss die andere geleert werden, sonst entstehen
Geisterzeichen.
### D4a: 80×25 ist nirgends eine Konstante
Anforderung des Projektinhabers (2026-09-03), Priorität für das ganze
Programm: 80×25 ist stets Synonym für „voller Bildschirm", nie eine feste
Grenze. Moderne Terminals haben keine feste Größe, und sie ändert sich
während der Ausführung.
*Konsequenz für die Umsetzung:* Kein Zweig darf gegen 80 oder 25
vergleichen. Die Abmessungen kommen ausschließlich aus dem Puffer
(`cols()`/`rows()`), abgeleitet aus der Darstellungsfläche. Betroffen
sind `CLS` (voller aktueller Bildschirm), der voreingestellte
Scrollbereich, die Umbruchspalte, die Scrollzeile sowie die
Grenzprüfungen von `LOCATE` und der Funktionsform von `SCREEN`.
*Größenänderung zur Laufzeit* ist damit kein Sonderfall, sondern der
Normalfall: Das Größenänderungsereignis kommt über den Host (D2), der
Puffer wird angepasst, Inhalt bleibt oben links, Cursor und
`VIEW PRINT`-Bereich werden geklemmt. Ein Bereich, der durch die
Verkleinerung leer würde, fällt auf den vollen Bildschirm zurück, statt
ungültig zu bleiben.
*Das Mindestmaß bleibt eine Darstellungsschranke:* Ist die Fläche kleiner
als 80×25, zeigt die Darstellungsschicht den Hinweis „Terminal zu klein"
(bestehende Entscheidung 2026-09-02). Das ist eine untere Schranke der
Anzeige, keine Bildschirmgröße für das Programm.
*Prüfbarkeit:* Der Test-Host bekommt seine Größe je Korpusprogramm
explizit gesetzt, ohne stillschweigenden Vorgabewert. Mindestens ein
Bildschirmprogramm läuft bei zwei Größen mit je eigener Sollausgabe —
eine hartkodierte 80 oder 25 fällt damit sofort auf. Ein weiteres
durchläuft eine Größenänderung mitten in der Ausführung.
### D4b: Das Inventar geht der Umfangsschätzung vor
Die Erhebung in Aufgabe 1.1 (2026-09-03) hat gezeigt, dass die
ursprüngliche Umfangsliste dieses Changes drei ganze Gruppen nicht
enthielt: die 13 finanzmathematischen Funktionen, die 14
Record-Konvertierungsfunktionen und einen Rest an Dateisystem- und
Systemelementen. Sie hat außerdem zwei Elemente widerlegt, die
`phase-3-isam` fälschlich führte (`CHECKPOINT`, `TEXTCOMP`).
*Konsequenz für die Arbeitsweise:* Maßgeblich ist das Inventar, nicht die
Aufzählung im Proposal. Wo beide auseinandergehen, wird das Proposal
nachgezogen. Aufzählungen in Proposal und Specs sind Mindestumfang.
*Konsequenz für die Quelle:* `bas7advr.hlp/TOPIC_LIST.html` ist
nachweislich unvollständig — `SGN`, `SQR`, `SPACE$`, `STRING$`, `CSRLIN`,
`BEEP` und `DATE$` als Funktion fehlen dort. Das Inventar bildet die
Vereinigungsmenge aus dieser Liste, `qb45advr.hlp/TOPIC_LIST.html` und
`docs/sprachreferenz.md`; jeder Eintrag nennt seine Fundstelle. Die
Zählung einer einzelnen Themenliste ist kein Vollständigkeitsnachweis.
### D5: Inventar als Markdown-Tabelle mit Abgleichstest
`docs/inventar.md` trägt eine Pipe-Tabelle mit festen Spalten (Name, Art,
Gruppe, Status, Fundstelle). Ein Test parst sie und hält sie gegen
`builtin_fn`/`builtin_stmt`, die `Unsupported`-Marker und
`banned_feature`.
*Warum Markdown und nicht TOML/YAML:* Der Plan nennt „maschinenlesbar",
aber keinen Konsumenten außer der Messbarkeit selbst; Zielpfad ist
ausdrücklich `docs/inventar.md`, und das IDE-Hilfesystem (Phase 5)
rendert `docs/`-Markdown. Eine Pipe-Tabelle ist mit einem Split
maschinenlesbar. Ein zweites Format bräuchte einen Generator, um wieder
bei Markdown zu landen.
*Der Test ist der eigentliche Punkt:* Ohne ihn verrottet der Status. Mit
ihm kann das Inventar nicht falsch werden, ohne dass die Suite rot wird.
### D6: `Unsupported`-Marker bleiben, aber nur noch für Phase 4
Die Marker verschwinden nicht — Ereignissteuerung, `SETUEVENT`, `MSGBOX`
und `INPUTBOX$` behalten sie bis Phase 4. Der Abgleichstest aus D5 stellt
sicher, dass genau die im Inventar als `offen` geführten Elemente noch
Marker tragen.
### D7: Reihenfolge der Umsetzung
```
1. Inventar (Sollseite) -> misst alles Folgende
2. Puffer-Umzug + Host + Snapshot -> BREAKING, zusammen in einem Schritt
3. Bildschirmanweisungen -> braucht 2
4. Strings/Format/Datum/Mathematik -> unabhaengig, jederzeit
5. Datei-E/A -> unabhaengig von 2/3
6. Altlasten Phase 2 -> unabhaengig
```
Schritt 2 ist der einzige Bruch und wird bewusst als eine Einheit
umgesetzt: Puffer-Umzug, `Host`-Neuschnitt und Snapshot-Umstellung hängen
so eng zusammen, dass ein Zwischenzustand die Suite ohnehin rot ließe.
Schritte 46 können vorgezogen werden, falls Schritt 2 sich zieht.
## Risks / Trade-offs
- **Der `Host`-Bruch legt kurzzeitig die gesamte Suite lahm** → Schritt 2
als eine Einheit umsetzen, nicht in Teilschritten; erst wenn Puffer,
Host und Harness zusammen stehen, wird gemessen.
- **Neu erzeugte Golden Files zementieren einen Fehler** → Der Diff der
acht Dateien wird einzeln geprüft. Erwartung: `PRINT`-only-Programme
ändern sich nicht. Jede Abweichung wird begründet oder ist ein Bug.
- **Doppelzellen brechen bestehende Annahmen** (`POS` = Zeichenzahl,
Zelle = Zeichen) → Korpustest mit CJK/Emoji inklusive Umbruch am
rechten Rand, bevor die übrige Bildschirmarbeit darauf aufsetzt.
- **`RND`-Kompatibilität ist Rekonstruktionsarbeit** — die Zahlenfolge
des Vorbilds ist nur über die Dokumentation und Beobachtung greifbar →
Algorithmus dokumentieren; gelingt die exakte Folge nicht, wird die
Abweichung in der Sprachreferenz festgehalten statt still
abzuweichen.
- **UTF-32-Records machen Dateien binär inkompatibel zum Vorbild** →
bewusst entschieden (2026-09-02); Preis ist, dass Originaldateien nicht
gelesen werden können. Muss in der Sprachreferenz stehen.
- **`SHELL`, `FILES`, Satzsperren und `LPRINT` sind plattformabhängig** →
jede Abweichung wird in der Sprachreferenz unter „Abweichungen"
benannt; stilles Abweichen ist laut Guiding Principle ein Bug.
- **Das Inventar aus der Original-Hilfe zu erheben ist der stillste
Aufwandstreiber** → als eigener erster Schritt geführt, damit sein
Umfang sichtbar wird, statt sich in die Implementierungsarbeit zu
mischen.
## Migration Plan
1. Inventar anlegen (rein additiv, kein Bruch).
2. Bruchschritt in einem Zug: `TextScreen` nach `tb-runtime::screen`,
`tb-ui` auf Adapterrolle, `Host` neu, Harness auf Snapshot, acht
Golden Files neu erzeugen und Diff prüfen.
3. Alles Weitere additiv — jedes neue Element wechselt im Inventar von
`offen` auf `implementiert`, der Abgleichstest hält beides zusammen.
Rücknahme: Schritt 2 ist ein zusammenhängender Commit und als Ganzes
rücknehmbar. Danach gibt es keinen weiteren Bruch.
## Open Questions
- Umfang der `KEY n`-Funktionstasten-Makros (`KEY LIST`/`ON`/`OFF`): Die
Anweisung steht im Scope; welche Makro-Semantik das Vorbild genau
zeigt, ist bei der Umsetzung aus der Original-Hilfe zu klären und in
docs/sprachreferenz.md festzuhalten. Berührt weder Puffer noch Host
noch Aufgabenschnitt.
- Ersatzwert für `FRE` auf einer Plattform ohne DOS-Speichermodell: bei
der Umsetzung zu wählen und zu dokumentieren.
- Konkrete Gestalt der Schnittstelle, über die die Forms-Engine in
`tb-ui` später eigene Zeichenbereiche im Puffer belegt und wieder
freigibt: erst in Phase 4 zu klären, wenn die Steuerelemente stehen.
Ändert weder Puffer noch Host noch Aufgabenschnitt dieses Changes.

View File

@@ -0,0 +1,186 @@
# Phase 3 (Kern) — Laufzeitbibliothek, Bildschirm und Datei-E/A
## Why
Phase 2 hat eine lauffähige VM geliefert, aber nur eine dünne
Bibliotheksscheibe: rund 50 dokumentierte Anweisungen und Funktionen sind
im Frontend zwar typgeprüft, senken aber auf `HStmtKind::Unsupported`/
`HExpr::Unsupported` ab und enden zur Laufzeit in Fehler 73. Betroffen
sind alle Bildschirmanweisungen (`CLS`, `LOCATE`, `COLOR`, `VIEW PRINT`,
`CSRLIN`, `POS`, `INKEY$`), die komplette Datei-E/A, `PRINT USING`,
die Datums-/Zeitfunktionen und die System-Anweisungen. Klassische
Konsolenprogramme des Vorbilds laufen damit nicht.
Zusätzlich fehlt das Messinstrument: die Leitplanke „Vollständigkeit ist
das Soll" fordert ein Inventar aller Anweisungen/Funktionen mit
Abdeckungsstatus als Abnahmekriterium für Phase 6 — bislang existiert nur
die Implementierungsseite (die `Unsupported`-Marker), nicht die Sollseite
aus der Original-Hilfe.
Dieser Change löst den Plan-Meilenstein „klassische Konsolenprogramme
laufen unverändert" ein. ISAM ist als eigener Change `phase-3-isam`
ausgegliedert und schließt Phase 3 ab.
## What Changes
- **Vollständigkeits-Inventar** (`docs/inventar.md`): Tabelle aller
Anweisungen, Funktionen und Metabefehle des Vorbilds aus der
Original-Hilfe mit Status `implementiert` / `offen` / `Non-Feature`
und Fundstelle. Ein automatischer Test gleicht die Tabelle gegen
`builtin_fn`/`builtin_stmt` und die `Unsupported`-Marker im Code ab;
Divergenz schlägt fehl. Damit misst sich die Abdeckung selbst.
- **Bildschirmpuffer wandert nach `tb-runtime`** (Entscheidung
2026-09-03, Explore-Session): `Cell`/`TextScreen` mit der kompletten
Bildschirmsemantik (Cursor, Farbattribute, Scrollen, `VIEW PRINT`,
`resize`) ziehen ratatui-frei von `tb-ui::screen` nach
`tb-runtime::screen`. In `tb-ui` bleiben nur die Ratatui-Anbindung
(`basic_color`, `impl Widget`) und künftig der Terminal-Adapter.
Begründung: `PRINT`, `LOCATE`, `CLS` und `SCREEN()` sind Elemente der
Laufzeitbibliothek und müssen den Puffer erreichen; zugleich bleiben
`tb-vm` und `tb-runtime` damit frei von einer Terminal-Abhängigkeit,
sodass jedes Bildschirmverhalten ohne Terminal prüfbar ist. Die
Forms-Engine bleibt laut PLAN.md in `tb-ui::forms` (Entscheidung
2026-09-03) und zeichnet von dort in denselben Puffer — `tb-ui` hängt
künftig an `tb-runtime`, nicht umgekehrt.
- **BREAKING: `Host`-Trait neu geschnitten**: statt `write(&str)` /
`read_line()` künftig Präsentation eines Zellenpuffers und
Ereignisabfrage. `write`/`read_line` können den Bildschirmzustand
nicht transportieren (`LOCATE`, `COLOR`, `CSRLIN`, `SCREEN(r,c)` liest
vom Bildschirm zurück). Betrifft `ConsoleHost`, `CaptureHost` und
`tbc run`.
- **BREAKING: Korpusvergleich auf Bildschirm-Snapshot** (getrimmt):
`.out`-Dateien halten künftig das Textbild des Puffers bis zur letzten
belegten Zelle statt eines Byte-Streams; eine Attributebene kommt nur
hinzu, wenn das Programm `COLOR` verwendet. Die acht bestehenden
Golden Files werden neu erzeugt. Ein Byte-Stream kann `LOCATE`/`COLOR`
nicht abbilden.
- **Bildschirmanweisungen und -funktionen**: `CLS`, `COLOR`, `LOCATE`,
`WIDTH`, `SCREEN` (Anweisung und Funktion), `VIEW PRINT`, `CSRLIN`,
`POS`, `INKEY$`, `INPUT$`, `TAB`, `SPC`, `KEY` (inkl. Klärung des
Umfangs der Funktionstasten-Makros `KEY LIST`/`ON`/`OFF`).
- **80×25 ist nirgends eine feste Grenze** (Vorgabe des Projektinhabers
2026-09-03, Priorität für das ganze Programm): 80×25 steht stets als
Synonym für „voller Bildschirm". Kein beobachtbares Verhalten darf eine
feste Spalten- oder Zeilenzahl voraussetzen — `CLS`, der
voreingestellte Scrollbereich, Umbruch- und Scrollgrenzen sowie die
Bereichsprüfungen von `LOCATE` und `SCREEN()` folgen den aktuellen
Abmessungen. Größenänderungen während der Ausführung werden als
Ereignis zugestellt und angepasst (Inhalt oben links erhalten, Cursor
und `VIEW PRINT`-Bereich geklemmt). Das Mindestmaß 80×25 bleibt
ausschließlich eine untere Schranke der Darstellung.
- **Breite Unicode-Zeichen belegen zwei Zellen** (Entscheidung
2026-09-02): Zellenmodell, Cursorfortschritt, `POS`/`LOCATE` und
Umbruch am rechten Rand berücksichtigen die Darstellungsbreite
(unicode-width). Ersetzt die bisherige Regel „1 Zeichen = 1 Zelle".
- **Vollständige String- und Zahlenbibliothek**: die restlichen
dokumentierten Stringfunktionen sowie `PRINT USING` und `FORMAT$`
vollständig, inklusive Klärung des `%`-Präfixes bei Feldüberlauf.
- **Datums- und Zeitfunktionen**: `NOW`, `DATESERIAL`, `TIMESERIAL`,
`DATEVALUE`, `TIMEVALUE`, `DAY`, `MONTH`, `YEAR`, `WEEKDAY`, `HOUR`,
`MINUTE`, `SECOND` sowie `DATE$`/`TIME$` als Anweisungsform.
- **Finanzmathematik** (Befund aus Aufgabe 1.1, 2026-09-03 — im
ursprünglichen Umfang übersehen): `FV#`, `PV#`, `Pmt#`, `IPmt#`,
`PPmt#`, `NPer#`, `Rate#`, `NPV#`, `IRR#`, `MIRR#`, `SLN#`, `SYD#`,
`DDB#`.
- **Record-Konvertierungsfunktionen** (ebenfalls Befund 1.1):
`MKI$`/`MKL$`/`MKS$`/`MKD$`/`MKC$` und `CVI`/`CVL`/`CVS`/`CVD`/`CVC`
sowie die MBF-Varianten `MKSMBF$`/`MKDMBF$`/`CVSMBF`/`CVDMBF` — sie
gehören zum `FIELD`-basierten wahlfreien Zugriff.
- **Weitere Befunde aus 1.1**: `CURDIR$`, `DIR$`, `CHDRIVE`,
`SHELL` als Funktion, `LPOS`, `STACK` (Anweisung und Funktion),
`SYSTEM`, `ERDEV`/`ERDEV$`, `SetFormatCC`.
- **Signaturen für alle Inventarelemente**: Die Semantik führt für jedes
im Inventar geführte Element eine Signatur, auch wenn das
Laufzeitverhalten noch aussteht — sonst enden dokumentierte Elemente
in „unbekannter Bezeichner" statt in einer namentlichen Ablehnung.
- **Mathematik vervollständigen**: kompatibler `RND`/`RANDOMIZE`-PRNG
(gleiche Zahlenfolge wie das Vorbild bei gleichem Startwert),
Rundungsverhalten, Integer-Überlauf → Fehler 6.
- **Datei-E/A**: `OPEN` in beiden Syntaxen (sequenziell, random, binär),
`CLOSE`, `RESET`, `PRINT #`, `WRITE #`, `INPUT #`, `LINE INPUT #`,
`GET`, `PUT`, `FIELD`, `LSET`, `RSET`, `SEEK` (Anweisung und
Funktion), `EOF`, `LOF`, `LOC`, `FREEFILE`, `FILEATTR`, `LOCK`/
`UNLOCK`, `NAME … AS`, `LPRINT`. Feste Strings in Records als UTF-32
(Entscheidung 2026-09-02, 4 Bytes/Zeichen, feste Recordlänge).
- **System-Anweisungen**: `FILES`, `KILL`, `CHDIR`, `MKDIR`, `RMDIR`,
`SHELL`, `ENVIRON`/`ENVIRON$`, `CLEAR`, `FRE`, `TRON`/`TROFF`,
plattformübergreifende Pfadsemantik.
- **Drei Altlasten aus Phase 2**:
- `ON ERROR GOTO`-Scoping: ein Handler-Label auf Modulebene ist auch
aus Prozeduren heraus ansprechbar; heute wird nicht-lokales
`ON ERROR` in einer Prozedur fälschlich wie `ON LOCAL ERROR`
behandelt (`sema.rs`, `lower_stmt`/`OnError`).
- DATA-Rohtext: unquotierte `DATA`-Elemente verlieren die Groß-/
Kleinschreibung, weil der Lexer Bezeichner normalisiert.
- `TODO verify`-Zellen der Konvertierungsmatrix in
`docs/tbvm-design.md` gegen die Original-Hilfe auflösen
(CURRENCY-Promotion mit Gleitkomma, `^`-Ergebnistyp,
Exponentialform-Schwellen, CURRENCY-Ausgabeformat).
**Non-Goals:** ISAM (eigener Change `phase-3-isam`, schließt Phase 3 ab);
Forms-Engine, Ereignisschleife und Ereignissteuerung (`TIMER/KEY(n) ON|
OFF|STOP`, `ON SIGNAL`/`SIGNAL`, `SETUEVENT`, `MSGBOX`, `INPUTBOX$`
Phase 4); IDE und
Debugger (Phase 5); `tbc build --exe` (Phase 6). Die Forms-Engine bleibt
laut PLAN.md in `tb-ui::forms` (Entscheidung 2026-09-03); dieser Change
schafft ihr mit dem Puffer in `tb-runtime` nur die Zeichenfläche.
## Capabilities
### New Capabilities
- `datei-eio`: Dateiverwaltung und Datenübertragung — `OPEN`/`CLOSE`,
die drei Zugriffsarten (sequenziell, random, binär), Record-Layout mit
UTF-32-Festtextfeldern, `FIELD`/`LSET`/`RSET`, Positions- und
Statusfunktionen (`EOF`/`LOF`/`LOC`/`SEEK`/`FREEFILE`/`FILEATTR`),
Sperren, Dateisystem-Anweisungen und plattformübergreifende
Pfadsemantik.
- `sprachinventar`: das Vollständigkeits-Inventar als prüfbares
Artefakt — Aufbau der Tabelle, Statusvokabular, Pflicht zur
Vollständigkeit gegenüber der Original-Hilfe und der automatische
Abgleich gegen den Code.
### Modified Capabilities
- `textbildschirm`: Der Zellenpuffer SHALL in `tb-runtime` liegen und
ratatui-frei sein; das Unicode-Zellenmodell wechselt von „1 Zeichen =
1 Zelle" auf Darstellungsbreite (breite Zeichen belegen zwei Zellen);
neue Anforderung für die Bildschirmanweisungen des Dialekts auf dem
Puffer.
- `konsolen-basisbibliothek`: Der `Host`-Trait wechselt vom Stream- auf
ein Bildschirmmodell (Präsentation + Ereignisabfrage); die
Funktionsliste wird von der Korpusscheibe auf die vollständige
String-, Zahlen-, Formatierungs- (`PRINT USING`) und Datums-/
Zeitbibliothek erweitert; `RND` erhält eine Kompatibilitätsanforderung.
- `kompat-testkorpus`: Der Laufzeitvergleich wechselt vom Byte-Stream
auf einen getrimmten Bildschirm-Snapshot; neue Abdeckungsanforderung
für Bildschirm-, Formatierungs- und Datei-E/A-Semantik.
- `sprach-frontend`: `ON ERROR GOTO` auf Modulebene SHALL aus
Prozeduren heraus ansprechbar sein (bisher fälschlich lokal);
unquotierte `DATA`-Elemente SHALL ihren Rohtext behalten.
## Impact
- `crates/tb-ui`: `screen.rs` verliert Puffer und Semantik an
`tb-runtime`; zurück bleiben `basic_color` und `impl Widget` als
Adapter auf den Runtime-Puffer. Neue Abhängigkeit `tb-runtime`
(bisher waren beide Blätter im Abhängigkeitsgraphen); `forms.rs`
bleibt als Platzhalter für Phase 4 unberührt.
- `crates/tb-runtime`: neues `screen`-Modul; `host.rs` neu geschnitten
(**BREAKING**); `strings`, `format`, `math`, `datetime`, `fileio`,
`builtins` von Stub/Scheibe auf Vollimplementierung; neue
Abhängigkeit `unicode-width`.
- `crates/tb-frontend`: rund 50 `Unsupported`-Marker weichen echter
Absenkung; rund 30 bislang signaturlose Elemente (Finanzmathematik,
`MK…$`/`CV…`, `CURDIR$`, `DIR$`, `CHDRIVE`, `LPOS`, `STACK`, `SYSTEM`,
`ERDEV`/`ERDEV$`, `SetFormatCC`) erhalten Signaturen; `sema.rs` (`ON ERROR`-Scoping), `lexer.rs` (DATA-Rohtext).
- `crates/tb-vm`: neue Builtin-Indizes; `Instr::Unsupported` bleibt für
die verbleibenden Phase-4-Marker bestehen.
- `crates/tb-cli`: `tbc run` auf den neuen `Host`; Harness auf
Snapshot-Vergleich (**BREAKING** für die acht bestehenden `.out`).
- `tests/compat`: acht Golden Files neu erzeugt, neue Korpusdateien für
Bildschirm, `PRINT USING`, Datei-E/A, Datum/Zeit, breite Zeichen.
- `docs/`: neu `docs/inventar.md` und `docs/bibliothek.md`;
fortgeschrieben `docs/sprachreferenz.md` (Doppelzellen, `KEY n`,
`PRINT USING`-Überlauf) und `docs/tbvm-design.md`
(Konvertierungsmatrix). PLAN.md-Haken folgen bei Abschluss.

View File

@@ -0,0 +1,295 @@
# Rohliste — Themen der Original-Hilfe (Aufgabe 1.1)
**Quelle:** `bas7advr.hlp` (BASIC 7 Advisor, Sprachreferenz der
Professional Edition), Themenliste unter
https://dos-help.soulsphere.org/bas7advr.hlp/TOPIC_LIST.html
(abgerufen 2026-09-03).
**Nicht verwendet:** `vbdpss.hlp` ist eine Knowledge-Base mit
Artikelnummern und Support-Adressen, keine Sprachreferenz — geprüft und
verworfen.
Die Liste ist wortgetreu übernommen. Sie enthält neben Sprachthemen auch
Unterseiten (`SCREEN Mode …`, `DRAW Statement Macro Language`,
`PLAY Statement (Music) — …`) und einen Anker (`@L8000`); diese sind
keine eigenen Sprachelemente und gehen nicht als Inventareintrag ein.
## Themen (wortgetreu)
$INCLUDE Metacommand
$STATIC and $DYNAMIC Metacommands
@L8000
ABS Function
ASC Function
ATN Function
Absolute Routine
BEGINTRANS Statement
BLOAD Statement
BOF Function
BSAVE Statement
CALL Statement (BASIC Procedures)
CALL, CALLS Statements (Non-BASIC Procedures)
CCUR Function
CDBL Function
CHAIN Statement
CHDIR Statement
CHDRIVE Statement
CHR$ Function
CINT Function
CIRCLE Statement
CLEAR Statement
CLNG Function
CLOSE Statement
CLS Statement
COLOR Statement
COM Statements
COMMAND$ Function
COMMITTRANS Statement
COMMON Statement
CONST Statement
COS Function
CREATEINDEX Statement
CSNG Function
CURDIR$ Function
CVI, CVL, CVS, CVD, and CVC Functions
CVSMBF, CVDMBF Function
DATA Statement
DATE$ Statement
DDB# Function
DECLARE Statement (BASIC Procedures)
DECLARE Statement (Non-BASIC Procedures)
DEF FN Statement
DEF SEG Statement
DEFtype Statement
DELETE Statement
DELETEINDEX Statement
DELETETABLE Statement
DIM Statement
DIR$ Function
DO...LOOP Statement
DRAW Statement - Differences from BASICA
DRAW Statement Macro Language
DateSerial# Function
DateValue# Function
Day& Function
END Statement
ENVIRON Statement
ENVIRON$ Function
EOF Function
ERASE Statement
ERDEV, ERDEV$ Function
ERR Statement
ERR, ERL Functions
ERROR Statement
EVENT Statements
EXIT Statement
EXP Function
FIELD Statement
FILEATTR Function
FILES Statement
FIX Function
FOR...NEXT Statement
FRE Function
FREEFILE Function
FUNCTION Statement
FV# Function
FormatX$ Functions
GET Statement (File I/O)
GET Statement (Graphics)
GETINDEX$ Function
GOSUB...RETURN Statement
GOTO Statement
HEX$ Function
Hour& Function
IF...THEN...ELSE Statement
INKEY$ Function
INP Function
INPUT # Statement
INPUT Statement
INPUT$ Function
INSERT Statement
INSTR Function
INT Function
IOCTL Statement
IOCTL$ Function
IPmt# Function
IRR# Function
Interrupt, InterruptX Routines
KEY Statements (Assignment)
KEY Statements (Event Trapping)
KILL Statement
LBOUND Function
LCASE$ Function
LEFT$ Function
LEN Function
LET Statement
LINE INPUT # Statement
LINE INPUT Statement
LINE Statement
LOC Function
LOCATE Statement
LOCK...UNLOCK Statement
LOF Function
LOG Function
LPOS Function
LPRINT Statement
LPRINT USING Statement
LSET Statement
LTRIM$ Function
MID$ Function
MID$ Statement
MIRR# Function
MKDIR Statement
MKI$, MKL$, MKS$, MKD$, and MKC$ Functions
MKSMBF$, MKDMBF$ Functions
MOVEFIRST, MOVELAST, MOVENEXT, MOVEPREVIOUS Statements
Minute& Function
Month& Function
NAME Statement
NPV# Function
NPer# Function
Now# Function
OCT$ Function
ON COM Statement
ON ERROR Statement
ON KEY Statement
ON PEN Statement
ON PLAY Statement
ON SIGNAL Statement
ON STRIG Statement
ON TIMER Statement
ON UEVENT Statement
ON...GOSUB and ON...GOTO Statement
OPEN COM Statement
OPEN Statement (File I/O)
OPTION BASE Statement
OUT Statement
PAINT Statement
PALETTE, PALETTE USING Statements
PCOPY Statement
PEEK Function
PEN Function
PEN Statements
PLAY Statement (Music)
PLAY Statements (Event Trapping)
PMAP Function
POINT Function
POKE Statement
POS Function
PPmt# Function
PRESET Statement
PRINT # Statement
PRINT Statement
PRINT USING Statement
PSET Statement
PUT Statement (File I/O)
PUT Statement (Graphics)
PV# Function
Pmt# Function
RANDOMIZE Statement
READ Statement
REDIM Statement
REM Statement
RESTORE Statement
RESUME Statement
RETRIEVE Statement
RETURN Statement
RIGHT$ Function
RMDIR Statement
RND Function
ROLLBACK, ROLLBACK ALL Statements
RSET Statement
RTRIM$ Function
RUN Statement
Rate# Function
SADD Function
SAVEPOINT Function
SCREEN Function
SCREEN Statement
SEEK Function
SEEK Statement
SEEKGT, SEEKGE, SEEKEQ Statements
SELECT CASE Statement
SETINDEX Statement
SETMEM Function
SHARED Statement
SHELL Function
SHELL Statement
SIGNAL Statements
SIN Function
SLEEP Statement
SLN# Function
SOUND Statement
SPC Function
SSEG Function
SSEGADD Function
STACK Function
STACK Statement
STATIC Statement
STICK Function
STOP Statement
STR$ Function
STRIG Function
STRIG Statements
SUB Statement
SWAP Statement
SYD# Function
SYSTEM Statement
Second& Function
SetFormatCC Routine
SetUEvent Routine
StringAddress Routine
StringAssign Routine
StringLength Routine
StringRelease Routine
TAB Function
TAN Function
TIME$ Function
TIME$ Statement
TIMER Function
TIMER Statements
TRON/TROFF Statements
TYPE Statement
TimeSerial# Function
TimeValue# Function
UBOUND Function
UCASE$ Function
UEVENT Statements
UNLOCK Statement
UPDATE Statement
VAL Function
VARPTR$ Function
VARPTR, VARSEG Functions
VIEW PRINT Statement
VIEW Statement (Graphics)
WAIT Statement
WHILE...WEND Statement
WIDTH Statements
WINDOW Statement
WRITE # Statement
WRITE Statement
Weekday& Function
Year& Function
## Gegenprobe (Aufgabe 1.1, Befund C)
`bas7advr.hlp/TOPIC_LIST.html` ist **nicht vollständig**. Die Gegenprobe
gegen `qb45advr.hlp/TOPIC_LIST.html` (abgerufen 2026-09-03) belegt das:
diese Liste führt interne Ankernamen statt Klarnamen, enthält aber
Einträge, zu denen `bas7advr` kein Thema führt.
| Anker in `qb45advr` | Element | in `bas7advr`-Themenliste |
|---|---|---|
| `.sgnr` / `.sgnx` | `SGN` | fehlt |
| `.sqrr` / `.sqrx` | `SQR` | fehlt |
| `.sp$r` / `.sp$x` | `SPACE$` | fehlt |
| `.str$$$r` / `.str$$$x` | `STRING$` | fehlt |
| `.csrlinr` / `.csrlinx` | `CSRLIN` | fehlt |
| `.beepr` / `.beepx` | `BEEP` | fehlt |
| `.datef` | `DATE$` (Funktion) | nur `DATE$ Statement` |
**Folge für das Inventar:** Maßgeblich ist die Vereinigungsmenge aus
beiden Themenlisten und `docs/sprachreferenz.md`. Jeder Inventareintrag
führt seine Fundstelle; Einträge, die nur über die Gegenprobe belegt
sind, nennen `qb45advr`. Die Zählung einer einzelnen Themenliste ist
kein hinreichender Vollständigkeitsnachweis.

View File

@@ -0,0 +1,173 @@
## Purpose
Die Datei-E/A stellt die Dateiverwaltung des Dialekts bereit: sequenzieller,
wahlfreier und binärer Zugriff über Dateinummern, Record-Puffer mit
Festtextfeldern, Positions- und Statusfunktionen sowie die
Dateisystem-Anweisungen — plattformübergreifend und mit den
Laufzeitfehlern des Vorbilds.
## ADDED Requirements
### Requirement: Dateinummern und Öffnen in drei Zugriffsarten
`OPEN` SHALL in beiden Syntaxen des Vorbilds (Klausel- und Kurzform) die
Zugriffsarten sequenziell (`INPUT`, `OUTPUT`, `APPEND`), wahlfrei
(`RANDOM`) und binär (`BINARY`) unterstützen und die Datei an eine
Dateinummer binden. `FREEFILE` SHALL die kleinste freie Dateinummer
liefern. `CLOSE` ohne Argument SHALL alle offenen Dateien schließen,
`RESET` ebenso. Eine bereits belegte Dateinummer MUST Laufzeitfehler 55
„File already open" auslösen, eine nicht geöffnete Nummer Fehler 52
„Bad file name or number", eine fehlende Datei bei `INPUT` Fehler 53
„File not found".
#### Scenario: Sequenzielles Schreiben und Lesen
- **WHEN** eine Datei mit `OPEN "d.txt" FOR OUTPUT AS #1` beschrieben, geschlossen und mit `FOR INPUT` wieder geöffnet wird
- **THEN** liefert das Lesen genau die geschriebenen Zeilen
#### Scenario: Doppeltes Öffnen derselben Nummer
- **WHEN** `OPEN` eine bereits offene Dateinummer verwendet
- **THEN** tritt Laufzeitfehler 55 auf
#### Scenario: Freie Dateinummer
- **WHEN** `#1` offen ist und `FREEFILE` aufgerufen wird
- **THEN** liefert `FREEFILE` eine Nummer, die noch nicht belegt ist
### Requirement: Sequenzielle Datenübertragung
`PRINT #` SHALL wie `PRINT` formatieren (Druckzonen, Zahlendarstellung mit
Vorzeichenspalte), `WRITE #` SHALL Elemente komma-getrennt mit Strings in
Anführungszeichen schreiben. `INPUT #` SHALL komma-getrennte Felder lesen
und dabei Anführungszeichen auswerten, `LINE INPUT #` die ganze Zeile ohne
Zeilenende. `EOF` SHALL das Erreichen des Dateiendes melden; Lesen über das
Dateiende hinaus MUST Laufzeitfehler 62 „Input past end of file" auslösen.
#### Scenario: WRITE # und INPUT # sind gegenläufig
- **WHEN** `WRITE #1, "a,b", 5` geschrieben und die Zeile mit `INPUT #1, s$, n` gelesen wird
- **THEN** enthält `s$` den Text `a,b` und `n` den Wert 5
#### Scenario: Lesen über das Dateiende
- **WHEN** `INPUT #1, x` nach dem letzten Datensatz ausgeführt wird
- **THEN** tritt Laufzeitfehler 62 auf
### Requirement: Wahlfreier Zugriff mit Record-Puffern
`OPEN … FOR RANDOM … LEN = n` SHALL Datensätze fester Länge bereitstellen.
`GET` und `PUT` SHALL einen Datensatz an einer 1-basierten Recordnummer
lesen bzw. schreiben; ohne Nummer gilt der Satz nach der letzten Operation.
`FIELD` SHALL den Recordpuffer in benannte Festtextfelder aufteilen,
`LSET`/`RSET` SHALL links- bzw. rechtsbündig in ein Feld schreiben und
überlange Werte abschneiden. Alternativ SHALL `GET`/`PUT` mit einer
Variablen eines benutzerdefinierten Typs arbeiten.
#### Scenario: Datensatz schreiben und an gleicher Stelle lesen
- **WHEN** ein Record an Position 3 geschrieben und anschließend von Position 3 gelesen wird
- **THEN** stimmen alle Feldwerte mit den geschriebenen überein
#### Scenario: RSET schneidet ab
- **WHEN** in ein Feld der Länge 5 mit `RSET` der Text `ABCDEFG` geschrieben wird
- **THEN** enthält das Feld genau 5 Zeichen
### Requirement: Record-Konvertierungsfunktionen
Die Bibliothek SHALL die Konvertierungsfunktionen für Recordpuffer
bereitstellen: `MKI$`, `MKL$`, `MKS$`, `MKD$` und `MKC$` wandeln einen
numerischen Wert in seine Byte-Darstellung als String, `CVI`, `CVL`,
`CVS`, `CVD` und `CVC` wandeln zurück. Jedes Paar MUST gegenläufig sein.
Ein Argument, dessen Länge nicht zur Zielbreite passt, MUST
Laufzeitfehler 5 „Illegal function call" auslösen. `MKSMBF$`, `MKDMBF$`,
`CVSMBF` und `CVDMBF` SHALL dieselbe Rolle für das
Microsoft-Binärformat älterer BASIC-Versionen erfüllen; ist dieses
Format ein deklariertes Non-Feature, MUST die Ablehnung namentlich
erfolgen und in der Sprachreferenz unter „Abweichungen" stehen.
#### Scenario: MK und CV sind gegenläufig
- **WHEN** `CVL(MKL$(123456))` ausgewertet wird
- **THEN** ist das Ergebnis 123456
#### Scenario: Falsche Argumentlänge
- **WHEN** `CVI("x")` mit einem ein Zeichen langen String ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: Festtextfelder als UTF-32 mit fester Recordlänge
Feste Strings (`STRING * n`) in Recordpuffern SHALL als UTF-32 gespeichert
werden — 4 Bytes je Zeichen, damit `STRING * n` stets genau `4 * n` Bytes
belegt und die Recordlänge unabhängig vom Zeicheninhalt konstant bleibt.
Die daraus folgende Binär-Inkompatibilität zu Dateien des Vorbilds ist
beschlossen (2026-09-02) und MUST in der Sprachreferenz unter
„Abweichungen" dokumentiert sein.
#### Scenario: Recordlänge unabhängig vom Inhalt
- **WHEN** in ein Feld `STRING * 10` einmal `abc` und einmal `äöüßÄÖÜ` geschrieben wird
- **THEN** belegt der Datensatz in beiden Fällen dieselbe Byteanzahl und der Folgesatz beginnt an derselben Position
### Requirement: Binärzugriff auf Byteebene
`OPEN … FOR BINARY` SHALL byteweise Positionierung erlauben. `GET`/`PUT`
SHALL an einer 1-basierten Byteposition lesen bzw. schreiben, wobei die
übertragene Länge der Größe der Zielvariablen entspricht. `SEEK` als
Anweisung SHALL die Position setzen, `SEEK` als Funktion sie liefern.
#### Scenario: Positioniertes Byte überschreiben
- **WHEN** in einer Binärdatei an Position 4 ein Byte geschrieben und anschließend gelesen wird
- **THEN** liefert das Lesen den geschriebenen Wert und die übrigen Bytes bleiben unverändert
### Requirement: Positions- und Statusfunktionen
`LOF` SHALL die Dateigröße in Bytes liefern, `LOC` die aktuelle Position
in der Einheit der Zugriffsart (Datensatz bei `RANDOM`, Byte bei
`BINARY`), `SEEK` die nächste Lese-/Schreibposition und `FILEATTR` den
Modus bzw. das Betriebssystem-Handle. Alle Funktionen MUST bei einer nicht
geöffneten Dateinummer Laufzeitfehler 52 auslösen.
#### Scenario: Größe nach dem Schreiben
- **WHEN** 100 Bytes geschrieben wurden und `LOF(1)` aufgerufen wird
- **THEN** liefert `LOF(1)` den Wert 100
#### Scenario: Statusfunktion auf geschlossener Datei
- **WHEN** `LOF(9)` ohne offene Datei 9 aufgerufen wird
- **THEN** tritt Laufzeitfehler 52 auf
### Requirement: Satzsperren
`LOCK` und `UNLOCK` SHALL einen Datensatz-, Byte- oder den gesamten
Dateibereich sperren und wieder freigeben. Auf Plattformen ohne
entsprechende Sperrmechanik MUST das Verhalten in der Sprachreferenz unter
„Abweichungen" dokumentiert sein statt still abzuweichen.
#### Scenario: Sperren und Freigeben
- **WHEN** ein Datensatzbereich gesperrt und anschließend mit denselben Grenzen freigegeben wird
- **THEN** läuft die Folgeoperation auf diesem Bereich ohne Fehler
### Requirement: Dateisystem-Anweisungen mit plattformübergreifender Pfadsemantik
`KILL`, `NAME … AS`, `FILES`, `CHDIR`, `CHDRIVE`, `MKDIR`, `RMDIR`,
`CURDIR$`, `DIR$` sowie `SHELL` als Anweisung **und** als Funktion SHALL
verfügbar sein. `CURDIR$` SHALL das aktuelle Verzeichnis liefern, `DIR$`
den ersten bzw. — bei leerem Argument — den nächsten Treffer eines
Suchmusters und den leeren String, wenn keiner mehr folgt. Die
`SHELL`-Funktion SHALL den Beendigungsstatus des aufgerufenen Prozesses
liefern. `CHDRIVE` SHALL auf Plattformen ohne Laufwerksbuchstaben
namentlich abgewiesen oder als Non-Feature dokumentiert werden. Pfade SHALL sowohl `\` als auch `/` als Trennzeichen
akzeptieren und auf die Konvention der laufenden Plattform abgebildet
werden; Laufwerksbuchstaben SHALL auf Nicht-Windows-Plattformen als
gewöhnlicher Namensbestandteil behandelt oder mit benannter Ablehnung
abgewiesen werden. Fehlende Dateien MUST Fehler 53 auslösen, fehlende
Pfade Fehler 76 „Path not found".
#### Scenario: Rückwärts-Schrägstrich auf Unix
- **WHEN** `OPEN "unter\d.txt" FOR OUTPUT AS #1` auf einer Unix-Plattform ausgeführt wird
- **THEN** entsteht die Datei `d.txt` im Verzeichnis `unter`
#### Scenario: Verzeichnis durchlaufen
- **WHEN** `DIR$("*.txt")` und danach `DIR$("")` wiederholt ausgewertet werden
- **THEN** liefern sie nacheinander alle passenden Namen und zuletzt den leeren String
#### Scenario: Fehlender Pfad
- **WHEN** `MKDIR` in einem nicht existierenden Elternverzeichnis aufgerufen wird
- **THEN** tritt Laufzeitfehler 76 auf
### Requirement: LPRINT als Druckausgabe
`LPRINT` und `LPRINT USING` SHALL wie `PRINT` formatieren und in einen
Druckerkanal schreiben. `LPOS` SHALL die aktuelle Spalte im
Druckerpuffer liefern. Existiert auf der Plattform kein Druckerkanal,
MUST das Ziel (Datei, Standardausgabe oder Ablehnung) in der
Sprachreferenz unter „Abweichungen" dokumentiert sein.
#### Scenario: LPRINT formatiert wie PRINT
- **WHEN** `LPRINT 1; 2` ausgeführt wird
- **THEN** entspricht der erzeugte Text der Ausgabe von `PRINT 1; 2`
#### Scenario: Druckerspalte
- **WHEN** nach `LPRINT "abc";` die Funktion `LPOS(0)` ausgewertet wird
- **THEN** liefert sie die Spalte hinter dem ausgegebenen Text

View File

@@ -0,0 +1,85 @@
## ADDED Requirements
### Requirement: Korpusabdeckung der Phase-3-Semantik
Der Korpus SHALL um Referenzprogramme mit dokumentierter Sollausgabe für
die Bildschirmsteuerung (`LOCATE`, `COLOR`, `CLS`, `VIEW PRINT`-Scrollen,
`CSRLIN`/`POS`, Zurücklesen per `SCREEN`), die Formatierung
(`PRINT USING` inklusive Feldüberlauf), breite Unicode-Zeichen
(Doppelzellen, Umbruch am rechten Rand), Datum und Zeit sowie die
Datei-E/A in allen drei Zugriffsarten erweitert werden. Dateiprogramme
MUST in einem temporären Arbeitsverzeichnis laufen und dürfen keine
Artefakte im Projektbaum hinterlassen.
#### Scenario: Bildschirmsteuerung als Korpustest
- **WHEN** die Testsuite läuft
- **THEN** existiert ein Korpusprogramm, das mit `LOCATE` und `COLOR` an definierten Positionen ausgibt, und sein Snapshot entspricht der Sollausgabe
#### Scenario: Datei-Korpustest hinterlässt nichts
- **WHEN** ein Datei-E/A-Korpusprogramm gelaufen ist
- **THEN** ist das Arbeitsverzeichnis wieder entfernt und der Projektbaum unverändert
### Requirement: Nachweis der Größenunabhängigkeit
Die Bildschirmgröße des Test-Hosts SHALL je Korpusprogramm explizit
festgelegt und in der Sollausgabe vermerkt sein; ein Vorgabewert MUST NOT
stillschweigend gelten. Mindestens ein Korpusprogramm SHALL bei zwei
verschiedenen Bildschirmgrößen laufen und je Größe eine eigene
Sollausgabe besitzen, um nachzuweisen, dass Löschen, Umbruch, Scrollen
und Cursorgrenzen der jeweiligen Größe folgen. Mindestens ein
Korpusprogramm SHALL eine Größenänderung während der Ausführung
durchlaufen und danach die neuen Grenzen ausnutzen.
#### Scenario: Gleiches Programm bei zwei Größen
- **WHEN** dasselbe Bildschirm-Korpusprogramm bei 80×25 und bei 120×40 läuft
- **THEN** stimmt jede Ausgabe mit der Sollausgabe ihrer Größe überein und die Sollausgaben unterscheiden sich in Umbruch- und Scrollverhalten
#### Scenario: Größenänderung mitten im Programm
- **WHEN** der Test-Host während der Ausführung von 80×25 auf 120×40 wechselt
- **THEN** bleibt der bisherige Inhalt oben links erhalten und die anschließende Ausgabe nutzt die neuen Grenzen
## MODIFIED Requirements
### Requirement: Korpusdateien mit byte-genauer Sollausgabe
Jedes Korpusprogramm `tests/compat/<name>.bas` SHALL eine `<name>.out`
mit dem exakten Sollzustand des Bildschirms besitzen (UTF-8,
LF-Zeilenenden). Die Sollausgabe SHALL den Zellenpuffer als Textbild
abbilden, getrimmt bis zur letzten belegten Zeile und Spalte; nachgestellte
Leerzeichen innerhalb einer Zeile sind signifikant — `PRINT` gibt Zahlen
mit führendem Vorzeichen-/Leerzeichen und nachgestelltem Leerzeichen aus.
Verwendet ein Programm `COLOR`, SHALL die Sollausgabe zusätzlich eine
Attributebene gleicher Abmessung enthalten; ohne `COLOR` MUST sie
entfallen. `.gitattributes` MUST die `.out`-Dateien vor
Zeilenenden-Konvertierung schützen.
#### Scenario: Zahlformatierung in der Sollausgabe
- **WHEN** ein Korpusprogramm `PRINT 1; 2; 3` enthält
- **THEN** lautet die Sollzeile ` 1 2 3 ` (mit nachgestelltem Leerzeichen)
#### Scenario: Getrimmter Snapshot
- **WHEN** ein Korpusprogramm nur zwei Zeilen ausgibt
- **THEN** umfasst die Sollausgabe genau diese zwei Zeilen und keine leeren Folgezeilen
#### Scenario: Attributebene nur bei COLOR
- **WHEN** ein Korpusprogramm ohne `COLOR` läuft
- **THEN** enthält seine `.out` keine Attributebene
### Requirement: Laufzeitvergleich über den Korpus
Ein automatischer Test SHALL jede Korpusdatei `tests/compat/*.bas`
kompilieren, über die VM mit einem Host ohne Terminal ausführen und den
resultierenden Bildschirmzustand gegen die zugehörige `.out`-Datei
vergleichen — getrimmt, mit signifikanten Leerzeichen innerhalb der
Zeilen und, sofern vorhanden, einschließlich der Attributebene. Bei
Abweichung MUST der Test Datei, erste abweichende Zeile sowie Soll und
Ist nennen; weicht nur die Attributebene ab, MUST er Zeile, Spalte, Soll-
und Ist-Attribut nennen.
#### Scenario: Korpus läuft mit korrekter Ausgabe
- **WHEN** die Laufzeit-Testsuite läuft
- **THEN** stimmt der Bildschirmzustand jeder Korpusdatei mit ihrer `.out` überein
#### Scenario: Abweichung wird benannt
- **WHEN** ein Korpusprogramm eine abweichende Ausgabe erzeugt
- **THEN** schlägt der Test fehl und nennt Datei, Zeilennummer, Soll- und Ist-Zeile
#### Scenario: Abweichendes Farbattribut
- **WHEN** ein Korpusprogramm dasselbe Textbild, aber ein abweichendes Attribut erzeugt
- **THEN** schlägt der Test fehl und nennt Zeile, Spalte, Soll- und Ist-Attribut

View File

@@ -0,0 +1,208 @@
## ADDED Requirements
### Requirement: Vollständige Stringbibliothek
Die Bibliothek SHALL sämtliche in der Original-Hilfe dokumentierten
Stringfunktionen und -anweisungen mit der Semantik des Vorbilds
bereitstellen — darunter `LEN`, `LEFT$`, `RIGHT$`, `MID$` (Funktion und
Anweisung), `INSTR`, `UCASE$`, `LCASE$`, `LTRIM$`, `RTRIM$`, `STRING$`,
`SPACE$`, `CHR$`, `ASC`, `STR$`, `VAL`, `HEX$`, `OCT$` und `SWAP` für
Strings. Zeichen sind Unicode-Codepoints (dokumentierte Abweichung).
Randfälle folgen dem Vorbild: `VAL` liest das führende Zahlenpräfix und
überspringt Leerraum, `STR$` stellt nicht-negativen Zahlen ein Leerzeichen
voran, `ASC("")` löst Laufzeitfehler 5 aus, eine Startposition kleiner 1
bei `MID$`/`INSTR` ebenso, `LEFT$`/`RIGHT$` mit Länge über der Stringlänge
liefern den ganzen String. Welche Elemente die Liste umfasst, MUST das
Sprachinventar bestimmen; ein dort als `implementiert` geführtes Element
MUST verfügbar sein.
#### Scenario: VAL mit Restzeichen
- **WHEN** `VAL(" 12.5abc")` ausgewertet wird
- **THEN** ist das Ergebnis 12.5
#### Scenario: Länge über Stringende
- **WHEN** `LEFT$("ab", 10)` ausgewertet wird
- **THEN** ist das Ergebnis `ab`
#### Scenario: Ungültige Startposition
- **WHEN** `MID$("abc", 0)` ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: PRINT USING und FORMAT$
`PRINT USING`, `LPRINT USING` und `FORMAT$` SHALL die Formatzeichen des
Vorbilds unterstützen: numerische Platzhalter (`#`), Dezimalpunkt,
Tausendertrennung (`,`), Vorzeichenführung (`+`, `-`), Währungs- und
Füllzeichen (`$$`, `**`, `**$`), Exponentialform (`^^^^`) sowie die
String-Platzhalter `&`, `!` und `\ \`. Literale Zeichen SHALL unverändert
übernommen werden, `_` SHALL das Folgezeichen literal machen. Passt ein
Wert nicht in das Feld, SHALL die Ausgabe mit einem `%`-Präfix erfolgen
und der Wert vollständig dargestellt werden; dieses Überlaufverhalten MUST
in der Sprachreferenz festgehalten sein. Eine Formatzeichenkette ohne
Platzhalter bei vorhandenen Argumenten MUST Laufzeitfehler 5 auslösen.
`SetFormatCC` SHALL das für `$$` verwendete Währungszeichen und die
zugehörige Stellung setzen; ohne Aufruf gilt ein dokumentierter
Vorgabewert.
#### Scenario: Numerisches Feld mit Nachkommastellen
- **WHEN** `PRINT USING "###.##"; 3.14159` ausgeführt wird
- **THEN** lautet die Ausgabe ` 3.14`
#### Scenario: Feldüberlauf
- **WHEN** `PRINT USING "##"; 12345` ausgeführt wird
- **THEN** beginnt die Ausgabe mit `%` und enthält den vollständigen Wert
#### Scenario: Formatzeichenkette wird wiederverwendet
- **WHEN** `PRINT USING "## "; 1; 2; 3` ausgeführt wird
- **THEN** wird die Formatzeichenkette für jeden Wert erneut angewandt
### Requirement: Datums- und Zeitbibliothek
Die Bibliothek SHALL die Datums- und Zeitfunktionen des Vorbilds
bereitstellen: `DATE$` und `TIME$` als Funktion und als Anweisung, `TIMER`,
`NOW`, `DATESERIAL`, `TIMESERIAL`, `DATEVALUE`, `TIMEVALUE`, `DAY`,
`MONTH`, `YEAR`, `WEEKDAY`, `HOUR`, `MINUTE`, `SECOND`. Serielle Datumswerte
SHALL der Zählweise des Vorbilds folgen (ganzzahliger Anteil = Tag,
Nachkommaanteil = Tageszeit). `WEEKDAY` SHALL 1 für Sonntag liefern.
Ungültige Datums- oder Zeitangaben MUST Laufzeitfehler 5 auslösen.
#### Scenario: Serienwert und Rückumwandlung
- **WHEN** `d = DATESERIAL(1992, 3, 15)` gebildet und `YEAR(d)`, `MONTH(d)`, `DAY(d)` ausgewertet werden
- **THEN** liefern sie 1992, 3 und 15
#### Scenario: Wochentagszählung
- **WHEN** `WEEKDAY` auf einen Sonntag angewandt wird
- **THEN** ist das Ergebnis 1
#### Scenario: Ungültiges Datum
- **WHEN** `DATESERIAL(1992, 13, 1)` ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: Kompatibler Zufallszahlengenerator
`RND` und `RANDOMIZE` SHALL die Zahlenfolge des Vorbilds reproduzieren:
gleicher Startwert MUST dieselbe Folge liefern. `RND` ohne Argument und
mit positivem Argument SHALL die nächste Zahl liefern, mit Argument 0 die
zuletzt gelieferte wiederholen, mit negativem Argument die Folge auf einen
aus dem Argument abgeleiteten Startwert setzen. `RANDOMIZE` ohne Argument
SHALL einen Startwert erfragen, `RANDOMIZE TIMER` einen zeitabhängigen
setzen. Der verwendete Algorithmus MUST in der Sprachreferenz dokumentiert
sein.
#### Scenario: Reproduzierbare Folge
- **WHEN** zweimal `RANDOMIZE 42` gefolgt von drei `RND`-Aufrufen ausgeführt wird
- **THEN** sind beide Dreierfolgen identisch
#### Scenario: RND(0) wiederholt
- **WHEN** nach einem `RND`-Aufruf `RND(0)` ausgewertet wird
- **THEN** liefert es denselben Wert wie der vorangegangene Aufruf
### Requirement: Mathematikbibliothek mit Überlaufverhalten
Die Bibliothek SHALL die numerischen Funktionen des Vorbilds
bereitstellen (`ABS`, `SGN`, `INT`, `FIX`, `SQR`, `EXP`, `LOG`, `SIN`,
`COS`, `TAN`, `ATN`, `CINT`, `CLNG`, `CSNG`, `CDBL`, `CCUR`). Rundung
SHALL kaufmännisch-symmetrisch zur geraden Zahl erfolgen (Banker's
Rounding). Überschreitet ein Ergebnis den Wertebereich des Zieltyps, MUST
Laufzeitfehler 6 „Overflow" auftreten; `SQR` und `LOG` mit unzulässigem
Argument MUST Laufzeitfehler 5 auslösen, Division durch null Fehler 11.
#### Scenario: Rundung zur geraden Zahl
- **WHEN** `CINT(0.5)` und `CINT(1.5)` ausgewertet werden
- **THEN** liefern sie 0 und 2
#### Scenario: Überlauf bei Konvertierung
- **WHEN** `CINT(40000)` ausgewertet wird
- **THEN** tritt Laufzeitfehler 6 auf
#### Scenario: Wurzel aus negativer Zahl
- **WHEN** `SQR(-1)` ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: Finanzmathematische Funktionen
Die Bibliothek SHALL die finanzmathematischen Funktionen des Vorbilds
bereitstellen: `FV#` (Endwert), `PV#` (Barwert), `Pmt#` (Zahlung),
`IPmt#` (Zinsanteil), `PPmt#` (Tilgungsanteil), `NPer#` (Anzahl
Zahlungsperioden), `Rate#` (Zinssatz), `NPV#` (Kapitalwert), `IRR#`
(interner Zinsfuß), `MIRR#` (modifizierter interner Zinsfuß), `SLN#`
(lineare Abschreibung), `SYD#` (arithmetisch-degressive Abschreibung) und
`DDB#` (geometrisch-degressive Abschreibung). Alle SHALL in DOUBLE
rechnen. Das Argument für die Fälligkeit SHALL zwischen nachschüssiger
und vorschüssiger Zahlung unterscheiden. Ungültige Argumente — etwa ein
Zinssatz von null bei `NPer#` oder eine Periode außerhalb der Laufzeit
bei `IPmt#`/`PPmt#` — MUST Laufzeitfehler 5 auslösen. `Rate#` und `IRR#`
nähern sich iterativ; findet die Näherung keine Lösung, MUST
Laufzeitfehler 5 auftreten statt eines stillen Ersatzwerts. Die
Abbruchbedingung der Näherung MUST in docs/bibliothek.md dokumentiert
sein.
#### Scenario: Endwert einer Rentenzahlung
- **WHEN** `FV#` für 10 Perioden, 5 % Zins und eine Zahlung von 100 nachschüssig ausgewertet wird
- **THEN** entspricht das Ergebnis dem dokumentierten Sollwert der Bibliotheksreferenz
#### Scenario: Zins- und Tilgungsanteil ergänzen sich
- **WHEN** `IPmt#` und `PPmt#` für dieselbe Periode desselben Darlehens ausgewertet werden
- **THEN** ist ihre Summe gleich `Pmt#` für dieses Darlehen
#### Scenario: Näherung ohne Lösung
- **WHEN** `IRR#` mit einer Zahlungsreihe ohne Vorzeichenwechsel ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: System- und Umgebungsanweisungen
`ENVIRON$` SHALL Umgebungsvariablen nach Namen oder Position liefern,
`ENVIRON` sie setzen. `COMMAND$` SHALL die Aufrufargumente ohne
Programmnamen liefern. `FRE` SHALL einen Speicherwert liefern, `CLEAR`
Variablen zurücksetzen, `TRON`/`TROFF` die Ablaufverfolgung schalten.
`STACK` SHALL als Anweisung die Stapelgröße setzen und als Funktion die
verfügbare Stapelgröße liefern. `SYSTEM` SHALL das Programm beenden und
die Kontrolle an das Betriebssystem zurückgeben. `ERDEV` und `ERDEV$`
SHALL den Fehlercode bzw. den Namen des zuletzt meldenden Geräts
liefern. Nicht abbildbare Größen (Speicher- und Stapelwerte, Gerätefehler)
MUST einen definierten, dokumentierten Ersatzwert liefern statt still zu
variieren; der Ersatzwert MUST in docs/sprachreferenz.md unter
„Abweichungen" stehen.
#### Scenario: Umgebungsvariable lesen
- **WHEN** eine Umgebungsvariable gesetzt ist und `ENVIRON$("NAME")` ausgewertet wird
- **THEN** liefert es deren Wert
#### Scenario: SYSTEM beendet das Programm
- **WHEN** ein Programm `SYSTEM` ausführt
- **THEN** endet es mit demselben Beendigungsstatus wie bei `END`
#### Scenario: Unbekannte Umgebungsvariable
- **WHEN** `ENVIRON$` für einen nicht gesetzten Namen ausgewertet wird
- **THEN** ist das Ergebnis der leere String
## MODIFIED Requirements
### Requirement: Host-Abstraktion für Konsolen-E/A
Alle Konsolenwirkungen der Ausführungsschicht SHALL über eine
austauschbare Host-Schnittstelle laufen, die einen Bildschirmzustand
darstellt statt eines Zeichenstroms: Übergabe des Zellenpuffers zur
Anzeige, Abholen von Tastatur- und Größenänderungsereignissen sowie die
Abbruchprüfung (Strg+Untbr). Host-Aufrufe dürfen blockieren.
`tbc run` SHALL einen Konsolen-Host verwenden, der den Puffer im Terminal
darstellt und Tastendrücke liefert. Tests MUST einen Host verwenden
können, der ohne Terminal arbeitet, den Bildschirmzustand nach jedem
Schritt festhält und vorbereitete Tastendrücke einspeist. Eine
Bildschirmwirkung, die nur über einen Zeichenstrom ausdrückbar wäre, MUST
NOT vorkommen: `LOCATE`, `COLOR`, `CSRLIN`, `POS` und die Funktionsform
von `SCREEN` MUST über diese Schnittstelle vollständig abgebildet sein.
#### Scenario: Capture-Host im Test
- **WHEN** ein Korpusprogramm im Test-Harness läuft
- **THEN** entsteht der vollständige Bildschirmzustand im Capture-Host und ist vergleichbar, ohne dass ein Terminal vorhanden ist
#### Scenario: Cursorbewegung über die Schnittstelle
- **WHEN** ein Programm `LOCATE 5, 10 : PRINT "x"` ausführt
- **THEN** meldet der Host-Bildschirmzustand das Zeichen `x` an Position (5, 10)
#### Scenario: Tastendruck aus dem Host
- **WHEN** der Test-Host einen vorbereiteten Tastendruck liefert und das Programm `INKEY$` auswertet
- **THEN** erhält das Programm diese Taste
## REMOVED Requirements
### Requirement: Korpus-Stringfunktionen
**Reason**: Die auf den Phase-2-Korpus zugeschnittene Teilliste wird durch
die Anforderung „Vollständige Stringbibliothek" ersetzt, die den
vollständigen dokumentierten Funktionsumfang fordert und ihren Umfang aus
dem Sprachinventar bezieht.
**Migration**: Alle bisher geforderten Funktionen und Randfälle sind in
„Vollständige Stringbibliothek" enthalten; kein Verhalten entfällt.

View File

@@ -0,0 +1,54 @@
## ADDED Requirements
### Requirement: Jedes dokumentierte Element besitzt eine Signatur
Die Semantik SHALL für jedes im Sprachinventar geführte Element eine
Signatur besitzen (Argumentanzahl und -typen) — auch für Elemente, deren
Laufzeitverhalten noch aussteht. Ein im Inventar geführtes Element MUST
NOT als unbekannter Bezeichner oder mit einem generischen Syntaxfehler
abgewiesen werden; die Diagnose bzw. der Laufzeitfehler MUST es
namentlich nennen (Guiding Principle). Das gilt insbesondere für die
Gruppen, die bisher gar keine Signatur haben: die finanzmathematischen
Funktionen, die Record-Konvertierungsfunktionen (`MK…$`/`CV…`), die
Dateisystem-Funktionen `CURDIR$`, `DIR$`, `CHDRIVE`, sowie `LPOS`,
`STACK`, `SYSTEM`, `ERDEV`/`ERDEV$` und `SetFormatCC`.
#### Scenario: Element ohne Laufzeitverhalten wird namentlich abgewiesen
- **WHEN** ein Modul eine im Inventar als `offen` geführte Funktion verwendet
- **THEN** nennt die Ablehnung deren Namen und nicht „unbekannter Bezeichner"
#### Scenario: Argumentprüfung ohne Laufzeitverhalten
- **WHEN** ein Modul `MKL$()` ohne Argument enthält
- **THEN** meldet die Semantik eine Argumentanzahl-Diagnose, die `MKL$` nennt
### Requirement: Modulweites ON ERROR ist aus Prozeduren ansprechbar
`ON ERROR GOTO label` ohne `LOCAL` SHALL einen modulweiten Fehlerhandler
setzen, dessen Sprungziel auch dann aufgelöst wird, wenn die Anweisung in
einer Prozedur steht und das Label auf Modulebene liegt. Nur
`ON LOCAL ERROR GOTO label` SHALL prozedurlokale Handler-Auflösung
verlangen. Ein modulweites `ON ERROR` in einer Prozedur MUST NOT wie
`ON LOCAL ERROR` behandelt werden, und ein auf Modulebene vorhandenes
Label MUST NOT als „Label not defined" gemeldet werden.
#### Scenario: Handler auf Modulebene aus einer Prozedur
- **WHEN** ein Modul das Label `Fehler:` auf Modulebene führt und eine `SUB` die Anweisung `ON ERROR GOTO Fehler` enthält
- **THEN** wird das Label aufgelöst und es entsteht keine Diagnose
#### Scenario: ON LOCAL ERROR bleibt prozedurlokal
- **WHEN** eine `SUB` die Anweisung `ON LOCAL ERROR GOTO Fehler` enthält und `Fehler:` nur auf Modulebene existiert
- **THEN** wird „Label not defined" gemeldet
### Requirement: DATA-Elemente behalten ihren Rohtext
Unquotierte Elemente einer `DATA`-Anweisung SHALL exakt so erhalten
bleiben, wie sie im Quelltext stehen — insbesondere in ihrer Groß- und
Kleinschreibung. Die Normalisierung von Bezeichnern MUST NOT auf
`DATA`-Elemente wirken. Führender und nachgestellter Leerraum eines
unquotierten Elements SHALL entfernt werden, innenliegender erhalten
bleiben.
#### Scenario: Gemischte Schreibweise bleibt erhalten
- **WHEN** ein Modul `DATA Hallo Welt` enthält und `READ s$` ausgeführt wird
- **THEN** enthält `s$` den Text `Hallo Welt` mit unveränderter Groß- und Kleinschreibung
#### Scenario: Leerraum an den Rändern
- **WHEN** ein Modul `DATA ab cd ` enthält und gelesen wird
- **THEN** lautet der Wert `ab cd`

View File

@@ -0,0 +1,74 @@
## Purpose
Das Sprachinventar ist das Messinstrument für die Leitplanke
„Vollständigkeit ist das Soll": eine gepflegte Liste aller in der
Original-Hilfe des Vorbilds dokumentierten Anweisungen, Funktionen und
Metabefehle mit Abdeckungsstatus, gegen die sich der Implementierungsstand
jederzeit prüfen lässt.
## ADDED Requirements
### Requirement: Vollständiges Inventar der Original-Hilfe
`docs/inventar.md` SHALL jede in der Original-Hilfe des Vorbilds
dokumentierte Anweisung, Funktion, Metabefehl, Operator-Schlüsselwort und
Klausel als eigenen Eintrag führen. Ein dokumentiertes Element MUST NOT
fehlen; Vollständigkeit gegenüber der Quelle geht der Kürze vor. Jeder
Eintrag SHALL Name, Art (Anweisung/Funktion/Metabefehl), Themengruppe,
Status und Fundstelle tragen.
#### Scenario: Dokumentiertes Element ist erfasst
- **WHEN** die Original-Hilfe die Anweisung `VIEW PRINT` dokumentiert
- **THEN** enthält das Inventar einen Eintrag `VIEW PRINT` mit Art, Gruppe, Status und Fundstelle
#### Scenario: Non-Feature ist erfasst, nicht weggelassen
- **WHEN** `PEEK` als Non-Feature deklariert ist
- **THEN** steht `PEEK` mit Status `Non-Feature` im Inventar und die Fundstelle verweist auf den Abschnitt „Abweichungen" der Sprachreferenz
### Requirement: Festes Statusvokabular
Der Status eines Eintrags SHALL genau einen von drei Werten tragen:
`implementiert` (Frontend senkt ab und die Laufzeit führt aus),
`offen` (dokumentiert, noch nicht verfügbar) oder `Non-Feature`
(vom Projektinhaber abgelehnt und in der Sprachreferenz unter
„Abweichungen" gelistet). Ein Eintrag mit Status `Non-Feature` MUST eine
Fundstelle in der Sprachreferenz nennen.
#### Scenario: Unzulässiger Status
- **WHEN** ein Eintrag den Status `teilweise` trägt
- **THEN** schlägt die Inventarprüfung mit Nennung des Eintrags fehl
#### Scenario: Non-Feature ohne Fundstelle
- **WHEN** ein Eintrag den Status `Non-Feature` trägt, aber keine Fundstelle nennt
- **THEN** schlägt die Inventarprüfung mit Nennung des Eintrags fehl
### Requirement: Automatischer Abgleich Inventar gegen Implementierung
Ein automatischer Test SHALL das Inventar gegen den tatsächlichen
Implementierungsstand prüfen und bei jeder Divergenz fehlschlagen. Als
`implementiert` markierte Elemente MUST im Frontend eine Signatur besitzen
und MUST NOT auf einen „nicht verfügbar"-Marker absenken; als `offen`
markierte Elemente MUST auf einen solchen Marker absenken oder ohne
Signatur sein; als `Non-Feature` markierte Elemente MUST zur Compile-Zeit
mit „Feature unavailable" abgewiesen werden. Der Test MUST das
divergierende Element, seinen Inventarstatus und den vorgefundenen
Zustand benennen.
#### Scenario: Inventar hinkt der Implementierung hinterher
- **WHEN** `LOCATE` implementiert wurde, im Inventar aber noch `offen` steht
- **THEN** schlägt der Abgleich fehl und nennt `LOCATE`, Status `offen` und den Befund „implementiert"
#### Scenario: Inventar behauptet zu viel
- **WHEN** ein Eintrag `implementiert` trägt, das Element aber weiterhin auf den „nicht verfügbar"-Marker absenkt
- **THEN** schlägt der Abgleich fehl und nennt das Element
#### Scenario: Abdeckungsstand ist abrufbar
- **WHEN** der Abgleich läuft
- **THEN** nennt er die Zahl der Einträge je Status als Abdeckungsstand
### Requirement: Keine stillen Lücken bei dokumentierten Elementen
Ein Element mit Status `offen` MUST bei Verwendung eine benannte
Ablehnung erzeugen — entweder eine Compile-Diagnose oder den Laufzeitfehler
für nicht verfügbare Funktionen —, die das Element namentlich nennt. Ein
generischer Syntaxfehler oder „unbekannter Bezeichner" für ein
dokumentiertes Element MUST NOT auftreten (Guiding Principle).
#### Scenario: Offenes Element wird namentlich abgewiesen
- **WHEN** ein Programm eine im Inventar als `offen` geführte Anweisung verwendet
- **THEN** nennt die Ablehnung den Namen der Anweisung, nicht nur „Syntaxfehler"

View File

@@ -0,0 +1,173 @@
## ADDED Requirements
### Requirement: Zellenpuffer ohne Terminalabhängigkeit
Der Zellenpuffer mit der vollständigen Bildschirmsemantik (Cursor,
Farbattribute, Umbruch, Scrollen, Scrollbereich, Größenänderung) SHALL
ohne Terminal instanziierbar, veränderbar und auslesbar sein. Die
Anbindung an ein konkretes Terminal SHALL ausschließlich in der
Darstellungsschicht liegen. Damit MUST jedes Bildschirmverhalten in
automatischen Tests ohne Terminal prüfbar sein, und die Ausführungsschicht
MUST NOT von einer Terminal-Bibliothek abhängen.
#### Scenario: Bildschirmverhalten im Test ohne Terminal
- **WHEN** ein Testprogramm in einer Umgebung ohne Terminal `LOCATE 5, 10 : PRINT "x"` ausführt
- **THEN** trägt die Zelle (5, 10) das Zeichen `x` und der Test benötigt kein Terminal
### Requirement: Bildschirmanweisungen des Dialekts
`CLS`, `COLOR`, `LOCATE`, `WIDTH`, `VIEW PRINT` und die Anweisungsform von
`SCREEN` SHALL auf dem Zellenpuffer wirken. `CLS` SHALL den Scrollbereich
löschen und den Cursor an dessen Anfang setzen; `CLS 2` SHALL nur den
Textbereich löschen. `COLOR` SHALL Vordergrund und Hintergrund für
nachfolgende Ausgaben setzen, ausgelassene Argumente lassen den bisherigen
Wert unverändert. `WIDTH` SHALL die Spalten- und Zeilenzahl setzen, soweit
die Darstellungsfläche es zulässt. `VIEW PRINT oben TO unten` SHALL den
Scrollbereich begrenzen, `VIEW PRINT` ohne Argumente ihn auf den ganzen
Bildschirm zurücksetzen.
#### Scenario: CLS setzt Cursor zurück
- **WHEN** nach Ausgaben in Zeile 10 `CLS` ausgeführt wird
- **THEN** ist der Puffer leer und `CSRLIN` liefert 1, `POS(0)` liefert 1
#### Scenario: COLOR wirkt nur auf Folgeausgaben
- **WHEN** `PRINT "a" : COLOR 14, 1 : PRINT "b"` ausgeführt wird
- **THEN** trägt die Zelle mit `a` das vorherige Attribut und die Zelle mit `b` Vordergrund 14 auf Hintergrund 1
#### Scenario: Ausgelassenes COLOR-Argument
- **WHEN** nach `COLOR 14, 1` die Anweisung `COLOR , 4` ausgeführt wird
- **THEN** bleibt der Vordergrund 14 und der Hintergrund wird 4
### Requirement: Bildschirm-Abfragefunktionen
`CSRLIN` SHALL die aktuelle Cursorzeile liefern, `POS(0)` die aktuelle
Cursorspalte, beide 1-basiert. Die Funktionsform `SCREEN(zeile, spalte
[, farbe])` SHALL das Zeichen an der genannten Position als Codepoint
liefern, bei gesetztem dritten Argument stattdessen dessen Farbattribut.
Positionen außerhalb des Bildschirms MUST Laufzeitfehler 5 „Illegal
function call" auslösen.
#### Scenario: Zeichen zurücklesen
- **WHEN** `LOCATE 3, 7 : PRINT "Q";` ausgeführt und danach `SCREEN(3, 7)` ausgewertet wird
- **THEN** liefert `SCREEN(3, 7)` den Codepoint von `Q`
#### Scenario: Abfrage außerhalb des Bildschirms
- **WHEN** bei 80×25 `SCREEN(30, 1)` ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: Tastatureingabe ohne Zeilenmodell
`INKEY$` SHALL ohne zu blockieren die nächste anstehende Taste liefern:
den leeren String bei leerem Puffer, ein Zeichen bei einer
Zeichentaste, eine zwei Zeichen lange Folge mit führendem Nullzeichen bei
einer Sondertaste. `INPUT$(n [, #dateinummer])` SHALL genau `n` Zeichen
lesen und dabei blockieren, ohne sie am Bildschirm zu wiederholen.
#### Scenario: INKEY$ bei leerem Tastaturpuffer
- **WHEN** `INKEY$` ohne anstehende Taste ausgewertet wird
- **THEN** liefert es den leeren String und blockiert nicht
#### Scenario: Sondertaste als zwei Zeichen
- **WHEN** F1 gedrückt wurde und `INKEY$` ausgewertet wird
- **THEN** hat das Ergebnis die Länge 2 und beginnt mit dem Nullzeichen
### Requirement: Keine feste Bildschirmgröße im Verhalten
Kein beobachtbares Verhalten SHALL eine feste Spalten- oder Zeilenzahl
voraussetzen. Wo die Referenz des Vorbilds von 80×25 spricht, ist stets
der volle aktuelle Bildschirm gemeint. Insbesondere SHALL `CLS` den
vollen aktuellen Bildschirm löschen, der Scrollbereich ohne eigene
`VIEW PRINT`-Einstellung den vollen aktuellen Bildschirm umfassen, der
Zeilenumbruch an der aktuell letzten Spalte erfolgen, das Scrollen an
der aktuell letzten Zeile des Bereichs auslösen und die Grenzprüfung von
`LOCATE` und der Funktionsform von `SCREEN` gegen die aktuellen
Abmessungen prüfen. Die Werte 80 und 25 MUST NOT als Grenze in
beobachtbarem Verhalten auftreten.
#### Scenario: Löschen und Scrollen auf großem Bildschirm
- **WHEN** der Bildschirm 120×40 misst, in Zeile 40 ein Umbruch erfolgt und danach `CLS` ausgeführt wird
- **THEN** scrollt der Bildschirm erst an Zeile 40 und `CLS` löscht alle 40 Zeilen
#### Scenario: Adressierbarkeit jenseits von 80×25
- **WHEN** der Bildschirm 120×40 misst und `LOCATE 40, 120` ausgeführt wird
- **THEN** entsteht kein Fehler und `CSRLIN` liefert 40, `POS(0)` liefert 120
### Requirement: Größenänderung zur Laufzeit
Ändert sich die Größe der Darstellungsfläche während ein Programm läuft,
SHALL die Größenänderung als Ereignis bis zum Bildschirmzustand
durchgereicht und der Zellenpuffer angepasst werden. Der Inhalt SHALL
oben links erhalten bleiben; der Cursor SHALL in die neuen Grenzen
geklemmt werden; ein `VIEW PRINT`-Bereich, der nicht mehr vollständig in
den Bildschirm passt, SHALL auf die neuen Grenzen geklemmt und, falls er
dadurch leer würde, auf den vollen Bildschirm zurückgesetzt werden. Alle
programmseitig sichtbaren Größen — `CSRLIN`, `POS`, die Grenzen von
`LOCATE` und der Funktionsform von `SCREEN` — MUST unmittelbar nach der
Änderung die neuen Abmessungen widerspiegeln.
#### Scenario: Vergrößerung während der Ausführung
- **WHEN** ein laufendes Programm bei 80×25 ausgibt und die Fläche auf 120×40 wächst
- **THEN** bleibt der bisherige Inhalt oben links stehen und `LOCATE 40, 120` ist danach zulässig
#### Scenario: Verkleinerung klemmt den Cursor
- **WHEN** der Cursor auf Zeile 40 steht und die Fläche auf 80×25 schrumpft
- **THEN** liegt der Cursor danach innerhalb der neuen Grenzen
#### Scenario: Scrollbereich überlebt die Verkleinerung
- **WHEN** `VIEW PRINT 30 TO 38` gesetzt ist und die Fläche auf 25 Zeilen schrumpft
- **THEN** ist der Scrollbereich danach gültig und liegt vollständig innerhalb des Bildschirms
## MODIFIED Requirements
### Requirement: Dynamische Terminalgröße mit Mindestmaß
Der Bildschirm SHALL der Terminalgröße folgen (Puffer per `resize`
anpassbar; Inhalt bleibt oben links erhalten, Cursor wird geklemmt).
Die Größe SHALL zu jedem Zeitpunkt aus der Darstellungsfläche abgeleitet
und nicht fest vorgegeben werden. Die Mindestgröße ist 80×25: kleinere
Werte werden auf 80×25 geklemmt, und ist die Render-Fläche kleiner als
80×25, SHALL nur ein Hinweis „Terminal zu klein" mit Ist- und
Mindestgröße gerendert werden. Dieses Mindestmaß ist ausschließlich eine
untere Schranke der Darstellung; es MUST NOT als Bildschirmgröße im
Verhalten des Programms auftreten, solange die Fläche größer ist.
#### Scenario: Vergrößertes Terminal
- **WHEN** der Bildschirm auf 120×40 gesetzt wird
- **THEN** sind alle 120 Spalten und 40 Zeilen adressierbar (`LOCATE 40, 120`)
#### Scenario: Zu kleines Terminal
- **WHEN** die Render-Fläche 60×20 misst
- **THEN** erscheint statt des Puffers der Hinweis mit Minimum 80×25
### Requirement: Unicode-Zellenmodell
Der Puffer SHALL Unicode-Zeichen speichern (keine CP437-Emulation).
Zeichen mit Darstellungsbreite 2 (u. a. Emoji, CJK) SHALL zwei
nebeneinanderliegende Zellen belegen (Entscheidung 2026-09-02): die erste
trägt das Zeichen, die zweite ist als Fortsetzung markiert und MUST NOT
eigenständig beschrieben werden. Der Cursor SHALL nach der Ausgabe eines
breiten Zeichens um zwei Spalten vorrücken; `POS` SHALL die Spalte des
Zeichenanfangs zählen. Passt ein breites Zeichen nicht mehr in die letzte
Spalte, SHALL es vollständig in die nächste Zeile umgebrochen werden und
die letzte Spalte leer bleiben. `LOCATE` auf die Fortsetzungszelle SHALL
auf den Zeichenanfang wirken.
#### Scenario: Umlaute und Symbole
- **WHEN** `Ä☃` ausgegeben wird
- **THEN** belegen `Ä` und `☃` je genau eine Zelle
#### Scenario: Breites Zeichen belegt zwei Zellen
- **WHEN** an Spalte 1 ein CJK-Zeichen ausgegeben wird
- **THEN** ist Spalte 2 als Fortsetzung belegt und der Cursor steht auf Spalte 3
#### Scenario: Breites Zeichen am rechten Rand
- **WHEN** bei 80 Spalten der Cursor auf Spalte 80 steht und ein breites Zeichen ausgegeben wird
- **THEN** bleibt Spalte 80 leer und das Zeichen steht in Spalte 1 der Folgezeile
### Requirement: 1-basierte Cursor-API mit Bereichsprüfung
`LOCATE`, `CSRLIN` und `POS` SHALL 1-basiert arbeiten. `LOCATE`
außerhalb der aktuellen Bildschirmgrenzen SHALL Laufzeitfehler 5
„Illegal function call" auslösen. Ausgelassene Argumente von `LOCATE`
SHALL den jeweiligen Wert unverändert lassen; die Argumente für
Cursorsichtbarkeit und Cursorform SHALL entgegengenommen und, soweit das
Terminal sie nicht abbilden kann, folgenlos bleiben.
#### Scenario: Grenzprüfung
- **WHEN** bei 80×25 `LOCATE 26, 1` aufgerufen wird
- **THEN** tritt Laufzeitfehler 5 auf
#### Scenario: Ausgelassenes LOCATE-Argument
- **WHEN** der Cursor auf (5, 9) steht und `LOCATE , 3` ausgeführt wird
- **THEN** steht der Cursor auf (5, 3)

View File

@@ -0,0 +1,106 @@
## 1. Vollständigkeits-Inventar
- [x] 1.1 Anweisungs-, Funktions- und Metabefehlsliste aus der Original-Hilfe erheben (dos-help.soulsphere.org, Topic-Listen, README der Professional Edition) und als Rohliste ablegen; verifiziert dadurch, dass die Zahl der erfassten Themen gegen die Topic-Übersicht der Quelle abgeglichen und im Change notiert ist
- [x] 1.2 `docs/inventar.md` als Pipe-Tabelle mit den Spalten Name, Art, Gruppe, Status, Fundstelle anlegen und alle Einträge aus 1.1 mit Erststatus füllen; verifiziert dadurch, dass jede Zeile sechs Spalten hat (Name, Art, Gruppe, Status, Fundstelle, Quelle) und das Statusvokabular nur `implementiert`/`offen`/`Non-Feature` enthält
- [x] 1.3 Abgleichstest schreiben, der die Tabelle parst und gegen `builtin_fn`, `builtin_stmt`, `banned_feature` sowie die `Unsupported`-Marker hält; verifiziert dadurch, dass der Test auf dem Ist-Stand grün ist und nach einer künstlich falsch gesetzten Statuszeile mit Nennung des Elements fehlschlägt
- [x] 1.4 Prüfung ergänzen, dass `Non-Feature`-Einträge eine Fundstelle in docs/sprachreferenz.md nennen und dokumentierte `offen`-Elemente namentlich abgewiesen werden (kein generischer Syntaxfehler); verifiziert durch je einen Testfall pro Regel
- [x] 1.5 Abdeckungsstand (Anzahl je Status) im Testausgabetext ausweisen; verifiziert dadurch, dass `cargo test` die drei Zahlen nennt
- [x] 1.6 Vom Inventar aufgedeckte Abweichung von der Phase-1-Spec schließen: Non-Features, die der Compiler nicht abwies, ergänzen — `CALLS`, `SSEG`, `SSEGADD`, `StringAddress`/`Assign`/`Length`/`Release`, `POINT`, `VIEW`, `COM`, `PEN`, `STRIG`, `STICK` in `banned_feature`; `LINE` ohne `INPUT` und `OPEN "COMn:"` als „Feature unavailable"; verifiziert durch `dokumentierte_elemente_werden_namentlich_abgewiesen`
- [x] 1.7 Signaturen in `builtin_fn`/`builtin_stmt` für alle bislang signaturlosen Inventarelemente ergänzen (Finanzmathematik, `MK…$`/`CV…`, `CURDIR$`, `DIR$`, `CHDRIVE`, `LPOS`, `STACK`, `SYSTEM`, `ERDEV`/`ERDEV$`, `SetFormatCC`); verifiziert durch Frontend-Test über ein Programm, das jedes davon einmal verwendet, ohne Diagnose „unbekannter Bezeichner"
- [x] 1.8 Sicherstellen, dass jedes als `offen` geführte Element namentlich abgewiesen wird (Diagnose oder Laufzeitfehler nennt den Namen); verifiziert durch Test, dass `MKL$()` ohne Argument eine Diagnose mit dem Namen `MKL$` erzeugt
## 2. Bruchschritt: Puffer, Host, Snapshot-Harness
- [x] 2.1 `Cell`/`TextScreen` samt Tests von `tb-ui::screen` nach `tb-runtime::screen` verschieben, ratatui-Importe entfernen; verifiziert dadurch, dass `cargo test -p tb-runtime` grün ist und `tb-runtime/Cargo.toml` weiterhin weder ratatui noch crossterm führt
- [x] 2.2 `tb-runtime` als Abhängigkeit in `tb-ui` aufnehmen; `basic_color()` und `impl Widget` in `tb-ui` belassen und auf den Runtime-Typ umstellen; verifiziert dadurch, dass `cargo run -p tb-ui --example spike` unverändert rendert
- [x] 2.3 `Host`-Trait neu schneiden: Übergabe des Zellenpuffers zur Anzeige, Ereignisabholung (Taste, Größenänderung), Abbruchprüfung; verifiziert dadurch, dass `tb-runtime` kompiliert und der Trait keine Stream-Methoden mehr trägt
- [x] 2.4 `ConsoleHost` auf Darstellung des Puffers im Terminal und Tastaturereignisse umstellen; verifiziert dadurch, dass `tbc run tests/compat/hello.bas` im Terminal die erwartete Ausgabe zeigt
- [x] 2.5 `CaptureHost` auf Bildschirmzustand plus vorbereitete Tastendrücke umstellen; verifiziert durch einen Unit-Test, der Zeichen und Attribut einer Zelle nach `LOCATE`/`COLOR`/`PRINT` prüft
- [x] 2.6 Darstellungsaufrufe an die bestehenden Tick-Grenzen und vor blockierende Eingaben hängen; verifiziert dadurch, dass ein Programm mit Ausgabe vor `INPUT` den Text vor der Eingabeaufforderung zeigt
- [x] 2.7 Snapshot-Serialisierung schreiben: Textbild getrimmt bis zur letzten belegten Zeile/Spalte, Attributebene nur bei verwendetem `COLOR`; verifiziert durch Unit-Tests für getrimmte Ausgabe, signifikante Zeilen-Innenleerzeichen und Weglassen der Attributebene
- [x] 2.8 Harness `crates/tb-cli/tests/compat.rs` auf Snapshot-Vergleich umstellen, inklusive Fehlermeldung mit Datei, erster abweichender Zeile sowie Zeile/Spalte/Soll/Ist bei Attributabweichung; verifiziert durch je einen absichtlich abweichenden Testfall
- [x] 2.9 Die acht bestehenden `.out`-Dateien neu erzeugen und jeden Diff einzeln prüfen und begründen; verifiziert dadurch, dass `PRINT`-only-Programme unverändert bleiben und jede Abweichung im Change begründet notiert ist
- [x] 2.10 `.gitattributes` auf die neuen Snapshot-Dateien prüfen; verifiziert dadurch, dass `.out`-Dateien weiterhin vor Zeilenenden-Konvertierung geschützt sind
## 3. Größenunabhängigkeit und Laufzeit-Größenänderung
- [x] 3.1 Alle Bildschirmpfade auf die Abmessungen des Puffers umstellen (`CLS`, voreingestellter Scrollbereich, Umbruchspalte, Scrollzeile, Grenzprüfungen von `LOCATE` und `SCREEN()`); verifiziert dadurch, dass eine Suche über `tb-runtime` und `tb-ui` keine Vergleiche gegen die Literale 80 oder 25 außerhalb der Mindestmaß-Prüfung der Darstellungsschicht mehr findet
- [x] 3.2 Größenänderungsereignis vom Host bis zum Puffer durchreichen; verifiziert durch Test, dass ein vom Test-Host ausgelöster Wechsel die Abmessungen des Puffers ändert
- [x] 3.3 Anpassung bei Größenänderung: Inhalt oben links erhalten, Cursor klemmen, `VIEW PRINT`-Bereich klemmen und bei leerem Ergebnis auf den vollen Bildschirm zurücksetzen; verifiziert durch je einen Unit-Test für Vergrößerung, Verkleinerung und ungültig gewordenen Scrollbereich
- [x] 3.4 Test-Host mit explizit gesetzter Bildschirmgröße je Korpusprogramm, ohne stillschweigenden Vorgabewert; verifiziert dadurch, dass ein Korpusprogramm ohne Größenangabe vom Harness abgewiesen wird
- [x] 3.5 Bildschirm-Korpusprogramm bei 80×25 und 120×40 mit je eigener Sollausgabe; verifiziert dadurch, dass sich die Sollausgaben in Umbruch- und Scrollverhalten unterscheiden und beide Läufe grün sind
- [x] 3.6 Korpusprogramm mit Größenänderung während der Ausführung; verifiziert dadurch, dass der Snapshot den erhaltenen Inhalt und die Ausgabe in den neuen Grenzen zeigt
## 4. Unicode-Doppelzellen
- [x] 4.1 `unicode-width` als Abhängigkeit aufnehmen und Zellenmodell um Fortsetzungszellen erweitern; verifiziert durch Unit-Test, dass ein CJK-Zeichen an Spalte 1 die Spalte 2 als Fortsetzung belegt
- [x] 4.2 Cursorfortschritt, `POS` und Umbruch am rechten Rand auf Darstellungsbreite umstellen; verifiziert durch Unit-Tests für Vorrücken um zwei Spalten und vollständigen Umbruch bei belegter letzter Spalte
- [x] 4.3 Überschreiben einer Zellenhälfte leert die andere; verifiziert durch Unit-Test, dass keine Geisterzeichen zurückbleiben
- [x] 4.4 `LOCATE` auf eine Fortsetzungszelle auf den Zeichenanfang abbilden; verifiziert durch Unit-Test
- [x] 4.5 Korpusprogramm mit CJK und Emoji inklusive Randumbruch ergänzen; verifiziert dadurch, dass der Snapshot der dokumentierten Sollausgabe entspricht
- [x] 4.6 Abweichung in docs/sprachreferenz.md festhalten; verifiziert durch den Abschnittseintrag
## 5. Bildschirmanweisungen und -funktionen
- [x] 5.1 `CLS` (inkl. `CLS 2`), `COLOR` mit ausgelassenen Argumenten, `LOCATE` mit ausgelassenen Argumenten und Fehler 5 bei Grenzüberschreitung; verifiziert durch Korpustest mit Snapshot und je einem Fehlerfall
- [x] 5.2 `WIDTH`, `VIEW PRINT` (setzen und zurücksetzen), Scrollen im begrenzten Bereich; verifiziert durch Korpustest, dass Zeilen außerhalb des Bereichs unverändert bleiben
- [x] 5.3 `CSRLIN`, `POS(0)` und die Funktionsform `SCREEN(zeile, spalte [, farbe])` inklusive Fehler 5 außerhalb des Bildschirms; verifiziert durch Korpustest mit Zurücklesen eines geschriebenen Zeichens
- [x] 5.4 Anweisungsform `SCREEN` entgegennehmen und dokumentiertes Verhalten festlegen; verifiziert dadurch, dass keine `Unsupported`-Absenkung mehr erfolgt und das Verhalten in der Sprachreferenz steht
- [x] 5.5 `INKEY$` nicht blockierend (leerer String, Zeichen, Sondertaste als zwei Zeichen mit führendem Nullzeichen); verifiziert durch Test mit vorbereiteten Tastendrücken im Capture-Host
- [x] 5.6 `INPUT$(n)` blockierend ohne Echo; verifiziert durch Test, dass genau `n` Zeichen gelesen werden und der Bildschirm unverändert bleibt
- [x] 5.7 `TAB` und `SPC` in der `PRINT`-Familie; verifiziert durch Korpustest mit Spaltenpositionen
- [x] 5.8 `KEY`-Umfang (`KEY LIST`/`ON`/`OFF`, Funktionstasten-Makros) aus der Original-Hilfe klären, umsetzen und in docs/sprachreferenz.md festhalten; verifiziert durch Korpustest und Dokumentationsabschnitt
## 6. String-, Zahlen- und Formatbibliothek
- [x] 6.1 Alle im Inventar geführten Stringfunktionen vervollständigen inklusive Randfälle (`VAL`-Präfix, `STR$`-Leerzeichen, Fehler 5 bei Startposition < 1, Länge über Stringende); verifiziert durch Korpustest je Randfall
- [x] 6.2 `PRINT USING`/`LPRINT USING`/`FORMAT$` mit numerischen Platzhaltern, Tausendertrennung, Vorzeichenführung, `$$`/`**`/`**$`, Exponentialform und String-Platzhaltern; verifiziert durch Korpustest je Formatzeichenklasse
- [x] 6.3 Feldüberlauf mit `%`-Präfix umsetzen und in docs/sprachreferenz.md festhalten; verifiziert durch Korpustest und Dokumentationsabschnitt
- [x] 6.4 Wiederverwendung der Formatzeichenkette bei mehreren Werten; verifiziert durch Korpustest
- [x] 6.5 Mathematikfunktionen vervollständigen inklusive Banker's Rounding, Fehler 6 bei Überlauf, Fehler 5 bei `SQR`/`LOG`, Fehler 11 bei Division durch null; verifiziert durch Korpustest je Fehlerfall
- [x] 6.6 Kompatiblen `RND`/`RANDOMIZE`-PRNG umsetzen (`RND(0)` wiederholt, negatives Argument setzt Startwert) und den Algorithmus dokumentieren; verifiziert durch Korpustest mit reproduzierbarer Folge nach `RANDOMIZE 42`
- [x] 6.7 Datums- und Zeitfunktionen inklusive Serienwert-Zählweise, `WEEKDAY` = 1 für Sonntag und Fehler 5 bei ungültigen Angaben; verifiziert durch Korpustest mit festem Datum
- [x] 6.8 `DATE$`/`TIME$` als Anweisung; verifiziert durch Test, dass die Funktionsform danach den gesetzten Wert liefert
- [x] 6.9 Finanzmathematische Funktionen `FV#`, `PV#`, `Pmt#`, `IPmt#`, `PPmt#`, `NPer#`, `Rate#`, `NPV#`, `IRR#`, `MIRR#`, `SLN#`, `SYD#`, `DDB#` in DOUBLE mit Fälligkeitsargument; verifiziert durch Korpustest je Funktion gegen dokumentierte Sollwerte
- [x] 6.10 Fehler 5 bei ungültigen Argumenten der Finanzfunktionen und bei erfolgloser Näherung von `Rate#`/`IRR#`; verifiziert durch Korpustest je Fall
- [x] 6.11 Abbruchbedingung der Näherung in docs/bibliothek.md dokumentieren; verifiziert durch den Abschnittseintrag
- [x] 6.12 `SetFormatCC` für Währungszeichen und -stellung von `$$`; verifiziert durch Korpustest, dass `PRINT USING "$$#.##"` das gesetzte Zeichen verwendet
- [x] 6.13 `docs/bibliothek.md` anlegen und mit dem umgesetzten Stand füllen; verifiziert dadurch, dass jede in Gruppe 6 umgesetzte Funktion dort einen Eintrag hat
## 7. Datei-E/A
- [x] 7.1 Dateitabelle und `OPEN` in beiden Syntaxen für sequenziell, `RANDOM` und `BINARY`, `CLOSE` (mit und ohne Argument), `RESET`, `FREEFILE`; verifiziert durch Korpustest inklusive Fehler 55, 52 und 53
- [x] 7.2 Sequenzielle Übertragung: `PRINT #`, `WRITE #`, `INPUT #`, `LINE INPUT #`, `EOF`, Fehler 62 beim Lesen über das Dateiende; verifiziert durch Korpustest, dass `WRITE #` und `INPUT #` gegenläufig sind
- [x] 7.3 Recordpuffer mit `FIELD`, `LSET`, `RSET` inklusive Abschneiden überlanger Werte; verifiziert durch Korpustest
- [x] 7.4 Festtextfelder als UTF-32 mit konstanter Recordlänge; verifiziert durch Korpustest, dass ein Record mit ASCII und einer mit Nicht-ASCII dieselbe Byteanzahl belegen
- [x] 7.5 `GET`/`PUT` für `RANDOM` mit Recordnummer und mit UDT-Variablen; verifiziert durch Korpustest mit Schreiben und Lesen an Position 3
- [x] 7.6 Binärzugriff mit byteweiser Positionierung, `SEEK` als Anweisung und Funktion; verifiziert durch Korpustest, dass ein positioniert überschriebenes Byte zurückgelesen wird und die Nachbarbytes unverändert bleiben
- [x] 7.7 `LOF`, `LOC`, `FILEATTR` inklusive Fehler 52 auf geschlossener Datei; verifiziert durch Korpustest
- [x] 7.8 `LOCK`/`UNLOCK` umsetzen; verifiziert durch Korpustest für Sperren und Freigeben, plattformbedingte Abweichungen in docs/sprachreferenz.md notiert
- [x] 7.9 Dateisystem-Anweisungen `KILL`, `NAME … AS`, `FILES`, `CHDIR`, `MKDIR`, `RMDIR`, `SHELL` mit plattformübergreifender Pfadsemantik (`\` und `/`, Laufwerksbuchstaben) inklusive Fehler 53 und 76; verifiziert durch Korpustest mit Rückwärts-Schrägstrich
- [x] 7.10 `LPRINT`/`LPRINT USING` mit dokumentiertem Ausgabeziel sowie `LPOS`; verifiziert durch Test, dass die Formatierung `PRINT` entspricht, `LPOS` die Druckerspalte liefert, und durch den Abschnitt in der Sprachreferenz
- [x] 7.11 Record-Konvertierungsfunktionen `MKI$`/`MKL$`/`MKS$`/`MKD$`/`MKC$` und `CVI`/`CVL`/`CVS`/`CVD`/`CVC`; verifiziert durch Korpustest, dass jedes Paar gegenläufig ist und falsche Argumentlänge Fehler 5 auslöst
- [x] 7.12 MBF-Varianten `MKSMBF$`/`MKDMBF$`/`CVSMBF`/`CVDMBF` umsetzen oder als Non-Feature namentlich abweisen und in docs/sprachreferenz.md listen; verifiziert durch Korpustest bzw. den Abschnittseintrag
- [x] 7.13 `CURDIR$`, `DIR$` (erster und Folgetreffer, leerer String am Ende), `CHDRIVE` und `SHELL` als Funktion; verifiziert durch Korpustest, der ein Verzeichnis mit `DIR$` vollständig durchläuft
- [x] 7.14 Korpus-Dateiprogramme in einem temporären Arbeitsverzeichnis ausführen; verifiziert dadurch, dass nach `cargo test` `git status` sauber ist
## 8. System- und Umgebungsanweisungen
- [x] 8.1 `ENVIRON$` (nach Name und Position), `ENVIRON`, `COMMAND$`; verifiziert durch Korpustest inklusive leerem String für unbekannte Namen
- [x] 8.2 `FRE`, `CLEAR`, `TRON`, `TROFF` mit definiertem, dokumentiertem Verhalten; verifiziert dadurch, dass keine `Unsupported`-Absenkung mehr erfolgt und der Ersatzwert für `FRE` in der Sprachreferenz steht
- [x] 8.3 `STACK` als Anweisung und Funktion, `SYSTEM`, `ERDEV`/`ERDEV$` mit definierten Ersatzwerten; verifiziert durch Korpustest, dass `SYSTEM` mit demselben Status endet wie `END`, und durch die Ersatzwert-Einträge in docs/sprachreferenz.md
## 9. Altlasten aus Phase 2
- [x] 9.1 `ON ERROR GOTO` auf Modulebene aus Prozeduren auflösbar machen (`sema.rs`, `lower_stmt`/`OnError`), `ON LOCAL ERROR` bleibt prozedurlokal; verifiziert durch je einen Frontend-Test für beide Fälle
- [x] 9.2 DATA-Rohtext im Lexer erhalten (keine Bezeichner-Normalisierung, Randleerraum entfernt, Innenleerraum erhalten); verifiziert durch Korpustest mit gemischter Schreibweise
- [x] 9.3 `TODO verify`-Zellen der Konvertierungsmatrix in docs/tbvm-design.md gegen die Original-Hilfe auflösen (CURRENCY-Promotion mit Gleitkomma, `^`-Ergebnistyp, Exponentialform-Schwellen, CURRENCY-Ausgabeformat); verifiziert dadurch, dass keine `TODO verify`-Zelle mehr im Dokument steht
- [x] 9.4 Korpustest `konvertierung.bas` um die in 9.3 geklärten Randfälle schärfen; verifiziert durch die erweiterte Sollausgabe
## 10. Abschluss
- [x] 10.1 Inventarstatus für alle in diesem Change umgesetzten Elemente auf `implementiert` setzen; verifiziert dadurch, dass der Abgleichstest aus 1.3 grün bleibt
- [x] 10.2 docs/sprachreferenz.md fortschreiben (Doppelzellen, `KEY n`, `PRINT USING`-Überlauf, UTF-32-Records, plattformbedingte Abweichungen); verifiziert durch die vorhandenen Abschnitte
- [x] 10.3 Vollständige Suite ausführen; verifiziert dadurch, dass `cargo test --workspace` grün ist. **Nur macOS geprüft** — Windows und Linux stehen aus und gehören zu den Plattformtests in Phase 6 (PLAN.md); die Laufzeit enthält keinen plattformspezifischen Code außer der Pfadnormierung und `SHELL`.
- [x] 10.4 Meilenstein prüfen: klassische Konsolenprogramme des Korpus laufen unverändert; verifiziert dadurch, dass jedes Korpusprogramm ohne Laufzeitfehler 73 durchläuft
- [x] 10.5 PLAN.md Phase 3 abhaken, soweit dieser Change reicht, und den offenen ISAM-Teil auf `phase-3-isam` verweisen; verifiziert durch den aktualisierten Planabschnitt