DIRECTORY
BBAction
USING
[Action, NewAction, WaitForDataTaken],
BBBreak
USING
[BreakId, BreakIdRep, BreakList, CondProc, NullIndex],
BBObjectLocation
USING
[BreakpointHandler, ClearBreakpoint, EntryLocation, ExitLocation, Location, SetBreakpoint, TVToLocation],
BBZones
USING
[GetQuantizedZone],
RTBasic USING [TV];
BBBreakImpl:
CEDAR
MONITOR
IMPORTS BBAction, BBObjectLocation, BBSafety, BBZones
EXPORTS BBBreak
SHARES BBBreak
= BEGIN OPEN BBBreak, BBObjectLocation, Rope, RTBasic;
z: ZONE ← BBZones.GetQuantizedZone[];
LastBreakIdNumber: INT ← 0;
headBreakList: BreakList ← NIL;
BreakError: PUBLIC ERROR [reason: ROPE] = CODE;
BreakEntry:
PUBLIC
PROC
[proc: TV] RETURNS [index: INT] = TRUSTED {
inner:
PROC =
TRUSTED {
get the entry location
loc: Location ← EntryLocation[TVToLocation[proc]];
bid: BreakId ← AddBreakToList[loc];
bid.enabled ← bid.entry ← TRUE;
index ← bid.index;
};
msg: ROPE ← BBSafety.Mother[inner];
IF msg = NIL THEN RETURN;
ERROR BreakError[msg];
};
BreakExit:
PUBLIC
PROC
[proc: TV] RETURNS [index: INT] = TRUSTED {
inner:
PROC =
TRUSTED {
get the exit location
loc: Location ← ExitLocation[TVToLocation[proc]];
bid: BreakId ← AddBreakToList[loc];
bid.enabled ← bid.exit ← TRUE;
index ← bid.index;
};
msg: ROPE ← BBSafety.Mother[inner];
IF msg = NIL THEN RETURN;
ERROR BreakError[msg];
};
ClearBreak:
PUBLIC
PROC [index:
INT]
RETURNS [BreakId] =
TRUSTED {
bid: BreakId ← RemBreakFromList[index];
IF bid = NIL THEN RETURN [NIL];
[] ← BBObjectLocation.ClearBreakpoint[bid.loc, bid.cid];
RETURN [bid]};
ClearAllBreaks:
PUBLIC
ENTRY
PROC [condProc: CondProc ←
NIL] =
TRUSTED {
ENABLE UNWIND => NULL;
bl: BreakList ← headBreakList;
WHILE bl #
NIL
DO
bid: BreakId ← bl.first;
bl ← bl.rest;
IF condProc # bid.condProc THEN LOOP;
bid.enabled ← FALSE;
[] ← RemBreakFromListInternal[bid.index];
[] ← BBObjectLocation.ClearBreakpoint[bid.loc, bid.cid]
ENDLOOP
utility routines for breakpoint stuff
FindBreakLag:
PUBLIC
PROC [index:
LONG
INTEGER]
RETURNS [lag: BreakList] = {
lag ← NIL;
FOR bl: BreakList ← headBreakList, bl.rest
WHILE
NOT (bl =
NIL)
DO
IF bl.first.index >= index THEN EXIT;
lag ← bl
ENDLOOP};
FindBreakId:
PUBLIC
ENTRY
PROC [index:
INT]
RETURNS [id: BreakId] = {
ENABLE UNWIND => NULL;
id ← NIL;
FOR bl: BreakList ← headBreakList, bl.rest
WHILE
NOT (bl =
NIL)
DO
IF bl.first.index = index THEN RETURN [bl.first]
ENDLOOP};
AddBreakToList:
PUBLIC
ENTRY
PROC
[loc: BBObjectLocation.Location, condProc: CondProc ← NIL, condData: REF ← NIL]
RETURNS [BreakId] = {
ENABLE UNWIND => NULL;
RETURN [AddBreakToListInternal[loc, condProc, condData]]};
AddBreakToListInternal:
PROC
[loc: BBObjectLocation.Location, condProc: CondProc ← NIL, condData: REF ← NIL]
RETURNS [BreakId] = TRUSTED {
bid: BreakId ←
NEW[BreakIdRep ← [
loc: loc,
index: 0,
cid: NIL,
condProc: condProc,
condData: condData ,
entry: FALSE,
exit: FALSE,
enabled: TRUE]];
set the new breakpoint
bidl: BreakList ← LIST[bid];
lag: BreakList ← FindBreakLag[LastBreakIdNumber + 1];
bid.cid ← BBObjectLocation.SetBreakpoint[loc, MyBreakHandler, bid];
IF lag =
NIL
THEN {bidl.rest ← headBreakList; headBreakList ← bidl}
ELSE {bidl.rest ← lag.rest; lag.rest ← bidl};
LastBreakIdNumber ← bid.index ← LastBreakIdNumber + 1;
RETURN [bid]};
RemBreakFromList:
PUBLIC
ENTRY
PROC [index:
INT]
RETURNS [BreakId] = {
ENABLE UNWIND => NULL;
RETURN [RemBreakFromListInternal[index]]};
RemBreakFromListInternal:
PROC [index:
INT]
RETURNS [bid: BreakId] =
TRUSTED {
bidl: BreakList ← NIL;
bid ← NIL;
IF headBreakList #
NIL
AND headBreakList.first.index = index
THEN {
bidl ← headBreakList;
headBreakList ← headBreakList.rest}
ELSE {
lag: BreakList ← FindBreakLag[index];
IF lag #
NIL
THEN {
bidl ← lag.rest;
lag.rest ← IF bidl # NIL THEN bidl.rest ELSE NIL}};
IF bidl #
NIL
THEN {
bid ← bidl.first;
bid.index ← 0;
FREE[@bidl]};
NextBreak:
PUBLIC
ENTRY
PROC
[index: INT ← NullIndex] RETURNS [INT] = {
ENABLE UNWIND => NULL;
FOR bl: BreakList ← headBreakList, bl.rest
WHILE
NOT (bl =
NIL)
DO
bid: BreakId ← bl.first;
IF index = NullIndex THEN RETURN [bid.index];
IF index = bid.index THEN index ← NullIndex;
ENDLOOP;
RETURN [NullIndex];
};
MyBreakHandler: BBObjectLocation.BreakpointHandler =
TRUSTED {
[event: Event, id: BreakpointId, data: REF]
action: BBAction.Action ← NIL;
bid: BreakId ← NARROW[data];
first check for cases we may wish to handle quickly
IF bid = NIL OR NOT bid.enabled THEN RETURN;
IF bid.condProc #
NIL
THEN {
handle conditional breaks
IF NOT bid.condProc[bid, event.frame, bid.condData] THEN RETURN};
sigh, we must notify our normal handler
action ← BBAction.NewAction[event, break];
BBAction.WaitForDataTaken[action, bid];
};
END.