# 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.
