-- file: StackPack.Mesa
-- Edited by:
--            Bruce on October 8, 1980  11:53 AM
--            Barbara on April 4, 1979  7:28 PM
--            Sandman on January 9, 1980  9:22 AM

DIRECTORY
  Actions USING [CallInterpreter],
  Ascii USING [DEL, SP],
  Commands USING [GetComment, GetString, Prompt, Umbrella],
  DebugOps USING [fileSW, StringExpToDecimal],
  DOutput USING [Char, Decimal, EOL, Text],
  DSyms USING [GFHandle, GFrameMdi],
  Frames USING [
    DisplayLocalsF, DisplayLocalsGF, DisplayParametersF, DisplayParametersGF,
    DisplayResultsF, DisplayResultsGF, FlushFrameCache, Invalid],
  Gf USING [CheckStarted, Display, Frame, Handle, MainBody, Validate],
  Init USING [CheckSymTabLength, TopLevel],
  Lf USING [CatchFrame, Display, GF, Handle, NoPrevious, PC, Previous],
  MachineDefs USING [FHandle, GFHandle, NullGF],
  Pc USING [BytePC, Ep, Exit],
  Source USING [Display],
  State USING [Get, Handle, ResetParse, SetParse],
  String USING [LowerCase],
  Symbols USING [MDIndex, MDNull],
  SymbolTable USING [Missing],
  Table USING [Overflow],
  TextSW USING [BlinkingCaret];
  
StackPack: PROGRAM
  IMPORTS Actions, Commands, DebugOps, DOutput, DSyms, Frames, Gf, 
    Init, Lf, Pc, Source, State, String, SymbolTable, Table, TextSW
  EXPORTS Actions, Commands =
  BEGIN
  
  FHandle: TYPE = MachineDefs.FHandle;
  GFHandle: TYPE = MachineDefs.GFHandle;
  
  DFMsg: TYPE = {
    invalid, noSyms, options, gso, del, na, source, npf, dso, catch, lso};
    
  StackOptions: TYPE = {global, local, limited};
  options: StackOptions;
  
  WriteMsg: PROCEDURE [msg: DFMsg] =
    BEGIN
    DOutput.Text[SELECT msg FROM
      invalid => " ! Current context invalid."L,
      noSyms => "No symbols for "L,
      options => "--Options are: "L,
      gso =>
	""" "", --, List source, Parameters, Quit, Return values, Source, Variables"L,
      del => " XXX"L,
      na => " not available"L,
      source => " Source: "L,
      npf => "No previous frame!"L,
      dso => ", Globals, Jump, Next"L,
      catch => "CatchFrame:  "L,
      lso => "Jump, Next, Quit  >"L,
      ENDCASE => "?"L];
    END;
    
  DisplayStack: PUBLIC PROCEDURE =
    BEGIN
    h: State.Handle ← State.Get[];
    DOutput.EOL[];
    SELECT TRUE FROM
      h.lContext # NIL => LocalDump[h.lContext];
      h.gContext # NIL => GlobalDump[h.gContext];
      ENDCASE => WriteMsg[invalid];
    END;
    
  DisplayModule: PUBLIC PROCEDURE [m: STRING] =
    BEGIN --dump the global frame named by m
    f: MachineDefs.GFHandle ← MachineDefs.NullGF;
    f ← Gf.Frame[m ! Frames.Invalid => CONTINUE];
    IF f # MachineDefs.NullGF THEN GlobalDump[f];
    RETURN
    END;
    
  DumpFrame: PUBLIC PROCEDURE [f: UNSPECIFIED] =
    BEGIN IF ~Gf.Validate[f] THEN LocalDump[f] ELSE GlobalDump[f] END;
    
  Caret: PROC = 
    {DOutput.Text["  >"L]; TextSW.BlinkingCaret[DebugOps.fileSW, on]};
    
  GlobalDump: PROCEDURE [gf: GFHandle] = 
    BEGIN    --dump a global frame
    f: FHandle ← Gf.MainBody[gf];
    mdi: Symbols.MDIndex ← Symbols.MDNull;
    IF f # NIL THEN {LocalDump[f]; RETURN};
    DOutput.EOL[];
    mdi ← DSyms.GFrameMdi[gf ! SymbolTable.Missing => CONTINUE];
    DOutput.EOL[];
    IF mdi = Symbols.MDNull THEN {
      WriteMsg[noSyms]; Gf.Display[gf, NIL]; State.ResetParse[]; RETURN};
    Gf.Display[gf, NIL];
    State.Get[].h.interpretContext ← gf; options ← global;
    State.SetParse[StackCommands];
    Caret[];
    RETURN
    END;
    
  LocalDump: PROCEDURE [f: FHandle] = 
    BEGIN
    mdi: Symbols.MDIndex ← Symbols.MDNull;
    DOutput.EOL[];
    mdi ← DSyms.GFrameMdi[Lf.GF[f] ! SymbolTable.Missing => CONTINUE];
    State.Get[].h.interpretContext ← f;
    IF mdi = Symbols.MDNull THEN {WriteMsg[noSyms]; options ← limited}
    ELSE options ← local;
    IF Lf.CatchFrame[f] THEN WriteMsg[catch]; 
    Lf.Display[f];
    State.SetParse[StackCommands];
    Caret[];
    END;
    
  Jump: PROC [s: STRING] = {DumpJump[DebugOps.StringExpToDecimal[s]]};
  
  DumpJump: PROCEDURE [n: INTEGER] = 
    BEGIN
    i: INTEGER;
    frame: FHandle ← State.Get[].h.interpretContext;
    FOR i IN [0..n) DO
      frame ← Lf.Previous[frame ! Lf.NoPrevious =>
	BEGIN OPEN DOutput;
	IF i < n-1 THEN BEGIN Char['(]; Decimal[i]; Char[')] END;
	EXIT;
	END];
	IF i MOD 50 = 0 THEN Frames.FlushFrameCache[];
      ENDLOOP;
    DOutput.EOL[];
    LocalDump[frame];
    RETURN
    END;
    
  DoSource: PROC [frame: POINTER, load: BOOLEAN] = {
    SELECT options FROM
      local => {
	pc: Pc.BytePC ← Lf.PC[frame];
	gf: GFHandle ← Lf.GF[frame];
	IF Pc.Exit[frame, pc] THEN {
	  DOutput.Text[" at exit. "L];
	  pc ← Pc.Ep[pc, gf].start};
	Source.Display[gf, pc, load]};
      global => Source.Display[frame,[0],load];
      ENDCASE => BadChar[]};
      
  prompt: BOOLEAN;
  
  StackCommands: PROCEDURE [char: CHARACTER] = {
    prompt ← TRUE;
    Init.TopLevel[];
    Commands.Umbrella[stack, char];
    IF prompt THEN {Caret[]; TextSW.BlinkingCaret[DebugOps.fileSW, on]}};
    
  UDS: PUBLIC PROCEDURE [char: CHARACTER] =
    BEGIN ENABLE Table.Overflow => {Init.CheckSymTabLength[]; RETRY};
    frame: POINTER ← State.Get[].h.interpretContext;
    IF char # Ascii.SP AND char # Ascii.DEL THEN
      {DOutput.Char[char]; TextSW.BlinkingCaret[DebugOps.fileSW, off]};
    SELECT String.LowerCase[char] FROM
      'j =>
	IF options # global THEN {
	  prompt ← FALSE;
	  Commands.GetString[[sId:temp1, resetPrompt:FALSE],Jump,n10]}
	ELSE BadChar[];
      'n => IF options # global THEN {
	  DOutput.EOL[];
	  LocalDump[Lf.Previous[frame ! Lf.NoPrevious => GOTO npf]];
	  prompt ← FALSE}
	ELSE BadChar[];
      'p => SELECT options FROM
	local => Frames.DisplayParametersF[frame];
	global => {[] ← Gf.CheckStarted[frame]; Frames.DisplayParametersGF[frame]};
	ENDCASE => BadChar[];
      'v => SELECT options FROM
	local => Frames.DisplayLocalsF[frame];
	global => {[] ← Gf.CheckStarted[frame]; Frames.DisplayLocalsGF[frame]};
	ENDCASE => BadChar[];
      'r => SELECT options FROM
	local => Frames.DisplayResultsF[frame];
	global => {[] ← Gf.CheckStarted[frame]; Frames.DisplayResultsGF[frame]};
	ENDCASE => BadChar[];
      's => DoSource[frame,TRUE];
      'l => DoSource[frame,FALSE];
      'g =>
	IF options = local THEN Frames.DisplayLocalsGF[Lf.GF[frame]] ELSE BadChar[];
      'q, Ascii.DEL => {Commands.Prompt[]; prompt ← FALSE; RETURN};
      Ascii.SP => {Actions.CallInterpreter[]; prompt ← FALSE; RETURN};
      '- => {Commands.GetComment[FALSE]; prompt ← FALSE; RETURN};
      '? => ListOptions[];
      ENDCASE => BadChar[];
    RETURN;
    EXITS
      npf => {DOutput.EOL[]; WriteMsg[npf]; prompt ← FALSE; Commands.Prompt[]};
    END;
    
  BadChar: PROC = {DOutput.Char['?]};
    
  ListOptions: PROC = {
    WriteMsg[options];
    IF options = limited THEN WriteMsg[lso]
    ELSE {WriteMsg[gso]; IF options = local THEN WriteMsg[dso]};
    DOutput.EOL[]};
      
      
  END.