src/Pure/Tools/debugger.scala
changeset 75393 87ebf5a50283
parent 73565 1aa92bc4d356
child 75394 42267c650205
equal deleted inserted replaced
75388:b3ca4a6ed74b 75393:87ebf5a50283
     8 
     8 
     9 
     9 
    10 import scala.collection.immutable.SortedMap
    10 import scala.collection.immutable.SortedMap
    11 
    11 
    12 
    12 
    13 object Debugger
    13 object Debugger {
    14 {
       
    15   /* thread context */
    14   /* thread context */
    16 
    15 
    17   case object Update
    16   case object Update
    18 
    17 
    19   sealed case class Debug_State(pos: Position.T, function: String)
    18   sealed case class Debug_State(pos: Position.T, function: String)
    20   type Threads = SortedMap[String, List[Debug_State]]
    19   type Threads = SortedMap[String, List[Debug_State]]
    21 
    20 
    22   sealed case class Context(thread_name: String, debug_states: List[Debug_State], index: Int = 0)
    21   sealed case class Context(thread_name: String, debug_states: List[Debug_State], index: Int = 0) {
    23   {
       
    24     def size: Int = debug_states.length + 1
    22     def size: Int = debug_states.length + 1
    25     def reset: Context = copy(index = 0)
    23     def reset: Context = copy(index = 0)
    26     def select(i: Int): Context = copy(index = i + 1)
    24     def select(i: Int): Context = copy(index = i + 1)
    27 
    25 
    28     def thread_state: Option[Debug_State] = debug_states.headOption
    26     def thread_state: Option[Debug_State] = debug_states.headOption
    54     active: Int = 0,  // active views
    52     active: Int = 0,  // active views
    55     break: Boolean = false,  // break at next possible breakpoint
    53     break: Boolean = false,  // break at next possible breakpoint
    56     active_breakpoints: Set[Long] = Set.empty,  // explicit breakpoint state
    54     active_breakpoints: Set[Long] = Set.empty,  // explicit breakpoint state
    57     threads: Threads = SortedMap.empty,  // thread name ~> stack of debug states
    55     threads: Threads = SortedMap.empty,  // thread name ~> stack of debug states
    58     focus: Map[String, Context] = Map.empty,  // thread name ~> focus
    56     focus: Map[String, Context] = Map.empty,  // thread name ~> focus
    59     output: Map[String, Command.Results] = Map.empty)  // thread name ~> output messages
    57     output: Map[String, Command.Results] = Map.empty  // thread name ~> output messages
    60   {
    58   ) {
    61     def set_break(b: Boolean): State = copy(break = b)
    59     def set_break(b: Boolean): State = copy(break = b)
    62 
    60 
    63     def is_active: Boolean = active > 0
    61     def is_active: Boolean = active > 0
    64     def inc_active: State = copy(active = active + 1)
    62     def inc_active: State = copy(active = active + 1)
    65     def dec_active: State = copy(active = active - 1)
    63     def dec_active: State = copy(active = active - 1)
    66 
    64 
    67     def toggle_breakpoint(breakpoint: Long): (Boolean, State) =
    65     def toggle_breakpoint(breakpoint: Long): (Boolean, State) = {
    68     {
       
    69       val active_breakpoints1 =
    66       val active_breakpoints1 =
    70         if (active_breakpoints(breakpoint)) active_breakpoints - breakpoint
    67         if (active_breakpoints(breakpoint)) active_breakpoints - breakpoint
    71       else active_breakpoints + breakpoint
    68       else active_breakpoints + breakpoint
    72       (active_breakpoints1(breakpoint), copy(active_breakpoints = active_breakpoints1))
    69       (active_breakpoints1(breakpoint), copy(active_breakpoints = active_breakpoints1))
    73     }
    70     }
    74 
    71 
    75     def get_thread(thread_name: String): List[Debug_State] =
    72     def get_thread(thread_name: String): List[Debug_State] =
    76       threads.getOrElse(thread_name, Nil)
    73       threads.getOrElse(thread_name, Nil)
    77 
    74 
    78     def update_thread(thread_name: String, debug_states: List[Debug_State]): State =
    75     def update_thread(thread_name: String, debug_states: List[Debug_State]): State = {
    79     {
       
    80       val threads1 =
    76       val threads1 =
    81         if (debug_states.nonEmpty) threads + (thread_name -> debug_states)
    77         if (debug_states.nonEmpty) threads + (thread_name -> debug_states)
    82         else threads - thread_name
    78         else threads - thread_name
    83       val focus1 =
    79       val focus1 =
    84         focus.get(thread_name) match {
    80         focus.get(thread_name) match {
   102   }
    98   }
   103 
    99 
   104 
   100 
   105   /* protocol handler */
   101   /* protocol handler */
   106 
   102 
   107   class Handler(session: Session) extends Session.Protocol_Handler
   103   class Handler(session: Session) extends Session.Protocol_Handler {
   108   {
       
   109     val debugger: Debugger = new Debugger(session)
   104     val debugger: Debugger = new Debugger(session)
   110 
   105 
   111     private def debugger_state(msg: Prover.Protocol_Output): Boolean =
   106     private def debugger_state(msg: Prover.Protocol_Output): Boolean = {
   112     {
       
   113       msg.properties match {
   107       msg.properties match {
   114         case Markup.Debugger_State(thread_name) =>
   108         case Markup.Debugger_State(thread_name) =>
   115           val msg_body = Symbol.decode_yxml_failsafe(msg.text)
   109           val msg_body = Symbol.decode_yxml_failsafe(msg.text)
   116           val debug_states =
   110           val debug_states = {
   117           {
       
   118             import XML.Decode._
   111             import XML.Decode._
   119             list(pair(properties, string))(msg_body).map({
   112             list(pair(properties, string))(msg_body).map({
   120               case (pos, function) => Debug_State(pos, function)
   113               case (pos, function) => Debug_State(pos, function)
   121             })
   114             })
   122           }
   115           }
   124           true
   117           true
   125         case _ => false
   118         case _ => false
   126       }
   119       }
   127     }
   120     }
   128 
   121 
   129     private def debugger_output(msg: Prover.Protocol_Output): Boolean =
   122     private def debugger_output(msg: Prover.Protocol_Output): Boolean = {
   130     {
       
   131       msg.properties match {
   123       msg.properties match {
   132         case Markup.Debugger_Output(thread_name) =>
   124         case Markup.Debugger_Output(thread_name) =>
   133           Symbol.decode_yxml_failsafe(msg.text) match {
   125           Symbol.decode_yxml_failsafe(msg.text) match {
   134             case List(XML.Elem(Markup(name, props @ Markup.Serial(i)), body)) =>
   126             case List(XML.Elem(Markup(name, props @ Markup.Serial(i)), body)) =>
   135               val message = XML.Elem(Markup(Markup.message(name), props), body)
   127               val message = XML.Elem(Markup(Markup.message(name), props), body)
   146         Markup.DEBUGGER_STATE -> debugger_state,
   138         Markup.DEBUGGER_STATE -> debugger_state,
   147         Markup.DEBUGGER_OUTPUT -> debugger_output)
   139         Markup.DEBUGGER_OUTPUT -> debugger_output)
   148   }
   140   }
   149 }
   141 }
   150 
   142 
   151 class Debugger private(session: Session)
   143 class Debugger private(session: Session) {
   152 {
       
   153   /* debugger state */
   144   /* debugger state */
   154 
   145 
   155   private val state = Synchronized(Debugger.State())
   146   private val state = Synchronized(Debugger.State())
   156 
   147 
   157   private val delay_update =
   148   private val delay_update =
   160     }
   151     }
   161 
   152 
   162 
   153 
   163   /* protocol commands */
   154   /* protocol commands */
   164 
   155 
   165   def update_thread(thread_name: String, debug_states: List[Debugger.Debug_State]): Unit =
   156   def update_thread(thread_name: String, debug_states: List[Debugger.Debug_State]): Unit = {
   166   {
       
   167     state.change(_.update_thread(thread_name, debug_states))
   157     state.change(_.update_thread(thread_name, debug_states))
   168     delay_update.invoke()
   158     delay_update.invoke()
   169   }
   159   }
   170 
   160 
   171   def add_output(thread_name: String, entry: Command.Results.Entry): Unit =
   161   def add_output(thread_name: String, entry: Command.Results.Entry): Unit = {
   172   {
       
   173     state.change(_.add_output(thread_name, entry))
   162     state.change(_.add_output(thread_name, entry))
   174     delay_update.invoke()
   163     delay_update.invoke()
   175   }
   164   }
   176 
   165 
   177   def is_active(): Boolean = session.is_ready && state.value.is_active
   166   def is_active(): Boolean = session.is_ready && state.value.is_active
   178 
   167 
   179   def ready(): Unit =
   168   def ready(): Unit = {
   180   {
       
   181     if (is_active())
   169     if (is_active())
   182       session.protocol_command("Debugger.init")
   170       session.protocol_command("Debugger.init")
   183   }
   171   }
   184 
   172 
   185   def init(): Unit =
   173   def init(): Unit =
   186     state.change(st =>
   174     state.change(st => {
   187     {
       
   188       val st1 = st.inc_active
   175       val st1 = st.inc_active
   189       if (session.is_ready && !st.is_active && st1.is_active)
   176       if (session.is_ready && !st.is_active && st1.is_active)
   190         session.protocol_command("Debugger.init")
   177         session.protocol_command("Debugger.init")
   191       st1
   178       st1
   192     })
   179     })
   193 
   180 
   194   def exit(): Unit =
   181   def exit(): Unit =
   195     state.change(st =>
   182     state.change(st => {
   196     {
       
   197       val st1 = st.dec_active
   183       val st1 = st.dec_active
   198       if (session.is_ready && st.is_active && !st1.is_active)
   184       if (session.is_ready && st.is_active && !st1.is_active)
   199         session.protocol_command("Debugger.exit")
   185         session.protocol_command("Debugger.exit")
   200       st1
   186       st1
   201     })
   187     })
   202 
   188 
   203   def is_break(): Boolean = state.value.break
   189   def is_break(): Boolean = state.value.break
   204   def set_break(b: Boolean): Unit =
   190   def set_break(b: Boolean): Unit = {
   205   {
       
   206     state.change(st => {
   191     state.change(st => {
   207       val st1 = st.set_break(b)
   192       val st1 = st.set_break(b)
   208       session.protocol_command("Debugger.break", b.toString)
   193       session.protocol_command("Debugger.break", b.toString)
   209       st1
   194       st1
   210     })
   195     })
   211     delay_update.invoke()
   196     delay_update.invoke()
   212   }
   197   }
   213 
   198 
   214   def active_breakpoint_state(breakpoint: Long): Option[Boolean] =
   199   def active_breakpoint_state(breakpoint: Long): Option[Boolean] = {
   215   {
       
   216     val st = state.value
   200     val st = state.value
   217     if (st.is_active) Some(st.active_breakpoints(breakpoint)) else None
   201     if (st.is_active) Some(st.active_breakpoints(breakpoint)) else None
   218   }
   202   }
   219 
   203 
   220   def breakpoint_state(breakpoint: Long): Boolean =
   204   def breakpoint_state(breakpoint: Long): Boolean =
   221     state.value.active_breakpoints(breakpoint)
   205     state.value.active_breakpoints(breakpoint)
   222 
   206 
   223   def toggle_breakpoint(command: Command, breakpoint: Long): Unit =
   207   def toggle_breakpoint(command: Command, breakpoint: Long): Unit = {
   224   {
   208     state.change(st => {
   225     state.change(st =>
   209       val (breakpoint_state, st1) = st.toggle_breakpoint(breakpoint)
   226       {
   210       session.protocol_command(
   227         val (breakpoint_state, st1) = st.toggle_breakpoint(breakpoint)
   211         "Debugger.breakpoint",
   228         session.protocol_command(
   212         Symbol.encode(command.node_name.node),
   229           "Debugger.breakpoint",
   213         Document_ID(command.id),
   230           Symbol.encode(command.node_name.node),
   214         Value.Long(breakpoint),
   231           Document_ID(command.id),
   215         Value.Boolean(breakpoint_state))
   232           Value.Long(breakpoint),
   216       st1
   233           Value.Boolean(breakpoint_state))
   217     })
   234         st1
   218   }
   235       })
   219 
   236   }
   220   def status(focus: Option[Debugger.Context]): (Debugger.Threads, List[XML.Tree]) = {
   237 
       
   238   def status(focus: Option[Debugger.Context]): (Debugger.Threads, List[XML.Tree]) =
       
   239   {
       
   240     val st = state.value
   221     val st = state.value
   241     val output =
   222     val output =
   242       focus match {
   223       focus match {
   243         case None => Nil
   224         case None => Nil
   244         case Some(c) =>
   225         case Some(c) =>
   250       }
   231       }
   251     (st.threads, output)
   232     (st.threads, output)
   252   }
   233   }
   253 
   234 
   254   def focus(): List[Debugger.Context] = state.value.focus.toList.map(_._2)
   235   def focus(): List[Debugger.Context] = state.value.focus.toList.map(_._2)
   255   def set_focus(c: Debugger.Context): Unit =
   236   def set_focus(c: Debugger.Context): Unit = {
   256   {
       
   257     state.change(_.set_focus(c))
   237     state.change(_.set_focus(c))
   258     delay_update.invoke()
   238     delay_update.invoke()
   259   }
   239   }
   260 
   240 
   261   def input(thread_name: String, msg: String*): Unit =
   241   def input(thread_name: String, msg: String*): Unit =
   264   def continue(thread_name: String): Unit = input(thread_name, "continue")
   244   def continue(thread_name: String): Unit = input(thread_name, "continue")
   265   def step(thread_name: String): Unit = input(thread_name, "step")
   245   def step(thread_name: String): Unit = input(thread_name, "step")
   266   def step_over(thread_name: String): Unit = input(thread_name, "step_over")
   246   def step_over(thread_name: String): Unit = input(thread_name, "step_over")
   267   def step_out(thread_name: String): Unit = input(thread_name, "step_out")
   247   def step_out(thread_name: String): Unit = input(thread_name, "step_out")
   268 
   248 
   269   def clear_output(thread_name: String): Unit =
   249   def clear_output(thread_name: String): Unit = {
   270   {
       
   271     state.change(_.clear_output(thread_name))
   250     state.change(_.clear_output(thread_name))
   272     delay_update.invoke()
   251     delay_update.invoke()
   273   }
   252   }
   274 
   253 
   275   def eval(c: Debugger.Context, SML: Boolean, context: String, expression: String): Unit =
   254   def eval(c: Debugger.Context, SML: Boolean, context: String, expression: String): Unit = {
   276   {
       
   277     state.change(st => {
   255     state.change(st => {
   278       input(c.thread_name, "eval", c.debug_index.getOrElse(0).toString,
   256       input(c.thread_name, "eval", c.debug_index.getOrElse(0).toString,
   279         SML.toString, Symbol.encode(context), Symbol.encode(expression))
   257         SML.toString, Symbol.encode(context), Symbol.encode(expression))
   280       st.clear_output(c.thread_name)
   258       st.clear_output(c.thread_name)
   281     })
   259     })
   282     delay_update.invoke()
   260     delay_update.invoke()
   283   }
   261   }
   284 
   262 
   285   def print_vals(c: Debugger.Context, SML: Boolean, context: String): Unit =
   263   def print_vals(c: Debugger.Context, SML: Boolean, context: String): Unit = {
   286   {
       
   287     require(c.debug_index.isDefined)
   264     require(c.debug_index.isDefined)
   288 
   265 
   289     state.change(st => {
   266     state.change(st => {
   290       input(c.thread_name, "print_vals", c.debug_index.getOrElse(0).toString,
   267       input(c.thread_name, "print_vals", c.debug_index.getOrElse(0).toString,
   291         SML.toString, Symbol.encode(context))
   268         SML.toString, Symbol.encode(context))