Projektmodule und vollständiges TBC-Kompilat umsetzen und Change archivieren
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
## Why
|
||||
|
||||
Mehrere Module/Formulare werden zu einem Quelltext und globalen Objektraum zusammengelegt. Dadurch scheitern formularlokale Namen, Fehlerorte stimmen nicht und FRM-Anfangswerte fehlen nach dem Kompilat-Rundlauf (F09–F11); Containerdokumentation und Spec sind außerdem überholt (F24). Siehe [Review vom 05.09.2026](../../../docs/reviews/2026-09-05-openspec-code-review.md).
|
||||
Mehrere Module/Formulare werden zu einem Quelltext und globalen Objektraum zusammengelegt. Dadurch scheitern formularlokale Namen, Fehlerorte stimmen nicht und FRM-Anfangswerte fehlen nach dem Kompilat-Rundlauf (F09–F11); Containerdokumentation und Spec sind außerdem überholt (F24). Siehe [Review vom 05.09.2026](../../../../docs/reviews/2026-09-05-openspec-code-review.md).
|
||||
|
||||
## What Changes
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
# Verifikation: projektmodule-und-kompilat
|
||||
|
||||
Geprüft am 05.09.2026: Arbeitsbaum auf Basis von `58b1f62`, alle sieben
|
||||
Delta-Requirements mit 21 Szenarien, Tasks, D1–D4, Implementierung und
|
||||
Abnahmenachweis. **Sechs offene Befunde; der Change ist nicht abnahmebereit.**
|
||||
Die vorherige Aussage vollständiger Umsetzung wird durch diese Verifikation
|
||||
korrigiert. Der Produktcode wurde bei diesem Review nicht verändert.
|
||||
|
||||
| Dimension | Ergebnis |
|
||||
| --- | --- |
|
||||
| Vollständigkeit | 7/7 Tasks sind angehakt und alle sieben Requirements haben Implementierungspfade. Die Befunde widerlegen jedoch die vollständige Erfüllung insbesondere von 1.1, 1.2 und 2.2; Checkboxen allein sind kein Abnahmenachweis. |
|
||||
| Korrektheit | 437 bestehende Workspace-Tests bestanden; zusätzliche unabhängige Review-Proben: 1 bestanden, 6 fehlgeschlagen. Vier Kernfunktionslücken (CRITICAL), zwei weitere Vertragsabweichungen (WARNING). |
|
||||
| Kohärenz | D4 und die FRM-Grundpfade von D3 sind umgesetzt. Quellorte und Modulkontexte gehen in weiteren Absenkungs-/Importpfaden verloren; der gemeinsame Objektraum berücksichtigt `$FORM` nicht vollständig. |
|
||||
|
||||
## CRITICAL — vor Archivierung beheben
|
||||
|
||||
### V1 — Quellorte und Breakpoints fehlen an Zweig- und Schleifengrenzen
|
||||
|
||||
**Priorität: hoch.** Delta „Zeilentabelle für Fehlerortung“ und
|
||||
„Unterbrechbare step()-Ausführung“, D1, Tasks 1.1/2.2.
|
||||
|
||||
Die Fehlerortung funktioniert bei einfachen Anweisungen, nicht jedoch bei
|
||||
weiteren ausführbaren Teilen zusammengesetzter Anweisungen:
|
||||
|
||||
| Probe | Erwartet | Beobachtet |
|
||||
| --- | --- | --- |
|
||||
| `IF 0 THEN` / `PRINT 1` / `ELSEIF 1/0 THEN` | Fehler 11 in Zeile 3 | Zeile 1 |
|
||||
| `SELECT CASE 1` / `CASE 1/0` | Fehler 11 in Zeile 2 | Zeile 1 |
|
||||
| `FOR i%=32767 TO 32767` / `PRINT 1` / `NEXT` | Überlauf beim NEXT in Zeile 3 | Zeile 2 |
|
||||
| `DO` / `PRINT 1` / `LOOP UNTIL 1/0` | Fehler 11 in Zeile 3 | Zeile 2 |
|
||||
| ELSEIF-Bedingung aus `cond.bi:1` | Include-Datei `cond.bi` | `main.bas:1:1` |
|
||||
| Breakpoint auf ELSEIF in Zeile 3 | Halt vor Bedingung | Programm endet ohne Halt |
|
||||
|
||||
**Ursache:** [ELSEIF-Absenkung](../../../../crates/tb-frontend/src/sema.rs#L1937)
|
||||
und [CASE-Absenkung](../../../../crates/tb-frontend/src/sema.rs#L2914) verwenden
|
||||
den Quellort des äußeren Statements. NEXT-/LOOP-Positionen werden nicht
|
||||
vollständig durch AST/HIR bis zur auszuführenden Grenze getragen. Der
|
||||
[FOR-Codegenerator](../../../../crates/tb-vm/src/codegen.rs#L737) dokumentiert
|
||||
selbst die bisherige Verschiebung einer genauen NEXT-Zuordnung auf Phase 5;
|
||||
das widerspricht der hier übernommenen vollständigen Quellortanforderung.
|
||||
|
||||
**Korrektur:** Physische Positionen aller ausführbaren Zweig-/Schleifenteile
|
||||
bereits beim Parsen erhalten und passende Source-/Stmt-Grenzen ausgeben.
|
||||
Nicht nur Fehlermeldungen umbenennen: Breakpoints, Einzelschritt und RESUME
|
||||
müssen dieselbe richtige Zuordnung verwenden. Numerische ERL-Labels separat
|
||||
lassen. Probe `v1_zweige_und_schleifen_behalten_eigene_quellorte`.
|
||||
|
||||
### V2 — Deklarationsimport verändert Typkontext und Abhängigkeitsreihenfolge
|
||||
|
||||
**Priorität: hoch.** Projektpipeline und vollständige Prozedursignaturen,
|
||||
D2, Tasks 1.2/2.1.
|
||||
|
||||
Drei zulässige Mehrmodulkonstellationen werden abgewiesen:
|
||||
|
||||
- MAIN ruft `Doppelt(3)` auf; LIB enthält `DEFINT A-Z` und
|
||||
`FUNCTION Doppelt(x)`. Erwartete Ausgabe 6, tatsächlich
|
||||
`Parameter type mismatch: MAIN!DOPPELT`.
|
||||
- MAIN enthält `CONST A=3` und verwendet B; LIB enthält `CONST A=3` und
|
||||
`CONST B=A+1`. Erwartet B=4, tatsächlich `LIB.bas:2:1: Invalid constant`.
|
||||
- Beide Module enthalten denselben TYPE Inner. LIB definiert anschließend
|
||||
TYPE Outer mit einem Feld `i AS Inner`; MAIN verwendet Outer.
|
||||
Erwartet korrektes Layout und Feldausgabe 3, tatsächlich `Type not defined`
|
||||
an der gültigen Outer-Definition sowie Folgefehler für Feldzugriffe.
|
||||
|
||||
**Ursache:** [import_declarations](../../../../crates/tb-vm/src/project.rs#L103)
|
||||
kopiert rohe Signatur-ASTs ohne den DEFtype-Kontext des definierenden Moduls.
|
||||
Fremde CONST-/TYPE-Knoten werden [vor sämtliche lokalen Deklarationen
|
||||
gehängt](../../../../crates/tb-vm/src/project.rs#L158). Dadurch fehlen ihnen zu
|
||||
diesem Zeitpunkt lokal vorhandene Abhängigkeiten. Die Fehlerposition in LIB
|
||||
ist hier irreführend: Die dortige Originalreihenfolge ist gültig.
|
||||
|
||||
**Korrektur:** Exportierte Signaturen und Konstanten im Ursprungskontext
|
||||
auflösen; abhängige Typdefinitionen mit erhaltenen Identitäten und gültiger
|
||||
Abhängigkeitsreihenfolge verbinden. Lokale Definitionen und echte Duplikate
|
||||
nicht wieder durch Text-Deduplizierung verstecken. Probe
|
||||
`v2_importierte_deklarationen_behalten_kontext_und_abhaengigkeiten`.
|
||||
|
||||
### V3 — `$FORM`-Module teilen versehentlich dasselbe Formularobjekt
|
||||
|
||||
**Priorität: hoch.** Delta „Objektzugriffe in Grammatik und Semantik“
|
||||
einschließlich `$FORM`, getrennte Formulare, D2/D3, Task 1.2.
|
||||
|
||||
A.bas und B.bas enthalten jeweils `'$FORM`. A setzt `Caption="a"`, ruft eine
|
||||
SUB aus B auf, die dort `Caption="b"` setzt, und liest anschließend die
|
||||
eigene Caption. **Erwartet: a. Beobachtet: b.** Das verknüpfte Objektverzeichnis
|
||||
enthält nur SCREEN und A. Auch `B.Caption` aus A wird als unbekanntes Objekt
|
||||
abgewiesen. Der Fehler besteht nach TBC-Rundlauf fort.
|
||||
|
||||
**Ursache:** [lower_with_forms](../../../../crates/tb-frontend/src/sema.rs#L404)
|
||||
erweitert pro Modul eine lokale Katalogkopie um das jeweilige `$FORM`-Objekt.
|
||||
Der Linker übernimmt [nur die Objekte des ersten Moduls](../../../../crates/tb-vm/src/project.rs#L188)
|
||||
und versetzt die Objektoperanden weiterer Module nicht. Deren Form-ID zeigt
|
||||
anschließend auf A.
|
||||
|
||||
**Korrektur:** Sämtliche FRM- und `$FORM`-Formulare vor der modulweisen
|
||||
Semantik in einen gemeinsamen Katalog mit stabilen IDs aufnehmen oder die
|
||||
Objekt-/Ereignisreferenzen beim Linken vollständig versetzen. Zugriffe,
|
||||
Form_Load-Bindungen und gegenseitige Formreferenzen für beide Quellarten
|
||||
prüfen. Probe `v3_form_metabefehle_erzeugen_getrennte_formularobjekte`.
|
||||
|
||||
### V4 — COMMON verliert Variablenidentität und initialisiert Arrays mehrfach
|
||||
|
||||
**Priorität: hoch.** Designrisiko SHARED/COMMON, D2, Task 1.2 und Erhalt der
|
||||
bestehenden COMMON-Sprachsemantik.
|
||||
|
||||
- Bereits ein Modul mit `COMMON SHARED c%, c$` wird mit
|
||||
`COMMON type mismatch: C` abgewiesen. Die beiden durch Typ-Suffixe
|
||||
verschiedenen Variablen dürfen nebeneinander existieren.
|
||||
- MAIN und LIB deklarieren dasselbe `COMMON SHARED a%(2)`. MAIN soll
|
||||
`a%(1)=7` setzen und LIB den gemeinsamen Wert 7 ausgeben. Stattdessen
|
||||
entsteht vor dem Nutzcode `LIB.bas:1:1: Runtime error 10: Duplicate definition`.
|
||||
|
||||
**Ursache:** Die [COMMON-Zuordnung](../../../../crates/tb-vm/src/project.rs#L270)
|
||||
verwendet nur Block und untypisierten Basisnamen. Arrays haben zusätzlich
|
||||
nur `TypeInit::Empty` als Slotvorbelegung; Elementtyp und Form gehen in der
|
||||
Vergleichsprüfung verloren. Der Slot wird zwar zusammengeführt, aber
|
||||
[beide DIM-Initialisierungen](../../../../crates/tb-vm/src/project.rs#L381)
|
||||
werden ausgeführt.
|
||||
|
||||
**Korrektur:** Vollständige Variablenidentität und Arrayvertrag beim Binden
|
||||
berücksichtigen. Kompatible gemeinsame Arrays einmal initialisieren;
|
||||
inkompatible Deklarationen vor der Ausführung am ursprünglichen Quellort
|
||||
ablehnen. Probe `v4_common_behaelt_typidentitaet_und_initialisiert_arrays_einmal`.
|
||||
|
||||
## WARNING — weitere Vertragsabweichungen
|
||||
|
||||
### V5 — LOAD/UNLOAD umgehen die explizite Containerauflösung
|
||||
|
||||
**Priorität: mittel.** Formularnamensraum und expliziter Containerzugriff,
|
||||
D2, Task 1.2.
|
||||
|
||||
Bei zwei Formularen mit jeweils Text1 als Control-Array werden
|
||||
`LOAD Form2!Text1(3)` und `UNLOAD Form2!Text1(3)` mit
|
||||
`Unknown object 'FORM2!TEXT1'` abgewiesen. Property-Zugriffe und die Übergabe
|
||||
desselben qualifizierten Controls an einen CONTROL-Parameter funktionieren.
|
||||
|
||||
**Ursache:** Der [LOAD-/UNLOAD-Pfad](../../../../crates/tb-frontend/src/sema.rs#L3370)
|
||||
übergibt den gesamten Bang-Pfad an `find_object`; die bereits vorhandene
|
||||
containerbezogene Auflösung wird hier nicht verwendet.
|
||||
|
||||
**Korrektur:** LOAD/UNLOAD über dieselbe Objekt-/Containerauflösung wie
|
||||
Property- und Referenzzugriffe führen; gleichnamige Arrays beider Formulare
|
||||
und dynamische Instanzen gemeinsam prüfen. Probe
|
||||
`v5_load_und_unload_loesen_den_expliziten_container_auf`.
|
||||
|
||||
### V6 — Linkerdiagnosen verlieren Datei, Zeile und Spalte
|
||||
|
||||
**Priorität: mittel.** Delta „Diagnostik mit Vorbild-Meldungen“, D1, Task 1.1.
|
||||
|
||||
MAIN deklariert `SUB F(x%)`, LIB implementiert `SUB F(x$)`. Die Ablehnung ist
|
||||
richtig, die Meldung jedoch `0:0: Parameter type mismatch: MAIN!F` ohne Datei.
|
||||
Das ist eine quellbezogene Diagnose, kein Fehler ohne zuordenbare Quelle.
|
||||
|
||||
**Ursache:** [diagnostic](../../../../crates/tb-vm/src/project.rs#L17) erzeugt
|
||||
`file=None` und `SourcePos::default()`. [Linkfehler](../../../../crates/tb-vm/src/project.rs#L66)
|
||||
werden erst nach `locate_diagnostics` in dieses Format umgewandelt. Dasselbe
|
||||
Problem betrifft COMMON-Konflikte und weitere symbolbezogene Linkfehler.
|
||||
|
||||
**Korrektur:** Ursprung der betroffenen Deklaration bzw. Aufrufstelle mit
|
||||
in die Linker-Symbolinformationen übernehmen und strukturierte Diagnosen
|
||||
mit tatsächlicher SourcePos zurückgeben. Keine pauschale Ersatzposition
|
||||
1:1 eintragen. Probe `v6_linkerdiagnose_nennt_den_urspruenglichen_dateiort`.
|
||||
|
||||
## Szenarioabdeckung und positive Nachweise
|
||||
|
||||
Alle 21 vorhandenen Delta-Szenarien wurden abgeglichen. Die einfachen
|
||||
Originalbeispiele besitzen Implementierungs- und Testnachweise; die oben
|
||||
reproduzierten Randpfade widersprechen den umfassenderen Requirements.
|
||||
|
||||
| Requirement / Szenarien | Ergebnis |
|
||||
| --- | --- |
|
||||
| Monomorpher Opcode-Satz: gemischter Ausdruck, aufgelöste Namen | Vorhandene Codegen-/HIR-Tests bestanden. Alle 152 Opcodes samt Operandentypen und Encodingbreiten stimmen mit der Dokumentation überein. |
|
||||
| TBC: Roundtrip, unbekannte Version, Formularwerte | CLI-/VM-Projekttests bestanden: bytegleicher Rundlauf, hello/world aus Designarrays 0/2 nach Entfernen sämtlicher BAS-/FRM-/MAK-/BI-Quellen, Ablehnung alter/höherer Versionen. V2/V3 begrenzen dennoch das vollständige Projektmodell. |
|
||||
| Quellorte: Fehlerzeile, Bibliotheksfehler | `lib.bas:2` und verschachtelte Include-Fehler bestehen. Unabhängig zusätzlich Fehler in physischer Zeile 42 geprüft. V1 zeigt fehlende Zweig-/Schleifenorte. |
|
||||
| Benannte Objekte: Lesen/Schreiben, keine Standardeigenschaft, Wertebereich, getrennte Controls | Bestehende Semantik-/VM-/Modelltests und neuer Zwei-FRM-Test bestanden; Check1.Value=3 bleibt Fehler 5. V3 betrifft weitere Formularquellen, V5 die weiteren qualifizierten Zugriffspfade. |
|
||||
| Diagnosen: Position, Include-Diagnose | Lexer-/Parser-/Semantikpfad trägt Originalpositionen. V6 betrifft die anschließende Linkerphase. |
|
||||
| Objektgrammatik/-semantik: unbekanntes Objekt/Eigenschaft, Typkonflikt, TYPEOF, gleiche Controls | Bestehende Tests bestanden. V3/V5 verletzen den allgemeinen Modul-/Containervertrag trotz grüner Property-Beispiele. |
|
||||
| Unterbrechung: Breakpoint, Inspektion, gleiche Zeile in zwei Modulen | Unabhängige Probe: MAIN passiert Zeile 10, LIB hält in Zeile 10; qualifizierte Array-/UDT-Inspektion liefert 7/8; Einzelschritt meldet Spalte 5; ERR/ERL bleiben 6/200. V1 lässt Breakpoints an ELSEIF aus. |
|
||||
|
||||
Erneut ausgeführt:
|
||||
|
||||
- `cargo test --workspace`: **437 bestanden, 0 fehlgeschlagen, 1 ignoriert**.
|
||||
Golden-Generator nicht ausgeführt, keine Sollausgaben geändert.
|
||||
- [Review-Proben](review-probes.rs): **1 bestanden, 6 fehlgeschlagen**.
|
||||
Jede fehlgeschlagene Probe entspricht einem der sechs Befunde; mehrere
|
||||
verwandte Reproduktionen werden innerhalb einer Probe gesammelt.
|
||||
- Zusätzlich zeitlich begrenzte CLI-Proben für die Befunde; temporäre
|
||||
Quellverzeichnisse anschließend entfernt.
|
||||
- `cargo bench -p tb-vm --bench compile`: 508 Zeilen **0,54 ms**, 49.760 Zeilen
|
||||
in 20 verbundenen Modulen **67 ms**; beide Budgets erfüllt.
|
||||
- Dokumentation: **152/152 Opcodes**, Operanden-/Gesamtbreiten und **9/9
|
||||
Containerabschnitte** gegen den aktuellen Code abgeglichen.
|
||||
- `cargo fmt --all -- --check`, `openspec validate projektmodule-und-kompilat --strict`
|
||||
und `git diff --check`: bestanden.
|
||||
- Clippy nicht nochmals ausgeführt: keine Produktcodeänderung seit dem
|
||||
erfolgreichen Clippy-Lauf der Implementierungsabnahme. Kein neuer
|
||||
interaktiver Originalsystemvergleich und keine Windows-/Linux-Testmatrix.
|
||||
|
||||
## Review-Proben reproduzieren
|
||||
|
||||
Im Repository-Wurzelverzeichnis ausführen. Der temporäre Treiber hält die
|
||||
noch roten Vertragsproben außerhalb der normalen Workspace-Suite; ihre
|
||||
Erwartungen beschreiben das Sollverhalten. Exit-Code ist bis zur Behebung 101.
|
||||
|
||||
```sh
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import json, subprocess, tempfile, os
|
||||
root = Path.cwd()
|
||||
with tempfile.TemporaryDirectory(prefix='tb-project-review-') as folder:
|
||||
p = Path(folder)
|
||||
manifest = '[package]\nname="tb-project-review"\nversion="0.0.0"\nedition="2021"\n[workspace]\n'
|
||||
manifest += '[[test]]\nname="probes"\npath=' + json.dumps(str(root / 'openspec/changes/archive/2026-09-05-projektmodule-und-kompilat/review-probes.rs')) + '\n[dependencies]\n'
|
||||
for name in ['tb-ui', 'tb-vm', 'tb-runtime', 'tb-frontend']:
|
||||
manifest += name + ' = {path=' + json.dumps(str(root / 'crates' / name)) + '}\n'
|
||||
(p / 'Cargo.toml').write_text(manifest)
|
||||
result = subprocess.run(['cargo', 'test', '--manifest-path', str(p / 'Cargo.toml'), '--offline', '--test', 'probes', '--', '--nocapture'], env={**os.environ, 'CARGO_TARGET_DIR': str(root / 'target/review-projektmodule')}, timeout=120)
|
||||
raise SystemExit(result.returncode)
|
||||
PY
|
||||
```
|
||||
|
||||
**Abnahmeentscheidung:** V1–V4 vor Archivierung beheben; V5/V6 ebenfalls in
|
||||
die vollständige Umsetzung aufnehmen. Keine zusätzlichen Stilvorschläge.
|
||||
@@ -0,0 +1,266 @@
|
||||
//! Unabhängige Vertragsproben; Ausführung mit dem temporären Treiber aus review.md.
|
||||
use tb_frontend::{
|
||||
forms::FormCatalog,
|
||||
source::{SourceSegment, SourceUnit},
|
||||
};
|
||||
use tb_runtime::{host::CaptureHost, value::Value};
|
||||
use tb_vm::{
|
||||
bytecode::CompiledModule,
|
||||
compile_project,
|
||||
interp::{RunEvent, Vm},
|
||||
};
|
||||
|
||||
fn units(files: &[(&str, &str)]) -> Vec<SourceUnit> {
|
||||
files
|
||||
.iter()
|
||||
.map(|(name, code)| SourceUnit::new(name, &format!("{name}.bas"), code))
|
||||
.collect()
|
||||
}
|
||||
fn compile(files: &[(&str, &str)]) -> Result<CompiledModule, Vec<tb_frontend::Diagnostic>> {
|
||||
compile_project("APP", &units(files), &FormCatalog::default(), &[])
|
||||
}
|
||||
fn run(module: CompiledModule) -> (RunEvent, String) {
|
||||
let bytes = module.to_tbc();
|
||||
let loaded = CompiledModule::from_tbc(&bytes).unwrap();
|
||||
assert_eq!(bytes, loaded.to_tbc());
|
||||
let mut vm = Vm::new(loaded);
|
||||
let event = vm.run(&mut CaptureHost::default());
|
||||
(event, tb_runtime::snapshot::text(&vm.rt.screen))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v1_zweige_und_schleifen_behalten_eigene_quellorte() {
|
||||
let mut failures = vec![];
|
||||
for (name, code, line) in [
|
||||
(
|
||||
"ELSEIF",
|
||||
"IF 0 THEN\nPRINT 1\nELSEIF 1/0 THEN\nPRINT 2\nEND IF",
|
||||
3,
|
||||
),
|
||||
("CASE", "SELECT CASE 1\nCASE 1/0\nPRINT 2\nEND SELECT", 2),
|
||||
("NEXT", "FOR i%=32767 TO 32767\nPRINT 1\nNEXT", 3),
|
||||
("LOOP", "DO\nPRINT 1\nLOOP UNTIL 1/0", 3),
|
||||
] {
|
||||
let (event, _) = run(compile(&[("MAIN", code)]).unwrap());
|
||||
if !matches!(event, RunEvent::Error { line: found, .. } if found == line) {
|
||||
failures.push(format!("{name}: erwartet Zeile {line}, erhalten {event:?}"));
|
||||
}
|
||||
}
|
||||
let source = SourceUnit {
|
||||
name: "MAIN".into(),
|
||||
segments: vec![
|
||||
SourceSegment {
|
||||
file: "main.bas".into(),
|
||||
first_line: 1,
|
||||
text: "IF 0 THEN\nPRINT 1\n".into(),
|
||||
},
|
||||
SourceSegment {
|
||||
file: "cond.bi".into(),
|
||||
first_line: 1,
|
||||
text: "ELSEIF 1/0 THEN\nPRINT 2\n".into(),
|
||||
},
|
||||
SourceSegment {
|
||||
file: "main.bas".into(),
|
||||
first_line: 4,
|
||||
text: "END IF\n".into(),
|
||||
},
|
||||
],
|
||||
};
|
||||
let mut vm = Vm::new(compile_project("APP", &[source], &FormCatalog::default(), &[]).unwrap());
|
||||
let event = vm.run(&mut CaptureHost::default());
|
||||
if vm.current_file() != "cond.bi" {
|
||||
failures.push(format!(
|
||||
"Include: {event:?} aus {} statt cond.bi",
|
||||
vm.current_file()
|
||||
));
|
||||
}
|
||||
// Das gleiche Problem darf nicht nur durch Umbenennen der Fehlermeldung behoben werden.
|
||||
let mut vm = Vm::new(
|
||||
compile(&[("MAIN", "IF 0 THEN\nPRINT 1\nELSEIF 1 THEN\nPRINT 2\nEND IF")]).unwrap(),
|
||||
);
|
||||
vm.add_module_breakpoint(0, 3);
|
||||
let event = vm.run(&mut CaptureHost::default());
|
||||
if event != (RunEvent::Breakpoint { line: 3 }) {
|
||||
failures.push(format!("Breakpoint ELSEIF: {event:?}"));
|
||||
}
|
||||
assert!(failures.is_empty(), "{}", failures.join("\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_importierte_deklarationen_behalten_kontext_und_abhaengigkeiten() {
|
||||
let cases = [
|
||||
(
|
||||
"DEFINT",
|
||||
"PRINT Doppelt(3)\nEND",
|
||||
"DEFINT A-Z\nFUNCTION Doppelt(x)\nDoppelt=x*2\nEND FUNCTION",
|
||||
" 6 \n",
|
||||
),
|
||||
(
|
||||
"CONST",
|
||||
"CONST A=3\nPRINT B\nEND",
|
||||
"CONST A=3\nCONST B=A+1",
|
||||
" 4 \n",
|
||||
),
|
||||
(
|
||||
"TYPE",
|
||||
"TYPE Inner\nx AS INTEGER\nEND TYPE\nDIM a AS Outer\na.i.x=3\nPRINT a.i.x\nEND",
|
||||
"TYPE Inner\nx AS INTEGER\nEND TYPE\nTYPE Outer\ni AS Inner\nEND TYPE",
|
||||
" 3 \n",
|
||||
),
|
||||
];
|
||||
let mut failures = vec![];
|
||||
for (name, main, lib, output) in cases {
|
||||
match compile(&[("MAIN", main), ("LIB", lib)]) {
|
||||
Err(e) => failures.push(format!("{name}: {e:?}")),
|
||||
Ok(module) => {
|
||||
let actual = run(module);
|
||||
if actual != (RunEvent::Ended, output.into()) {
|
||||
failures.push(format!("{name}: {actual:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(failures.is_empty(), "{}", failures.join("\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v3_form_metabefehle_erzeugen_getrennte_formularobjekte() {
|
||||
let module = compile(&[
|
||||
(
|
||||
"A",
|
||||
"'$FORM\nCaption=\"a\"\nCALL SetupB\nPRINT Caption\nEND",
|
||||
),
|
||||
("B", "'$FORM\nSUB SetupB\nCaption=\"b\"\nEND SUB"),
|
||||
])
|
||||
.unwrap();
|
||||
let names: Vec<_> = module.objects.iter().map(|o| o.name.clone()).collect();
|
||||
let actual = run(module);
|
||||
assert_eq!(
|
||||
actual,
|
||||
(RunEvent::Ended, "a\n".into()),
|
||||
"Objekte: {names:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v4_common_behaelt_typidentitaet_und_initialisiert_arrays_einmal() {
|
||||
let mut failures = vec![];
|
||||
for (name, files, want) in [
|
||||
(
|
||||
"Suffixe",
|
||||
vec![(
|
||||
"MAIN",
|
||||
"COMMON SHARED c%, c$\nc%=7\nc$=\"ok\"\nPRINT c%;c$\nEND",
|
||||
)],
|
||||
" 7 ok\n",
|
||||
),
|
||||
(
|
||||
"Array",
|
||||
vec![
|
||||
("MAIN", "COMMON SHARED a%(2)\na%(1)=7\nCALL F\nEND"),
|
||||
("LIB", "COMMON SHARED a%(2)\nSUB F\nPRINT a%(1)\nEND SUB"),
|
||||
],
|
||||
" 7 \n",
|
||||
),
|
||||
] {
|
||||
match compile(&files) {
|
||||
Err(e) => failures.push(format!("{name}: {e:?}")),
|
||||
Ok(module) => {
|
||||
let actual = run(module);
|
||||
if actual != (RunEvent::Ended, want.into()) {
|
||||
failures.push(format!("{name}: {actual:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(failures.is_empty(), "{}", failures.join("\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v5_load_und_unload_loesen_den_expliziten_container_auf() {
|
||||
use tb_frontend::forms::ObjectClass;
|
||||
let mut catalog = FormCatalog::default();
|
||||
for name in ["Form1", "Form2"] {
|
||||
catalog.add(name, ObjectClass::Form, None, false);
|
||||
catalog.add("Text1", ObjectClass::TextBox, Some(name), true);
|
||||
}
|
||||
let source = units(&[("MAIN", "LOAD Form2!Text1(3)\nForm2!Text1(3).Text=\"b\"\nPRINT Form2!Text1(3).Text\nUNLOAD Form2!Text1(3)\nEND")]);
|
||||
let module = compile_project("APP", &source, &catalog, &[]).unwrap();
|
||||
assert_eq!(run(module), (RunEvent::Ended, "b\n".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v6_linkerdiagnose_nennt_den_urspruenglichen_dateiort() {
|
||||
let errors = compile(&[
|
||||
("MAIN", "DECLARE SUB F(x%)\nCALL F(1)\nEND"),
|
||||
("LIB", "SUB F(x$)\nEND SUB"),
|
||||
])
|
||||
.unwrap_err();
|
||||
assert!(
|
||||
errors
|
||||
.iter()
|
||||
.any(|d| d.message.contains("Parameter type mismatch")),
|
||||
"{errors:?}"
|
||||
);
|
||||
assert!(
|
||||
errors
|
||||
.iter()
|
||||
.all(|d| d.file.is_some() && d.pos.line > 0 && d.pos.column > 0),
|
||||
"{errors:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modulbreakpoint_rundlauf_inspektion_und_numerische_erl_bleiben_getrennt() {
|
||||
let main = format!(
|
||||
"DIM a%(2)\nTYPE T\nx AS INTEGER\nEND TYPE\nDIM r AS T\na%(1)=7\nr.x=8\n{}CALL F\nEND",
|
||||
"\n\nn%=1\n"
|
||||
);
|
||||
let lib = format!("SUB F\n{}200 ERROR 6\nEND SUB", "\n".repeat(8));
|
||||
let module = compile(&[("MAIN", &main), ("LIB", &lib)]).unwrap();
|
||||
let bytes = module.to_tbc();
|
||||
let loaded = CompiledModule::from_tbc(&bytes).unwrap();
|
||||
assert_eq!(bytes, loaded.to_tbc());
|
||||
let mut vm = Vm::new(loaded);
|
||||
vm.add_module_breakpoint(1, 10);
|
||||
let mut host = CaptureHost::default();
|
||||
assert_eq!(vm.run(&mut host), RunEvent::Breakpoint { line: 10 });
|
||||
assert_eq!(vm.current_module(), 1);
|
||||
assert_eq!(vm.current_file(), "LIB.bas");
|
||||
assert!(matches!(
|
||||
vm.inspect_element("MAIN!a%", &[1]),
|
||||
Some(Value::Int(7))
|
||||
));
|
||||
assert!(matches!(
|
||||
vm.inspect_field("MAIN!r", &[0]),
|
||||
Some(Value::Int(8))
|
||||
));
|
||||
vm.remove_module_breakpoint(1, 10);
|
||||
vm.set_step(true);
|
||||
assert_eq!(vm.run(&mut host), RunEvent::Stepped { line: 10 });
|
||||
assert_eq!(vm.current_source_pos().column, 5);
|
||||
vm.set_step(false);
|
||||
assert!(matches!(
|
||||
vm.run(&mut host),
|
||||
RunEvent::Error {
|
||||
code: 6,
|
||||
line: 10,
|
||||
..
|
||||
}
|
||||
));
|
||||
let source = format!("{}ERROR 6", "\n".repeat(41));
|
||||
assert!(matches!(
|
||||
run(compile(&[("MAIN", &source)]).unwrap()).0,
|
||||
RunEvent::Error {
|
||||
code: 6,
|
||||
line: 42,
|
||||
..
|
||||
}
|
||||
));
|
||||
let module = compile(&[(
|
||||
"MAIN",
|
||||
"ON ERROR RESUME NEXT\n200 ERROR 6\nPRINT ERR;ERL\nEND",
|
||||
)])
|
||||
.unwrap();
|
||||
assert_eq!(run(module), (RunEvent::Ended, " 6 200 \n".into()));
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
# Verifikation: projektmodule-und-kompilat
|
||||
|
||||
Stand: 05.09.2026, Arbeitsbaum auf Basis von `58b1f62`.
|
||||
**Keine offenen Befunde: 0 CRITICAL, 0 WARNING, 0 SUGGESTION.**
|
||||
|
||||
Die sechs Befunde des [ersten Reviews](review-initial.md) sind behoben.
|
||||
Weitere bei der Nachprüfung reproduzierte Abweichungen wurden ebenfalls
|
||||
korrigiert und mit Regressionen abgesichert. Der Change ist abnahmebereit.
|
||||
|
||||
| Dimension | Ergebnis |
|
||||
| --- | --- |
|
||||
| Vollständigkeit | 12/12 Tasks umgesetzt; alle 7 Requirements und 21 Delta-Szenarien abgeglichen. |
|
||||
| Korrektheit | 453 Workspace-Tests bestanden, 0 fehlgeschlagen, 1 vorhandener Golden-Generator ignoriert. Die 7 unveränderten ursprünglichen Review-Proben bestehen auch im unabhängigen temporären Treiber. |
|
||||
| Kohärenz | D1–D4 erfüllt: physische Quellorte, getrennte Scopes, selbstständiges TBC 4 und dokumentierte Inline-Instruktionen. |
|
||||
|
||||
## Geschlossene Befunde
|
||||
|
||||
| Befund | Korrektur und Nachweis |
|
||||
| --- | --- |
|
||||
| V1: Zweig-/Schleifenorte | Parser und HIR erhalten ELSEIF-, CASE-, NEXT-, LOOP- und WEND-Positionen. Codegen emittiert die tatsächlichen Anweisungsgrenzen. Fehler, Breakpoints, WHILE-Rücksprung, LOOP-RESUME, NEXT-RESUME NEXT und Include-Enden in Zeile 42/Spalte 3 sind geprüft. Numerische ERL-Labels bleiben getrennt. |
|
||||
| V2: Importkontext | Exportierte Signaturen erhalten die DEFtype-Typen ihres Ursprungs. Konstanten werden dort gefaltet, einschließlich transitiver Abhängigkeiten über drei Module. TYPE-Abhängigkeiten werden geordnet und bei abweichenden lokalen Layouts intern qualifiziert. Echte lokale Duplikate bleiben Fehler. |
|
||||
| V3: `$FORM`-Identitäten | FRM- und `$FORM`-Objekte stehen vor jeder Modulübersetzung in einem gemeinsamen Katalog. Getrennte Captions, gegenseitige Referenzen und unterschiedliche Form_Load-Bindungen sind auch für gemischte FRM/BAS-Projekte nach TBC-Rundlauf geprüft. |
|
||||
| V4: COMMON | HIR übergibt Block, vollständigen Variablenschlüssel, Elementtyp und Arraygrenzen an den Linker. Typen, Ränge und bekannte Grenzen werden geprüft. `CommonArr` initialisiert einmal und prüft spätere dynamische Grenzen ohne Zurücksetzen des Handles oder der Werte. Offene Arraydeklarationen und gerundete Grenzen bleiben unterstützt. |
|
||||
| V5: LOAD/UNLOAD | Beide Anweisungen verwenden dieselbe explizite Containerauflösung und Indexprüfung wie andere Objektzugriffe. `Form2!Text1(3)` wird geladen, beschrieben, gelesen und entladen, auch wenn Form1 ebenfalls Text1 besitzt. |
|
||||
| V6: Diagnosen | Der Linker gibt strukturierte Diagnosen an den ursprünglichen Deklarationen zurück; Source-ID, Datei, Zeile und Spalte bleiben erhalten. Signaturkonflikte, COMMON-Konflikte im Include sowie doppelte Module sind geprüft. |
|
||||
|
||||
Die erweiterten Proben fanden zusätzlich folgende inzwischen behobene
|
||||
Abweichungen: transitive Konstantenimports, fremde TYPE-Layouts bei lokal
|
||||
abweichenden Definitionen, prozedurübergreifendes Durchsickern von DEFtype,
|
||||
Verwechslung typisierter Debuggernamen, Verwechslung von Formnamen mit
|
||||
suffixdeklarierten Variablen und fehlende Literalpositionen in Diagnosen.
|
||||
Letzteres ist durch `CALL F("wrong")` in `args.bi:42:10` abgesichert.
|
||||
Auch Konflikte erst in der dritten COMMON-Deklaration werden erkannt.
|
||||
|
||||
Die [16 dauerhaften Regressionstests](../../../../crates/tb-vm/tests/project_regressions.rs)
|
||||
enthalten die sieben ursprünglichen Proben mit unveränderten Erwartungen
|
||||
sowie neun ergänzende Tests mit mehreren verwandten Fällen. Die ursprüngliche
|
||||
[Probe-Datei](review-probes.rs) wurde nicht geändert. Es wurden keine Goldens
|
||||
neu erzeugt und keine Fehlererwartungen abgeschwächt.
|
||||
|
||||
## Abgleich aller Requirements und Szenarien
|
||||
|
||||
| Requirement | Szenarien / Nachweise |
|
||||
| --- | --- |
|
||||
| Monomorpher Opcode-Satz | Gemischter Ausdruck und aufgelöste Namen: vorhandene HIR-/Codegentests; numerische Projektverknüpfung. Alle 153 Opcode-Kennungen, Operandenfolgen und Encodingbreiten gegen die Dokumentation geprüft. |
|
||||
| TBC-Container | Bytegleicher Roundtrip; klare Ablehnung alter/unbekannter Versionen; vollständige Formularwerte und Designarrays. CLI-Projekttests entfernen sämtliche BAS-/BI-/FRM-/MAK-Quellen und führen das TBC selbstständig aus. |
|
||||
| Quellorte | Fehler in physischer Zeile 42; Fehler in lib.bas:2; verschachtelte Includes; zusätzliche ausführbare Zweig-/Schleifengrenzen und Initialisierungen. |
|
||||
| Benannte Objekte | Eigenschaften lesen/schreiben; keine Standardeigenschaft; Check1.Value=3 erzeugt Fehler 5; voneinander unabhängige Werte gleichnamiger Controls. Zwei FRM- und gemischte FRM/`$FORM`-Projekte geprüft. |
|
||||
| Diagnostik | 1-basierte Datei-/Zeilen-/Spaltenangaben in Lexer, Parser, Semantik und Linker; Include-Fehler einschließlich Literalargumenten. |
|
||||
| Objektgrammatik/-semantik | Unbekanntes Objekt und unbekannte Eigenschaft benennen; Eigenschaftstyp prüfen; TYPEOF; expliziter Form1/Form2-Container bei gleichnamigen Controls. Qualifiziertes LOAD/UNLOAD nutzt dieselbe Auflösung. |
|
||||
| Unterbrechung/Inspektion | Modulbezogener Breakpoint; scalar-, array- und UDT-Inspektion; Fortsetzen und Einzelschritt. Gleiche physische Zeile in MAIN und LIB bleibt getrennt, explizite Typ-Suffixe unterscheiden Variablen. ERR/ERL bleiben 6/200. |
|
||||
|
||||
Die konkreten ursprünglichen Szenario-/Testnamen und weitere Containerproben
|
||||
stehen im [Implementierungsnachweis](verification.md), den
|
||||
[VM-Projekttests](../../../../crates/tb-vm/tests/project.rs) und den
|
||||
[CLI-Projekttests](../../../../crates/tb-cli/tests/project.rs).
|
||||
|
||||
## Abschließende Prüfläufe
|
||||
|
||||
- `cargo test --workspace`: **453 bestanden, 0 fehlgeschlagen, 1 ignoriert**.
|
||||
- Unabhängiger Treiber aus [review-initial.md](review-initial.md): **7 bestanden**.
|
||||
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`: bestanden.
|
||||
- `cargo fmt --all -- --check`: bestanden.
|
||||
- `cargo bench -p tb-vm --bench compile`: 508 Zeilen **0,56 ms** (Budget 50 ms);
|
||||
49.760 Zeilen in 20 verbundenen Modulen **77 ms** (Budget 1000 ms).
|
||||
- Formatabgleich: **153/153 Opcodes**, Operandentypen und Gesamtbreiten;
|
||||
**9/9 Abschnittskennungen** stimmen zwischen Writer, Reader und Dokumentation überein.
|
||||
- `openspec validate projektmodule-und-kompilat --strict`: bestanden.
|
||||
- `git diff --check`: bestanden.
|
||||
|
||||
Die Verifikation prüft den aktuellen Code und die gesamten Change-Artefakte
|
||||
lokal und headless auf macOS. Ein neuer interaktiver Originalsystemvergleich
|
||||
oder eine Windows-/Linux-Testmatrix war nicht Teil dieses Prüflaufs.
|
||||
Die vier betroffenen Hauptspecs wurden am 05.09.2026 synchronisiert und
|
||||
mit `openspec validate --specs --strict` validiert (15/15 bestanden).
|
||||
Alle sieben Delta-Requirements stimmen vollständig mit den Hauptspecs
|
||||
überein; alle zuvor vorhandenen Szenarien und unberührten Requirements
|
||||
bleiben erhalten. Der Change ist unter
|
||||
`openspec/changes/archive/2026-09-05-projektmodule-und-kompilat` archiviert.
|
||||
@@ -0,0 +1,23 @@
|
||||
## 1. Quellen und Scopes
|
||||
|
||||
- [x] 1.1 Quell-/Modulidentitäten durch Include-Expansion und Frontend erhalten; verifizieren mit Compile- und Runtimefehlern aus lib.bas:2 und verschachtelten Includes.
|
||||
- [x] 1.2 Form-/Prozedurscopes korrekt auflösen; verifizieren mit zwei Form_Load-Prozeduren, zwei Text1-Controls und unterschiedlichen Form1!Text1/Form2!Text1-Werten sowie echten Duplikaten im selben Scope.
|
||||
|
||||
## 2. Kompilat und Debugger
|
||||
|
||||
- [x] 2.1 Vollständige Forms-Anfangsdaten, Quelltabelle und Prozedursignaturen serialisieren; verifizieren durch bytegleichen Kompilat-Rundlauf und gleiche Ausführung inklusive Designzeit-Control-Arrays.
|
||||
- [x] 2.2 Modulbezogene Breakpoints/Quellortmeldungen ergänzen; verifizieren mit identischen physischen Zeilennummern in zwei Modulen, Include-Fehlern, Einzelschritt und unverändertem ERR/ERL.
|
||||
- [x] 2.3 CLI-run für TBC anschließen und Versionsgrenze anheben; verifizieren mit build, Entfernen aller Quellen, run des Kompilats und klarer Ablehnung inkompatibler Versionen.
|
||||
|
||||
## 3. Abnahme
|
||||
|
||||
- [x] 3.1 Container und vollständige Opcode-/Operandentabelle dokumentieren; verifizieren mit Format-/Opcode-Abgleich, cargo test --workspace und dem Compile-Budget.
|
||||
- [x] 3.2 Delta-Specs vollständig gegen die erhaltenen Szenarien prüfen; verifizieren mit openspec validate projektmodule-und-kompilat --strict und git diff --check.
|
||||
|
||||
## 4. Reviewbefunde vollständig beheben
|
||||
|
||||
- [x] 4.1 V1: Physische Quellpositionen aller Zweige und Schleifenenden erhalten; Fehler, Breakpoints und RESUME prüfen.
|
||||
- [x] 4.2 V2/V6: Importierte Deklarationen im Ursprungskontext auflösen und Linkdiagnosen an Originalstellen melden.
|
||||
- [x] 4.3 V3/V5: Gemeinsame Formidentitäten und qualifiziertes LOAD/UNLOAD korrigieren.
|
||||
- [x] 4.4 V4: Vollständige COMMON-Identitäten und kompatible einmalige Arrayinitialisierung sicherstellen.
|
||||
- [x] 4.5 Unveränderte Reviewproben, ergänzende Nachbarfälle und sämtliche Change-Szenarien erneut prüfen; alle weiteren Befunde beheben.
|
||||
@@ -0,0 +1,106 @@
|
||||
# Implementierungsnachweis — 05.09.2026
|
||||
|
||||
Change: `projektmodule-und-kompilat`, Ausgangscommit `58b1f62`.
|
||||
|
||||
**Abschließende Verifikation:** [review.md](review.md) bestätigt die Behebung
|
||||
aller sechs ursprünglichen und aller zusätzlich reproduzierten Befunde.
|
||||
Der [erste Review](review-initial.md) bleibt als historischer Nachweis erhalten.
|
||||
|
||||
Alle zwölf Tasks (sieben Implementierungs- und fünf Review-Aufgaben) sind
|
||||
umgesetzt. F09, F10, F11 und F24 sind im Arbeitsbaum bearbeitet; die
|
||||
Hauptspec-Synchronisierung und Archivierung sind am 05.09.2026 abgeschlossen. Die Abnahme
|
||||
umfasst alle sieben Delta-Requirements mit ihren 21 Szenarien.
|
||||
|
||||
## Umsetzung
|
||||
|
||||
| Task / Befund | Umsetzung und Nachweis |
|
||||
| --- | --- |
|
||||
| 1.1 / F10 | `SourceUnit`/`SourceSegment` erhalten Modul, Datei und physische Zeile vor dem Parsen. Lexer- und Parserpositionen werden vor der Semantik den Originalquellen zugeordnet. CLI-Tests prüfen Compile-/Runtimefehler aus `lib.bas:2`, verschachtelten Includes und dem Codeabschnitt eines entfernten FRM. Auch leere Quellen funktionieren. |
|
||||
| 1.2 / F09 | Module werden getrennt aufgelöst und danach numerisch verbunden. Lokale Prozeduren und Controls haben Vorrang, `Form!Control` sucht direkt im angegebenen Formular. Eltern-IDs ersetzen Namensvergleiche auch bei Frames, Menüs, Optionsgruppen und Geometrie. Zwei Form_Load-Prozeduren initialisieren ihre jeweiligen Text1-Controls unabhängig; echte SUB-/CONST-/TYPE-Duplikate im selben Modul bleiben Fehler. |
|
||||
| 2.1 / F11 | TBC 4 enthält Module/Quellen, vollständige Parameter- und Rückgabetypen, Locals, Forms-Instanzen mit Eigenschaften, Designindizes und Eltern-IDs sowie das Startformular. `Vm::new` stellt diesen Anfangszustand her. Bytegleicher Rundlauf und Ausführung mit zwei Formularen und Designarrays 0/2 sind geprüft. |
|
||||
| 2.2 / F10 | `Source` plus `Stmt` liefern Datei/Spalte/physische Zeile. `InitStmt` erhält dieselben Informationen für globale Initialisierungen, ohne vorzeitig Ereignisse zuzustellen. Breakpoints verwenden Modul-ID und Zeile. Einzelschritt, Variableninspektion und Fortsetzen bleiben möglich. Numerische Labels führen separat `SetErl`; DEF FN erhält den tatsächlichen Quellort. |
|
||||
| 2.3 / F11 | `tbc run` lädt TBC direkt. Der CLI-Test baut ein Projekt, entfernt alle BAS-/BI-/FRM-/MAK-Dateien und vergleicht die Ausgabe des Kompilats mit der Quellausführung (`hello`, `world`, `7`). Ein zweiter Fall erhält nach Entfernen des FRM den Fehlerort `error.frm:6:1`. Versionen 1, 2, 3, 5 und 32767 werden ausdrücklich benannt und abgewiesen. |
|
||||
| 3.1 / F24 | [TBVM-Format](../../../../docs/tbvm-design.md) dokumentiert alle neun Abschnitte und alle 153 Opcodes einzeln mit Operanden, Encodingbreiten und Kennungen. Der Compile-Benchmark übersetzt und verbindet nun tatsächlich ein Projekt mit 20 Modulen. |
|
||||
| 3.2 | Alle Delta-Requirement-Blöcke behalten ihre bisherigen Szenarien. Neue Szenarien und die Implementierungsentscheidungen D1–D4 wurden gegen die unten genannten Tests und Codepfade abgeglichen. OpenSpec- und Diff-Prüfung bestanden. |
|
||||
|
||||
## Projektgrenzen und ergänzende Regressionen
|
||||
|
||||
Der Projektlink versetzt Prozedur-, Slot-, TYPE-, String-, DATA- und
|
||||
Sprungtabellenreferenzen. Hauptprogramminitialisierungen aller Mitglieder
|
||||
laufen vor der ersten Ereigniszustellung; die übrigen Modulrümpfe folgen der
|
||||
Projektreihenfolge. Eindeutige externe Prozeduren werden als Deklarationen
|
||||
importiert, lokale Namen bleiben erhalten. Eindeutige fremde Konstanten und
|
||||
TYPEs bleiben als Kompatibilitätsregel sichtbar. Es wird kein Quelltext zur
|
||||
Unterdrückung von Duplikaten gelöscht.
|
||||
|
||||
Geprüft sind wiederholt eingebundene Konstanten, gleichnamige lokale SUBs,
|
||||
modullokales SHARED, gemeinsame COMMON-Skalare und unterschiedliches OPTION
|
||||
BASE. Modulhandler werden getrennt gespeichert: ON ERROR GOTO 0 in der
|
||||
Bibliothek deaktiviert den Handler des Aufrufers nicht. Bestehende ERR-/ERL-
|
||||
und RESUME-Korpustests bestehen unverändert.
|
||||
|
||||
Der Signaturtest übergibt ein INTEGER-Array, einen UDT und einen Skalar an
|
||||
eine Funktion in einem anderen Modul. Er prüft Rückgabetyp, Array-/BYREF-
|
||||
Merkmale, Ausgabe und Rückwirkung einer UDT-Feldänderung auf den Aufrufer.
|
||||
Die dabei gefundene Inkonsistenz zwischen UDT-Argument und Parameter wurde
|
||||
im gemeinsamen Semantikpfad behoben. Bekannte externe Dialogdeklarationen
|
||||
funktionieren auch mit qualifizierten Prozedurnamen. ISAM-OPEN verwendet mit
|
||||
`PushUdtId` eine explizit versetzbare TYPE-Referenz; der Test vergleicht sie
|
||||
nach dem Rundlauf mit dem tatsächlichen UDT-Index.
|
||||
|
||||
Der Loader weist abgeschnittene Dateien an jedem Byteoffset, ungültige
|
||||
Flags/Abschnittsgrößen, doppelte Abschnitte sowie ungültige Quell-, Modul-,
|
||||
Prozedur- und Elternreferenzen ab. Inkonsistente Signaturen, doppelte
|
||||
Anfangseigenschaften, falsche Property-Typen und abweichende Designindizes
|
||||
werden vor dem VM-Start geprüft. Das ersetzt keinen vollständigen
|
||||
Stackverifizierer für beliebigen fremden Bytecode.
|
||||
|
||||
## Requirement- und Szenarioabgleich
|
||||
|
||||
Die neuen ausführbaren Nachweise liegen in
|
||||
[VM-Projekttests](../../../../crates/tb-vm/tests/project.rs) und
|
||||
[CLI-Projekttests](../../../../crates/tb-cli/tests/project.rs).
|
||||
Die folgende Tabelle führt auch die erhaltenen Szenarien auf; bestehende
|
||||
Tests werden durch neue Mehrmodul- und Include-Proben ergänzt.
|
||||
|
||||
| Requirement | Szenarien und Belege |
|
||||
| --- | --- |
|
||||
| Monomorpher Opcode-Satz | Gemischter Ausdruck: `codegen::tests::ausdruck_monomorph_mit_conv`; aufgelöste Namen: `sema::tests::hir_slots_aufgeloest` und die numerisch verbundenen Projektaufrufe. Vollständigkeit der Dokumentation zusätzlich gegen das `instrs!`-Makro geprüft. |
|
||||
| .tbc-Containerformat | Roundtrip: mehrere VM-Projekttests vergleichen die gesamten Bytes; unbekannte Version: CLI-Versionstests; Formularwerte: CLI-Ausgabe `hello` und `world` nach Entfernen sämtlicher Quellen. |
|
||||
| Zeilentabelle für Fehlerortung | Physische Fehlerzeile: Stmt-/Source-Zuordnung und CLI-Fehlerproben; Projektbibliothek: `lib.bas:2:5`, Include: `inner.bi:2:5`; zusätzlich InitStmt-, DEF-FN- und FRM-Codepositionen. |
|
||||
| Formulare und Steuerelemente als benannte Objekte | Lesen/Schreiben: bestehender VM-Test `objektzugriff_laeuft_ueber_objekt_und_eigenschaftsindex`; keine Standardeigenschaft: `sema::tests::eigenschaftstyp_schreibbarkeit_bang_und_hir_index`; Wertebereich: `forms::tests::defaults_bereich_und_implizites_laden` prüft Check1.Value = 3 → Fehler 5; unabhängige Werte: zwei Formulare mit Text1 und eigenem Form_Load im neuen Projekttest. |
|
||||
| Diagnostik mit Vorbild-Meldungen | Exakte Position: SourcePos bleibt 1-basiert; neue Tests prüfen Datei, Zeile und Spalte. Include-Diagnose: sowohl direktes SourceSegment als auch verschachtelte CLI-Expansion liefern die ursprüngliche Position des Typfehlers. |
|
||||
| Objektzugriffe in Grammatik und Semantik | Unbekanntes Objekt/Eigenschaft und Eigenschaftstyp: bestehende Semantiktests für Text9.Text, Text1.Farbe und Text1.Text = 5; TYPEOF: `typeof_form_control_und_form_metabefehl`; gleichnamige Controls: Form1!Text1/Form2!Text1 sowie lokale Text1-Zugriffe beider Form_Load-Rümpfe. |
|
||||
| Unterbrechbare step()-Ausführung | Breakpoint und Inspektion: vorhandene VM-Tests plus neuer Modulbreakpoint; gleiche Zeile in zwei Modulen: Modul A passiert Zeile 2, Modul B hält dort. Fortsetzen im Einzelschritt erhält `nested.bi:2`, physische Spalte 5 und getrenntes ERL = 200. |
|
||||
|
||||
## Ausgeführte Abnahme
|
||||
|
||||
- `cargo test --workspace`: **453 bestanden, 0 fehlgeschlagen, 1 ignoriert**.
|
||||
Der ignorierte Golden-Generator wurde nicht ausgeführt; Sollausgaben blieben unverändert.
|
||||
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`: bestanden.
|
||||
- `cargo fmt --all -- --check`: bestanden.
|
||||
- `cargo bench -p tb-vm --bench compile`: 508 Zeilen **0,56 ms** (Budget 50 ms);
|
||||
49.760 Zeilen in 20 verbundenen Modulen **77 ms** (Budget 1000 ms),
|
||||
335.421 Instruktionen. Release-Messung auf diesem Rechner.
|
||||
- Formatabgleich: **153/153 Opcodezeilen** einschließlich Operandentypen und
|
||||
Bytebreiten sowie **9/9 Abschnittskennungen** gegen Writer/Reader abgeglichen.
|
||||
- `openspec validate projektmodule-und-kompilat --strict`: bestanden.
|
||||
- `git diff --check`: bestanden.
|
||||
|
||||
Die Abnahme ist eine lokale Code-/Testprüfung auf macOS; sie ist kein neuer
|
||||
interaktiver Originalsystemvergleich und keine Windows-/Linux-Testmatrix.
|
||||
|
||||
## Reviewkorrekturen
|
||||
|
||||
Die ursprünglichen sieben Reviewproben bestehen unverändert, sowohl im
|
||||
separaten Treiber als auch in der Workspace-Suite. Die dauerhafte Datei
|
||||
`crates/tb-vm/tests/project_regressions.rs` ergänzt sie um neun Tests mit
|
||||
verwandten Fällen. [review.md](review.md) ordnet die Korrekturen V1–V6 und
|
||||
alle zusätzlich reproduzierten Abweichungen den Nachweisen zu.
|
||||
|
||||
`CommonArr` (`0x3B`) initialisiert gemeinsame Arrays einmal und prüft spätere
|
||||
Laufzeitgrenzen auf Kompatibilität; vorab bekannte Konflikte meldet der
|
||||
Linker an der ursprünglichen COMMON-Deklaration. Die neue Instruktion ist
|
||||
in TBC 4 serialisiert, validiert und vollständig dokumentiert. Typ-Suffixe
|
||||
bleiben in Debugger-Slotnamen erhalten. AST-Literale und sämtliche ausführbaren
|
||||
Zweig-/Schleifenteile tragen ihre tatsächlichen Quellpositionen.
|
||||
@@ -1,15 +0,0 @@
|
||||
## 1. Quellen und Scopes
|
||||
|
||||
- [ ] 1.1 Quell-/Modulidentitäten durch Include-Expansion und Frontend erhalten; verifizieren mit Compile- und Runtimefehlern aus lib.bas:2 und verschachtelten Includes.
|
||||
- [ ] 1.2 Form-/Prozedurscopes korrekt auflösen; verifizieren mit zwei Form_Load-Prozeduren, zwei Text1-Controls und unterschiedlichen Form1!Text1/Form2!Text1-Werten sowie echten Duplikaten im selben Scope.
|
||||
|
||||
## 2. Kompilat und Debugger
|
||||
|
||||
- [ ] 2.1 Vollständige Forms-Anfangsdaten, Quelltabelle und Prozedursignaturen serialisieren; verifizieren durch bytegleichen Kompilat-Rundlauf und gleiche Ausführung inklusive Designzeit-Control-Arrays.
|
||||
- [ ] 2.2 Modulbezogene Breakpoints/Quellortmeldungen ergänzen; verifizieren mit identischen physischen Zeilennummern in zwei Modulen, Include-Fehlern, Einzelschritt und unverändertem ERR/ERL.
|
||||
- [ ] 2.3 CLI-run für TBC anschließen und Versionsgrenze anheben; verifizieren mit build, Entfernen aller Quellen, run des Kompilats und klarer Ablehnung inkompatibler Versionen.
|
||||
|
||||
## 3. Abnahme
|
||||
|
||||
- [ ] 3.1 Container und vollständige Opcode-/Operandentabelle dokumentieren; verifizieren mit Format-/Opcode-Abgleich, cargo test --workspace und dem Compile-Budget.
|
||||
- [ ] 3.2 Delta-Specs vollständig gegen die erhaltenen Szenarien prüfen; verifizieren mit openspec validate projektmodule-und-kompilat --strict und git diff --check.
|
||||
Reference in New Issue
Block a user