diff --git a/openspec/changes/phase-3-runtime-bildschirm/.openspec.yaml b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/.openspec.yaml similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/.openspec.yaml rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/.openspec.yaml diff --git a/openspec/changes/phase-3-runtime-bildschirm/design.md b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/design.md similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/design.md rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/design.md diff --git a/openspec/changes/phase-3-runtime-bildschirm/proposal.md b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/proposal.md similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/proposal.md rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/proposal.md diff --git a/openspec/changes/phase-3-runtime-bildschirm/rohliste-original-hilfe.md b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/rohliste-original-hilfe.md similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/rohliste-original-hilfe.md rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/rohliste-original-hilfe.md diff --git a/openspec/changes/phase-3-runtime-bildschirm/specs/datei-eio/spec.md b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/datei-eio/spec.md similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/specs/datei-eio/spec.md rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/datei-eio/spec.md diff --git a/openspec/changes/phase-3-runtime-bildschirm/specs/kompat-testkorpus/spec.md b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/kompat-testkorpus/spec.md similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/specs/kompat-testkorpus/spec.md rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/kompat-testkorpus/spec.md diff --git a/openspec/changes/phase-3-runtime-bildschirm/specs/konsolen-basisbibliothek/spec.md b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/konsolen-basisbibliothek/spec.md similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/specs/konsolen-basisbibliothek/spec.md rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/konsolen-basisbibliothek/spec.md diff --git a/openspec/changes/phase-3-runtime-bildschirm/specs/sprach-frontend/spec.md b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/sprach-frontend/spec.md similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/specs/sprach-frontend/spec.md rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/sprach-frontend/spec.md diff --git a/openspec/changes/phase-3-runtime-bildschirm/specs/sprachinventar/spec.md b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/sprachinventar/spec.md similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/specs/sprachinventar/spec.md rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/sprachinventar/spec.md diff --git a/openspec/changes/phase-3-runtime-bildschirm/specs/textbildschirm/spec.md b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/textbildschirm/spec.md similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/specs/textbildschirm/spec.md rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/specs/textbildschirm/spec.md diff --git a/openspec/changes/phase-3-runtime-bildschirm/tasks.md b/openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/tasks.md similarity index 100% rename from openspec/changes/phase-3-runtime-bildschirm/tasks.md rename to openspec/changes/archive/2026-09-04-phase-3-runtime-bildschirm/tasks.md diff --git a/openspec/specs/datei-eio/spec.md b/openspec/specs/datei-eio/spec.md new file mode 100644 index 0000000..dad3901 --- /dev/null +++ b/openspec/specs/datei-eio/spec.md @@ -0,0 +1,175 @@ +# datei-eio Specification + +## 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. + +## 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 diff --git a/openspec/specs/kompat-testkorpus/spec.md b/openspec/specs/kompat-testkorpus/spec.md index 7ad91be..d243e7a 100644 --- a/openspec/specs/kompat-testkorpus/spec.md +++ b/openspec/specs/kompat-testkorpus/spec.md @@ -10,16 +10,28 @@ geprüft werden. ### Requirement: Korpusdateien mit byte-genauer Sollausgabe Jedes Korpusprogramm `tests/compat/.bas` SHALL eine `.out` -mit der exakten Konsolenausgabe besitzen (UTF-8, LF-Zeilenenden). -Nachgestellte Leerzeichen sind signifikant — `PRINT` gibt Zahlen mit -führendem Vorzeichen-/Leerzeichen und nachgestelltem Leerzeichen aus, -auch am Zeilenende; `.gitattributes` MUST die `.out`-Dateien vor +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: Frontend-Meilenstein über den Korpus Ein automatischer Test SHALL alle `tests/compat/*.bas` durch das Sprach-Frontend führen und fehlschlagen, sobald eine Datei Diagnosen @@ -32,19 +44,26 @@ hinzu.) ### Requirement: Laufzeitvergleich über den Korpus Ein automatischer Test SHALL jede Korpusdatei `tests/compat/*.bas` -kompilieren, über die VM mit Capture-Host ausführen und die Ausgabe -byte-genau (inklusive nachgestellter Leerzeichen und LF-Zeilenenden) -gegen die zugehörige `.out`-Datei vergleichen. Bei Abweichung MUST der -Test Datei, erste abweichende Zeile sowie Soll und Ist nennen. +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 die Ausgabe jeder Korpusdatei byte-genau mit ihrer `.out` überein +- **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 + ### Requirement: Korpusabdeckung der Phase-2-Semantik Der Korpus SHALL um Referenzprogramme mit dokumentierter Sollausgabe für die Zahlenkonvertierungs-Matrix (Rundung, Ganzzahldivision, logische @@ -55,3 +74,39 @@ Prozeduraufrufe mit BYREF-/BYVAL-Wirkung erweitert werden. #### Scenario: Konvertierungsmatrix als Korpustest - **WHEN** die Laufzeit-Testsuite läuft - **THEN** existiert ein Korpusprogramm, das die Matrix-Randfälle ausgibt, und seine Ausgabe entspricht der dokumentierten Sollausgabe + +### 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 diff --git a/openspec/specs/konsolen-basisbibliothek/spec.md b/openspec/specs/konsolen-basisbibliothek/spec.md index bc8c789..0563fcc 100644 --- a/openspec/specs/konsolen-basisbibliothek/spec.md +++ b/openspec/specs/konsolen-basisbibliothek/spec.md @@ -19,16 +19,30 @@ Opcode); die Tabelle lebt in der Laufzeitbibliothek und ist ohne - **THEN** wird `LEN` über seinen Tabellenindex aufgerufen und liefert 3 ### Requirement: Host-Abstraktion für Konsolen-E/A -Alle Konsolenwirkungen der VM SHALL über eine austauschbare -Host-Schnittstelle laufen (Textausgabe, zeilenweises Lesen für `INPUT`, -Abbruchprüfung). Host-Aufrufe dürfen blockieren; die Abbruchprüfung -(Strg+Untbr) obliegt dem Host. `tbc run` verwendet einen Konsolen-Host -(stdout/stdin); Tests MUST einen Capture-Host verwenden können, der die -Ausgabe byte-genau aufzeichnet. +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 die komplette Ausgabe im Capture-Host und ist byte-genau vergleichbar +- **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 ### Requirement: PRINT-Formatierung `PRINT` SHALL Zahlen im Format des Vorbilds ausgeben: führendes @@ -48,20 +62,171 @@ Zeilenumbruch. - **WHEN** `PRINT "12345678901234", "x"` ausgeführt wird - **THEN** beginnt `x` in Spalte 29 (Zone nach der belegten übersprungen) -### Requirement: Korpus-Stringfunktionen -Die Bibliothek SHALL mindestens folgende Funktionen mit der Semantik des -Vorbilds bereitstellen (Zeichen = Unicode-Codepoints, dokumentierte -UTF-8-Abweichung): `LEN`, `LEFT$`, `RIGHT$`, `MID$` (Funktion), -`INSTR`, `UCASE$`, `LCASE$`, `STRING$`, `SPACE$`, `CHR$`, `ASC`, -`STR$`, `VAL`. Randfälle folgen dem Vorbild, u. a.: `VAL` liest das -führende Zahlenpräfix und ignoriert Leerraum; `STR$` stellt -nicht-negativen Zahlen ein Leerzeichen voran; `ASC("")` löst Fehler 5 -„Illegal function call" aus. - -#### Scenario: Korpusdatei strings.bas -- **WHEN** `tests/compat/strings.bas` ausgeführt wird -- **THEN** entspricht die Ausgabe byte-genau `strings.out` +### 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 diff --git a/openspec/specs/sprach-frontend/spec.md b/openspec/specs/sprach-frontend/spec.md index 4348dee..fa0cd77 100644 --- a/openspec/specs/sprach-frontend/spec.md +++ b/openspec/specs/sprach-frontend/spec.md @@ -120,3 +120,56 @@ diagnose-freies Modul MUST ein vollständiges HIR ergeben. #### Scenario: Diagnose-freies Modul liefert HIR - **WHEN** ein Korpusmodul ohne Diagnosen analysiert wird - **THEN** liefert das Frontend ein HIR, aus dem der Codegen ohne erneute Namens- oder Typauflösung Bytecode erzeugen kann + +### 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` diff --git a/openspec/specs/sprachinventar/spec.md b/openspec/specs/sprachinventar/spec.md new file mode 100644 index 0000000..e2f3fb4 --- /dev/null +++ b/openspec/specs/sprachinventar/spec.md @@ -0,0 +1,76 @@ +# sprachinventar Specification + +## 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. + +## 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" diff --git a/openspec/specs/textbildschirm/spec.md b/openspec/specs/textbildschirm/spec.md index 8a89f04..8596b20 100644 --- a/openspec/specs/textbildschirm/spec.md +++ b/openspec/specs/textbildschirm/spec.md @@ -11,9 +11,13 @@ Ratatui. ### 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 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. +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 @@ -35,13 +39,20 @@ ohne eigene Einstellung folgt der Scrollbereich der Bildschirmgröße. - **THEN** scrollen nur die Zeilen 3–5; Kopfzeilen außerhalb bleiben unverändert ### Requirement: 1-basierte Cursor-API mit Bereichsprüfung -`LOCATE`, `CSRLIN` und `POS` SHALL 1-basiert arbeiten; `LOCATE` -außerhalb der aktuellen Bildschirmgrenzen SHALL als Fehler abgewiesen -werden (Basis für Laufzeitfehler 5). +`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** wird der Aufruf abgewiesen +- **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) ### Requirement: Klassische Farbpalette und Blink-Simulation Der Bildschirm SHALL die klassische Palette abbilden (Vordergrund 0–15, @@ -55,11 +66,136 @@ Terminal-Blinken. - **THEN** wird mit heller Vordergrundfarbe 9 gerendert ### Requirement: Unicode-Zellenmodell -Der Puffer SHALL Unicode-Zeichen speichern (keine CP437-Emulation); -aktuell gilt strikt 1 Zeichen = 1 Zelle. (Zeichen mit Darstellungsbreite -2 belegen künftig zwei Zellen — beschlossene Änderung, Umsetzung in -Phase 3 als eigenes Change.) +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: 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