# Design — Formularmodell und Objektsprache ## Context Siehe proposal.md — Why. Drei Bestandsbefunde schneiden den Entwurf zu: 1. **Der Punkt gehört heute zum Bezeichner.** Der Lexer nimmt `.` in den Namen auf (`a.b` ist ein Token), die Semantik zerlegt ihn nur, wenn die Basis ein UDT ist. Ein Objektzugriff fällt deshalb durch bis zur impliziten Variablen. 2. **`!` ist heute immer Typsuffix.** `Form1!Text1` liest sich als `Form1` (SINGLE) gefolgt von `Text1`. 3. **Der Rückrufweg existiert bereits** aus `phase-4-ereignisschleife`: die VM kann ein Ziel anspringen und zurückkehren. Ereignisprozeduren brauchen davon die Variante „Prozedur mit Argumenten" statt „`GOSUB`-Ziel". ## Goals / Non-Goals **Goals:** - Objektzugriffe, die zur Übersetzungszeit gegen die Klasse geprüft werden — kein Nachschlagen von Eigenschaftsnamen zur Laufzeit im Normalfall. - Ein Formularmodell, das die Steuerelemente des Folge-Changes nur noch füllen, nicht umbauen müssen. - Modales `SHOW` ohne zweiten Ausführungsstrang. **Non-Goals:** - Darstellung und Eingabebehandlung der Steuerelemente. - Ein offenes Objektsystem für Anwenderklassen (Stufe 2). ## Decisions ### D1 — Objektnamen werden zur Übersetzungszeit aufgelöst Formulare und Steuerelemente sind zur Übersetzungszeit bekannt: sie stammen aus der `.FRM`-Beschreibung bzw. dem Formular-Designer. Der Compiler löst `Text1.Text` deshalb in „Objekt 7, Eigenschaft 12" auf und prüft Typ und Schreibbarkeit sofort. | Alternative | Warum nicht | |---|---| | Eigenschaftsnamen zur Laufzeit nachschlagen | Verlagert jeden Tippfehler in eine Laufzeitmeldung — genau die stille Lücke, die der Guiding Principle verbietet; zudem eine Hashsuche pro Zugriff | Der Zugriff über `CONTROL`-Parameter (`SUB Setze (c AS CONTROL)`) bleibt dynamisch; dort prüft die Laufzeit und `TYPEOF` fragt die Klasse ab. ### D2 — Der Punkt wird im Lexer nicht mehr gefaltet, sondern im Parser zerlegt Der Lexer liefert weiterhin ein Token, das Punkte enthalten kann (die Rückwärtskompatibilität für Variablennamen mit Punkt bleibt: klassische Programme nutzen `Kunde.Name` als gewöhnlichen Variablennamen). Die Auflösung entscheidet die Semantik in dieser Reihenfolge: ``` Basis ist UDT-Variable -> Feldzugriff wie bisher Basis ist Formular/Control -> Eigenschaftszugriff Basis ist SCREEN -> Bildschirmobjekt sonst -> Diagnose mit Basis- und Gliedname (heute: implizite Variable) ``` Damit ändert sich für bestehende Programme nichts, solange kein Objekt den Namen trägt; Objekte gewinnen gegen implizite Variablen, weil implizite Variablen mit Punkt im Namen ohnehin ein Bug waren. ### D3 — `!` entscheidet sich am folgenden Token Folgt auf `!` unmittelbar ein Bezeichner, ist es der Container-Operator; sonst das Typsuffix. `Wert! = 1.5` und `Form1!Text1.Text = "a"` sind damit unterscheidbar, ohne dass der Lexer wissen muss, was `Form1` ist. Der Fall `Wert!Text` — SINGLE-Variable direkt gefolgt von einem Bezeichner — ist in keiner gültigen Syntax des Dialekts erreichbar. ### D4 — Modales SHOW ist ein Frame-Zustand, kein zweiter Strang `SHOW 1` markiert den aufrufenden Frame als „wartet auf Formular X" und gibt an die Ereignisschleife zurück. Die Schleife stellt weiter zu; wird X entladen oder verborgen, läuft der markierte Frame an der Anweisung nach `SHOW` weiter. ``` Form1.SHOW 1 | +-- Frame markieren (wartet auf Form1) --> Ereignisschleife | Ereignisse zustellen <--+ | UNLOAD Form1 ------------+ | PRINT "danach" <-- Marke faellt, Frame laeuft weiter ``` Eine geschachtelte Schleife innerhalb des `SHOW`-Aufrufs wäre die naheliegende Variante, macht aber die Stapeltiefe von der Zahl verschachtelter modaler Formulare abhängig und verträgt sich nicht mit dem Einzelschritt des Debuggers in Phase 5. ### D5 — Ereignisprozeduren sind gewöhnliche Prozeduren mit fester Signatur Der Dispatch ruft `Command1_Click` wie jeden anderen Prozeduraufruf, nur angestoßen von der Schleife statt von einer Anweisung. Damit gelten Frames, `ON ERROR`, `EXIT SUB` und der Debugger unverändert. Die Zuordnung Name → Objekt/Ereignis entsteht zur Übersetzungszeit; zur Laufzeit ist es ein Index. ### D6 — Das Inventar bekommt eine zweite Quelle Die Themenliste der Original-Hilfe führt das Objektmodell nicht. Statt es unerfasst zu lassen — und damit die Abnahme der Phase 6 blind zu machen —, führt das Inventar Eigenschaften, Methoden und Ereignisse je Klasse mit der Forms-Referenz als Quelle. Der bestehende Abgleichstest prüft sie mit denselben Regeln. Größenordnung: 17 Klassen, in Summe einige hundert Einträge. Das ist der Preis dafür, dass „Vollständigkeit ist das Soll" für Forms überhaupt messbar wird. ## Risks / Trade-offs - **Namenskollision Objekt gegen Variable** → Objekte gewinnen; ein Programm mit einer Variablen `Text1` und einem Steuerelement `Text1` bekommt eine Diagnose statt einer stillen Umdeutung. - **Der Inventarzuwachs erschlägt die Tabelle** → eigene Gruppe je Klasse, damit die bestehenden Gruppen lesbar bleiben; der Abgleichstest nennt weiterhin einzelne Einträge. - **Modale Marke und Debugger** → der Fortsetzungspunkt ist derselbe Mechanismus wie `STOP`/`CONT`; er wird zusammen mit Phase 5 geprüft. - **`.FRM` fehlt noch** → bis dahin entstehen Formulare im Test aus einer im Code aufgebauten Beschreibung; das Objektmodell hängt nicht am Dateiformat. ## Open Questions - Z-Reihenfolge bei überlappenden Steuerelementen (offene Detailfrage der Forms-Referenz) — betrifft die Darstellung, nicht das Objektmodell. - Ob `ControlPanel` alle 18 Systemfarbwerte des Vorbilds abbildet oder eine Teilmenge, entscheidet sich mit der Darstellung im Folge-Change.