diff --git a/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/.openspec.yaml b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/.openspec.yaml new file mode 100644 index 0000000..032461f --- /dev/null +++ b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-02 diff --git a/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/proposal.md b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/proposal.md new file mode 100644 index 0000000..5ca9bbe --- /dev/null +++ b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/proposal.md @@ -0,0 +1,53 @@ +## Why + +Die Phasen 0 (Exploration, Grundsatzentscheidungen, Referenzrekonstruktion) +und 1 (Sprach-Frontend) sind bereits implementiert, aber noch nicht als +OpenSpec-Spezifikationen erfasst. Dieses Baseline-Change rüstet die Specs +für den umgesetzten Stand nach, damit alle folgenden Phasen auf einem +vollständigen Spec-Fundament aufsetzen (Workflow ab jetzt: Explore → +Proposal → Umsetzung je Phase). + +## What Changes + +- Nachdokumentation des implementierten Verhaltens als Spezifikationen — + keine Code-Änderungen. +- Erfasst werden die vier umgesetzten Fähigkeiten: + - Sprach-Frontend (Lexer, Parser, semantische Analyse) aus Phase 1 + - Laufzeitfehler-Katalog aus Phase 0 + - Textbildschirm-Emulation (dynamische Größe, Farben) aus Phase 0 + - Kompatibilitäts-Testkorpus (Konventionen) aus Phase 0 +- Projekt-Grundsatzentscheidungen (TBVM, UTF-8, dynamische Terminalgröße, + Non-Features, Performance-Budgets) bleiben in PLAN.md und + docs/sprachreferenz.md dokumentiert; die Specs referenzieren sie. + +## Capabilities + +### New Capabilities + +- `sprach-frontend`: Kompilierbarkeit von Terminal-Basic-Quelltext — + Lexik (Typ-Suffixe, Literal-Typisierung, Zeilenfortsetzung, + Metabefehle), vollständige Anweisungs-Grammatik, semantische Prüfung + (Typen, implizite Deklaration, DEFtype, OPTION EXPLICIT, UDT-Felder, + Konstanten), Diagnostik mit Vorbild-Meldungstexten und Compile-Zeit- + Abweisung deklarierter Non-Features. +- `laufzeitfehler`: klassischer Fehlerkatalog (Codes 1–76, ISAM 80–89, + Forms 260–480) mit originalgetreuen Meldungstexten als + Kompatibilitätsvertrag für `ERR`/`ERROR n`. +- `textbildschirm`: emulierter Unicode-Textbildschirm mit dynamischer + Terminalgröße (Minimum 80×25), klassischer 16-Farben-Palette, + PRINT-/LOCATE-/CLS-/VIEW-PRINT-Semantik und Blink-als-Hell-Simulation. +- `kompat-testkorpus`: Konventionen des Kompatibilitäts-Testkorpus + (byte-genaue Sollausgaben, signifikante Zeilenend-Leerzeichen, + Frontend-Meilenstein „Korpus parst und wird typgeprüft"). + +### Modified Capabilities + + + +## Impact + +- Nur `openspec/`-Artefakte (Delta-Specs → Haupt-Specs nach Sync/Archiv). +- Kein Code, keine Doku unter `docs/` betroffen. +- Referenzen: PLAN.md (Phasen 0/1 abgeschlossen), docs/sprachreferenz.md, + crates/tb-frontend, crates/tb-runtime (errors), crates/tb-ui (screen), + tests/compat. diff --git a/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/kompat-testkorpus/spec.md b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/kompat-testkorpus/spec.md new file mode 100644 index 0000000..1d8c3f4 --- /dev/null +++ b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/kompat-testkorpus/spec.md @@ -0,0 +1,30 @@ +## Purpose + +Der Kompatibilitäts-Testkorpus hält das Sollverhalten des Dialekts als +ausführbare Spezifikation fest: Referenzprogramme mit byte-genau +dokumentierter Ausgabe, gegen die Frontend und (ab Phase 2) Laufzeit +geprüft werden. + +## ADDED Requirements + +### 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 +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) + +### 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 +liefert. (Ab Phase 2 kommt der Laufzeitvergleich `tbc run` ↔ `.out` +hinzu.) + +#### Scenario: Korpus bleibt kompilierbar +- **WHEN** die Frontend-Testsuite läuft +- **THEN** parsen alle Korpusdateien diagnose-frei und der Test nennt andernfalls Datei und Diagnose diff --git a/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/laufzeitfehler/spec.md b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/laufzeitfehler/spec.md new file mode 100644 index 0000000..8e5b951 --- /dev/null +++ b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/laufzeitfehler/spec.md @@ -0,0 +1,32 @@ +## Purpose + +Der Laufzeitfehler-Katalog bildet Codes und Meldungstexte des Vorbilds +originalgetreu ab; Programme prüfen `ERR` gegen diese Nummern, daher sind +sie Teil des Kompatibilitätsvertrags. + +## ADDED Requirements + +### Requirement: Klassischer Fehlerkatalog +Die Laufzeitbibliothek SHALL alle Fehlercodes des Vorbilds mit den +originalen (englischen) Meldungstexten bereitstellen: klassische Codes +1–76 (z. B. 6 „Overflow", 9 „Subscript out of range", 53 „File not +found"), ISAM-Codes 80–89 und Forms-Codes 260–480 (z. B. 272 „Invalid +when forms are showing", 403 „MDI form cannot be shown modally", +431 „No currently active form"). + +#### Scenario: Bekannter Code +- **WHEN** Fehlercode 6 abgefragt wird +- **THEN** lautet der Meldungstext exakt „Overflow" + +#### Scenario: Forms-Code +- **WHEN** Fehlercode 431 abgefragt wird +- **THEN** lautet der Meldungstext „No currently active form" + +### Requirement: Unbelegte Codes +Unbelegte Fehlernummern SHALL den Meldungstext „Unprintable error" +liefern (Verhalten des Vorbilds bei `ERROR n`); Nummer 105 ist im +Vorbild intern reserviert und bleibt unbelegt. + +#### Scenario: Unbelegter Code +- **WHEN** Fehlercode 105 oder 200 abgefragt wird +- **THEN** lautet der Meldungstext „Unprintable error" diff --git a/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/sprach-frontend/spec.md b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/sprach-frontend/spec.md new file mode 100644 index 0000000..5b1428d --- /dev/null +++ b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/sprach-frontend/spec.md @@ -0,0 +1,103 @@ +## Purpose + +Das Sprach-Frontend übersetzt Terminal-Basic-Quelltext (VBDOS-kompatibler +Dialekt) in einen typgeprüften AST: Lexer, fehlertoleranter Parser und +semantische Analyse mit Diagnostik nach den Meldungstexten des Vorbilds. + +## ADDED Requirements + +### Requirement: Lexikalische Analyse nach Sprachreferenz +Der Lexer SHALL Quelltext gemäß docs/sprachreferenz.md §1 zerlegen: +Typ-Suffixe (`% & ! # $ @`) an Bezeichnern und Literalen, case-insensitive +Keywords (Bibliotheksnamen bleiben Bezeichner), `'`/`REM`-Kommentare, +`:`-Anweisungstrenner, Zeilenfortsetzung mit `_`, Hex- (`&H`) und +Oktal-Literale (`&O`), `""`-Escape in Strings sowie die Metabefehle +`'$INCLUDE`, `'$STATIC`, `'$DYNAMIC`. + +#### Scenario: Suffix trennt Bibliotheksfunktion von Keyword +- **WHEN** der Lexer `STRING$` und `STRING` liest +- **THEN** wird `STRING$` als Bezeichner (Builtin) und `STRING` als Typ-Keyword erkannt + +#### Scenario: Zeilenfortsetzung +- **WHEN** eine Zeile nach Leerraum mit `_` endet +- **THEN** wird die Folgezeile ohne Zeilenende-Token angeschlossen + +### Requirement: Literal-Typisierung +Der Lexer SHALL numerische Literale typisieren: Ganzzahlen INTEGER → LONG +→ Gleitkomma nach Wertebereich; `E`-Exponent → SINGLE, `D`-Exponent → +DOUBLE; Suffixe erzwingen den Typ (Überlauf → Diagnose „Overflow"); +Dezimalpunkt-Literale bis 7 signifikante Stellen → SINGLE, darüber → +DOUBLE (Projektentscheidung 2026-09-02); `@`-Literale als +Currency-Festkomma ×10 000. + +#### Scenario: Schwelle SINGLE/DOUBLE +- **WHEN** die Literale `1.5` und `3.14159265` gelext werden +- **THEN** ist `1.5` SINGLE und `3.14159265` DOUBLE + +### Requirement: Vollständige Anweisungs-Grammatik +Der Parser SHALL den Anweisungssatz des Dialekts in einen AST überführen, +darunter: Zuweisung inkl. `MID$`-Anweisung, `PRINT`/`LPRINT` (mit +`USING`/`#`-Datei, `?`-Kurzform), `INPUT`/`LINE INPUT`, `IF` (Block und +einzeilig, `THEN zeilennummer`), `SELECT CASE` (Werte, `TO`-Bereiche, +`IS`-Vergleiche, `CASE ELSE`), `FOR`/`DO`/`WHILE`-Schleifen mit `EXIT`, +`GOTO`/`GOSUB`/`RETURN`/`ON … GOTO|GOSUB`, `ON [LOCAL] ERROR`/`RESUME`, +`DIM`/`REDIM`/`ERASE`/`CONST`/`DEFtype`/`OPTION`/`TYPE…END TYPE`/ +`DECLARE`/`SUB`/`FUNCTION`/`CALL`, `COMMON`/`SHARED`/`STATIC`, +`DATA`/`READ`/`RESTORE`, `DEF FN` (einzeilig und Blockform), +`VIEW PRINT`, `NAME … AS`, Ereignissteuerung (`TIMER/KEY(n)/UEVENT +ON|OFF|STOP`) sowie die komplette Datei-E/A-Grammatik (`OPEN` in beiden +Syntaxen inkl. `ISAM`-/`ACCESS`-/`LOCK`-Klauseln, `CLOSE`, `FIELD`, +`GET`/`PUT`, `LSET`/`RSET`, `WRITE`, `SEEK`, `LOCK`/`UNLOCK`). +Zeilennummern und Labels am Zeilenanfang SHALL als Sprungziele erfasst +werden. + +#### Scenario: Blockstrukturen über mehrere Zeilen +- **WHEN** ein `SELECT CASE` mit `CASE 1: PRINT "eins"` und `CASE ELSE` geparst wird +- **THEN** entsteht ein Select-Knoten mit zwei Armen und Inline-Anweisungen im ersten Arm + +#### Scenario: Fehlertoleranz je Anweisung +- **WHEN** eine Anweisung einen Syntaxfehler enthält +- **THEN** wird eine Diagnose mit Position gesammelt, bis zum Anweisungsende synchronisiert und die Folgeanweisung normal geparst + +### Requirement: Semantische Prüfung +Die Semantik SHALL prüfen: Typkompatibilität (numerisch ↔ numerisch, +String ↔ String; sonst „Type mismatch"), implizite Deklaration bei +Erstverwendung (Suffix-getrennte Variablen), `DEFtype`-Buchstabenbereiche, +`OPTION EXPLICIT` („Variable not defined"), Arrays (implizit, `DIM`, +`REDIM`; doppelte explizite Deklaration → „Duplicate definition"), +UDT-Feldzugriffe (`kunde.name` mit Feldtyp; unbekanntes Feld → „Element +not defined"), `SHARED`-Import von Modulvariablen in Prozeduren, +Konstantenfaltung für `CONST` (nicht konstant → „Invalid constant"), +Sprungziele („Label not defined") sowie Prozedur- und Builtin-Signaturen +(Anzahl → „Argument-count mismatch", Typen). + +#### Scenario: Typkonflikt +- **WHEN** `a$ = 1` geprüft wird +- **THEN** wird „Type mismatch" mit Quelltextposition gemeldet + +#### Scenario: UDT-Feldtyp +- **WHEN** ein `TYPE` mit Feld `Name AS STRING * 30` deklariert ist und `k.Name = 5` geprüft wird +- **THEN** wird „Type mismatch" gemeldet + +### Requirement: Compile-Zeit-Abweisung deklarierter Non-Features +Die Semantik MUST jede Verwendung der in docs/sprachreferenz.md +(„Abweichungen") deklarierten Non-Features — Hardware-Nähe (`PEEK`, +`POKE`, `INP`, `OUT`, `WAIT`, `BLOAD`/`BSAVE`, `VARPTR`-Familie, `CALL +ABSOLUTE`/`INTERRUPT`, `IOCTL`), `CHAIN`, Grafik-Anweisungen, `SOUND`/ +`PLAY` und die Event-Geräte `COM`/`PEN`/`PLAY`/`STRIG` — zur Compile-Zeit +mit der Meldung „Feature unavailable" abweisen. Dokumentierte Features +außerhalb dieser Liste MUST NOT abgewiesen werden (Guiding Principle). + +#### Scenario: Hardware-Zugriff +- **WHEN** `POKE 100, 1` oder `x = PEEK(100)` kompiliert wird +- **THEN** erscheint die Compile-Diagnose „Feature unavailable" + +### Requirement: Diagnostik mit Vorbild-Meldungen +Diagnosen SHALL exakte 1-basierte Quelltextpositionen (Zeile, Spalte) +tragen; die Meldungstexte SHALL dem Katalog des Vorbilds folgen, wo eine +Entsprechung existiert (z. B. „Type mismatch", „Duplicate definition", +„Label not defined", „Subprogram not defined", „Overflow"). + +#### Scenario: Position in der Diagnose +- **WHEN** in Zeile 3 ein Typkonflikt auftritt +- **THEN** nennt die Diagnose Zeile 3 und die Spalte des Ausdrucks diff --git a/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/textbildschirm/spec.md b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/textbildschirm/spec.md new file mode 100644 index 0000000..18c22fb --- /dev/null +++ b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/specs/textbildschirm/spec.md @@ -0,0 +1,64 @@ +## Purpose + +Der emulierte Textbildschirm ist die Rendering-Grundlage für `PRINT`, +`LOCATE`, `COLOR`, `CLS` und später die Forms-Engine: Unicode-Zellenpuffer +mit dynamischer Terminalgröße und klassischer 16-Farben-Palette auf +Ratatui. + +## ADDED 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 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. + +#### 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: PRINT-Semantik mit Umbruch und Scrollen +`print` SHALL Zeichen an der Cursorposition ausgeben, am rechten Rand +umbrechen und am unteren Rand des Scrollbereichs den Bereich um eine +Zeile nach oben scrollen; `\n` bricht um, `\r` setzt an den Zeilenanfang. +`VIEW PRINT oben TO unten` SHALL das Scrollen auf den Bereich begrenzen; +ohne eigene Einstellung folgt der Scrollbereich der Bildschirmgröße. + +#### Scenario: Scrollen in VIEW-PRINT-Bereich +- **WHEN** der Scrollbereich Zeilen 3–5 umfasst und in Zeile 5 ein Umbruch erfolgt +- **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). + +#### Scenario: Grenzprüfung +- **WHEN** bei 80×25 `LOCATE 26, 1` aufgerufen wird +- **THEN** wird der Aufruf abgewiesen + +### Requirement: Klassische Farbpalette und Blink-Simulation +Der Bildschirm SHALL die klassische Palette abbilden (Vordergrund 0–15, +Hintergrund 0–7) und auf ANSI-Indexfarben mappen (klassisch 1 = Blau ↔ +ANSI 4 usw.). Blinkende Vordergrundfarben (16–31) SHALL als „hell" +simuliert werden (Farbe − 16, Intensitätsbit gesetzt) — kein echtes +Terminal-Blinken. + +#### Scenario: Blink wird hell +- **WHEN** `COLOR 17, 0` gesetzt wird (blinkend Blau) +- **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.) + +#### Scenario: Umlaute und Symbole +- **WHEN** `Ä☃` ausgegeben wird +- **THEN** belegen `Ä` und `☃` je genau eine Zelle diff --git a/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/tasks.md b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/tasks.md new file mode 100644 index 0000000..985111f --- /dev/null +++ b/openspec/changes/archive/2026-09-02-baseline-phasen-0-1/tasks.md @@ -0,0 +1,11 @@ +## 1. Baseline gegen Implementierung verifizieren + +- [x] 1.1 Sprach-Frontend-Spec gegen Implementierung geprüft: `cargo test -p tb-frontend` grün (33 Tests inkl. Korpus-Meilenstein `tests/corpus.rs`) +- [x] 1.2 Laufzeitfehler-Spec geprüft: `cargo test -p tb-runtime` grün (Katalog-Tests inkl. Forms-/ISAM-Codes und „Unprintable error") +- [x] 1.3 Textbildschirm-Spec geprüft: `cargo test -p tb-ui` grün (PRINT/Scroll/VIEW PRINT, Resize/Mindestgröße, Blink-als-Hell, Farbabbildung) +- [x] 1.4 Korpus-Konventionen geprüft: `.out`-Dateien mit signifikanten Zeilenend-Leerzeichen vorhanden, `.gitattributes` schützt vor EOL-Konvertierung + +## 2. Specs übernehmen + +- [x] 2.1 Delta-Specs in Haupt-Specs überführen und Change archivieren; Verifikation: `openspec validate --specs` grün, vier Haupt-Specs unter `openspec/specs/` vorhanden + diff --git a/openspec/specs/kompat-testkorpus/spec.md b/openspec/specs/kompat-testkorpus/spec.md new file mode 100644 index 0000000..616e69a --- /dev/null +++ b/openspec/specs/kompat-testkorpus/spec.md @@ -0,0 +1,31 @@ +# kompat-testkorpus Specification + +## Purpose +Der Kompatibilitäts-Testkorpus hält das Sollverhalten des Dialekts als +ausführbare Spezifikation fest: Referenzprogramme mit byte-genau +dokumentierter Ausgabe, gegen die Frontend und (ab Phase 2) Laufzeit +geprüft werden. + +## Requirements + +### 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 +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) + +### 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 +liefert. (Ab Phase 2 kommt der Laufzeitvergleich `tbc run` ↔ `.out` +hinzu.) + +#### Scenario: Korpus bleibt kompilierbar +- **WHEN** die Frontend-Testsuite läuft +- **THEN** parsen alle Korpusdateien diagnose-frei und der Test nennt andernfalls Datei und Diagnose diff --git a/openspec/specs/laufzeitfehler/spec.md b/openspec/specs/laufzeitfehler/spec.md new file mode 100644 index 0000000..4a98184 --- /dev/null +++ b/openspec/specs/laufzeitfehler/spec.md @@ -0,0 +1,33 @@ +# laufzeitfehler Specification + +## Purpose +Der Laufzeitfehler-Katalog bildet Codes und Meldungstexte des Vorbilds +originalgetreu ab; Programme prüfen `ERR` gegen diese Nummern, daher sind +sie Teil des Kompatibilitätsvertrags. + +## Requirements + +### Requirement: Klassischer Fehlerkatalog +Die Laufzeitbibliothek SHALL alle Fehlercodes des Vorbilds mit den +originalen (englischen) Meldungstexten bereitstellen: klassische Codes +1–76 (z. B. 6 „Overflow", 9 „Subscript out of range", 53 „File not +found"), ISAM-Codes 80–89 und Forms-Codes 260–480 (z. B. 272 „Invalid +when forms are showing", 403 „MDI form cannot be shown modally", +431 „No currently active form"). + +#### Scenario: Bekannter Code +- **WHEN** Fehlercode 6 abgefragt wird +- **THEN** lautet der Meldungstext exakt „Overflow" + +#### Scenario: Forms-Code +- **WHEN** Fehlercode 431 abgefragt wird +- **THEN** lautet der Meldungstext „No currently active form" + +### Requirement: Unbelegte Codes +Unbelegte Fehlernummern SHALL den Meldungstext „Unprintable error" +liefern (Verhalten des Vorbilds bei `ERROR n`); Nummer 105 ist im +Vorbild intern reserviert und bleibt unbelegt. + +#### Scenario: Unbelegter Code +- **WHEN** Fehlercode 105 oder 200 abgefragt wird +- **THEN** lautet der Meldungstext „Unprintable error" diff --git a/openspec/specs/sprach-frontend/spec.md b/openspec/specs/sprach-frontend/spec.md new file mode 100644 index 0000000..7d31488 --- /dev/null +++ b/openspec/specs/sprach-frontend/spec.md @@ -0,0 +1,104 @@ +# sprach-frontend Specification + +## Purpose +Das Sprach-Frontend übersetzt Terminal-Basic-Quelltext (VBDOS-kompatibler +Dialekt) in einen typgeprüften AST: Lexer, fehlertoleranter Parser und +semantische Analyse mit Diagnostik nach den Meldungstexten des Vorbilds. + +## Requirements + +### Requirement: Lexikalische Analyse nach Sprachreferenz +Der Lexer SHALL Quelltext gemäß docs/sprachreferenz.md §1 zerlegen: +Typ-Suffixe (`% & ! # $ @`) an Bezeichnern und Literalen, case-insensitive +Keywords (Bibliotheksnamen bleiben Bezeichner), `'`/`REM`-Kommentare, +`:`-Anweisungstrenner, Zeilenfortsetzung mit `_`, Hex- (`&H`) und +Oktal-Literale (`&O`), `""`-Escape in Strings sowie die Metabefehle +`'$INCLUDE`, `'$STATIC`, `'$DYNAMIC`. + +#### Scenario: Suffix trennt Bibliotheksfunktion von Keyword +- **WHEN** der Lexer `STRING$` und `STRING` liest +- **THEN** wird `STRING$` als Bezeichner (Builtin) und `STRING` als Typ-Keyword erkannt + +#### Scenario: Zeilenfortsetzung +- **WHEN** eine Zeile nach Leerraum mit `_` endet +- **THEN** wird die Folgezeile ohne Zeilenende-Token angeschlossen + +### Requirement: Literal-Typisierung +Der Lexer SHALL numerische Literale typisieren: Ganzzahlen INTEGER → LONG +→ Gleitkomma nach Wertebereich; `E`-Exponent → SINGLE, `D`-Exponent → +DOUBLE; Suffixe erzwingen den Typ (Überlauf → Diagnose „Overflow"); +Dezimalpunkt-Literale bis 7 signifikante Stellen → SINGLE, darüber → +DOUBLE (Projektentscheidung 2026-09-02); `@`-Literale als +Currency-Festkomma ×10 000. + +#### Scenario: Schwelle SINGLE/DOUBLE +- **WHEN** die Literale `1.5` und `3.14159265` gelext werden +- **THEN** ist `1.5` SINGLE und `3.14159265` DOUBLE + +### Requirement: Vollständige Anweisungs-Grammatik +Der Parser SHALL den Anweisungssatz des Dialekts in einen AST überführen, +darunter: Zuweisung inkl. `MID$`-Anweisung, `PRINT`/`LPRINT` (mit +`USING`/`#`-Datei, `?`-Kurzform), `INPUT`/`LINE INPUT`, `IF` (Block und +einzeilig, `THEN zeilennummer`), `SELECT CASE` (Werte, `TO`-Bereiche, +`IS`-Vergleiche, `CASE ELSE`), `FOR`/`DO`/`WHILE`-Schleifen mit `EXIT`, +`GOTO`/`GOSUB`/`RETURN`/`ON … GOTO|GOSUB`, `ON [LOCAL] ERROR`/`RESUME`, +`DIM`/`REDIM`/`ERASE`/`CONST`/`DEFtype`/`OPTION`/`TYPE…END TYPE`/ +`DECLARE`/`SUB`/`FUNCTION`/`CALL`, `COMMON`/`SHARED`/`STATIC`, +`DATA`/`READ`/`RESTORE`, `DEF FN` (einzeilig und Blockform), +`VIEW PRINT`, `NAME … AS`, Ereignissteuerung (`TIMER/KEY(n)/UEVENT +ON|OFF|STOP`) sowie die komplette Datei-E/A-Grammatik (`OPEN` in beiden +Syntaxen inkl. `ISAM`-/`ACCESS`-/`LOCK`-Klauseln, `CLOSE`, `FIELD`, +`GET`/`PUT`, `LSET`/`RSET`, `WRITE`, `SEEK`, `LOCK`/`UNLOCK`). +Zeilennummern und Labels am Zeilenanfang SHALL als Sprungziele erfasst +werden. + +#### Scenario: Blockstrukturen über mehrere Zeilen +- **WHEN** ein `SELECT CASE` mit `CASE 1: PRINT "eins"` und `CASE ELSE` geparst wird +- **THEN** entsteht ein Select-Knoten mit zwei Armen und Inline-Anweisungen im ersten Arm + +#### Scenario: Fehlertoleranz je Anweisung +- **WHEN** eine Anweisung einen Syntaxfehler enthält +- **THEN** wird eine Diagnose mit Position gesammelt, bis zum Anweisungsende synchronisiert und die Folgeanweisung normal geparst + +### Requirement: Semantische Prüfung +Die Semantik SHALL prüfen: Typkompatibilität (numerisch ↔ numerisch, +String ↔ String; sonst „Type mismatch"), implizite Deklaration bei +Erstverwendung (Suffix-getrennte Variablen), `DEFtype`-Buchstabenbereiche, +`OPTION EXPLICIT` („Variable not defined"), Arrays (implizit, `DIM`, +`REDIM`; doppelte explizite Deklaration → „Duplicate definition"), +UDT-Feldzugriffe (`kunde.name` mit Feldtyp; unbekanntes Feld → „Element +not defined"), `SHARED`-Import von Modulvariablen in Prozeduren, +Konstantenfaltung für `CONST` (nicht konstant → „Invalid constant"), +Sprungziele („Label not defined") sowie Prozedur- und Builtin-Signaturen +(Anzahl → „Argument-count mismatch", Typen). + +#### Scenario: Typkonflikt +- **WHEN** `a$ = 1` geprüft wird +- **THEN** wird „Type mismatch" mit Quelltextposition gemeldet + +#### Scenario: UDT-Feldtyp +- **WHEN** ein `TYPE` mit Feld `Name AS STRING * 30` deklariert ist und `k.Name = 5` geprüft wird +- **THEN** wird „Type mismatch" gemeldet + +### Requirement: Compile-Zeit-Abweisung deklarierter Non-Features +Die Semantik MUST jede Verwendung der in docs/sprachreferenz.md +(„Abweichungen") deklarierten Non-Features — Hardware-Nähe (`PEEK`, +`POKE`, `INP`, `OUT`, `WAIT`, `BLOAD`/`BSAVE`, `VARPTR`-Familie, `CALL +ABSOLUTE`/`INTERRUPT`, `IOCTL`), `CHAIN`, Grafik-Anweisungen, `SOUND`/ +`PLAY` und die Event-Geräte `COM`/`PEN`/`PLAY`/`STRIG` — zur Compile-Zeit +mit der Meldung „Feature unavailable" abweisen. Dokumentierte Features +außerhalb dieser Liste MUST NOT abgewiesen werden (Guiding Principle). + +#### Scenario: Hardware-Zugriff +- **WHEN** `POKE 100, 1` oder `x = PEEK(100)` kompiliert wird +- **THEN** erscheint die Compile-Diagnose „Feature unavailable" + +### Requirement: Diagnostik mit Vorbild-Meldungen +Diagnosen SHALL exakte 1-basierte Quelltextpositionen (Zeile, Spalte) +tragen; die Meldungstexte SHALL dem Katalog des Vorbilds folgen, wo eine +Entsprechung existiert (z. B. „Type mismatch", „Duplicate definition", +„Label not defined", „Subprogram not defined", „Overflow"). + +#### Scenario: Position in der Diagnose +- **WHEN** in Zeile 3 ein Typkonflikt auftritt +- **THEN** nennt die Diagnose Zeile 3 und die Spalte des Ausdrucks diff --git a/openspec/specs/textbildschirm/spec.md b/openspec/specs/textbildschirm/spec.md new file mode 100644 index 0000000..8a89f04 --- /dev/null +++ b/openspec/specs/textbildschirm/spec.md @@ -0,0 +1,65 @@ +# textbildschirm Specification + +## Purpose +Der emulierte Textbildschirm ist die Rendering-Grundlage für `PRINT`, +`LOCATE`, `COLOR`, `CLS` und später die Forms-Engine: Unicode-Zellenpuffer +mit dynamischer Terminalgröße und klassischer 16-Farben-Palette auf +Ratatui. + +## 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 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. + +#### 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: PRINT-Semantik mit Umbruch und Scrollen +`print` SHALL Zeichen an der Cursorposition ausgeben, am rechten Rand +umbrechen und am unteren Rand des Scrollbereichs den Bereich um eine +Zeile nach oben scrollen; `\n` bricht um, `\r` setzt an den Zeilenanfang. +`VIEW PRINT oben TO unten` SHALL das Scrollen auf den Bereich begrenzen; +ohne eigene Einstellung folgt der Scrollbereich der Bildschirmgröße. + +#### Scenario: Scrollen in VIEW-PRINT-Bereich +- **WHEN** der Scrollbereich Zeilen 3–5 umfasst und in Zeile 5 ein Umbruch erfolgt +- **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). + +#### Scenario: Grenzprüfung +- **WHEN** bei 80×25 `LOCATE 26, 1` aufgerufen wird +- **THEN** wird der Aufruf abgewiesen + +### Requirement: Klassische Farbpalette und Blink-Simulation +Der Bildschirm SHALL die klassische Palette abbilden (Vordergrund 0–15, +Hintergrund 0–7) und auf ANSI-Indexfarben mappen (klassisch 1 = Blau ↔ +ANSI 4 usw.). Blinkende Vordergrundfarben (16–31) SHALL als „hell" +simuliert werden (Farbe − 16, Intensitätsbit gesetzt) — kein echtes +Terminal-Blinken. + +#### Scenario: Blink wird hell +- **WHEN** `COLOR 17, 0` gesetzt wird (blinkend Blau) +- **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.) + +#### Scenario: Umlaute und Symbole +- **WHEN** `Ä☃` ausgegeben wird +- **THEN** belegen `Ä` und `☃` je genau eine Zelle