From a6f005d02361a5f1fd2ffaea01dd0f390e49b873 Mon Sep 17 00:00:00 2001 From: Chili Palmer Date: Wed, 2 Sep 2026 11:33:51 +0200 Subject: [PATCH] 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 --- .../.openspec.yaml | 0 .../2026-09-02-phase-2-bytecode-vm}/design.md | 0 .../proposal.md | 0 .../specs/bytecode-kompilat/spec.md | 0 .../specs/kompat-testkorpus/spec.md | 0 .../specs/konsolen-basisbibliothek/spec.md | 0 .../specs/sprach-frontend/spec.md | 0 .../specs/vm-ausfuehrung/spec.md | 0 .../specs/vm-fehlerbehandlung/spec.md | 0 .../2026-09-02-phase-2-bytecode-vm}/tasks.md | 0 openspec/specs/bytecode-kompilat/spec.md | 65 ++++++++++ openspec/specs/kompat-testkorpus/spec.md | 26 ++++ .../specs/konsolen-basisbibliothek/spec.md | 67 ++++++++++ openspec/specs/sprach-frontend/spec.md | 18 +++ openspec/specs/vm-ausfuehrung/spec.md | 116 ++++++++++++++++++ openspec/specs/vm-fehlerbehandlung/spec.md | 72 +++++++++++ 16 files changed, 364 insertions(+) rename openspec/changes/{phase-2-bytecode-vm => archive/2026-09-02-phase-2-bytecode-vm}/.openspec.yaml (100%) rename openspec/changes/{phase-2-bytecode-vm => archive/2026-09-02-phase-2-bytecode-vm}/design.md (100%) rename openspec/changes/{phase-2-bytecode-vm => archive/2026-09-02-phase-2-bytecode-vm}/proposal.md (100%) rename openspec/changes/{phase-2-bytecode-vm => archive/2026-09-02-phase-2-bytecode-vm}/specs/bytecode-kompilat/spec.md (100%) rename openspec/changes/{phase-2-bytecode-vm => archive/2026-09-02-phase-2-bytecode-vm}/specs/kompat-testkorpus/spec.md (100%) rename openspec/changes/{phase-2-bytecode-vm => archive/2026-09-02-phase-2-bytecode-vm}/specs/konsolen-basisbibliothek/spec.md (100%) rename openspec/changes/{phase-2-bytecode-vm => archive/2026-09-02-phase-2-bytecode-vm}/specs/sprach-frontend/spec.md (100%) rename openspec/changes/{phase-2-bytecode-vm => archive/2026-09-02-phase-2-bytecode-vm}/specs/vm-ausfuehrung/spec.md (100%) rename openspec/changes/{phase-2-bytecode-vm => archive/2026-09-02-phase-2-bytecode-vm}/specs/vm-fehlerbehandlung/spec.md (100%) rename openspec/changes/{phase-2-bytecode-vm => archive/2026-09-02-phase-2-bytecode-vm}/tasks.md (100%) create mode 100644 openspec/specs/bytecode-kompilat/spec.md create mode 100644 openspec/specs/konsolen-basisbibliothek/spec.md create mode 100644 openspec/specs/vm-ausfuehrung/spec.md create mode 100644 openspec/specs/vm-fehlerbehandlung/spec.md diff --git a/openspec/changes/phase-2-bytecode-vm/.openspec.yaml b/openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/.openspec.yaml similarity index 100% rename from openspec/changes/phase-2-bytecode-vm/.openspec.yaml rename to openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/.openspec.yaml diff --git a/openspec/changes/phase-2-bytecode-vm/design.md b/openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/design.md similarity index 100% rename from openspec/changes/phase-2-bytecode-vm/design.md rename to openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/design.md diff --git a/openspec/changes/phase-2-bytecode-vm/proposal.md b/openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/proposal.md similarity index 100% rename from openspec/changes/phase-2-bytecode-vm/proposal.md rename to openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/proposal.md diff --git a/openspec/changes/phase-2-bytecode-vm/specs/bytecode-kompilat/spec.md b/openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/bytecode-kompilat/spec.md similarity index 100% rename from openspec/changes/phase-2-bytecode-vm/specs/bytecode-kompilat/spec.md rename to openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/bytecode-kompilat/spec.md diff --git a/openspec/changes/phase-2-bytecode-vm/specs/kompat-testkorpus/spec.md b/openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/kompat-testkorpus/spec.md similarity index 100% rename from openspec/changes/phase-2-bytecode-vm/specs/kompat-testkorpus/spec.md rename to openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/kompat-testkorpus/spec.md diff --git a/openspec/changes/phase-2-bytecode-vm/specs/konsolen-basisbibliothek/spec.md b/openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/konsolen-basisbibliothek/spec.md similarity index 100% rename from openspec/changes/phase-2-bytecode-vm/specs/konsolen-basisbibliothek/spec.md rename to openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/konsolen-basisbibliothek/spec.md diff --git a/openspec/changes/phase-2-bytecode-vm/specs/sprach-frontend/spec.md b/openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/sprach-frontend/spec.md similarity index 100% rename from openspec/changes/phase-2-bytecode-vm/specs/sprach-frontend/spec.md rename to openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/sprach-frontend/spec.md diff --git a/openspec/changes/phase-2-bytecode-vm/specs/vm-ausfuehrung/spec.md b/openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/vm-ausfuehrung/spec.md similarity index 100% rename from openspec/changes/phase-2-bytecode-vm/specs/vm-ausfuehrung/spec.md rename to openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/vm-ausfuehrung/spec.md diff --git a/openspec/changes/phase-2-bytecode-vm/specs/vm-fehlerbehandlung/spec.md b/openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/vm-fehlerbehandlung/spec.md similarity index 100% rename from openspec/changes/phase-2-bytecode-vm/specs/vm-fehlerbehandlung/spec.md rename to openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/specs/vm-fehlerbehandlung/spec.md diff --git a/openspec/changes/phase-2-bytecode-vm/tasks.md b/openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/tasks.md similarity index 100% rename from openspec/changes/phase-2-bytecode-vm/tasks.md rename to openspec/changes/archive/2026-09-02-phase-2-bytecode-vm/tasks.md diff --git a/openspec/specs/bytecode-kompilat/spec.md b/openspec/specs/bytecode-kompilat/spec.md new file mode 100644 index 0000000..f31e398 --- /dev/null +++ b/openspec/specs/bytecode-kompilat/spec.md @@ -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 diff --git a/openspec/specs/kompat-testkorpus/spec.md b/openspec/specs/kompat-testkorpus/spec.md index 616e69a..7ad91be 100644 --- a/openspec/specs/kompat-testkorpus/spec.md +++ b/openspec/specs/kompat-testkorpus/spec.md @@ -29,3 +29,29 @@ 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 + +### 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 diff --git a/openspec/specs/konsolen-basisbibliothek/spec.md b/openspec/specs/konsolen-basisbibliothek/spec.md new file mode 100644 index 0000000..bc8c789 --- /dev/null +++ b/openspec/specs/konsolen-basisbibliothek/spec.md @@ -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 diff --git a/openspec/specs/sprach-frontend/spec.md b/openspec/specs/sprach-frontend/spec.md index 7d31488..4348dee 100644 --- a/openspec/specs/sprach-frontend/spec.md +++ b/openspec/specs/sprach-frontend/spec.md @@ -102,3 +102,21 @@ Entsprechung existiert (z. B. „Type mismatch", „Duplicate definition", #### Scenario: Position in der Diagnose - **WHEN** in Zeile 3 ein Typkonflikt auftritt - **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 diff --git a/openspec/specs/vm-ausfuehrung/spec.md b/openspec/specs/vm-ausfuehrung/spec.md new file mode 100644 index 0000000..8ecf799 --- /dev/null +++ b/openspec/specs/vm-ausfuehrung/spec.md @@ -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 diff --git a/openspec/specs/vm-fehlerbehandlung/spec.md b/openspec/specs/vm-fehlerbehandlung/spec.md new file mode 100644 index 0000000..f86959c --- /dev/null +++ b/openspec/specs/vm-fehlerbehandlung/spec.md @@ -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