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: REF ← NIL;
rtn: REF ← NIL; -- 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: BOOL ← FALSE;
FindWorld:
PUBLIC
PROC [name:
ROPE, new:
BOOL ←
FALSE]
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.