OpenSpec-Baseline: Phasen 0/1 als Specs nachgeruestet
Change "baseline-phasen-0-1" (Explore/Retrofit des umgesetzten Stands), per Archiv in die Haupt-Specs uebernommen und validiert: - sprach-frontend (6 Requirements: Lexik, Literal-Typisierung, Anweisungs-Grammatik, Semantik, Non-Feature-Abweisung, Diagnostik) - laufzeitfehler (2: Katalog 1-480, Unprintable error) - textbildschirm (5: dynamische Groesse, PRINT/Scroll, Cursor-API, Farbpalette/Blink, Unicode-Zellenmodell) - kompat-testkorpus (2: byte-genaue Sollausgaben, Frontend-Meilenstein) Workflow ab jetzt je Phase: Explore -> Proposal -> Umsetzung -> Archiv. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
schema: spec-driven
|
||||||
|
created: 2026-09-02
|
||||||
@@ -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
|
||||||
|
|
||||||
|
<!-- keine — es existieren noch keine Haupt-Specs -->
|
||||||
|
|
||||||
|
## 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.
|
||||||
@@ -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/<name>.bas` SHALL eine `<name>.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
|
||||||
@@ -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"
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
31
openspec/specs/kompat-testkorpus/spec.md
Normal file
31
openspec/specs/kompat-testkorpus/spec.md
Normal file
@@ -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/<name>.bas` SHALL eine `<name>.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
|
||||||
33
openspec/specs/laufzeitfehler/spec.md
Normal file
33
openspec/specs/laufzeitfehler/spec.md
Normal file
@@ -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"
|
||||||
104
openspec/specs/sprach-frontend/spec.md
Normal file
104
openspec/specs/sprach-frontend/spec.md
Normal file
@@ -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
|
||||||
65
openspec/specs/textbildschirm/spec.md
Normal file
65
openspec/specs/textbildschirm/spec.md
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user