Files
TerminalBasic/openspec/specs/ereignissteuerung/spec.md

11 KiB

ereignissteuerung Specification

Purpose

Die Ereignissteuerung bestimmt, woher Ereignisse kommen, wann ein laufendes Programm sie zu sehen bekommt und wie es darauf reagiert: Ereignisquellen (Tastatur, Maus, Zeit, benutzerdefiniert) und ihre Warteschlange, die abschließende Liste der Zustellpunkte, die Maskierung je Quelle und global, sowie die Zustellung als GOSUB in das laufende Programm. Sie ist die gemeinsame Grundlage der klassischen Ereignis-Traps und späterer Forms-Ereignisse.

Requirements

Requirement: Ereignisquellen mit Zeit vom Host

Die Laufzeit SHALL Ereignisse aus vier Quellen führen: Tastatur, Maus, Zeit und benutzerdefinierte Ereignisse. Die Zeit SHALL vom Host bezogen werden; die Laufzeit MUST NOT für die Ereigniszustellung selbst auf die Systemuhr zugreifen. Ein Host ohne Terminal MUST die Zeit frei stellen können, sodass zeitgesteuerte Programme ohne Wartezeit und mit reproduzierbarem Ergebnis prüfbar sind.

Scenario: Zeitgesteuerter Trap ohne echte Wartezeit

  • WHEN ein Testhost die Zeit um 5 Sekunden vorstellt und ein Programm ON TIMER(5) GOSUB Marke mit TIMER ON aktiv hat
  • THEN wird der Trap zugestellt, ohne dass der Test tatsächlich wartet

Scenario: Wiederholter Lauf liefert dasselbe Ergebnis

  • WHEN dasselbe zeitgesteuerte Korpusprogramm zweimal mit demselben Zeitverlauf ausgeführt wird
  • THEN ist die Ausgabe beide Male identisch

Requirement: Mausereignisse in Zellenkoordinaten

Die Darstellungsschicht SHALL Mausereignisse der Ausführungsumgebung an die Laufzeit weitergeben: Drücken, Loslassen und Bewegung, jeweils mit gedrückter Taste, Umschaltzustand und Position. Die Position SHALL in Zellen des Textbildschirms angegeben werden, gezählt wie bei LOCATE, also 1-basiert. Ereignisse außerhalb der aktuellen Bildschirmfläche MUST verworfen werden. Die Reihenfolge zwischen Maus- und Tastenereignissen SHALL der Reihenfolge ihres Eintreffens entsprechen. Solange kein Verbraucher ein Mausereignis annimmt, MUST es am Zustellpunkt verworfen werden, damit die Warteschlange nicht unbegrenzt wächst.

Scenario: Position als Zelle

  • WHEN in der linken oberen Ecke der Darstellungsfläche die linke Maustaste gedrückt wird
  • THEN trägt das Ereignis Zeile 1 und Spalte 1

Scenario: Reihenfolge bleibt erhalten

  • WHEN eine Taste gedrückt und danach die Maus geklickt wird
  • THEN liefert die Warteschlange erst das Tasten-, dann das Mausereignis

Scenario: Ereignis außerhalb der Fläche

  • WHEN ein Mausereignis eine Position außerhalb der aktuellen Bildschirmgröße nennt
  • THEN wird es verworfen und erreicht die Warteschlange nicht

Scenario: Kein Verbraucher, keine Anhäufung

  • WHEN ein Programm ohne Verbraucher für Mausereignisse läuft und die Maus dauerhaft bewegt wird
  • THEN wächst die Warteschlange nicht über ihre Grenze und das Programm läuft unverändert weiter

Requirement: Abschließende Liste der Zustellpunkte

Ereignisse SHALL ausschließlich an folgenden Punkten zugestellt werden — das Vorbild prüft die Ereignismarke „before executing the next statement": an einer Anweisungsgrenze, bei DOEVENTS, während SLEEP und vor einer blockierenden Eingabe. Zwischen zwei Zustellpunkten MUST NOT ein Trap-Handler beginnen; insbesondere MUST NOT eine Anweisung in ihrer Mitte unterbrochen werden. Ein zugestelltes Ereignis SHALL ein laufendes SLEEP beenden.

Scenario: Keine Zustellung innerhalb einer Anweisung

  • WHEN ein Ereignis fällig wird, während eine mehrteilige Anweisung ausgewertet wird
  • THEN läuft die Anweisung zu Ende und der Handler beginnt erst an der folgenden Anweisungsgrenze

Scenario: SLEEP endet durch Ereignis

  • WHEN ein Programm SLEEP 60 ausführt und nach 2 Sekunden ein aktiver Trap fällig wird
  • THEN wird der Handler ausgeführt und SLEEP kehrt danach zurück, ohne die vollen 60 Sekunden abzuwarten

Scenario: DOEVENTS stellt zu

  • WHEN ein anstehendes Ereignis vorliegt und DOEVENTS ausgewertet wird
  • THEN läuft der zugehörige Handler, bevor DOEVENTS einen Wert liefert

Requirement: Maskierung je Quelle mit drei Zuständen

Jede Ereignisquelle SHALL drei Zustände kennen. ON stellt Ereignisse zu. OFF verwirft sie; ein während OFF eingetretenes Ereignis MUST NOT nachträglich zugestellt werden, und ein zuvor unter STOP gemerktes Ereignis MUST von OFF verworfen werden. STOP merkt höchstens ein anstehendes Ereignis und stellt es beim nächsten ON zu. Ohne vorangehende ON …-Trap-Definition MUST eine Steueranweisung wirkungslos bleiben, aber keinen Fehler auslösen.

Scenario: OFF verwirft

  • WHEN TIMER OFF gilt, die Frist verstreicht und danach TIMER ON ausgeführt wird
  • THEN wird kein Handler ausgeführt

Scenario: STOP merkt genau eines

  • WHEN KEY(1) STOP gilt, F1 dreimal gedrückt wird und danach KEY(1) ON ausgeführt wird
  • THEN läuft der Handler genau einmal

Scenario: OFF verwirft das unter STOP Gemerkte

  • WHEN TIMER STOP gilt, die Frist verstreicht, danach TIMER OFF und dann TIMER ON ausgeführt werden
  • THEN läuft kein Handler

Requirement: EVENT klammert Abschnitte ohne Ereignisprüfung

EVENT OFF SHALL die Ereignisprüfung für den folgenden Abschnitt abschalten, EVENT ON sie wieder einschalten; die beiden klammern einen Abschnitt, in dem keine Ereignisse erkannt werden müssen. Ein dritter Zustand MUST NOT bestehen: EVENT STOP ist im Vorbild nicht dokumentiert und MUST namentlich abgewiesen werden. Der Schalter SHALL die Zustände der einzelnen Quellen überlagern, ohne sie zu verändern: nach EVENT ON gilt für jede Quelle wieder ihr eigener Zustand. Ereignisse, die während EVENT OFF eintreten, MUST NOT nachträglich zugestellt werden.

Scenario: Klammer überlagert Einzelzustand

  • WHEN TIMER ON gilt und danach EVENT OFF ausgeführt wird
  • THEN wird kein Zeit-Trap zugestellt, und nach EVENT ON wird wieder zugestellt, ohne dass TIMER ON erneut nötig ist

Scenario: EVENT STOP gibt es nicht

  • WHEN ein Modul EVENT STOP enthält
  • THEN wird es namentlich abgewiesen

Requirement: Zustellung als GOSUB ohne Wiedereintritt

Ein zugestelltes Ereignis SHALL das GOSUB-Ziel seines Traps ausführen und danach an die unterbrochene Stelle zurückkehren; der unterbrochene Zustand (aufrufende Prozedur, Schleifen, Variablen) MUST erhalten bleiben. Beim Eintritt in den Handler SHALL für seine eigene Quelle selbsttätig STOP wirken, sodass keine rekursiven Traps entstehen; das RETURN SHALL für sie selbsttätig ON ausführen — es sei denn, im Handler wurde ausdrücklich OFF für diese Quelle ausgeführt, dann bleibt sie aus. Ein RETURN label aus einem Handler MUST erlaubt sein.

Scenario: Rückkehr in die unterbrochene Schleife

  • WHEN ein Trap während einer FOR-Schleife zugestellt wird
  • THEN läuft die Schleife nach RETURN mit unverändertem Zählerstand weiter

Scenario: Kein Wiedereintritt

  • WHEN ein Zeit-Trap läuft und die nächste Frist während des Handlers verstreicht
  • THEN wird der Handler nicht erneut betreten, sondern das Ereignis nach RETURN einmal zugestellt

Scenario: OFF im Handler überlebt das RETURN

  • WHEN ein Handler TIMER OFF ausführt und danach RETURN erreicht
  • THEN bleibt die Quelle aus und kein weiterer Zeit-Trap wird zugestellt

Requirement: Getrappte Tasten verlassen den Eingabestrom

Eine Taste, für die ein aktiver ON KEY-Trap besteht, SHALL dem Trap zugestellt werden und MUST NOT zusätzlich über INKEY$, INPUT, LINE INPUT oder INPUT$ sichtbar werden. Bei OFF oder STOP der Quelle SHALL die Taste dem normalen Eingabestrom erhalten bleiben.

Scenario: Getrappte Taste erscheint nicht bei INKEY$

  • WHEN ON KEY(1) GOSUB Marke mit KEY(1) ON gilt und F1 gedrückt wird
  • THEN läuft der Handler und ein anschließendes INKEY$ liefert den leeren String

Scenario: Nicht getrappte Taste bleibt im Strom

  • WHEN derselbe Trap mit KEY(1) OFF gilt und F1 gedrückt wird
  • THEN liefert INKEY$ die Sondertastenfolge für F1

Requirement: Benutzerdefiniertes Ereignis

SetUEvent SHALL ein benutzerdefiniertes Ereignis auslösen, das über ON UEVENT GOSUB und die Steueranweisung UEVENT denselben Regeln für Maskierung und Zustellung unterliegt wie die übrigen Quellen.

Scenario: SetUEvent löst den Handler aus

  • WHEN ON UEVENT GOSUB Marke mit UEVENT ON gilt und SetUEvent aufgerufen wird
  • THEN läuft der Handler am nächsten Zustellpunkt genau einmal

Requirement: Reihenfolge bei mehreren fälligen Ereignissen

Sind an einem Zustellpunkt mehrere Ereignisse fällig, SHALL genau eines zugestellt werden; die übrigen bleiben anstehend und werden an folgenden Zustellpunkten zugestellt. Die Reihenfolge SHALL festgelegt und dokumentiert sein, sodass sie über Läufe hinweg gleich bleibt.

Scenario: Zwei gleichzeitig fällige Traps

  • WHEN an einem Zustellpunkt ein Zeit- und ein Tasten-Trap zugleich fällig sind
  • THEN läuft zuerst genau ein Handler und der andere am nächsten Zustellpunkt

Requirement: Fehler in einem Handler

Ein Laufzeitfehler in einem Trap-Handler SHALL der geltenden Fehlerbehandlung unterliegen. RESUME und RESUME NEXT SHALL sich auf die Anweisung im Handler beziehen, nicht auf die unterbrochene Anweisung.

Scenario: Fehler im Handler erreicht den Handler des Moduls

  • WHEN ein Trap-Handler eine Anweisung mit Laufzeitfehler ausführt und ein modulweiter ON ERROR GOTO-Handler gesetzt ist
  • THEN wird dieser Handler betreten und ERL nennt die Zeile im Trap-Handler

Requirement: Signal-Trap auf Betriebssystemsignalen

ON SIGNAL(n%) GOSUB und die Steueranweisung SIGNAL(n%) SHALL denselben Regeln für Maskierung, Zustellung und Wiedereintritt unterliegen wie die übrigen Quellen. n% SHALL auf Betriebssystemsignale abgebildet werden, und zwar ausschließlich auf die Menge, die auf allen Zielplattformen besteht: 1 auf den Unterbrechungswunsch (SIGINT), 2 auf den Beendigungswunsch (SIGTERM). Ein anderer Wert MUST namentlich abgewiesen werden — zur Übersetzungszeit, wenn er konstant ist, sonst mit Laufzeitfehler 5. Ein Signal MUST NOT im Signalkontext verarbeitet werden; es SHALL über den Host als Ereignis in die Warteschlange gelangen. Die Abweichung zur OS/2-gebundenen Quelle des Vorbilds SHALL in der Sprachreferenz ausgewiesen sein.

Scenario: Signal-Trap folgt der Maskierung

  • WHEN ON SIGNAL(1) GOSUB Marke mit SIGNAL(1) STOP gilt und ein SIGINT eintrifft
  • THEN läuft der Handler erst nach SIGNAL(1) ON, und zwar genau einmal

Scenario: Unzulässige Signalnummer

  • WHEN ein Modul ON SIGNAL(7) GOSUB Marke enthält
  • THEN wird es namentlich abgewiesen und die Meldung nennt den zulässigen Bereich

Scenario: Signal ohne Trap bleibt Abbruch

  • WHEN ein SIGINT eintrifft, ohne dass ein SIGNAL(1)-Trap aktiv ist
  • THEN bleibt es beim bisherigen Abbruchverhalten