-- File: Dispatch.mesa  edit by:
  -- Bruce October 21, 1980  12:46 PM
  -- Sandman July 30, 1980  9:47 AM
  
DIRECTORY
  Actions USING [
    AsciiDisplay, AsciiRead, AttachImage, AttachLoadState, CallInterpreter, CallNub,
    DisplayFrame, DisplayModule, DisplayStack, DoKill, DoProceed, DoQuit, FindVar,
    OctalRead, OctalWrite, PrintCoremap, SearchMode, SetOctalContext, 
    SetProcessContext, StartUser, TeleDebug, TreeMode, UserScreen, WorryMode],
  Ascii USING [ControlC, ControlD, ControlN, ControlS, ControlT, DEL, ESC, SP],
  BP USING [
    AttachCondition, AttachExpression, BreakAllEntries, BreakAllXits, BreakEntry,
    BreakExit, ClearAllBreaks, ClearAllEntries, ClearAllXits, ClearBreak, ClearCondition, 
    ClearDefault, ClearEntryBreak, ClearEntryTrace, ClearExpression, ClearOctal,
    ClearXitBreak, ClearXitTrace, Conditionalize, Expressionalize,
    List, ListBreak, ListBreaks, OctalBreak, TraceAllEntries, TraceAllXits, TraceEntry,
    TraceExit],
  CommandList USING [Command, Error],
  Commands USING [
    Command, Confirm, DispatchChar, Error, Execute, GetComment, GetString, GetTwoStrings,
    Login, ModuleBreak, Umbrella, WriteCommand, WriteError],
  DContext USING [
    DisplayConfig, DisplayCurrent, ListConfigs, Reset, SetConfig, SetModule,SetRootConfig],
  DebugOps USING [
    Abort, BBHandle, fileSW, InvalidateFileCache, Kill, Proceed, Quit, UserAborted],
  DOutput USING [Char, Decimal, EOL, Line, Text],
  DPsb USING [
    DisplayProcess, DisplayQueue, DisplayReadyList, ListProcesses, ResetCache],
  DSyms USING [AttachSymbols],
  Dump USING [EvalStack],
  Frames USING [FlushFrameCache],
  Gf USING [DisplayGFT],
  Init USING [CoreSwap, FlushCaches, TopLevel],
  MachineDefs USING [CoPilot, FHandle, GFHandle],
  Nub USING [DoCommand],
  State USING [Get, GetGS, GSHandle, Handle, Pop, Push, top],
  String USING [AppendChar, LowerCase],
  TextSW USING [BlinkingCaret],
  UserInput USING [userAbort],
  TajoMisc USING [SetState];
  
Dispatch: PROGRAM
  IMPORTS
    Actions, BP, Commands, DContext, DebugOps, DOutput, DPsb, DSyms, Dump, 
    Frames, Gf, Init, Nub, State, String, UserInput, TajoMisc, TextSW 
  EXPORTS Commands =
  BEGIN OPEN Actions, Commands;
  
  Command: PUBLIC TYPE = CommandList.Command;
  Error: PUBLIC TYPE = CommandList.Error;
  GFHandle: TYPE = MachineDefs.GFHandle;
  FHandle: TYPE = MachineDefs.FHandle;
  
  data: State.GSHandle ← State.GetGS[];
  
  CommandNotAllowed: PUBLIC SIGNAL = CODE;
  
  SmashedContext: ERROR = CODE;
  
  DoExp: PUBLIC PROC [param: DebugOps.BBHandle] = 
    BEGIN
    IF param = NIL THEN RETURN;
    IF param.bt.bt = trace THEN {
      SendChars[SELECT param.bt.ex FROM
	entry => "DSP"L, exit => "DSR"L, ENDCASE => "DSV"L];
      [] ← TajoMisc.SetState[on]};
    IF param.exp # NIL THEN SendChars[param.exp];
    END;
    
  SendChars: PROC [s: STRING] =
    BEGIN
    FOR i: CARDINAL IN [0..s.length) DO
      IF UserInput.userAbort THEN SIGNAL DebugOps.UserAborted;
      data.parse[s[i]];
      ENDLOOP;
    END;
    
    
  Go: PUBLIC PROCEDURE [bb: DebugOps.BBHandle ← NIL] =
    BEGIN
    State.Push[];
    data.inNub ← FALSE;
    IF data.StatePtr = NIL THEN data.initBCD ← TRUE;
    DContext.Reset[];
    IF data.signal # LOOPHOLE[0] THEN Commands.Umbrella[ucs, 0];
    DO
      Prompt[];
      BEGIN ENABLE
	BEGIN
	DebugOps.Abort, ABORTED => CONTINUE;
	DebugOps.Kill => GOTO kill;
	DebugOps.Quit =>
	  IF data.inNub THEN {LeaveNub[]; CONTINUE} ELSE GOTO abort;
	DebugOps.Proceed =>
	  IF data.inNub THEN {LeaveNub[]; CONTINUE} ELSE EXIT;
	UNWIND => State.Pop[];
	END;
      thisBreak ← bb;
      Commands.Umbrella[exp, bb ! ANY => {bb ← NIL; REJECT}];
      bb ← NIL;
      [] ← TajoMisc.SetState[on];
      Commands.Umbrella[notifier,NIL];
      EXITS
	kill =>
	  BEGIN
	  State.Pop[];
	  Init.CoreSwap[kill ! DebugOps.Abort => LOOP];
	  SIGNAL DebugOps.Abort;
	  END;
	abort =>
	  BEGIN
	  State.Pop[];
	  Init.CoreSwap[quit ! DebugOps.Abort => LOOP];
	  SIGNAL DebugOps.Abort;
	  END;
      END;
      ENDLOOP;
    State.Pop[];
    RETURN
    END;
    
  thisBreak: DebugOps.BBHandle;
  LeaveNub: PROC = {data.nubLevel ← data.nubLevel - 1; data.inNub ← FALSE};
  DebuggingMode: PUBLIC PROC = BEGIN data.debugging ← ~data.debugging END;
  
  Invalidate: PROC = {
    Frames.FlushFrameCache[];
    DPsb.ResetCache[];
    Init.FlushCaches[flushSymbols];
    DebugOps.InvalidateFileCache[]};
    
  DisplayB: PROC [s: STRING] = {
    SELECT TRUE FROM
      s.length # 0 => {DOutput.EOL[]; BP.ListBreak[s]};
      GetBreak[] => {DOutput.EOL[]; BP.List[thisBreak]};
      ENDCASE};
      
  ClearB: PROC [s: STRING] = {
    IF s.length # 0 THEN {BP.ClearBreak[s]; thisBreak ← NIL; RETURN};
    IF GetBreak[] THEN {BP.ClearDefault[thisBreak]; thisBreak ← NIL}};
    
  ClearC: PROC [s: STRING] = {
    IF s.length # 0 THEN {BP.ClearCondition[s]; RETURN};
    IF GetBreak[] THEN BP.Conditionalize[thisBreak,NIL]};
    
  ClearE: PROC [s: STRING] = {
    IF s.length # 0 THEN {BP.ClearExpression[s]; RETURN};
    IF GetBreak[] THEN BP.Expressionalize[thisBreak,NIL]};
    
  GetBreak: PROC RETURNS [BOOLEAN] = {
    IF thisBreak = NIL THEN {Commands.WriteError[notAtBreak, FALSE]; DOutput.EOL[]}
    ELSE {DOutput.Decimal[thisBreak.num]; DOutput.EOL[]};
    RETURN[thisBreak # NIL]};
    
  Prefix: TYPE = {
    ba, s, a, as, at, o, l, li,  d, se, b, t, ta, top, cl, cla, cle, clx, c, re};
    
  prefix: Prefix ← top;
  cs: STRING ← [4];
  
  param: STRING;
  
  GetFrame: PROC [s: STRING] =
    {param ← s; IF s # NIL THEN Confirm[null, StartFrame]};
  StartFrame: PROC = {StartUser[param]};
  
  GetDebuggee: PROC [s: STRING] =
    {param ← s; IF s # NIL THEN Confirm[null, RemoteDebuggee]};
  RemoteDebuggee: PROC = {TeleDebug[param]};
  
  DispatchChar: PUBLIC PROCEDURE [char: CHARACTER] =
    BEGIN OPEN Ascii, Commands; 
    c: CHARACTER;
    i: [0..4];
    IF data.tool THEN RETURN;
    IF prefix = top THEN
      IF char = ESC THEN
	BEGIN
	FOR i IN [0..cs.length) DO DispatchChar[cs[i]] ENDLOOP;
	RETURN
	END
      ELSE cs.length ← 0;
    String.AppendChar[cs, char];
    SELECT (c←String.LowerCase[char]) FROM
      'a =>
	SELECT prefix FROM
	  cl => BEGIN prefix ← cla; WriteCommand[all]; DOutput.Char[' ]; END;
	  b => BEGIN prefix ← ba; WriteCommand[all]; DOutput.Char[' ]; END;
	  t => BEGIN prefix ← ta; WriteCommand[all]; DOutput.Char[' ]; END;
	  top => BEGIN prefix ← a; WriteCommand[a];END;
	  ENDCASE => GOTO what;
      'b =>
	SELECT prefix FROM
	  d => GetString[[sId: bbNum, prompt: bbNum], DisplayB, break];
	  li => Confirm[breaks, BP.ListBreaks];
	  cl => GetString[[sId: bbNum, prompt: bbNum], ClearB, break];
	  cla => Confirm[breaks, BP.ClearAllBreaks];
	  cle =>
	    GetString[[sId: proc], BP.ClearEntryBreak, breakProc];
	  clx =>
	    GetString[[sId: proc], BP.ClearXitBreak, breakProc];
	  top => BEGIN prefix ← b; WriteCommand[break]; DOutput.Char[SP] END;
	  ENDCASE => GOTO what;
      'c =>
	SELECT prefix FROM
	  at => GetTwoStrings[[sId: bbNum, prompt: bbNum, resetPrompt: FALSE],
	    [sId: exp, prompt: condition, resetPrompt: FALSE, atom: FALSE],
	    BP.AttachCondition, Condition];
	  cl => GetString[[sId: bbNum, prompt: bbNum], ClearC, Condition];
	  d => Execute[config, DContext.DisplayConfig];
	  li => Confirm[configs, DContext.ListConfigs];
	  o => GetTwoStrings[[sId: frame, resetPrompt: FALSE], [
	    prompt: bytePC, sId: pc, resetPrompt: FALSE],
	    BP.ClearOctal, clearGlobal];
	  se => GetString[[sId: config], DContext.SetConfig, config];
	  top => BEGIN prefix ← c; WriteCommand[c]; END;
	  ENDCASE => GOTO what;
      'd =>
	SELECT prefix FROM
	  as => GetTwoStrings[[sId: num1,resetPrompt: FALSE], [
	    sId: num2, prompt: n10, resetPrompt: FALSE], AsciiDisplay, display];
	  top => {WriteCommand[display]; DOutput.Char[SP]; prefix ← d};
	  ENDCASE => GOTO what;
      'e =>
	SELECT prefix FROM
	  d => Execute[evalStack, Dump.EvalStack];
	  s => BEGIN WriteCommand[set]; DOutput.Char[SP]; prefix ← se END;
	  b => GetString[[sId: proc], BP.BreakEntry, entryProc];
	  ba => ModuleBreak[BP.BreakAllEntries, entriesMod];
	  t => GetString[[sId: proc], BP.TraceEntry, entryProc];
	  ta => ModuleBreak[BP.TraceAllEntries, entriesMod];
	  cl => BEGIN WriteCommand[entry]; DOutput.Char[SP]; prefix ← cle END;
	  cla => GetString[[sId: module], BP.ClearAllEntries, entriesMod];
	  ENDCASE => GOTO what;
      'f =>
	SELECT prefix FROM
	  d =>
	    GetString[[sId: frame, resetPrompt: FALSE], DisplayFrame, frame];
	  top => GetString[[sId: var], FindVar, find];
	  ENDCASE => GOTO what;
      'g =>
	SELECT prefix FROM
	  d => Execute[gft, Gf.DisplayGFT];
	  ENDCASE => GOTO what;
      'i =>
	SELECT prefix FROM
	  at => IF MachineDefs.CoPilot THEN GOTO what
	    ELSE GetString[[sId: image], Actions.AttachImage, image];
	  l => BEGIN prefix ← li; WriteCommand[list]; DOutput.Char[SP]; END;
	  ENDCASE => GOTO what;
      'k =>
	SELECT prefix FROM
	  at => GetTwoStrings[[sId: bbNum, prompt: bbNum, resetPrompt: FALSE],
	    [sId: exp, prompt: expression, resetPrompt: FALSE, atom: FALSE],
	    BP.AttachExpression, Exp];
	  cl => GetString[[sId: bbNum, prompt: bbNum], ClearE, Exp];
	  top => Confirm[kill, DoKill];
	  ENDCASE => GOTO what;
      'l =>
	SELECT prefix FROM
	  c => BEGIN prefix ← cl; WriteCommand[clear]; DOutput.Char[SP]; END;
	  at => IF MachineDefs.CoPilot THEN GOTO what
	    ELSE GetString[[sId: image], Actions.AttachLoadState, loadstate];
	  top => BEGIN prefix ← l; WriteCommand[l]; END;
	  ENDCASE => GOTO what;
      'm =>
	SELECT prefix FROM
	  d => GetString[
	    [sId: module, resetPrompt: FALSE], DisplayModule, module];
	  se => GetString[[sId: module], DContext.SetModule, moduleCtx];
	  re => GetString[[sId: temp1, resetPrompt: FALSE], GetDebuggee, remote];
	  ENDCASE => GOTO what;
      'o =>
	SELECT prefix FROM
	  c => IF MachineDefs.CoPilot THEN GOTO what ELSE Confirm[coremap, PrintCoremap];
	  l => Commands.Login[];
	  se => GetString[[sId: frame], SetOctalContext, octalCtx];
	  top => {prefix ← o; WriteCommand[octal]; DOutput.Char[SP]};
	  ENDCASE => GOTO what;
      'p =>
	SELECT prefix FROM
	  d => GetString[
	    [sId: process, resetPrompt: FALSE], DPsb.DisplayProcess, process];
	  li => Confirm[processes, DPsb.ListProcesses];
	  se => GetString[[sId: process], SetProcessContext, processCtx];
	  top => Confirm[proceed, DoProceed];
	  ENDCASE => GOTO what;
      'q =>
	SELECT prefix FROM
	  d => GetString[
	    [sId: queue, resetPrompt: FALSE], DPsb.DisplayQueue, queue];
	  top => Confirm[quit, DoQuit];
	  ENDCASE => GOTO what;
      'r =>
	SELECT prefix FROM
	  as => GetTwoStrings[[sId: num1,resetPrompt: FALSE], [
	    sId: num2, prompt: n10, resetPrompt: FALSE], AsciiRead, read];
	  d => Execute[readyList, DPsb.DisplayReadyList, FALSE];
	  o => GetTwoStrings[[sId: num1, resetPrompt: FALSE], [
	    prompt: n10, sId: num2, resetPrompt: FALSE], OctalRead, read];
	  se => GetString[[sId: rconfig], DContext.SetRootConfig, rootCtx];
	  top => {prefix ← re; WriteCommand[re]};
	  ENDCASE => GOTO what;
      's =>
	SELECT prefix FROM
	  d => Execute[stack, DisplayStack, FALSE];
	  o => GetTwoStrings[[sId: frame, resetPrompt: FALSE],
	    [sId: pc, prompt: bytePC, resetPrompt: FALSE],
	    BP.OctalBreak, breakGlobal];
	  a => BEGIN prefix ← as; WriteCommand[ascii]; DOutput.Char[SP] END;
	  at => GetTwoStrings[
	    [prompt: symbols, sId: frame, resetPrompt: FALSE], [
	    sId:file, prompt:name, resetPrompt:FALSE], DSyms.AttachSymbols];
	  re => Confirm[reset, DContext.Reset];
	  top => BEGIN prefix ← s; WriteCommand[s]; END;
	  ENDCASE => GOTO what;
      't =>
	SELECT prefix FROM
	  top => BEGIN prefix ← t; WriteCommand[trace]; DOutput.Char[SP] END;
	  cla => Confirm[traces, BP.ClearAllBreaks];
	  cle => GetString[[sId: proc], BP.ClearEntryTrace, traceProc];
	  clx =>
	    GetString[[sId: proc], BP.ClearXitTrace, traceProc];
	  s => GetString[[sId: frame, resetPrompt: FALSE], GetFrame, start];
	  a => BEGIN prefix ← at; WriteCommand[attach]; DOutput.Char[SP] END;
	  ENDCASE => GOTO what;
      'u =>
	SELECT prefix FROM
	  c => Execute[current, DContext.DisplayCurrent];
	  top => Confirm[userscreen, UserScreen];
	  ENDCASE => GOTO what;
      'w =>
	SELECT prefix FROM
	  o => GetTwoStrings[[sId: num1, resetPrompt: FALSE], [
	    prompt: gets, sId: num2, resetPrompt: FALSE, colon: FALSE],
	    OctalWrite, write];
	  top =>
	    BEGIN
	    WriteCommand[worry];
	    Confirm[IF data.worryBreaks THEN off ELSE on, WorryMode];
	    END;
	  ENDCASE => GOTO what;
      'x =>
	SELECT prefix FROM
	  b => GetString[[sId: proc], BP.BreakExit, xitProc];
	  ba => ModuleBreak[BP.BreakAllXits, xitsMod];
	  t => GetString[[sId: proc], BP.TraceExit, xitProc];
	  ta => ModuleBreak[BP.TraceAllXits, xitsMod];
	  cl => BEGIN prefix ← clx; WriteCommand[xit]; DOutput.Char[SP]; END;
	  cla => GetString[[sId:module], BP.ClearAllXits, xitsMod];
	  ENDCASE => GOTO what;
      ENDCASE =>
	SELECT TRUE FROM
	  prefix = top =>
	    SELECT char FROM
	      ControlC => {
		WriteCommand[check];
		Confirm[IF data.debugging THEN off ELSE on, DebuggingMode]};
	      ControlD => Confirm[debug, CallNub];
	      ControlN => Confirm[spare2, Invalidate];
	      ControlS =>
		BEGIN
		WriteCommand[IF data.search THEN callStack ELSE oneFrame];
		Confirm[null, SearchMode];
		END;
	      ControlT =>
		BEGIN
		WriteCommand[treePrinting];
		Confirm[IF data.tree THEN off ELSE on, TreeMode];
		END;
	      SP => CallInterpreter[TRUE];
	      '- => GetComment[TRUE];
	      '? => UnknownCommand[firstCommand, kill];
	      ENDCASE => GOTO what;
	  char = '? =>
	    SELECT prefix FROM
	      ba,ta => UnknownCommand[entriesMod, xitsMod];
	      re => UnknownCommand[remote, reset];
	      s => UnknownCommand[start, set];
	      a => UnknownCommand[ascii, attach];
	      as => UnknownCommand[adisplay, read];
	      at => IF MachineDefs.CoPilot THEN UnknownCommand[Symbols, Exp]
		ELSE UnknownCommand[image, loadstate];
	      o => UnknownCommand[read, clearGlobal];
	      l => UnknownCommand[login, list];
	      li => UnknownCommand[configs, breaks];
	      d => UnknownCommand[module, config];
	      se => UnknownCommand[config, rootCtx];
	      b,t => UnknownCommand[all, xitProc];
	      c => UnknownCommand[clear, IF MachineDefs.CoPilot THEN current ELSE coremap];
	      cl => UnknownCommand[entry, all];
	      cla => UnknownCommand[breaks, xitsMod];
	      cle => UnknownCommand[breakProc, traceProc];
	      clx => UnknownCommand[breakProc, traceProc];
	      ENDCASE => UnknownCommand[clear, current];
	  ENDCASE => GOTO what;
    RETURN
    EXITS what => UnknownChar[char];
    END;
    
  UnknownCommand: PROCEDURE [first, last: Command] =
    BEGIN OPEN DOutput; 
    i: Command;
    Line[" ?"L];
    Text["Your options are: "L];
    FOR i IN Command[first..last) DO 
      WriteCommand[i];
      Text[", "L];
      ENDLOOP;
    WriteCommand[last];
    EOL[];
    Prompt[];
    RETURN
    END;
    
  UnknownChar: PROCEDURE [char: CHARACTER] =
    BEGIN OPEN DOutput;
    IF char = Ascii.DEL THEN WriteCommand[del]
    ELSE {Char[char]; Char['?]};
    Prompt[];
    RETURN
    END;
    
  Prompt: PUBLIC PROCEDURE=
    BEGIN 
    inNub: BOOLEAN ← data.inNub;
    level: CARDINAL ← IF inNub THEN data.nubLevel ELSE data.level;
    h: State.Handle ← State.Get[];
    data.resetPrompt ← data.resetParse ← TRUE;
    DOutput.EOL[];
    THROUGH [1..level] DO DOutput.Char[IF inNub THEN '/ ELSE '>] ENDLOOP;
    data.parse ← IF inNub THEN Nub.DoCommand ELSE DispatchChar;
    TextSW.BlinkingCaret[DebugOps.fileSW, on];
    prefix ← top;
    Init.TopLevel[];
    h.interpretContext ← SELECT h.howSet FROM
      none => NIL,
      local => h.lContext,
      psb => h.lContext,
      global => h.gContext,
      state => h.lContext,
      ENDCASE => ERROR SmashedContext;
    END;
    
  END.