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: ROPENIL; -- shadows contents of errorLabel
container: ViewerClasses.Viewer ← NIL;
watchdogProcess: PROCESS ← NIL;
labelMax: NAT ← 64;
entryOption: BOOLFALSE;
exitOption: BOOLFALSE;
oneShotOption: BOOLFALSE;
allVarsOption: BOOLFALSE;
abortNextChar: BOOLFALSE;
emptyName: ROPE ← " ";
ts: TypeScript.TSNIL; -- 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],
paint: TRUE];
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: ROPENIL;
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: ROPENIL;
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: TVNIL;
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: ROPENIL;
index: INT ← -1;
backupPC: BOOLFALSE;
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: TVNIL;
tryFrame: BOOLTRUE;
errmsg: ROPENIL;
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: ROPENIL] = {
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: BOOLFALSE] = 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: REFNIL;
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: BOOLFALSE] = 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: TVNIL;
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: BOOLFALSE] = 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: BOOLFALSE] = TRUSTED {
current: TVNIL;
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: BOOLTRUE] = TRUSTED {
PrintTV.Print[tv, putClosure, defaultDepth, defaultWidth];
IF newLine THEN putProc[NIL, '\n];
};
utility procs
WalkContext: PROC [delta: INT ← 1] RETURNS [lf: TVNIL] = TRUSTED {
current: TVNIL;
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: ROPENIL] = 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: ROPENIL] = 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: ROPENIL] = 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 TEXTNEW[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: ROPENIL;
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: ROPENIL;
tv: TVNIL;
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[];
END.