OpenSpec: phase-2-bytecode-vm archiviert, Delta-Specs in Hauptspecs gesynct
- Neue Hauptspecs: bytecode-kompilat, vm-ausfuehrung, vm-fehlerbehandlung, konsolen-basisbibliothek - Erweitert: sprach-frontend (Typisiertes HIR als Sema-Ausgabe), kompat-testkorpus (Laufzeitvergleich, Phase-2-Korpusabdeckung) - Change nach openspec/changes/archive/2026-09-02-phase-2-bytecode-vm verschoben; openspec validate --all: 9/9 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
65
openspec/specs/bytecode-kompilat/spec.md
Normal file
65
openspec/specs/bytecode-kompilat/spec.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# bytecode-kompilat Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Das Bytecode-Kompilat ist das serialisierbare Ergebnis der Übersetzung:
|
||||||
|
Der Codegenerator senkt das typisierte HIR in einen monomorphen
|
||||||
|
Opcode-Satz ab, der `.tbc`-Container hält es als stabiles, dokumentiertes
|
||||||
|
Format, und das Instant-Compile-Budget sichert den schnellen
|
||||||
|
Edit-Run-Zyklus.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Monomorpher Opcode-Satz
|
||||||
|
Der Codegenerator SHALL jedes HIR-Konstrukt in typisierte, monomorphe
|
||||||
|
Opcodes übersetzen: Arithmetik, Vergleiche und Konvertierungen tragen den
|
||||||
|
Operandentyp im Opcode (kein Tag-Dispatch über Werte zur Laufzeit);
|
||||||
|
implizite Konvertierungen erscheinen als explizite Konvertierungs-Opcodes
|
||||||
|
an den vom HIR bestimmten Stellen. Der Opcode-Satz SHALL in
|
||||||
|
docs/tbvm-design.md vollständig dokumentiert sein.
|
||||||
|
|
||||||
|
#### Scenario: Gemischter Ausdruck wird monomorph
|
||||||
|
- **WHEN** `d# = i% + 1.5#` übersetzt wird (INTEGER-Variable, DOUBLE-Ziel)
|
||||||
|
- **THEN** enthält der Bytecode einen Konvertierungs-Opcode INTEGER→DOUBLE und eine DOUBLE-Addition, keinen generischen Additions-Opcode
|
||||||
|
|
||||||
|
#### Scenario: Namen sind zur Laufzeit aufgelöst
|
||||||
|
- **WHEN** eine Variable oder Prozedur im Bytecode referenziert wird
|
||||||
|
- **THEN** geschieht das über Slot- bzw. Tabellenindizes, nicht über Namens-Lookups
|
||||||
|
|
||||||
|
### Requirement: `.tbc`-Containerformat
|
||||||
|
Das Kompilat SHALL als `.tbc`-Datei serialisierbar und wieder ladbar sein:
|
||||||
|
Magic `TBC\0`, Formatversion, Abschnittstabelle mit den Abschnitten
|
||||||
|
CONSTS (deduplizierter Konstantenpool), TYPES (TYPE-Layouts), PROCS
|
||||||
|
(modul-qualifizierte Prozedurtabelle mit Signatur, Locals-Anzahl,
|
||||||
|
Code-Offset), CODE, DATA (`READ`/`RESTORE`-Segment) und LINES
|
||||||
|
(Zeilentabelle). Laden und erneutes Serialisieren MUST verlustfrei sein;
|
||||||
|
eine unbekannte Formatversion MUST mit einer klaren Fehlermeldung
|
||||||
|
abgewiesen werden.
|
||||||
|
|
||||||
|
#### Scenario: Roundtrip
|
||||||
|
- **WHEN** ein kompiliertes Modul als `.tbc` geschrieben und wieder geladen wird
|
||||||
|
- **THEN** ist das geladene Kompilat funktional identisch (gleiche Ausführung, gleiche Zeilenzuordnung)
|
||||||
|
|
||||||
|
#### Scenario: Unbekannte Version
|
||||||
|
- **WHEN** eine `.tbc`-Datei mit höherer Formatversion geladen wird
|
||||||
|
- **THEN** wird das Laden mit einer Meldung abgelehnt, die die Version nennt
|
||||||
|
|
||||||
|
### Requirement: Zeilentabelle für Fehlerortung
|
||||||
|
Der Bytecode SHALL jede Anweisung ihrem Ursprung (Moduldatei, Zeile)
|
||||||
|
zuordnen, sodass Laufzeitfehlermeldungen, `ERL`, Breakpoints und
|
||||||
|
Einzelschritt die Quellzeile exakt benennen können.
|
||||||
|
|
||||||
|
#### Scenario: Fehler nennt Zeile
|
||||||
|
- **WHEN** in Zeile 42 eines Programms ein Laufzeitfehler ohne Handler auftritt
|
||||||
|
- **THEN** nennt die Fehlermeldung Zeile 42
|
||||||
|
|
||||||
|
### Requirement: Instant-Compile-Budget
|
||||||
|
Die Übersetzung (Lexen bis Bytecode) SHALL ohne globale Analysepasses
|
||||||
|
auskommen; Vorwärtsreferenzen werden über Fixups aufgelöst. Ein
|
||||||
|
Benchmark MUST das Budget nachweisbar machen: ein Projekt von ~50.000
|
||||||
|
Zeilen kompiliert in unter 1 s, ein einzelnes Modul in unter 50 ms
|
||||||
|
(Release-Build, Referenzrechner); die Messwerte werden in
|
||||||
|
docs/tbvm-design.md festgehalten.
|
||||||
|
|
||||||
|
#### Scenario: Budget wird gemessen
|
||||||
|
- **WHEN** die Benchmarks in `benches/` laufen
|
||||||
|
- **THEN** wird die Kompilierzeit für das ~50k-Zeilen-Projekt und für ein Einzelmodul ausgewiesen und gegen das Budget verglichen
|
||||||
@@ -29,3 +29,29 @@ hinzu.)
|
|||||||
#### Scenario: Korpus bleibt kompilierbar
|
#### Scenario: Korpus bleibt kompilierbar
|
||||||
- **WHEN** die Frontend-Testsuite läuft
|
- **WHEN** die Frontend-Testsuite läuft
|
||||||
- **THEN** parsen alle Korpusdateien diagnose-frei und der Test nennt andernfalls Datei und Diagnose
|
- **THEN** parsen alle Korpusdateien diagnose-frei und der Test nennt andernfalls Datei und Diagnose
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
|
||||||
|
### Requirement: Korpusabdeckung der Phase-2-Semantik
|
||||||
|
Der Korpus SHALL um Referenzprogramme mit dokumentierter Sollausgabe für
|
||||||
|
die Zahlenkonvertierungs-Matrix (Rundung, Ganzzahldivision, logische
|
||||||
|
Operatoren, Überlauf-Randfälle über Fehlerbehandlung), die
|
||||||
|
Fehlerbehandlung (`ON ERROR`, `RESUME`-Varianten, `ERR`/`ERL`) sowie
|
||||||
|
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
|
||||||
|
|||||||
67
openspec/specs/konsolen-basisbibliothek/spec.md
Normal file
67
openspec/specs/konsolen-basisbibliothek/spec.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# konsolen-basisbibliothek Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Die Konsolen-Basisbibliothek ist die in Phase 2 vorgezogene Scheibe der
|
||||||
|
Laufzeitbibliothek: die Builtin-Aufrufschnittstelle der VM, ein
|
||||||
|
`Host`-Abstraktion für Konsolen-E/A sowie PRINT-Formatierung und die vom
|
||||||
|
Testkorpus benötigten Stringfunktionen.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Builtin-Aufrufschnittstelle
|
||||||
|
Die VM SHALL Bibliotheksfunktionen und -anweisungen über eine indizierte
|
||||||
|
Dispatch-Tabelle aufrufen (Argumente auf dem Operandenstack, Index im
|
||||||
|
Opcode); die Tabelle lebt in der Laufzeitbibliothek und ist ohne
|
||||||
|
Änderung am Opcode-Satz erweiterbar (Phase 3 füllt sie auf).
|
||||||
|
|
||||||
|
#### Scenario: Builtin über Tabelle
|
||||||
|
- **WHEN** `PRINT LEN("abc")` ausgeführt wird
|
||||||
|
- **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.
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
|
||||||
|
### Requirement: PRINT-Formatierung
|
||||||
|
`PRINT` SHALL Zahlen im Format des Vorbilds ausgeben: führendes
|
||||||
|
Leerzeichen für nicht-negative bzw. `-` für negative Werte,
|
||||||
|
nachgestelltes Leerzeichen (auch am Zeilenende); Zahlendarstellung je
|
||||||
|
Typ wie beim Vorbild (u. a. kein Dezimalpunkt bei ganzzahligen Werten,
|
||||||
|
signifikante Stellen je nach SINGLE/DOUBLE). `;` schließt direkt an,
|
||||||
|
`,` springt zur nächsten 14-Zeichen-Druckzone (belegt ein Element die
|
||||||
|
Zone ganz, zur übernächsten); ohne abschließendes `;`/`,` folgt ein
|
||||||
|
Zeilenumbruch.
|
||||||
|
|
||||||
|
#### Scenario: Zahlen mit Vorzeichenspalte
|
||||||
|
- **WHEN** `PRINT 1; -2; 3.5` ausgeführt wird
|
||||||
|
- **THEN** lautet die Ausgabe ` 1 -2 3.5 ` mit Zeilenumbruch
|
||||||
|
|
||||||
|
#### Scenario: Druckzonen
|
||||||
|
- **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`
|
||||||
|
|
||||||
|
#### Scenario: VAL mit Restzeichen
|
||||||
|
- **WHEN** `VAL(" 12.5abc")` ausgewertet wird
|
||||||
|
- **THEN** ist das Ergebnis 12.5
|
||||||
@@ -102,3 +102,21 @@ Entsprechung existiert (z. B. „Type mismatch", „Duplicate definition",
|
|||||||
#### Scenario: Position in der Diagnose
|
#### Scenario: Position in der Diagnose
|
||||||
- **WHEN** in Zeile 3 ein Typkonflikt auftritt
|
- **WHEN** in Zeile 3 ein Typkonflikt auftritt
|
||||||
- **THEN** nennt die Diagnose Zeile 3 und die Spalte des Ausdrucks
|
- **THEN** nennt die Diagnose Zeile 3 und die Spalte des Ausdrucks
|
||||||
|
|
||||||
|
### Requirement: Typisiertes HIR als Sema-Ausgabe
|
||||||
|
Die semantische Analyse SHALL neben den Diagnosen einen typisierten,
|
||||||
|
abgesenkten Zwischenbaum (HIR) liefern, der die Codegen-Eingabe bildet:
|
||||||
|
Namen sind zu Slot-/Tabellenindizes aufgelöst, jeder Ausdrucksknoten
|
||||||
|
trägt seinen Ergebnistyp, `CONST`-Werte sind gefaltet, `DEFtype`-Regeln
|
||||||
|
angewandt und implizite Konvertierungen als explizite
|
||||||
|
Konvertierungsknoten materialisiert. Bei Diagnosen mit Fehlercharakter
|
||||||
|
darf kein HIR für das betroffene Konstrukt garantiert werden; ein
|
||||||
|
diagnose-freies Modul MUST ein vollständiges HIR ergeben.
|
||||||
|
|
||||||
|
#### Scenario: Konvertierung wird materialisiert
|
||||||
|
- **WHEN** `d# = i% + 1.5#` semantisch analysiert wird
|
||||||
|
- **THEN** enthält das HIR einen expliziten Konvertierungsknoten INTEGER→DOUBLE unter dem Additionsknoten und die Zuweisung trägt den Zieltyp DOUBLE
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
|||||||
116
openspec/specs/vm-ausfuehrung/spec.md
Normal file
116
openspec/specs/vm-ausfuehrung/spec.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# vm-ausfuehrung Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Die TBVM führt das Bytecode-Kompilat mit der exakten Semantik des
|
||||||
|
Dialekts aus: Ausdrücke mit der Zahlenkonvertierungs-Matrix des Vorbilds,
|
||||||
|
Kontrollfluss, Prozeduraufrufe mit BYREF, `GOSUB`, unterbrechbare
|
||||||
|
`step()`-Ausführung als Grundlage für Debugger und Ereignisschleife.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Zahlenkonvertierungs-Matrix
|
||||||
|
Die VM SHALL implizite und explizite Zahlenkonvertierungen nach der in
|
||||||
|
docs/tbvm-design.md dokumentierten Matrix ausführen, insbesondere:
|
||||||
|
Gleitkomma→Ganzzahl rundet kaufmännisch zur nächsten geraden Zahl
|
||||||
|
(Banker's Rounding); Bereichsüberschreitung löst Fehler 6 „Overflow"
|
||||||
|
aus; `/` liefert stets Gleitkomma, `\` und `MOD` konvertieren ihre
|
||||||
|
Operanden vorab zu Ganzzahlen; logische Operatoren (`AND`, `OR`, `XOR`,
|
||||||
|
`EQV`, `IMP`) arbeiten bitweise auf zu Ganzzahlen konvertierten
|
||||||
|
Operanden; CURRENCY rechnet als Festkomma ×10 000. Die Matrix SHALL
|
||||||
|
durch ein Korpusprogramm mit dokumentierter Sollausgabe abgedeckt sein.
|
||||||
|
|
||||||
|
#### Scenario: Banker's Rounding
|
||||||
|
- **WHEN** `PRINT CINT(0.5); CINT(1.5); CINT(2.5)` ausgeführt wird
|
||||||
|
- **THEN** lautet die Ausgabe ` 0 2 2 `
|
||||||
|
|
||||||
|
#### Scenario: Überlauf bei Konvertierung
|
||||||
|
- **WHEN** einer INTEGER-Variablen der Wert 40000 zugewiesen wird
|
||||||
|
- **THEN** tritt Laufzeitfehler 6 „Overflow" auf
|
||||||
|
|
||||||
|
#### Scenario: Ganzzahldivision rundet Operanden vor
|
||||||
|
- **WHEN** `PRINT 7.5 \ 2` ausgeführt wird
|
||||||
|
- **THEN** wird 7.5 zuerst zu 8 gerundet und die Ausgabe ist ` 4 `
|
||||||
|
|
||||||
|
### Requirement: Kontrollfluss
|
||||||
|
Die VM SHALL `IF`/`ELSEIF`/`ELSE`, `SELECT CASE` (Werte, Bereiche,
|
||||||
|
`IS`-Vergleiche, `CASE ELSE`), `FOR`/`NEXT` (inkl. `STEP`, null
|
||||||
|
Durchläufen bei unpassender Grenze), `DO`/`LOOP` (alle vier
|
||||||
|
Bedingungsformen), `WHILE`/`WEND`, `GOTO`, `ON expr GOTO/GOSUB` und
|
||||||
|
`EXIT FOR/DO` mit der Semantik des Vorbilds ausführen.
|
||||||
|
|
||||||
|
#### Scenario: FOR ohne Durchlauf
|
||||||
|
- **WHEN** `FOR i% = 3 TO 1: PRINT i%: NEXT` ausgeführt wird
|
||||||
|
- **THEN** wird der Schleifenkörper nicht betreten
|
||||||
|
|
||||||
|
#### Scenario: Korpus Kontrollfluss
|
||||||
|
- **WHEN** `tests/compat/kontrollfluss.bas` ausgeführt wird
|
||||||
|
- **THEN** entspricht die Ausgabe byte-genau `kontrollfluss.out`
|
||||||
|
|
||||||
|
### Requirement: GOSUB/RETURN neben Prozeduraufrufen
|
||||||
|
`GOSUB` SHALL die Rücksprungadresse auf einem GOSUB-Stack im aktuellen
|
||||||
|
Frame ablegen (kein eigener Frame); `RETURN` kehrt dorthin zurück,
|
||||||
|
`RETURN label` an das benannte Ziel. Ein `RETURN` ohne anhängigen
|
||||||
|
`GOSUB` MUST Fehler 3 „RETURN without GOSUB" auslösen.
|
||||||
|
|
||||||
|
#### Scenario: RETURN ohne GOSUB
|
||||||
|
- **WHEN** ein Programm `RETURN` ohne vorangehendes `GOSUB` ausführt
|
||||||
|
- **THEN** tritt Laufzeitfehler 3 auf
|
||||||
|
|
||||||
|
### Requirement: Prozeduraufrufe mit BYREF-Semantik
|
||||||
|
SUB-/FUNCTION-Aufrufe SHALL eigene Frames mit Locals-Slots verwenden.
|
||||||
|
Variablen, Arrayelemente und UDT-Felder werden BYREF übergeben
|
||||||
|
(Änderungen im Rumpf wirken auf das Argument zurück); ein geklammertes
|
||||||
|
Argument oder ein Ausdruck wird als temporärer Wert übergeben (BYVAL-
|
||||||
|
Wirkung). `STATIC`-Prozeduren behalten ihre Locals zwischen Aufrufen;
|
||||||
|
rekursive Aufrufe nicht-statischer Prozeduren erhalten frische Locals.
|
||||||
|
`DEF FN`-Funktionen werten im Modulkontext aus (Zugriff auf
|
||||||
|
Modulvariablen), ihre Parameter wirken lokal.
|
||||||
|
|
||||||
|
#### Scenario: BYREF wirkt zurück
|
||||||
|
- **WHEN** `SUB Inc(x%) : x% = x% + 1 : END SUB` mit `Inc n%` aufgerufen wird
|
||||||
|
- **THEN** ist `n%` danach um 1 erhöht
|
||||||
|
|
||||||
|
#### Scenario: Klammern erzwingen Wertübergabe
|
||||||
|
- **WHEN** dieselbe SUB mit `Inc (n%)` aufgerufen wird
|
||||||
|
- **THEN** bleibt `n%` unverändert
|
||||||
|
|
||||||
|
### Requirement: DATA/READ/RESTORE
|
||||||
|
`READ` SHALL die `DATA`-Konstanten des Moduls in Deklarationsreihenfolge
|
||||||
|
konsumieren und in den Zieltyp konvertieren; `RESTORE [label]` setzt den
|
||||||
|
Lesezeiger auf den Anfang bzw. auf die erste `DATA`-Anweisung ab dem
|
||||||
|
Label. Lesen hinter dem letzten Element MUST Fehler 4 „Out of DATA"
|
||||||
|
auslösen; eine nicht konvertierbare Konstante MUST Fehler 13 „Type
|
||||||
|
mismatch" auslösen.
|
||||||
|
|
||||||
|
#### Scenario: Out of DATA
|
||||||
|
- **WHEN** ein Programm mehr Werte liest als `DATA` bereitstellt
|
||||||
|
- **THEN** tritt Laufzeitfehler 4 auf
|
||||||
|
|
||||||
|
### Requirement: Unterbrechbare step()-Ausführung
|
||||||
|
Die VM SHALL als zustandsbehaftete, vom Einbetter getriebene Struktur
|
||||||
|
ausführbar sein: An Anweisungsgrenzen prüft sie ein Flag-Wort und kann
|
||||||
|
anhalten (Breakpoint auf (Modul, Zeile), Einzelschritt, Abbruchwunsch).
|
||||||
|
Im angehaltenen Zustand MUST der Einbetter Variableninhalte (Skalare,
|
||||||
|
Arrayelemente, UDT-Felder) inspizieren und die Ausführung fortsetzen
|
||||||
|
können. Die Tick-Prüfung erfolgt nur an Anweisungsgrenzen, nicht pro
|
||||||
|
Opcode.
|
||||||
|
|
||||||
|
#### Scenario: Breakpoint hält an
|
||||||
|
- **WHEN** ein Breakpoint auf Zeile 10 gesetzt ist und die Ausführung Zeile 10 erreicht
|
||||||
|
- **THEN** hält die VM vor der Anweisung an und meldet Modul und Zeile
|
||||||
|
|
||||||
|
#### Scenario: Inspektion im Halt
|
||||||
|
- **WHEN** die VM an einem Breakpoint steht
|
||||||
|
- **THEN** liefert die Inspektions-API den aktuellen Wert einer benannten Variablen
|
||||||
|
|
||||||
|
### Requirement: Programmende im Runner
|
||||||
|
Außerhalb der IDE SHALL `END` (und das Erreichen des Programmendes) den
|
||||||
|
Prozess mit Exit-Code 0 beenden; `STOP` SHALL mit der Meldung
|
||||||
|
`STOP in line n` (bzw. Modul/Zeile) und einem Exit-Code ungleich 0
|
||||||
|
terminieren (Projektentscheidung 2026-09-02). `SYSTEM` verhält sich wie
|
||||||
|
`END`. `CONT` existiert nur als IDE-Konzept (Phase 5) und ist kein
|
||||||
|
Programmbestandteil.
|
||||||
|
|
||||||
|
#### Scenario: STOP im Runner
|
||||||
|
- **WHEN** ein per `tbc run` gestartetes Programm `STOP` in Zeile 7 ausführt
|
||||||
|
- **THEN** endet der Prozess mit Exit-Code ungleich 0 und die Meldung nennt Zeile 7
|
||||||
72
openspec/specs/vm-fehlerbehandlung/spec.md
Normal file
72
openspec/specs/vm-fehlerbehandlung/spec.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# vm-fehlerbehandlung Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Die BASIC-Fehlersemantik (`ON ERROR GOTO`, `ON LOCAL ERROR`, `RESUME`,
|
||||||
|
`ERR`/`ERL`) ist Teil des Kompatibilitätsvertrags: Programme des Vorbilds
|
||||||
|
verlassen sich auf Handler-Scoping, Propagation und Wiederaufnahme exakt
|
||||||
|
wie dokumentiert.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Handler-Scoping nach Vorbild
|
||||||
|
`ON ERROR GOTO label` SHALL einen modulweiten Handler aktivieren (auch
|
||||||
|
wenn die Anweisung in einer Prozedur steht); `ON LOCAL ERROR GOTO label`
|
||||||
|
SHALL einen prozedurlokalen Handler aktivieren, der den modulweiten für
|
||||||
|
die Dauer des Prozedurlaufs verdeckt. `ON [LOCAL] ERROR GOTO 0`
|
||||||
|
deaktiviert den jeweiligen Handler. Tritt ein Fehler in einer Prozedur
|
||||||
|
ohne zuständigen Handler auf, SHALL er die Aufrufkette hochpropagieren,
|
||||||
|
bis ein aktiver Handler gefunden ist; ohne Handler bricht das Programm
|
||||||
|
mit der Fehlermeldung und der Quellzeile ab.
|
||||||
|
|
||||||
|
#### Scenario: Modulweiter Handler fängt Prozedurfehler
|
||||||
|
- **WHEN** das Hauptprogramm `ON ERROR GOTO Fehler` gesetzt hat und eine gerufene SUB Fehler 6 auslöst
|
||||||
|
- **THEN** springt die Ausführung in den Handler `Fehler` und `ERR` ist 6
|
||||||
|
|
||||||
|
#### Scenario: Lokaler Handler verdeckt modulweiten
|
||||||
|
- **WHEN** eine Prozedur `ON LOCAL ERROR GOTO L` gesetzt hat und in ihr ein Fehler auftritt
|
||||||
|
- **THEN** behandelt `L` den Fehler, nicht der modulweite Handler
|
||||||
|
|
||||||
|
#### Scenario: Ohne Handler bricht das Programm ab
|
||||||
|
- **WHEN** Fehler 9 ohne aktiven Handler auftritt
|
||||||
|
- **THEN** endet das Programm mit der Meldung „Subscript out of range" und der Quellzeile
|
||||||
|
|
||||||
|
### Requirement: ERR und ERL
|
||||||
|
Beim Eintritt in einen Handler SHALL `ERR` den Fehlercode liefern und
|
||||||
|
`ERL` die zuletzt vor dem Fehler ausgeführte **numerische** Zeilennummer
|
||||||
|
(0, wenn keine numerischen Zeilennummern durchlaufen wurden —
|
||||||
|
alphanumerische Labels zählen nicht). `ERROR n` SHALL Fehler `n`
|
||||||
|
künstlich auslösen und dieselbe Maschinerie durchlaufen.
|
||||||
|
|
||||||
|
#### Scenario: ERL bei Label-Programm
|
||||||
|
- **WHEN** ein Programm ohne numerische Zeilennummern einen Fehler behandelt
|
||||||
|
- **THEN** liefert `ERL` 0
|
||||||
|
|
||||||
|
#### Scenario: ERROR-Anweisung
|
||||||
|
- **WHEN** `ERROR 53` bei aktivem Handler ausgeführt wird
|
||||||
|
- **THEN** wird der Handler mit `ERR` = 53 betreten
|
||||||
|
|
||||||
|
### Requirement: RESUME-Semantik
|
||||||
|
Im Handler SHALL `RESUME` (bzw. `RESUME 0`) die fehlerauslösende
|
||||||
|
Anweisung wiederholen, `RESUME NEXT` mit der Anweisung danach
|
||||||
|
fortfahren und `RESUME label` an das Ziel springen. `RESUME` außerhalb
|
||||||
|
einer aktiven Fehlerbehandlung MUST Fehler 20 „RESUME without error"
|
||||||
|
auslösen. Nach `RESUME` gilt die Fehlerbehandlung als abgeschlossen
|
||||||
|
(`ERR` wird zurückgesetzt).
|
||||||
|
|
||||||
|
#### Scenario: RESUME NEXT
|
||||||
|
- **WHEN** ein Handler nach Fehler 11 (`Division by zero`) `RESUME NEXT` ausführt
|
||||||
|
- **THEN** wird die auf die Division folgende Anweisung ausgeführt
|
||||||
|
|
||||||
|
#### Scenario: RESUME ohne Fehler
|
||||||
|
- **WHEN** `RESUME` außerhalb eines Handlers ausgeführt wird
|
||||||
|
- **THEN** tritt Laufzeitfehler 20 auf
|
||||||
|
|
||||||
|
### Requirement: Fehler im Handler ist fatal
|
||||||
|
Tritt ein Fehler auf, während die Fehlerbehandlung aktiv ist (zwischen
|
||||||
|
Handler-Eintritt und `RESUME`), SHALL das Programm ohne erneute
|
||||||
|
Handler-Suche mit der Fehlermeldung abbrechen (keine Fehlerkaskaden,
|
||||||
|
Verhalten des Vorbilds).
|
||||||
|
|
||||||
|
#### Scenario: Kein Kaskadieren
|
||||||
|
- **WHEN** im aktiven Handler selbst Fehler 6 auftritt
|
||||||
|
- **THEN** bricht das Programm mit „Overflow" ab, auch wenn ein Handler registriert ist
|
||||||
Reference in New Issue
Block a user