BBVExec.mesa
Russ Atkinson, April 13, 1983 8:11 pm
DIRECTORY
AMBridge
USING
[GetWorld, GFHFromTV, IsRemote, RemoteGFHFromTV, TVToCardinal],
AMEvents USING [Event],
AMTypes
USING
[Class, DynamicParent, Error, Signal, TVType, TypeClass],
BBAction
USING
[Abort, Action, ActionError, ActionId, Event, ForceChange, NextPendingAction, PeekData, TakeData, WaitForChange],
BBBreak
USING
[AddBreakToList, BreakId, BreakIndex, ClearAllBreaks, ClearBreak, CondProc, FindBreakId, NextBreak, NullIndex],
BBBugOut USING [SetDefaultPut],
BBContext
USING
[Context, ContextForLocalFrame, ContextForWorld, GetContents, GetDefaultGlobalContext, SetDefaultGlobalContext],
BBDisableBreaks USING [DisableBreakPoints],
BBFocus
USING
[GetDefaultActionAndContext, SameLocalFrame, SetDefaultActionAndContext],
BBObjectLocation
USING
[EntryLocation, ExitLocation, GFandPCFromLocation, IsLocationAtLocation, Location, LocationToSource, TVFromLocation],
BBSafety USING [Mother],
BBVForUserExec USING [DisplayFrame, SourceFromTV, OpenSource, ReportProc],
BBVOps USING [LocationFromSelection, SourceError, ViewerFromLocation],
Buttons USING [Button, SetDisplayStyle],
Commander USING [CommandProc, Register],
Containers USING [ChildXBound, ChildYBound],
Convert USING [MapValue, ValueToRope],
Labels USING [Create, Label, Set],
Menus
USING
[CreateEntry, CreateMenu, InsertMenuEntry, Menu, MenuProc],
PrintTV
USING
[Print, PrintArguments, PutClosure, PutProc],
Process USING [Detach],
Rope
USING
[Cat, Fetch, Flatten, FromRefText, Index, Map, ROPE, Size, Text],
RTBasic USING [TV],
TypeScript USING [Create, PutChar, TS],
VFonts USING [CharWidth, FontHeight],
ViewerClasses USING [Viewer],
ViewerOps USING [ComputeColumn, CreateViewer],
VMenus USING [Create, GetDimensions, VButtonList, ViewerList],
WorldVM USING [LocalWorld, World, WorldName];
BBVExec:
CEDAR
PROGRAM
IMPORTS
AMBridge, AMTypes, BBAction, BBBreak, BBBugOut, BBContext, BBDisableBreaks, BBFocus, BBObjectLocation, BBSafety, BBVForUserExec, BBVOps, Buttons, Commander, Containers, Convert, Labels, Menus, PrintTV, Process, Rope, TypeScript, VFonts, ViewerOps, VMenus, WorldVM
SHARES BBBreak
= BEGIN OPEN Rope, RTBasic;
Action: TYPE = BBAction.Action;
BreakId: TYPE = BBBreak.BreakId;
BreakIndex:
TYPE = BBBreak.BreakIndex;
NullIndex: BreakIndex = BBBreak.NullIndex;
Context: TYPE = BBContext.Context;
Event: TYPE = AMEvents.Event;
Location: TYPE = BBObjectLocation.Location;
World: TYPE = WorldVM.World;
defaultDepth: NAT ← 3;
defaultWidth: NAT ← 32;
emWidth: INTEGER;
emHeight: INTEGER;
headLabel: Labels.Label ← NIL;
frameLabel: Labels.Label ← NIL;
errorLabel: Labels.Label ← NIL;
errorMsg: ROPE ← NIL; -- shadows contents of errorLabel
container: ViewerClasses.Viewer ← NIL;
watchdogProcess: PROCESS ← NIL;
labelMax: NAT ← 64;
entryOption: BOOL ← FALSE;
exitOption: BOOL ← FALSE;
oneShotOption: BOOL ← FALSE;
allVarsOption: BOOL ← FALSE;
abortNextChar: BOOL ← FALSE;
emptyName: ROPE ← " ";
ts: TypeScript.TS ← NIL; -- the output for various goodies (init in BuildTool)
StripExtension:
PROC [name:
ROPE]
RETURNS [Rope.Text] = {
pos: INT ← name.Index[0, "."];
RETURN [name.Flatten[0, pos]]
};
BuildTool: Commander.CommandProc =
TRUSTED {
[cmd: Handle]
[in, out, err: IO.STREAM, commandLine: ROPE, command: ROPE, propertyList: List.AList]
x,y: INTEGER ← 0;
xmax,ymax: INTEGER ← 0;
vMenuY: INTEGER ← 0;
list: VMenus.ViewerList ← NIL;
AddLabel:
PROC
[indent: INTEGER ← 0, trail: INTEGER ← 2]
RETURNS [Labels.Label] = TRUSTED {
AddLabel adds a new label to the container at the given position
returns the button and new position
label: Labels.Label ← NIL;
x: INTEGER ← 0;
y: INTEGER ← ymax;
w: INTEGER ← emWidth * labelMax;
h: INTEGER ← emHeight;
label ←
Labels.Create
[[name: emptyName, parent: container, border:
FALSE,
wx: x + indent, wy: y, ww: w, wh: h]];
x ← label.wx + label.ww - 1;
y ← label.wy + label.wh - 1 + trail;
IF x > xmax THEN xmax ← x;
IF y > ymax THEN ymax ← y;
RETURN [label]
};
AddVMenu:
PROC [name:
ROPE, specs: VMenus.VButtonList] =
TRUSTED {
y ← vMenuY;
x ← xmax;
list ← VMenus.Create[name, specs, container, x, y];
[,,x,y] ← VMenus.GetDimensions[list];
IF x > xmax THEN xmax ← x;
IF y > ymax THEN ymax ← y;
};
menu: Menus.Menu ← Menus.CreateMenu[lines: 1];
emWidth ← VFonts.CharWidth['M];
emHeight ← VFonts.FontHeight[];
container ←
ViewerOps.CreateViewer[
flavor: $Container,
info: [name: "BBV", iconic: TRUE, column: right],
build up the menu
Menus.InsertMenuEntry
[menu: menu, entry: Menus.CreateEntry[name: "ResetDefault!", proc: ResetDefaultHit]];
Menus.InsertMenuEntry
[menu: menu, entry: Menus.CreateEntry[name: "Stop!", proc: StopHit]];
Menus.InsertMenuEntry
[menu: menu, entry: Menus.CreateEntry[name: "Bigger", proc: BiggerHit]];
Menus.InsertMenuEntry
[menu: menu, entry: Menus.CreateEntry[name: "Smaller", proc: SmallerHit]];
container.menu ← menu;
current action head line
headLabel ← AddLabel[];
frame label line
frameLabel ← AddLabel[indent: 2 * emWidth];
first line of buttons
xmax ← 0;
vMenuY ← ymax;
AddVMenu
["Show stack",
LIST
[[DisplayTopHit, "This frame"],
[DisplayStackHit, "Full stack"],
[DisplayStackWithArgsHit, " + Args"],
[DisplayStackWithVarsHit, " + Vars"]]];
AddVMenu
["Walk stack",
LIST
[[CurrentActionHit, "Restart"],
[NextFrameHit, "Next/Prev"],
[NextWithArgsHit, " + Args"],
[NextWithVarsHit, " + Vars"]]];
AddVMenu
["Control",
LIST
[[SourceHit, "Source"],
[ProceedHit, "Proceed"],
[AbortHit, "Abort"],
[NextActionHit, "Next action"]]];
AddVMenu
["Breaks",
LIST
[[SetBreakHit, "Set"],
[ClearBreakHit, "Clear"],
[ClearAllBreaksHit, "Clear *"],
[OnOffHit, "on/off"]]];
AddVMenu
["Options",
LIST
[[AllVarsOptionHit, "allVars"],
[EntryOptionHit, "Entry"],
[ExitOptionHit, "Exit"],
[OneShotOptionHit, "1-shot"]]];
AddVMenu
["Display",
LIST
[[DisplayBreaksHit, "Breaks"],
[DisplayActionsHit, "Actions"],
[SignalArgsHit, "Signal"]]];
error label line
ymax ← ymax + 2;
errorLabel ← AddLabel[];
typescript area
ymax ← ymax + 2;
ts ← TypeScript.Create
[info: [parent: container, wx: 0, wy: ymax, ww: 64, wh: 64],
paint: FALSE];
Containers.ChildXBound[container, ts];
Containers.ChildYBound[container, ts];
container.openHeight ← ymax + 128;
[] ← BBBugOut.SetDefaultPut[putClosure];
Process.Detach[watchdogProcess ← FORK LabelWatcher[]];
};
EntryOptionHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
ShowOption[viewer, entryOption ← NOT entryOption];
};
ExitOptionHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
ShowOption[viewer, exitOption ← NOT exitOption];
};
OneShotOptionHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
abortNextChar ← FALSE;
ShowOption[viewer, oneShotOption ← NOT oneShotOption];
};
AllVarsOptionHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
abortNextChar ← FALSE;
ShowOption[viewer, allVarsOption ← NOT allVarsOption];
};
ResetDefaultHit: Menus.MenuProc =
TRUSTED {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
abortNextChar ← FALSE;
[] ← BBContext.SetDefaultGlobalContext
[BBContext.ContextForWorld[WorldVM.LocalWorld[]]];
};
StopHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
abortNextChar ← TRUE;
};
BiggerHit: Menus.MenuProc =
TRUSTED {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
container.openHeight ← container.openHeight + 64;
ViewerOps.ComputeColumn[container.column];
};
SmallerHit: Menus.MenuProc =
TRUSTED {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
container.openHeight ← container.openHeight - 64;
ViewerOps.ComputeColumn[container.column];
};
MyNormalBreak: BBBreak.CondProc =
TRUSTED {
[bid: BreakId, lf: TV, data: REF ← NIL] RETURNS [break: BOOL]
RETURN [TRUE];
};
MyOneShotBreak: BBBreak.CondProc = {
[bid: BreakId, lf: TV, data: REF ← NIL] RETURNS [break: BOOL]
bid.enabled ← FALSE;
RETURN [TRUE];
};
SetBreakHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
innerLoc:
PROC = {
old: BBObjectLocation.Location ← loc;
loc ← NIL;
SELECT
TRUE
FROM
forceEntry => loc ← BBObjectLocation.EntryLocation[old];
forceExit => loc ← BBObjectLocation.ExitLocation[old];
ENDCASE => loc ← old;
};
inner:
PROC = {
Kvetch["Setting break..."];
msg ← "invalid location";
IF loc =
NIL
THEN
loc ← BBVOps.LocationFromSelection
[world ! BBVOps.SourceError => {msg ← reason; CONTINUE}];
IF loc #
NIL
THEN {
proc: TV ← BBObjectLocation.TVFromLocation[loc];
bid: BreakId ← NIL;
msg ← BBSafety.Mother[innerLoc];
IF msg # NIL THEN GO TO bye;
[] ← BBVOps.ViewerFromLocation
[loc ! BBVOps.SourceError => {msg ← reason; GO TO bye}];
IF loc #
NIL
THEN {
bid: BreakId ←
BBBreak.AddBreakToList
[loc, IF oneShotOption THEN MyOneShotBreak ELSE MyNormalBreak];
KvetchBreak[bid.index, IF oneShotOption THEN " set (oneShot)" ELSE " set"];
RETURN};
EXITS bye => {}};
Kvetch["Break NOT set: ", msg];
};
forceEntry: BOOL ← entryOption;
forceExit: BOOL ← exitOption;
loc: Location ← NIL;
msg: ROPE ← NIL;
world: World ← GetCurrentWorld[];
abortNextChar ← FALSE;
BBDisableBreaks.DisableBreakPoints[inner];
IF forceEntry
AND forceExit
AND loc #
NIL
THEN {
forceEntry ← FALSE;
BBDisableBreaks.DisableBreakPoints[inner]};
};
ClearBreakHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
innerLoc:
PROC = {
old: BBObjectLocation.Location ← loc;
loc ← NIL;
SELECT
TRUE
FROM
forceEntry => loc ← BBObjectLocation.EntryLocation[old];
forceExit => loc ← BBObjectLocation.ExitLocation[old];
ENDCASE => loc ← old;
};
inner:
PROC = {
Kvetch["Clearing break..."];
IF loc =
NIL
THEN loc ← BBVOps.LocationFromSelection
[world ! BBVOps.SourceError => {msg ← reason; CONTINUE}];
IF loc #
NIL
THEN msg ← BBSafety.Mother[innerLoc]
ELSE IF msg = NIL THEN msg ← "invalid location";
IF loc #
NIL
THEN {
bx: BreakIndex ← BreakFromLocation[loc];
IF bx # NullIndex
THEN {
[] ← BBBreak.ClearBreak[bx];
KvetchBreak[bx, " cleared"]}
ELSE Kvetch["No such break"];
RETURN};
Kvetch["Break NOT found: ", msg];
};
forceEntry: BOOL ← entryOption;
forceExit: BOOL ← exitOption;
loc: Location ← NIL;
msg: ROPE ← NIL;
world: World ← GetCurrentWorld[];
abortNextChar ← FALSE;
BBDisableBreaks.DisableBreakPoints[inner];
IF forceEntry
AND forceExit
AND loc #
NIL
THEN {
forceEntry ← FALSE;
BBDisableBreaks.DisableBreakPoints[inner]};
};
SourceHit: Menus.MenuProc =
TRUSTED {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
inner:
PROC =
TRUSTED {
action: Action ← NIL;
ctx: Context ← NIL;
tv, gfTV: TV ← NIL;
msg: ROPE ← "Source? What source?";
Kvetch["Finding source..."];
[action, ctx] ← BBFocus.GetDefaultActionAndContext[];
[,gfTV, tv] ← BBContext.GetContents[ctx];
IF tv = NIL THEN tv ← gfTV;
IF tv =
NIL
THEN
tv ← BBContext.GetContents[BBContext.GetDefaultGlobalContext[]].gf;
IF tv #
NIL
THEN {
we have a live one!
name: ROPE ← NIL;
index: INT ← -1;
backupPC: BOOL ← FALSE;
SELECT
TRUE
FROM
AMTypes.TypeClass[AMTypes.TVType[tv]] # localFrame => {};
action = NIL OR action.kind # break => {};
BBFocus.SameLocalFrame[action.event.frame, tv] => backupPC ← TRUE;
ENDCASE;
[name, index] ← BBVForUserExec.SourceFromTV[tv, Report, backupPC];
IF name #
NIL
THEN
BBVForUserExec.OpenSource[name, index, 2, Report];
RETURN;
};
Kvetch[msg];
};
abortNextChar ← FALSE;
BBDisableBreaks.DisableBreakPoints[inner];
};
ClearAllBreaksHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
inner:
PROC = {
Kvetch["Clearing breaks..."];
BBBreak.ClearAllBreaks[MyNormalBreak];
BBBreak.ClearAllBreaks[MyOneShotBreak];
BBBreak.ClearAllBreaks[];
Kvetch["All breaks cleared"];
};
abortNextChar ← FALSE;
BBDisableBreaks.DisableBreakPoints[inner];
};
OnOffHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
inner:
PROC = {
loc: Location ← NIL;
msg: ROPE ← "invalid location";
IF mouseButton = red
THEN Kvetch["Enabling break..."]
ELSE Kvetch["Disabling break..."];
loc ← BBVOps.LocationFromSelection
[ ! BBVOps.SourceError => {msg ← reason; CONTINUE}];
IF loc #
NIL
THEN {
bx: BreakIndex ← BreakFromLocation[loc];
bid: BreakId ← BBBreak.FindBreakId[bx];
IF bx # NullIndex
AND bid #
NIL
THEN {
bid.enabled ← mouseButton = red;
KvetchBreak[bx, IF bid.enabled THEN " enabled" ELSE " disabled"]}
ELSE Kvetch["No such break"];
RETURN
};
Kvetch["Break NOT found: ", msg];
};
abortNextChar ← FALSE;
BBDisableBreaks.DisableBreakPoints[inner];
};
ProceedHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
action: Action ← GetCurrentAction[];
IF action = NIL THEN RETURN;
Kvetch["Proceeding current action..."];
[] ← BBAction.TakeData[action ! ANY => CONTINUE];
Kvetch["Proceeded."];
};
AbortHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
action: Action ← GetCurrentAction[];
IF action = NIL THEN RETURN;
Kvetch["Aborting current action..."];
BBFocus.SetDefaultActionAndContext[NIL, NIL];
BBAction.Abort[action ! ANY => CONTINUE];
Kvetch["Aborted."];
};
DisplayTopHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
action: Action ← GetCurrentAction[];
ctx: Context ← BBFocus.GetDefaultActionAndContext[].ctx;
lf: TV ← BBContext.GetContents[ctx].lf;
IF action = NIL OR lf = NIL THEN RETURN;
Kvetch["Displaying current frame..."];
DisplayLocalFrame[lf, TRUE, TRUE];
};
NextFrameHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
delta: INT ← 1;
action: Action ← GetCurrentAction[];
IF action = NIL THEN RETURN;
IF mouseButton # red THEN delta ← -1;
Kvetch["Walking..."];
DisplayLocalFrame[WalkContext[delta]];
};
NextWithArgsHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
delta: INT ← 1;
action: Action ← GetCurrentAction[];
IF action = NIL THEN RETURN;
IF mouseButton # red THEN delta ← -1;
Kvetch["Walking..."];
DisplayLocalFrame[WalkContext[delta], TRUE];
};
NextWithVarsHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
delta: INT ← 1;
action: Action ← GetCurrentAction[];
IF action = NIL THEN RETURN;
IF mouseButton # red THEN delta ← -1;
Kvetch["Walking..."];
DisplayLocalFrame[WalkContext[delta], TRUE, TRUE];
};
DisplayBreaksHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
Kvetch["Displaying breaks..."];
putRope["\n"];
FOR i: BreakIndex ← BBBreak.NextBreak[NullIndex], BBBreak.NextBreak[i]
WHILE NOT (i = NullIndex) DO
bid: BreakId ← BBBreak.FindBreakId[i];
IF bid #
NIL
THEN
-- display this break with optional verbosity
DisplayBreak[bid, mouseButton = blue];
ENDLOOP;
Kvetch[];
};
DisplayActionsHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
Kvetch["Displaying actions..."];
putRope["\n"];
FOR action: Action ← BBAction.NextPendingAction[
NIL],
BBAction.NextPendingAction[action] WHILE action # NIL DO
DisplayAction[action, mouseButton = blue];
ENDLOOP;
Kvetch[];
};
DisplayStackHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
action: Action ← GetCurrentAction[];
IF action = NIL THEN RETURN;
Kvetch["Displaying stack..."];
DisplayStack[];
};
DisplayStackWithArgsHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
action: Action ← GetCurrentAction[];
IF action = NIL THEN RETURN;
Kvetch["Displaying stack..."];
DisplayStack[TRUE];
};
DisplayStackWithVarsHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
action: Action ← GetCurrentAction[];
IF action = NIL THEN RETURN;
Kvetch["Displaying stack..."];
DisplayStack[TRUE, TRUE];
};
CurrentActionHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
context: Context ← NIL;
action: Action ← GetCurrentAction[];
IF action = NIL THEN RETURN;
Kvetch["Walking to the top..."];
context ← BBContext.ContextForLocalFrame[action.event.frame];
BBFocus.SetDefaultActionAndContext[action, context];
BBAction.ForceChange[];
Kvetch[];
};
NextActionHit: Menus.MenuProc = {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
action: Action ← NIL;
context: Context ← NIL;
Kvetch["Next action..."];
abortNextChar ← FALSE;
[action, context] ← BBFocus.GetDefaultActionAndContext[];
action ← BBAction.NextPendingAction[action];
IF action #
NIL
THEN
IF action.status # pendingOut
THEN action ← NIL
ELSE context ← BBContext.ContextForLocalFrame[action.event.frame];
BBFocus.SetDefaultActionAndContext[action, context];
BBAction.ForceChange[];
Kvetch[];
};
SignalArgsHit: Menus.MenuProc =
TRUSTED {
[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
viewer: ViewerClasses.Viewer ← NARROW[parent];
context: Context ← NIL;
sigTV, lfTV: TV ← NIL;
tryFrame: BOOL ← TRUE;
errmsg: ROPE ← NIL;
action: Action ← GetCurrentAction[];
inner:
PROC =
TRUSTED {
sigTV ← AMTypes.Signal[lfTV];
putRope["signal: "];
DisplayTV[sigTV];
putRope[" args: "];
IF tryFrame
THEN {PrintTV.PrintArguments[lfTV, putClosure]; putChar['\n]}
ELSE DisplayTV[lfTV];
};
IF action = NIL THEN RETURN;
[action, context] ← BBFocus.GetDefaultActionAndContext[];
IF action = NIL OR context = NIL THEN RETURN;
Kvetch["Signal arguments..."];
lfTV ← BBContext.GetContents[context].lf;
sigTV ← AMTypes.Signal
[lfTV !
AMTypes.Error => {tryFrame ← FALSE; CONTINUE};
ABORTED => REJECT;
ANY => CONTINUE];
IF sigTV =
NIL
AND action.kind = signal
THEN {
event: Event ← action.event;
WITH e: event
SELECT
FROM
signal => {sigTV ← e.signal; lfTV ← e.args};
ENDCASE;
};
IF sigTV = NIL THEN {Kvetch["Signal? What signal?"]; RETURN};
errmsg ← BBSafety.Mother[inner];
IF errmsg = NIL THEN {Kvetch[]; RETURN};
Kvetch["Can't get signal arguments: ", errmsg];
};
display procs for actions, breakpoints & the frames
these procs can raise ABORTED if the output is aborted (by Stop!)
putProc: PrintTV.PutProc =
TRUSTED {
[data: REF, c: CHAR]
IF abortNextChar
THEN {
abort the current request & say why
abortNextChar ← FALSE;
TypeScript.PutChar[ts, '\n];
KvetchMore[" aborted."];
ERROR ABORTED};
TypeScript.PutChar[ts, c];
};
putClosure: PrintTV.PutClosure ← [putProc, NIL];
putChar: PROC [c: CHAR] = {putProc[NIL, c]};
putCharB: PROC [c: CHAR] RETURNS [BOOL] = {putProc[NIL, c]; RETURN [FALSE]};
putRope: PROC [r: ROPE] = {[] ← Rope.Map[base: r, action: putCharB]};
putRopes:
PROC [r1,r2,r3,r4,r5,r6:
ROPE ←
NIL] = {
IF r1 # NIL THEN putRope[r1];
IF r2 # NIL THEN putRope[r2];
IF r3 # NIL THEN putRope[r3];
IF r4 # NIL THEN putRope[r4];
IF r5 # NIL THEN putRope[r5];
IF r6 # NIL THEN putRope[r6];
};
putInt: PROC [int: INT] = {Convert.MapValue[putChar, [signed[int]]]};
putCard:
PROC [card:
LONG
CARDINAL] = {
Convert.MapValue[putChar, [unsigned[card, 8]]];
putChar['B];
};
DisplayAction:
PROC [action: Action, verbose:
BOOL ←
FALSE] =
TRUSTED {
event: AMEvents.Event ← NIL;
IF action = NIL THEN RETURN;
event ← action.event;
putRope["Action #"]; putInt[action.id];
SELECT action.status
FROM
pendingOut => {};
new => putRope[" (new)"];
busy => putRope[" (busy)"];
pendingIn => putRope[" (pendingIn)"];
dead => putRope[" (dead)"];
new => putRope[" (new)"];
ENDCASE => putRope[" (??)"];
putRope[", process = "];
putCard[AMBridge.TVToCardinal[action.event.process]];
IF event.world # WorldVM.LocalWorld[]
THEN
putRopes[", world = ", WorldVM.WorldName[event.world]];
putChar['\n];
DisplayLocalFrame[event.frame];
WITH e: event
SELECT
FROM
break =>
IF action.status = pendingOut
THEN {
ref: REF ← NIL;
ref ← BBAction.PeekData[action ! BBAction.ActionError => CONTINUE];
WITH ref
SELECT
FROM
bid: BreakId => DisplayBreak[bid, verbose];
ENDCASE => putRope["break ??"];
};
call =>
putRopes["callDebugger[", e.msg, "]"];
signal => {
putRope["uncaught "];
DisplayTV[e.signal, FALSE];
IF e.args #
NIL
THEN {
putRope["["];
DisplayTV[e.args, FALSE];
putRope["]"]};
};
interrupt =>
putRope["interrupt"];
unknown =>
putRopes["???? ", e.why];
ENDCASE;
putChar['\n];
};
DisplayBreak:
PROC [break: BreakId, verbose:
BOOL ←
FALSE] =
TRUSTED {
loc: Location ← break.loc;
IF loc = NIL THEN RETURN;
putRope["Break #"]; putInt[break.index]; putRope[" in "];
DisplayTV[BBObjectLocation.TVFromLocation[break.loc], FALSE];
putRope[" (source: "];
putInt[BBObjectLocation.LocationToSource[loc].sourceIndex];
IF verbose
THEN {
gf: TV ← NIL;
pc, gfh: CARDINAL ← 0;
[gf, pc] ← BBObjectLocation.GFandPCFromLocation[loc];
IF AMBridge.IsRemote[gf]
THEN {
putRope[", world: "];
putRope[WorldVM.WorldName[AMBridge.GetWorld[gf]]];
gfh ← LOOPHOLE[AMBridge.RemoteGFHFromTV[gf].gfh, CARDINAL]}
ELSE gfh ← LOOPHOLE[AMBridge.GFHFromTV[gf], CARDINAL];
putRope[", gfh: "]; putCard[gfh];
putRope[", pc: "]; putCard[pc];
};
putRope[")\n"];
};
DisplayLocalFrame:
PROC [lf:
TV, args,vars:
BOOL ←
FALSE] =
TRUSTED {
IF lf = NIL THEN RETURN;
putChar['\n];
BBVForUserExec.DisplayFrame[
frame: lf, put: putClosure, report: Report,
args: args, vars: vars, allVars: vars AND allVarsOption];
};
DisplayStack:
PROC [args,vars:
BOOL ←
FALSE] =
TRUSTED {
current: TV ← NIL;
context: Context ← NIL;
action: Action ← NIL;
[action, context] ← BBFocus.GetDefaultActionAndContext[];
IF action = NIL OR context = NIL THEN RETURN;
abortNextChar ← FALSE;
current ← BBContext.GetContents[context].lf;
WHILE current #
NIL
DO
DisplayLocalFrame[current, args, vars];
current ← AMTypes.DynamicParent[current];
ENDLOOP;
};
DisplayTV:
PROC [tv:
TV, newLine:
BOOL ←
TRUE] =
TRUSTED {
PrintTV.Print[tv, putClosure, defaultDepth, defaultWidth];
IF newLine THEN putProc[NIL, '\n];
};
utility procs
WalkContext:
PROC [delta:
INT ← 1]
RETURNS [lf:
TV ←
NIL] =
TRUSTED {
current: TV ← NIL;
context: Context ← NIL;
action: Action ← NIL;
[action, context] ← BBFocus.GetDefaultActionAndContext[];
IF action = NIL OR context = NIL THEN RETURN;
abortNextChar ← FALSE;
current ← BBContext.GetContents[context].lf;
IF current = NIL THEN {Kvetch["What current frame?"]; RETURN};
SELECT delta
FROM
< 0 => {
advance one frame "later" in frame order
lag: TV ← lf ← action.event.frame; -- start at top
lagDist: INT ← 0;
IF BBFocus.SameLocalFrame[lf, current]
THEN
lf ← NIL;
WHILE lf #
NIL
DO
next: TV ← AMTypes.DynamicParent[lf];
IF abortNextChar
THEN {
abortNextChar ← FALSE; Kvetch["Walk aborted!"]; ERROR ABORTED};
IF BBFocus.SameLocalFrame[lf, current]
THEN {
found it! (or something close)
lf ← lag;
EXIT};
SELECT delta
FROM
= -1 => lag ← lf;
< lagDist => lagDist ← lagDist - 1;
ENDCASE => lag ← AMTypes.DynamicParent[lag];
lf ← next;
IF next = NIL THEN EXIT;
ENDLOOP;
};
> 0 => {
advance one frame "earlier" in frame order
lf ← AMTypes.DynamicParent[current];
WHILE (delta ← delta - 1) > 0
AND lf #
NIL
DO
next: TV ← AMTypes.DynamicParent[lf];
IF abortNextChar
THEN {
abortNextChar ← FALSE;
Kvetch["Walk aborted!"];
ERROR ABORTED};
IF next = NIL THEN EXIT;
lf ← next;
ENDLOOP;
};
ENDCASE;
IF lf = NIL THEN {Kvetch["No context change."] ; RETURN};
context ← BBContext.ContextForLocalFrame[lf];
BBFocus.SetDefaultActionAndContext[action, context];
BBAction.ForceChange[];
};
GetCurrentAction:
PROC
RETURNS [action: Action] =
TRUSTED {
abortNextChar ← FALSE;
action ← BBFocus.GetDefaultActionAndContext[].action;
IF action =
NIL
OR action.status # pendingOut
THEN {
Kvetch["No current action."]; action ← NIL};
};
GetCurrentWorld:
PROC
[context: Context ← NIL] RETURNS [world: World] = TRUSTED {
abortNextChar ← FALSE;
IF context =
NIL
THEN {
context ← BBFocus.GetDefaultActionAndContext[].ctx;
IF context = NIL THEN context ← BBContext.GetDefaultGlobalContext[]};
world ← BBContext.GetContents[context].world;
IF world = NIL THEN world ← WorldVM.LocalWorld[];
};
ShowOption:
PROC [button: Buttons.Button, flag:
BOOL] =
TRUSTED {
IF flag
THEN Buttons.SetDisplayStyle[button, $WhiteOnBlack]
ELSE Buttons.SetDisplayStyle[button, $BlackOnWhite];
};
BreakFromLocation:
PROC [loc: Location]
RETURNS [BreakIndex] = {
return the first breakpoint index for the given location
IF loc = NIL THEN RETURN [NullIndex];
FOR i: BreakIndex ← BBBreak.NextBreak[NullIndex], BBBreak.NextBreak[i]
WHILE NOT (i = NullIndex) DO
bid: BreakId ← BBBreak.FindBreakId[i];
IF bid #
NIL
THEN
-- see if this one is the right one
IF BBObjectLocation.IsLocationAtLocation[loc, bid.loc]
THEN
RETURN [i]
ENDLOOP;
RETURN [NullIndex]
};
Kvetch:
PROC [msg1,msg2,msg3,msg4:
ROPE ←
NIL] =
TRUSTED {
msg: ROPE ← Rope.Cat[msg1,msg2,msg3,msg4];
IF msg = NIL THEN msg ← emptyName;
Labels.Set[errorLabel, errorMsg ← msg];
};
KvetchMore:
PROC [msg1,msg2,msg3,msg4:
ROPE ←
NIL] =
TRUSTED {
msg: ROPE ← Rope.Cat[errorMsg, msg1,msg2,msg3,msg4];
IF msg = NIL THEN msg ← emptyName;
Labels.Set[errorLabel, errorMsg ← msg];
};
Report: BBVForUserExec.ReportProc = {
Kvetch[msg];
};
KvetchBreak:
PROC [break: BreakIndex, msg1,msg2:
ROPE ←
NIL] =
TRUSTED {
Kvetch["Break #", RopeFromInt[break], msg1, msg2];
};
RopeFromInt:
PROC [int:
INT]
RETURNS [
ROPE] = {
RETURN [Convert.ValueToRope[[signed[int]]]];
};
LabelWatcher:
PROC = {
changeNum: INT ← 0;
action, lastAction: Action ← NIL;
event: Event ← NIL;
maxReportedId: BBAction.ActionId ← 0;
ctx, lastCtx: Context ← NIL;
max: NAT ← labelMax;
buffer: REF TEXT ← NEW[TEXT[max]];
oldDefCtx: Context ← NIL;
inner:
PROC =
TRUSTED {
localMax: BBAction.ActionId ← maxReportedId;
defCtx: Context ← NIL;
changeNum ← BBAction.WaitForChange[changeNum];
IF container.destroyed THEN RETURN;
[action, ctx] ← BBFocus.GetDefaultActionAndContext[];
event ← NIL;
IF action =
NIL
OR action.status # pendingOut
THEN
if the action was clobberred for some reason...
BBFocus.SetDefaultActionAndContext[action ← NIL, ctx ← NIL];
FOR act: Action ← BBAction.NextPendingAction[
NIL],
BBAction.NextPendingAction[act] WHILE act # NIL DO
report all new actions
IF act.status # pendingOut THEN LOOP;
IF act.id <= maxReportedId THEN EXIT;
putRope["\n"];
DisplayAction[act];
IF act.id > localMax THEN localMax ← act.id;
IF action = NIL THEN {action ← act; ctx ← NIL};
ENDLOOP;
maxReportedId ← localMax;
IF action #
NIL
AND ctx =
NIL
THEN
ctx ← BBContext.ContextForLocalFrame[action.event.frame];
defCtx ← BBContext.GetDefaultGlobalContext[];
IF action # lastAction
OR ctx # lastCtx
OR defCtx # oldDefCtx
THEN {
we have to update the label
addChar:
PROC [c:
CHAR] =
TRUSTED {
IF len < max THEN {buffer[len] ← c; len ← len + 1}
};
addRope:
PROC [r:
ROPE] =
TRUSTED {
FOR i:
INT
IN [0..r.Size[])
DO
addChar[r.Fetch[i]];
ENDLOOP;
};
setLabel:
PROC [label: Labels.Label] =
TRUSTED {
msg: ROPE ← NIL;
buffer.length ← len;
msg ← Rope.FromRefText[buffer];
IF msg.Size[] = 0 THEN msg ← emptyName;
Labels.Set[label, msg];
len ← 0;
max ← labelMax;
};
len: NAT ← 0;
putProc: PrintTV.PutProc = TRUSTED {addChar[c]};
world: World ← GetCurrentWorld[ctx];
set the action # and process #
kind: ROPE ← NIL;
tv: TV ← NIL;
tempCtx: Context ← ctx;
max ← labelMax;
IF action #
NIL
AND action.status # dead
THEN {
show the action attributes
event: Event ← action.event;
SELECT action.kind
FROM
break => kind ← "break";
signal => kind ← "signal";
other => kind ← "other";
ENDCASE => kind ← "??";
addRope["Action #"];
Convert.MapValue[addChar, [signed[action.id]]];
addRope[", "]; addRope[kind];
IF event #
NIL
THEN {
addRope[", process = "];
Convert.MapValue
[addChar,
[unsigned[AMBridge.TVToCardinal[event.process], 8]]];
addRope["B"]};
};
IF len = 0 THEN addRope["No action"];
IF world #
NIL
THEN {
addRope[", world = "];
addRope[WorldVM.WorldName[world]]};
setLabel[headLabel];
IF tempCtx = NIL THEN tempCtx ← defCtx;
tv ← BBContext.GetContents[tempCtx].lf;
IF tv = NIL THEN tv ← BBContext.GetContents[tempCtx].gf;
IF tv # NIL THEN PrintTV.Print[tv: tv, put: [putProc]];
setLabel[frameLabel];
BBFocus.SetDefaultActionAndContext[lastAction ← action, lastCtx ← ctx];
oldDefCtx ← defCtx;
};
};
each:
PROC =
TRUSTED {
msg: ROPE ← BBSafety.Mother[inner];
IF msg # NIL THEN putRopes["\nBELCH! Error in reporting loop: ", msg, "\n"];
};
WHILE
NOT container.destroyed
DO
BBDisableBreaks.DisableBreakPoints[each ! ABORTED => EXIT];
ENDLOOP;
watchdogProcess ← NIL;
};
Init:
PROC =
TRUSTED {
IF watchdogProcess # NIL THEN RETURN;
Commander.Register[
"bbv",
BuildTool,
"BBV is an alternative interface to some BugBane commands."];
};
Init[];