Phase 4: Formularmodell und Objektsprache

This commit is contained in:
2026-09-04 17:30:32 +02:00
parent 5cf5a6582c
commit 54488b5b67
35 changed files with 7195 additions and 627 deletions

View File

@@ -0,0 +1,138 @@
# forms-objektmodell Specification
## Purpose
Das Forms-Objektmodell macht Formulare und Steuerelemente zu benannten
Objekten des laufenden Programms: Eigenschaften lesen und schreiben,
Formulare laden, zeigen, verbergen und entladen — modal wie nicht-modal —,
Steuerelement-Arrays führen und Ereignisse an die Prozeduren
`Name_Ereignis` zustellen. Es ist die Grundlage der Steuerelemente und der
vordefinierten Dialoge.
## Requirements
### Requirement: Formulare und Steuerelemente als benannte Objekte
Ein Formular SHALL unter seinem Namen ansprechbar sein, ein
Steuerelement unter seinem Namen innerhalb seines Formulars. Eigenschaften
SHALL über `objekt.eigenschaft` gelesen und geschrieben werden, mit dem
in der Forms-Referenz festgelegten Typ und Wertebereich. Es SHALL keine
Standardeigenschaft geben: `Text1 = "x"` MUST abgewiesen werden. Das
Schreiben eines Wertes außerhalb des Wertebereichs MUST Laufzeitfehler 5
auslösen; eine zur Laufzeit schreibgeschützte Eigenschaft MUST bei
Zuweisung einen Fehler auslösen.
#### Scenario: Eigenschaft lesen und schreiben
- **WHEN** `Text1.Text = "hallo"` ausgeführt und danach `Text1.Text` gelesen wird
- **THEN** liefert der Zugriff `hallo`
#### Scenario: Keine Standardeigenschaft
- **WHEN** ein Programm `Text1 = "x"` enthält
- **THEN** wird es abgewiesen und die Meldung nennt `Text1`
#### Scenario: Wert außerhalb des Bereichs
- **WHEN** `Check1.Value = 3` ausgeführt wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: Container-Zugriff über den Bang-Operator
`form!steuerelement.eigenschaft` SHALL ein Steuerelement eines benannten
Formulars ansprechen. Die Schreibweise MUST NOT mit dem Typsuffix `!`
für SINGLE verwechselt werden; eine Variable `Form1!` und ein Zugriff
`Form1!Text1` MUST unterscheidbar bleiben.
#### Scenario: Zugriff über den Container
- **WHEN** `Form1!Text1.Text = "a"` ausgeführt wird
- **THEN** trägt die Eigenschaft `Text` des Steuerelements `Text1` in `Form1` den Wert `a`
#### Scenario: Typsuffix bleibt Typsuffix
- **WHEN** ein Programm die Variable `Wert!` verwendet
- **THEN** bleibt sie eine SINGLE-Variable und wird nicht als Containerzugriff gelesen
### Requirement: Lade- und Entladezyklus
`LOAD form` SHALL das Formular anlegen und `Form_Load` ausführen, bevor
es sichtbar wird. `UNLOAD form` SHALL `Form_Unload (Cancel)` ausführen;
ein von der Prozedur gesetzter Wert `Cancel <> 0` MUST das Entladen
verhindern. `HIDE` SHALL nur die Sichtbarkeit zurücknehmen und das
Formular geladen lassen. Der Zugriff auf ein nicht geladenes Formular
SHALL es implizit laden.
#### Scenario: Load läuft vor der Anzeige
- **WHEN** ein Formular gezeigt wird, dessen `Form_Load` eine Eigenschaft setzt
- **THEN** ist der gesetzte Wert bereits in der ersten Anzeige sichtbar
#### Scenario: Entladen abbrechen
- **WHEN** `Form_Unload` den Parameter `Cancel` auf 1 setzt und `UNLOAD Form1` ausgeführt wird
- **THEN** bleibt das Formular geladen und sichtbar
#### Scenario: HIDE entlädt nicht
- **WHEN** `Form1.HIDE` ausgeführt und danach eine Eigenschaft von `Form1` gelesen wird
- **THEN** ist der zuvor gesetzte Wert erhalten und `Form_Load` läuft nicht erneut
### Requirement: Modales und nicht-modales Anzeigen
`form.SHOW [style%]` SHALL das Formular anzeigen; `style%` 0 (Vorgabe)
zeigt es nicht-modal, 1 modal. Bei modaler Anzeige MUST die Anweisung
nach `SHOW` erst ausgeführt werden, wenn das Formular entladen oder
verborgen wurde; die Ereignisschleife MUST währenddessen weiterlaufen.
Verstöße gegen die Stapelregeln des Vorbilds MUST die Fehler 400403
auslösen.
#### Scenario: Modal hält den Ablauf an
- **WHEN** ein Programm `Form1.SHOW 1 : PRINT "danach"` ausführt und ein Ereignis `Form1` entlädt
- **THEN** erscheint `danach` erst nach dem Entladen
#### Scenario: Ereignisse laufen während der Modalität
- **WHEN** ein modales Formular angezeigt wird und ein Ereignis eintrifft
- **THEN** läuft die zugehörige Ereignisprozedur
### Requirement: Steuerelement-Arrays
Steuerelemente mit gleichem Namen und `Index` SHALL als Array
ansprechbar sein. `LOAD ctl(index%)` SHALL ein weiteres Element zur
Laufzeit anlegen, `UNLOAD ctl(index%)` es entfernen. Der Versuch, ein zur
Entwurfszeit angelegtes Element zu entladen, MUST Fehler 362 auslösen.
Bei einem Array MUST `Index AS INTEGER` als erster Parameter der
Ereignisprozedur übergeben werden.
#### Scenario: Element zur Laufzeit anlegen
- **WHEN** `LOAD Command1(3)` ausgeführt wird
- **THEN** existiert `Command1(3)` mit den Eigenschaften des Elements 0 als Vorlage
#### Scenario: Entwurfszeit-Element ist nicht entladbar
- **WHEN** `UNLOAD Command1(0)` für ein zur Entwurfszeit angelegtes Element ausgeführt wird
- **THEN** tritt Fehler 362 auf
#### Scenario: Index als erster Parameter
- **WHEN** ein Klick auf `Command1(3)` zugestellt wird
- **THEN** wird `Command1_Click` mit `Index = 3` aufgerufen
### Requirement: Ereignisdispatch an Name_Ereignis
Ein Ereignis SHALL die Prozedur `Name_Ereignis` des betroffenen Objekts
aufrufen und ihr die Argumente der in der Forms-Referenz festgelegten
Signatur übergeben. Fehlt die Prozedur, MUST das Ereignis wirkungslos
verfallen, ohne Fehler. Die Zustellung SHALL an den Zustellpunkten der
Ereignissteuerung erfolgen; es MUST NOT neue Zustellpunkte geben.
#### Scenario: Ereignisprozedur wird gerufen
- **WHEN** ein Klick auf `Command1` zugestellt wird und `SUB Command1_Click` existiert
- **THEN** läuft die Prozedur genau einmal
#### Scenario: Fehlende Ereignisprozedur
- **WHEN** ein Klick auf ein Steuerelement ohne passende Prozedur zugestellt wird
- **THEN** läuft das Programm unverändert weiter und es entsteht kein Fehler
#### Scenario: Signatur mit Mausargumenten
- **WHEN** `Form_MouseDown` definiert ist und ein Mausereignis in Zeile 5, Spalte 7 zugestellt wird
- **THEN** erhält die Prozedur Taste, Umschaltzustand und die Position in Zellen
### Requirement: SCREEN-Objekt
`SCREEN` SHALL als Objekt ansprechbar sein mit `ActiveControl`,
`ActiveForm`, `Height`, `Width`, `MousePointer` und `ControlPanel` sowie
den Methoden `SHOW` und `HIDE`. `Height` und `Width` SHALL die
**aktuelle** Terminalgröße in Zeichen liefern und schreibgeschützt sein;
die feste Größe des Vorbilds MUST als Abweichung dokumentiert sein.
#### Scenario: Größe folgt dem Terminal
- **WHEN** die Darstellungsfläche 120×40 misst und `SCREEN.Width` gelesen wird
- **THEN** liefert es 120
#### Scenario: Aktives Formular
- **WHEN** zwei Formulare geladen sind und eines den Fokus hat
- **THEN** liefert `SCREEN.ActiveForm` dieses Formular

View File

@@ -247,3 +247,55 @@ und nennt dabei das Label.
#### Scenario: Unbekanntes Trap-Ziel
- **WHEN** ein Modul `ON TIMER(1) GOSUB Fehlt` ohne Label `Fehlt` enthält
- **THEN** meldet die Übersetzung ein undefiniertes Sprungziel und nennt `Fehlt`
### Requirement: Objektzugriffe in Grammatik und Semantik
Der Parser SHALL Punktpfade auf Formulare und Steuerelemente
(`objekt.eigenschaft`), den Container-Operator
`form!steuerelement[.eigenschaft]`, `IF TYPEOF ausdruck IS klasse`, den
Metabefehl `$FORM` und die Datentypen `FORM` und `CONTROL` als
Parametertypen erkennen. Die Semantik SHALL Eigenschaften gegen die
Klasse des Objekts prüfen und ihren Typ bestimmen. Ein Punktpfad, dessen
Basis weder ein benutzerdefinierter Typ noch ein bekanntes Objekt ist,
MUST eine Diagnose erzeugen, die Basis und Eigenschaft namentlich nennt;
er MUST NOT zu einer impliziten Variablen mit Punkt im Namen werden.
#### Scenario: Unbekanntes Objekt wird benannt
- **WHEN** ein Modul `Text9.Text = "a"` ohne Steuerelement `Text9` enthält
- **THEN** nennt die Diagnose `Text9` als unbekanntes Objekt statt „Type mismatch" zu melden
#### Scenario: Unbekannte Eigenschaft wird benannt
- **WHEN** ein Modul `Text1.Farbe = 3` enthält
- **THEN** nennt die Diagnose `Farbe` als unbekannte Eigenschaft von `TextBox`
#### Scenario: Eigenschaftstyp wird geprüft
- **WHEN** ein Modul `Text1.Text = 5` enthält
- **THEN** meldet die Semantik einen Typkonflikt mit Nennung der Eigenschaft
#### Scenario: TYPEOF
- **WHEN** ein Modul `IF TYPEOF Ziel IS CommandButton THEN` enthält
- **THEN** wird es übersetzt und die Klasse gegen die bekannten Steuerelementklassen geprüft
### Requirement: Bang-Operator neben dem SINGLE-Suffix
Der Lexer SHALL `!` als Container-Operator erkennen, wenn ihm ein
Bezeichner folgt, und andernfalls als Typsuffix für SINGLE. Beide Formen
MUST im selben Modul nebeneinander verwendbar sein.
#### Scenario: Beide Bedeutungen im selben Modul
- **WHEN** ein Modul `Wert! = 1.5` und `Form1!Text1.Text = "a"` enthält
- **THEN** wird die erste Zeile als SINGLE-Variable und die zweite als Containerzugriff übersetzt
### Requirement: Ereignisprozeduren mit festen Signaturen
Die Semantik SHALL eine `SUB`, deren Name der Form `Objekt_Ereignis`
entspricht und deren Objekt bekannt ist, als Ereignisprozedur erkennen
und ihre Parameterliste gegen die Signatur der Forms-Referenz prüfen.
Eine abweichende Parameterliste MUST namentlich gemeldet werden. Eine
`SUB` mit Unterstrich im Namen ohne bekanntes Objekt MUST weiterhin eine
gewöhnliche Prozedur sein.
#### Scenario: Falsche Signatur
- **WHEN** ein Modul `SUB Form_MouseDown (X AS SINGLE)` enthält
- **THEN** nennt die Diagnose die erwartete Parameterliste der Ereignisprozedur
#### Scenario: Gewöhnliche SUB mit Unterstrich
- **WHEN** ein Modul `SUB Zins_Berechnen (n AS INTEGER)` ohne Objekt `Zins` enthält
- **THEN** wird sie als gewöhnliche Prozedur übersetzt

View File

@@ -12,10 +12,14 @@ jederzeit prüfen lässt.
### Requirement: Vollständiges Inventar der Original-Hilfe
`docs/inventar.md` SHALL jede in der Original-Hilfe des Vorbilds
dokumentierte Anweisung, Funktion, Metabefehl, Operator-Schlüsselwort und
Klausel als eigenen Eintrag führen. Ein dokumentiertes Element MUST NOT
Klausel als eigenen Eintrag führen. Darüber hinaus SHALL es das
**Forms-Objektmodell** führen: je Klasse ihre Eigenschaften, Methoden und
Ereignisse als eigene Einträge. Ein dokumentiertes Element MUST NOT
fehlen; Vollständigkeit gegenüber der Quelle geht der Kürze vor. Jeder
Eintrag SHALL Name, Art (Anweisung/Funktion/Metabefehl), Themengruppe,
Status und Fundstelle tragen.
Eintrag SHALL Name, Art (Anweisung/Funktion/Metabefehl/Eigenschaft/
Methode/Ereignis), Themengruppe, Status, Fundstelle und Quelle tragen.
Für Einträge des Objektmodells SHALL die Quelle die Forms-Referenz sein,
weil die Themenliste der Original-Hilfe sie nicht führt.
#### Scenario: Dokumentiertes Element ist erfasst
- **WHEN** die Original-Hilfe die Anweisung `VIEW PRINT` dokumentiert
@@ -25,6 +29,14 @@ Status und Fundstelle tragen.
- **WHEN** `PEEK` als Non-Feature deklariert ist
- **THEN** steht `PEEK` mit Status `Non-Feature` im Inventar und die Fundstelle verweist auf den Abschnitt „Abweichungen" der Sprachreferenz
#### Scenario: Eigenschaft einer Steuerelementklasse ist erfasst
- **WHEN** die Forms-Referenz für `TextBox` die Eigenschaft `SelStart` führt
- **THEN** enthält das Inventar einen Eintrag für `TextBox.SelStart` mit Art `Eigenschaft`, Status und Quelle Forms-Referenz
#### Scenario: Ereignis einer Klasse ist erfasst
- **WHEN** die Forms-Referenz für `Form` das Ereignis `Resize` führt
- **THEN** enthält das Inventar einen Eintrag für `Form_Resize` mit Art `Ereignis`
### Requirement: Festes Statusvokabular
Der Status eines Eintrags SHALL genau einen von drei Werten tragen:
`implementiert` (Frontend senkt ab und die Laufzeit führt aus),