BBNubImpl.mesa
Russ Atkinson, July 1, 1983 11:18 am
This module is a transducer between AMEvents and the rest of BugBane.
DIRECTORY
AMBridge USING
[GetWorld],
AMEvents USING [Event, EventProc, GetEvents, StopEvents],
BBAction USING
[Action, ActionKind, NewAction, WaitForDataTaken],
BBBreak USING
[BreakId, ClearBreak, FindBreakId, NextBreak, NullIndex],
BBContext USING
[GetDefaultGlobalContext, SetDefaultGlobalContext],
BBNub USING [],
BBObjectLocation USING
[CatchBreakpoint, GFandPCFromLocation, Location],
Rope USING [Equal, ROPE],
RTBasic USING [TV],
WorldVM USING
[BadWorld, GetWorld, LocalWorld, LookupFailed, World, WorldName];
BBNubImpl: CEDAR MONITOR
IMPORTS
AMBridge, BBAction, BBBreak, BBContext, BBObjectLocation, AMEvents, Rope, WorldVM
EXPORTS BBNub
SHARES BBContext
= BEGIN OPEN Rope, RTBasic;
Event: TYPE = AMEvents.Event;
World: TYPE = WorldVM.World;
HandleEvents: AMEvents.EventProc = TRUSTED {
[data: REF ANY, event: Event] RETURNS[outcome: Outcome]
ENABLE ABORTED => GO TO abort;
actionKind: BBAction.ActionKind ← other;
myAction: BBAction.Action ← NIL;
info: REFNIL;
rtn: REFNIL; -- place holder for returned TV for signals
world: WorldVM.World ← event.world;
WITH e: event SELECT FROM
break => {
actionKind ← break;
IF BBObjectLocation.CatchBreakpoint[event] THEN RETURN;
RETURN; -- we should try to world-swap this
};
signal => actionKind ← signal;
booted => {
Inform BBContext that the world is bogus.
IF world = BBContext.GetDefaultGlobalContext[].world THEN
[] ← BBContext.SetDefaultGlobalContext[NIL];
Remove all breakpoints associated with older incarnations of the world. We assume that there are no current breakpoints for the current incarnation (pretty safe, since this IS a booted event).
FOR bx: INT ← BBBreak.NextBreak[BBBreak.NullIndex], BBBreak.NextBreak[bx]
WHILE bx # BBBreak.NullIndex DO
bid: BBBreak.BreakId = BBBreak.FindBreakId[bx];
loc: BBObjectLocation.Location = bid.loc;
gf: TV = BBObjectLocation.GFandPCFromLocation[loc].gf;
IF gf = NIL OR AMBridge.GetWorld[gf] # world THEN LOOP;
[] ← BBBreak.ClearBreak[bx];
ENDLOOP;
};
ENDCASE;
myAction ← BBAction.NewAction[event, actionKind];
BBAction.WaitForDataTaken[myAction, info];
IF actionKind = signal THEN {
eventually have some method for returning a TV
};
EXITS
abort => RETURN [[quit[]]];
};
worldList: LIST OF World ← NIL;
localListen: BOOLFALSE;
FindWorld: PUBLIC PROC [name: ROPE, new: BOOLFALSE] RETURNS [World] = TRUSTED {
finds a named world (returns NIL if none)
if new, then starts listening
listening twice to the same world is a no-op (& returns the same world)
world: World ← Lookup[name];
IF NOT new THEN RETURN [world];
IF world = NIL THEN {
newWorld: World ← WorldVM.GetWorld[
name
! ABORTED => GO TO abort;
WorldVM.LookupFailed, WorldVM.BadWorld => GO TO cant];
world ← AddWorld[name, newWorld];
IF world = newWorld THEN
AMEvents.GetEvents[world, NIL, HandleEvents];
};
IF world = WorldVM.LocalWorld[] AND NOT localListen THEN {
AMEvents.GetEvents[world, NIL, HandleEvents];
localListen ← TRUE};
RETURN [world];
EXITS
abort => ERROR ABORTED;
cant => RETURN [NIL];
};
Lookup: ENTRY PROC [name: ROPE] RETURNS [World] = TRUSTED {
finds a named world (returns NIL if none)
if new, then starts listening
listening twice to the same world is a no-op (& returns the same world)
IF name = NIL OR name.Equal["Local", FALSE] THEN RETURN [WorldVM.LocalWorld[]];
FOR list: LIST OF World ← worldList, list.rest UNTIL list = NIL DO
each: World ← list.first;
IF name.Equal[WorldVM.WorldName[each], FALSE] THEN
RETURN [each];
ENDLOOP;
RETURN [NIL];
};
AddWorld: ENTRY PROC [name: ROPE, newWorld: World] RETURNS [World] = TRUSTED {
finds a named world (returns NIL if none)
if new, then starts listening
listening twice to the same world is a no-op (& returns the same world)
FOR list: LIST OF World ← worldList, list.rest UNTIL list = NIL DO
each: World ← list.first;
IF name.Equal[WorldVM.WorldName[each], FALSE] THEN
RETURN [each];
ENDLOOP;
worldList ← CONS[newWorld, worldList];
RETURN [newWorld];
};
RemWorld: ENTRY PROC [name: ROPE] RETURNS [World] = TRUSTED {
removes a named world (returns NIL if none)
lag: LIST OF World ← NIL;
FOR list: LIST OF World ← worldList, list.rest UNTIL list = NIL DO
each: World ← list.first;
IF name.Equal[WorldVM.WorldName[each], FALSE] THEN {
IF lag = NIL THEN worldList ← list.rest ELSE lag.rest ← list.rest;
RETURN [each]};
lag ← list;
ENDLOOP;
RETURN [NIL];
};
NextWorld: PUBLIC ENTRY PROC [last: World ← NIL] RETURNS [World] = TRUSTED {
enumerates the worlds currently known, as in:
FOR w: World ← NextWorld[NIL], NextWorld[w] WHILE w # NIL DO
... body of loop
ENDLOOP;
IF last = NIL AND localListen THEN RETURN [WorldVM.LocalWorld[]];
IF last = NIL OR last = WorldVM.LocalWorld[] THEN
RETURN [IF worldList = NIL THEN NIL ELSE worldList.first];
FOR list: LIST OF World ← worldList, list.rest UNTIL list = NIL DO
each: World ← list.first;
IF each = last THEN
RETURN [IF list.rest = NIL THEN NIL ELSE list.rest.first];
ENDLOOP;
RETURN [NIL];
};
TurnADeafEar: PUBLIC PROC [world: World] = TRUSTED {
stops listening to the given world
this is a no-op if the world is not already being listened to
IF world = NIL THEN RETURN;
IF world = WorldVM.LocalWorld[]
THEN localListen ← FALSE
ELSE world ← RemWorld[WorldVM.WorldName[world]];
IF world # NIL THEN AMEvents.StopEvents[world];
};
END.