home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / dbguser / commands.sml < prev    next >
Encoding:
Text File  |  1993-01-27  |  21.1 KB  |  707 lines

  1. (* User-level debugger code. *)
  2. structure UserDebugCommands : 
  3. sig
  4.    type int
  5.    type string
  6.    type unit
  7.    type 'a option
  8.    type 'a ref
  9.    val selectCurrent : unit -> unit
  10.    val selectBackTrace : unit -> unit
  11.    val selectNear: string -> int -> unit
  12.    val selectNext: unit -> unit
  13.    val selectPrev: unit -> unit
  14.    val showEvents: string -> unit
  15.    val breakWhen: int -> int
  16.    val breakNear: (string * int * int) -> int option
  17.    val deleteBreak: int -> unit
  18.    val clearBreaks: unit -> unit
  19.    val showBreaks: unit -> unit
  20.    val showBreakTimes: unit -> unit
  21.    val toggleBreak: unit -> unit
  22.    val bfunc: (unit -> unit) -> unit
  23.    val tfunc: int -> (unit -> unit) -> unit
  24.    val nofunc: int -> unit
  25.    val current : unit -> unit
  26.    val ss : unit -> unit
  27.    val ssb : unit -> unit
  28.    val forward: unit -> unit
  29.    val backward: unit -> unit
  30.    val jump: int -> unit
  31.    val sk: unit -> unit
  32.    val skb: unit -> unit
  33.    val jumpTrace: unit -> unit
  34.    val showCalls: int -> unit
  35.    val upCall: unit -> unit
  36.    val downCall: unit -> unit
  37.    val showVal: string -> unit
  38.    val emacsShowVal: string -> unit
  39.    val complete: unit -> unit
  40.    val abort: unit -> unit
  41.    val usedbg: string -> unit
  42.    val usedbg_live: string -> unit
  43.    val usedbg_stream: instream -> unit
  44.    val usedbg_string : string -> unit
  45.    val usedbg_script: instream -> instream -> unit
  46.    val run: string -> unit
  47.    val execute: string -> unit
  48.    val debugdebug: bool -> unit
  49.    val emacsInit: unit -> unit
  50.    val cd: string -> unit
  51.    val haltOnSignal: System.Signals.signal * bool -> unit
  52.    val setSignal: System.Signals.signal -> unit
  53.    val clearSignal: System.Signals.signal -> unit
  54.    nonfix it selectCurrent selectBackTrace selectNear
  55.        selectNext selectPrev showEvents breakWhen breakNear
  56.        deleteBreak clearBreaks showBreaks showBreakTimes
  57.        toggleBreak bfunc tfunc nofunc current ss ssb forward backward
  58.        jump sk skb jumpTrace showCalls upCall downCall
  59.        showVal emacsShowVal complete abort usedbg usedbg_live
  60.        usedbg_stream usedbg_string usedbg_script run execute debugdebug cd 
  61.        haltOnSignal setSignal clearSignal
  62. end
  63.  = struct
  64.  open System.Control.Debug
  65.  open UserDebugUtil UserDebugInterface UserDebugBreaks UserDebugEmacs
  66.  
  67.  val say = System.Print.say
  68.  
  69.  type int = int
  70.  type string = string
  71.  type unit = unit
  72.  type 'a option = 'a option
  73.  type 'a ref = 'a ref
  74.  nonfix it selectCurrent selectBackTrace selectNear
  75.         selectNext selectPrev showEvents breakWhen breakNear
  76.     deleteBreak clearBreaks showBreaks showBreakTimes
  77.     toggleBreak bfunc tfunc nofunc current ss ssb forward backward
  78.     jump sk skb jumpTrace showCalls upCall downCall
  79.     showVal emacsShowVal complete abort usedbg usedbg_live
  80.     usedbg_stream usedbg_string usedbg_script run execute debugdebug cd 
  81.     haltOnSignal setSignal clearSignal
  82.  
  83.  
  84.  val _ = debugging := true
  85.  
  86.  (* When running under Emacs, we need to know the current working 
  87.   * directory so that we can equate filenames that the user gives us, 
  88.   * which may be relative to the current directory, with filenames that
  89.   * Emacs gives us, which are absolute.
  90.   * getWD is horribly slow and unreliable, so we remember the current directory
  91.   * in currentWD, rebind cd to update this reference, and force an emacs
  92.   * dbg session to issue a cd to the current directory first thing. *)
  93.  val currentWD = ref ""
  94.  fun cd s = (System.Directory.cd s;
  95.          currentWD := absolute s (!currentWD))
  96.  
  97.  
  98.  (* Selection functions *)
  99.  
  100.  fun selectCurrent () =
  101.  (* Command run by M-c in emacs.  Select the current event. *)
  102.      emacsSelect (!currentEv)
  103.  
  104.  fun selectBackTrace () =
  105.  (* Select the backtrace event, or the current event if there is no
  106.   * backtrace event.  Not currently used; perhaps this should be bound
  107.   * to some key? *)
  108.      emacsSelect (case !backtrace of
  109.               SOME (_, (ev, _)) => SOME ev
  110.             | NONE => !currentEv)
  111.  
  112.  fun selectNear filename cp =
  113.  (* Command run by M-e in emacs.  Select an event near the given character
  114.   * position. *)
  115.      emacsSelect
  116.      (SOME (hd (ZeventsAfterLocation
  117.         (if filename = runBufferName
  118.              then runName else filename, cp)))
  119.       handle Hd => NONE)
  120.  
  121.  fun selectNext () =
  122.  (* Command run by M-n in emacs.  Select the next event. *)
  123.      case ofSome(nextEvent, !selected) of
  124.      SOME e => emacsSelect (SOME e)
  125.        | NONE => emacsError "No further events"
  126.  
  127.  fun selectPrev () =
  128.  (* Command run by M-p in emacs.  Select the previous event. *)
  129.      case ofSome(prevEvent, !selected) of
  130.      SOME e => emacsSelect (SOME e)
  131.        | NONE => emacsError "No previous events"
  132.  
  133.  (** Text display functions.
  134.   ** These display debugger information in a textual format. *)
  135.  
  136.  fun prLoc ((file:filename,charno:charno),vis:visible) =
  137.    (say "file \""; say file; say "\"";
  138.     if not vis then say " [hidden version]" else ();
  139.     if !emacs then 
  140.       (say " char "; say(makestring charno))
  141.     else 
  142.       let val (line,pos) = ZlineposForCharno (file,charno)
  143.       in say " line "; say(makestring line); say " pos "; print(makestring pos)
  144.       end)
  145.  
  146.  fun prWhere where =
  147.    let val (s,_,loc,vis) = ensureD(ZeventDesc where, "prWhere") 
  148.    in say (s ^ " event at "); prLoc (loc,vis)
  149.    end
  150.  
  151.  fun prWhereWhen ((where,when):wherewhen) =
  152.      (prWhere where;
  153.       printL [" (time ", makestring when, ")"])
  154.  
  155.  fun prExn () =
  156.    let val exn = 
  157.        safeQuery(fn now => 
  158.              let val (_,finalTime) = YboundingTimes()
  159.              in case Yexception() of
  160.              SOME exn => if now = finalTime then
  161.                  SOME exn
  162.                      else NONE
  163.                | NONE => NONE
  164.              end)
  165.    in case exn of 
  166.         SOME exn => (say "[Execution blocked by exception: ";
  167.                  say (System.exn_name exn);
  168.              say " ";
  169.              case exn of 
  170.                (* known exceptions *)
  171.                Io s => say s
  172.              | System.Unsafe.CInterface.SystemCall s => say s
  173.              | _ => (* unknown exn *)
  174.                 safeQuery (fn _ =>
  175.                      case YexnArg exn of
  176.                        SOME (x,t) => YprintVal(x,t)
  177.                      | NONE => ());
  178.              say "]\n")
  179.       | NONE => ()
  180.    end
  181.  
  182.  
  183.  fun prSignal () =
  184.   let val signal = safeQuery (fn _ => Ysignal())
  185.       open System.Signals
  186.       fun makestring SIGHUP = "SIGHUP"
  187.         | makestring SIGINT = "SIGINT"
  188.     | makestring SIGQUIT = "SIGQUIT"
  189.     | makestring SIGALRM  = "SIGALRM"
  190.     | makestring SIGTERM = "SIGTERM"
  191.     | makestring SIGURG = "SIGURG"
  192.     | makestring SIGCHLD = "SIGCHLD" 
  193.     | makestring SIGIO = "SIGIO"
  194.     | makestring SIGWINCH = "SIGWINCH"
  195.     | makestring SIGUSR1 = "SIGUSR1"
  196.     | makestring SIGUSR2 = "SIGUSR2"
  197.     | makestring SIGTSTP = "SIGTSTP"
  198.     | makestring SIGCONT = "SIGCONT"
  199.     | makestring SIGGC = "SIGGC"
  200.         | makestring SIGVTALRM = "SIGVTALRM"
  201.     | makestring SIGPROF = "SIGPROF"
  202.   in case signal of
  203.        SOME signal => say (implode["[About to deliver signal ",
  204.                      makestring signal, ".]\n"])
  205.      | NONE => ()
  206.   end
  207.  
  208.  val haltOnSignal = ZhaltOnSignal
  209.  
  210.  val setSignal = XsetSignal
  211.  val clearSignal = XclearSignal
  212.  
  213.  fun showEvents filename =
  214.     let fun f loc =
  215.       let val whrl = ZeventsAfterLocation loc
  216.           val (_,_,(_,charno),_) =
  217.           ensureD(ZeventDesc (hd whrl) (* may raise Hd *),
  218.               "showEvents")
  219.           fun p whr =
  220.         let val (s,_,_,_) = ensureD(ZeventDesc whr, "showEvents")
  221.         in say "\t"; say s
  222.         end
  223.       in if !emacs then say(makestring charno)
  224.          else let val (line,pos) = ZlineposForCharno (filename,charno)
  225.           in say(makestring line); say "\t"; say(makestring pos)
  226.           end;
  227.          app p whrl;
  228.          say "\n";
  229.          f (filename,charno+1)
  230.       end
  231.     in f (filename,1) handle Hd => ()
  232.     end
  233.  
  234.  (** Breakpoints
  235.   ** Every breakpoint has an associated id, which is returned when the
  236.   ** breakpoint is set and which is used to refer to the breakpoint. *)
  237.  
  238.  (* Insert a breakpoint at a given time. Intended for use outside of emacs. *)
  239.  fun breakWhen time =
  240.      insertBreak (TIME time)
  241.  
  242.  (* Set breakpoint at an event near given line/character position. 
  243.     Intended for use outside of emacs *)
  244.  fun breakNear (filename:string,line:int,pos:int) : int option =
  245.      let val cp = ZcharnoForLinepos(filename,line,pos)
  246.      in SOME (insertBreak (EVENT (hd (ZeventsAfterLocation (filename,cp)))))
  247.      handle Hd => NONE
  248.      end
  249.  
  250.  (* For internal use. *)
  251.  fun breakWhere place = 
  252.  (* Insert a breakpoint at the given event. *)
  253.      emacsModify [place] (fn () => insertBreak (EVENT place))
  254.  
  255.  fun modifyBreak bn f =
  256.  (* Perform a function that may modify the given breakpoint, updating the
  257.   * screen appropriately if under emacs. *)
  258.    if !emacs then
  259.      let val ev =
  260.      case (getBreak bn) of
  261.          SOME (EVENT e) => SOME e
  262.        | _ => NONE
  263.      in emacsModify (somes [ev]) f
  264.      end
  265.    else f()
  266.  
  267.  
  268.  fun deleteBreak (bn:int) =
  269.  (* Delete a breakpoint, given its id. *)
  270.      modifyBreak bn
  271.       (fn () =>
  272.        (resetBreakFunc bn;
  273.     if (not (removeBreak bn)) then
  274.       (say "[Error: breakpoint #"; say(makestring bn); say " doesn't exist.]\n")
  275.     else ()))
  276.  
  277.  fun clearBreaks () =
  278.  (* Delete all breakpoints. *)
  279.      app (fn (n, _) => deleteBreak n) (!breakList)
  280.  
  281.  fun setBreakFunc (bn, f) =
  282.  (* Set the break function at the given breakpoint. *)
  283.      modifyBreak bn (fn () =>
  284.              (resetBreakFunc bn;  (* in case some function was already
  285.                        * there *)
  286.               breakFuncList := (bn, f) :: (!breakFuncList)))
  287.  
  288.  fun showBreaks () =
  289.  (* Show all breakpoints.  Primarily intended to be used outside emacs, but
  290.   * might be useful in Emacs as well. *)
  291.    let fun p (n,TIME whn) =
  292.          (say(makestring n); say "\t"; say "Time ";
  293.           say(makestring whn); say "\n")
  294.      | p (n,EVENT place) =
  295.          (say(makestring n); say "\t"; prWhere place; say "\n")
  296.    in say "Breakpoints:\n";
  297.       app p (!breakList)
  298.    end
  299.  
  300.  fun showBreakTimes () =
  301.  (* Show break times in the Emacs minibuffer.  Invoked by C-M-k. *)
  302.      let val btimes =
  303.      (fold
  304.       (fn ((_, TIME t), s) => s ^ " " ^ makestring t
  305.               | (_, s) => s) (!breakList) "")
  306.      in
  307.      emacsMessage
  308.      ("Time breakpoints:" ^
  309.       (if (String.length btimes > 0) then btimes else " (none)"))
  310.      end
  311.  
  312.  fun toggleBreak () =
  313.  (* Command run by M-k in Emacs.  Toggle whether there is a breakpoint at
  314.   * the selected event. *)
  315.      case !selected of
  316.      NONE => ()
  317.        | SOME ev => 
  318.          (case breakId ev of
  319.           SOME n => deleteBreak n
  320.         | NONE => breakWhere ev)
  321.  
  322.  fun currentBreak () = (* currently unused *)
  323.  (* Returns the breakpoint number of the breakpoint at the current event
  324.   * or at the current time. *)
  325.      let val eventB = ofSome(breakId, SOME(establishedPlace()))
  326.      val eventT = ofSome(breakIdAtTime, SOME(establishedTime()))
  327.      in if isSome eventB then eventB else eventT
  328.      end
  329.  
  330.  fun selectedBreak () = (* currently unused *)
  331.  (* Returns the breakpoint number of the currently selected breakpoint,
  332.   * if any. *)
  333.      ofSome(breakId, !selected)
  334.  
  335.  fun doBreakFunc () =
  336.  (* Perform the break function at the current event or time.
  337.   * Executed after we have stopped at a breakpoint. *)
  338.      case ofSome(getBreakFunc, currentBreak ()) of
  339.      SOME f => f ()
  340.        | NONE => ()
  341.  
  342.  fun bfunc f =
  343.  (* Sets f to be the break function at the currently selected breakpoint.
  344.   * User function. *)
  345.      case selectedBreak () of
  346.      SOME bn => setBreakFunc (bn, f)
  347.        | NONE => say "[No breakpoint is selected]\n"
  348.  
  349.  fun tfunc t f =
  350.  (* Sets f to be the break function at the breakpoint at the given time.
  351.   * User function. *)
  352.      case breakIdAtTime t of
  353.      SOME bk => setBreakFunc (bk, f)
  354.        | NONE => printL ["[No breakpoint exists at time ", makestring t, "]\n"]
  355.  
  356.  fun nofunc t =
  357.  (* Resets the break function at the breakpoint at the given time.
  358.   * User function. *)
  359.      case breakIdAtTime t of
  360.      SOME bk => resetBreakFunc bk
  361.        | NONE => printL ["[No breakpoint exists at time ", makestring t, "]\n"]
  362.  
  363.  (** Execution-related commands *)
  364.  val envTime : time ref = ref 0
  365.  fun setEnvTime () =
  366.     let val time = 
  367.            case onSome(#2,!backtrace) of
  368.          NONE => safeQuery(fn t => t)
  369.        | SOME (_,t) => t
  370.     in envTime := time;
  371.        ZsetEnvTime time
  372.     end
  373.  
  374.  fun prCurrent (s:string) =
  375.  (* For use outside Emacs.  Display the current event in a textual form. *)
  376.     let fun f ww = (say "[";say s; say " "; prWhereWhen ww; say "]\n";
  377.             prExn(); prSignal())
  378.     in if ZinDebug() then
  379.        f (safeQuery (fn t => (hd(YcurrentPlaces()),t)))
  380.        else printNotUnder()
  381.     end
  382.  
  383.  fun current() = prCurrent "At" 
  384.  
  385.  fun doMove f =  (* both *)
  386.  (* Execute the given function, which causes the current code position to
  387.   * change, while maintaining the display and its state variables. 
  388.   * ZinDebug is assumed true. *)
  389.      if !emacs then
  390.      (emacsDeselect ();
  391.       (case f () of
  392.          COMPLETED _ => (prExn(); prSignal())
  393.        | INTERRUPTED _ => (prExn(); prSignal(); emacsError "(Interrupted)")
  394.        | NOTRUNNING => raise (DebugUserError "domove"));
  395.       setEnvTime();
  396.       emacsUpdate ())
  397.      else (selected := NONE; 
  398.        backtrace := NONE; 
  399.        currentEv := NONE;
  400.        case f () of
  401.          COMPLETED _ => prCurrent "Stopped at"
  402.        | INTERRUPTED _ => prCurrent "Interrupted at"
  403.        | NOTRUNNING => raise (DebugUserError "domove");
  404.        setEnvTime())
  405.  
  406.  fun moveUnderDebug f =  (* both *)
  407.    if ZinDebug() then doMove f else printNotUnder()
  408.  
  409.  fun step () =
  410.  (* Attempt step forward.  Does not update display. *)
  411.    Xjump (establishedTime() + 1)
  412.  
  413.  fun stepb () =
  414.  (* Attempt step backward. Does not update display. *)
  415.    Xjump (establishedTime() - 1)
  416.  
  417.  fun ss () = moveUnderDebug step
  418.  
  419.  fun ssb () =  moveUnderDebug stepb
  420.  
  421.  fun goforward () =  
  422.  (* Move forward until breakpoint or end of compilation unit.
  423.     Do break function if any. *)
  424.      let val now = establishedTime()
  425.      val (_,finalTime) = safeQuery(fn _ => YboundingTimes ())
  426.      val minbtime = fold (fn ((_,TIME t),m) => if t > now
  427.                         then min(t,m)
  428.                         else m
  429.                 | (_,m) => m) 
  430.                    (!breakList) finalTime
  431.          fun lastTime p = 
  432.         if exists (fn p' => p' = p) (YcurrentPlaces()) then
  433.           YcurrentTime()
  434.         else #1(YlastTimes p)
  435.      fun getetimes () = fold (fn ((_,EVENT p),etl) => 
  436.                       lastTime p :: etl
  437.                     | (_,etl) => etl) (!breakList) []
  438.          val etimes = safeQuery (fn _ => getetimes())
  439.      fun minchanged () = 
  440.         fold (fn ((old,new),m) =>
  441.                if (new > old) andalso (new > now) andalso 
  442.               (new < m) then new else m)
  443.          (pairlist etimes (getetimes())) Zinfinity
  444.      in XbinSearch(minchanged,minbtime,false)
  445.      end before
  446.      doBreakFunc()
  447.  
  448.  fun forward () =  moveUnderDebug goforward
  449.  
  450.  fun backward() =
  451.  (* Move backward until breakpoint or start of compilation unit.
  452.     Do break function if any. *)
  453.     moveUnderDebug (fn () =>
  454.       let val now = establishedTime()
  455.           val (initialTime,_) = safeQuery (fn _ => YboundingTimes())
  456.       val target = safeQuery (fn _ =>
  457.          fold (fn ((_,TIME t), m) => if (t < now) then max(t,m) else m
  458.                   | ((_,EVENT p), m) => max (#2(YlastTimes p),m))
  459.               (!breakList) initialTime)
  460.       in Xjump target
  461.       end before 
  462.       doBreakFunc())
  463.  
  464.  fun jump t =
  465.      moveUnderDebug (fn () => Xjump t)
  466.  
  467.  fun skip () =
  468.  (* Skip forward, using binary search primitive.
  469.   * Does not update display. *)
  470.       let val now = establishedTime()
  471.       fun check_ancestors () = 
  472.         (* return upper bound on time when time 'now' is no longer on stack
  473.            or infinity if no such bound known. 
  474.            Note: this function can take a painfully long time to 
  475.            evaluate; on interrupt, Ycaller should return 0, terminating
  476.            the recursion in f... *)
  477.         let fun parent t = let val (_,(_,pt)) = Ycaller t
  478.                    in pt end
  479.         fun f (0,bound) = bound (*??*)
  480.           | f (when,bound) = 
  481.                if when = now then Zinfinity
  482.                else if when < now then bound
  483.                else f (parent when,when)
  484.         val ct = YcurrentTime()
  485.         in f (ct,ct)
  486.         end                
  487.        in if (safeQuery YatCall) then
  488.          XbinSearch(check_ancestors,Zinfinity,true)
  489.           else
  490.         step()
  491.        end
  492.  
  493.  fun sk() =
  494.    moveUnderDebug skip
  495.  
  496.  fun skipb () =
  497.  (* Skip backward.
  498.   * Does not update display. *)
  499.     let val now = establishedTime()
  500.     fun parent t = let val (_,(_,pt)) = Ycaller t in pt end
  501.     val init_parent = parent now
  502.     fun f(0,s) = s (* paranoia *)
  503.       | f(t,s) = 
  504.         if t = init_parent then
  505.           s
  506.         else f(parent t,SOME t)
  507.     in case Xjump(now-1) of
  508.      COMPLETED (w,t) => 
  509.       (case XwithEstablishedTime(fn _ => f(t,NONE)) of
  510.          COMPLETED(NONE) => COMPLETED (w,t)
  511.        | COMPLETED(SOME t) => Xjump t
  512.        | INTERRUPTED _  => INTERRUPTED (w,t)
  513.        | NOTRUNNING => NOTRUNNING)
  514.        | INTERRUPTED ww => INTERRUPTED ww
  515.        | NOTRUNNING => NOTRUNNING
  516.     end
  517.  
  518.  fun skb() = moveUnderDebug skipb
  519.  
  520.  fun jumpTrace () =
  521.  (* If the backtrace event is selected, jump to its time.
  522.   * Invoked by M-t in emacs. *)
  523.      case !selected of
  524.      NONE => ()
  525.        | SOME ev =>
  526.          case onSome(#2, !backtrace) of
  527.          SOME (place,time) =>
  528.              if ev = place then jump time else ()
  529.            | NONE => ()
  530.  
  531.  
  532.  (** Stack backtrace commands *)
  533.  
  534.  fun showCalls maxdepth =  
  535.    let fun p (top::rest) =
  536.         let fun prvar ((n:string,t:ty),v:value) = 
  537.              (say "\t"; say n; say " = "; YprintVal(v,t))
  538.         fun prcall (w as (whr,whn),vw as (vwhr,vwhn),bvlist) = 
  539.            (prWhereWhen w; say "\n";
  540.             if (whn > 0) then
  541.               (if (vwhn < whn andalso vwhn > 0) then
  542.              (say "via\t"; prWhereWhen vw; say "\n")
  543.                else ();
  544.                say "  bound values:"; app prvar bvlist; say "\n";
  545.                if (vwhn > 0) then
  546.              (say "  call: "; YprintBind (vw,8); say "\n")
  547.                else ())
  548.             else ())
  549.         in say "At\t"; prcall top;
  550.            app (fn c => (say "From\t"; prcall c)) rest
  551.         end
  552.      | p _ = ()
  553.        fun f t = p (YcallTrace (max(maxdepth,1)-1) t)
  554.    in interruptableQuery f
  555.    end
  556.  
  557. local 
  558.  fun backtr () =  onSome(#1,!backtrace)
  559. in
  560.  fun upCall () =  (* both *)
  561.     if ZinDebug() then
  562.        ((case backtr() of
  563.        NONE => emacsSetBackTrace (SOME 1)
  564.      | SOME n => emacsSetBackTrace (SOME (n+1)))
  565.             handle SetBackTrace => emacsError "At top of call chain";
  566.        setEnvTime())
  567.     else printNotUnder()
  568.  
  569.  fun downCall () = (* both *)
  570.     if ZinDebug() then
  571.       (case backtr() of
  572.         NONE => emacsError "At bottom of call chain"
  573.         | SOME 1 => emacsSetBackTrace NONE
  574.         | SOME n => emacsSetBackTrace (SOME (n-1));
  575.        setEnvTime())
  576.     else printNotUnder()
  577. end
  578.  
  579.  (** Variable display functions *)
  580.  fun showVal n =  
  581.  (* Print a value and the position of its binding site.
  582.   * For use outside Emacs. *)
  583.    let fun f _ = 
  584.      case YgetVal n (!envTime) of
  585.        SOME(v,t,w as (whr,whn)) =>
  586.      if ZisFn(t)
  587.      then (say n; say "\tfunction bound by code:\n\t\t";
  588.            YprintBind(w,16); say "\n";
  589.            say "\t\t["; prWhereWhen w; say "]\n")
  590.      else (say n; say "\t"; YprintVal(v,t); 
  591.            say "\t["; prWhereWhen w; say "]\n")
  592.      | NONE => (say n; say "\tNot bound\n")
  593.    in interruptableQuery f
  594.    end
  595.  
  596.  fun emacsShowVal n = 
  597.  (* Like the preceding function, but moves the selection to the binding site
  598.   * of the variable or function.
  599.   * Invoked by M-l in Emacs. *)
  600.    let fun f _ = 
  601.        case YgetVal n (!envTime) of
  602.      SOME(v, t, w as (whr, _)) =>
  603.           (printL [n, " = "];
  604.            YprintVal(v,t);
  605.            say "\n";
  606.            emacsSelect (SOME whr))
  607.        | NONE => printL [n, " is not bound\n"]
  608.    in interruptableQuery f
  609.    end
  610.  
  611.  (** Miscellaneous functions *)
  612.  
  613.  fun debugdebug (on:bool) = Wdd := on
  614.    (* call with true for internal debugger diagnostics *)
  615.  
  616.  fun startUp s () =  (* interactive startup *)
  617.     (if !emacs then
  618.        emacsInitDebug s
  619.      else ();
  620.      setEnvTime())
  621.  
  622.  fun nullStartUp () = ()  
  623.  
  624.  fun shutDown () = (* interactive shutdown *)
  625.     (if !emacs then
  626.        (clearBreaks();  (* remove all breakpoints *)
  627.     emacsTermDebug())
  628.      else (breakList := nil;
  629.        selected := NONE;
  630.        backtrace := NONE;
  631.        currentEv := NONE))
  632.  
  633.  fun complete() = 
  634.  (* Complete the execution of the compilation unit. *)
  635.      if ZinDebug() then
  636.      (shutDown();
  637.       Xcomplete(); 
  638.       ()) (* doesn't return if successful *)
  639.      else printNotUnder()
  640.  
  641.  fun abort() = 
  642.  (* Abort execution of compilation unit. *)
  643.      if ZinDebug() then
  644.      (shutDown();
  645.       Xabort();
  646.       ())    (* doesn't return if successful *)
  647.      else printNotUnder()
  648.  
  649.  (** Source code functions *)
  650.  
  651.  fun usedbg file = 
  652.      if ZinDebug() then
  653.        say "[Already running under debugger.]\n"
  654.      else 
  655.        (* If under emacs we convert the filename to absolute form 
  656.       because Emacs will send that form of filename to us. *)
  657.        let val file = if !emacs then absolute file (!currentWD) else file
  658.        in Xuse_file(FULL,file)
  659.        end
  660.  
  661.  fun usedbg_live file = 
  662.      if ZinDebug() then
  663.        say "[Already running under debugger.]\n"
  664.      else 
  665.        let val file = if !emacs then absolute file (!currentWD) else file
  666.        in Xuse_file(LIVE (NONE,startUp NONE,shutDown), file)
  667.        end
  668.  
  669.  fun usedbg_stream s = 
  670.      if ZinDebug() then
  671.        say "[Already running under debugger.]\n"
  672.      else Xuse_stream(FULL,s)
  673.  
  674.  fun usedbg_string s = usedbg_stream (open_string s)
  675.  
  676.  fun usedbg_script (source:instream) (commands:instream) =
  677.     if ZinDebug() then
  678.       say "[Already running under debugger.]\n"
  679.     else 
  680.       Xuse_stream(LIVE(SOME ("<script>",commands),startUp NONE,shutDown),
  681.           source)
  682.  
  683.  fun run s =
  684.     if ZinDebug() then
  685.       say "[Already running under debugger.]\n"
  686.     else 
  687.       Xuse_stream(LIVE(NONE,startUp (SOME s),shutDown),open_string s)
  688.  
  689.  fun execute s =
  690.     if ZinDebug() then    
  691.       if safeQuery(fn now => 
  692.          let val (_,finalTime) = YboundingTimes()
  693.          in now < finalTime
  694.              end) then 
  695.       (say "[processing interpolation]\n";
  696.        Xinterpolate_stream(open_string s);
  697.        jump Zinfinity (* should stop at end of interpolation *))
  698.       else say "[Cannot interpolate at end of compilation unit.]\n"
  699.    else printNotUnder()
  700. end
  701.  
  702.  
  703.  
  704.  
  705.  
  706.  
  707.