src/Pure/PIDE/command.scala
author wenzelm
Thu Aug 12 14:22:23 2010 +0200 (2010-08-12 ago)
changeset 38362 754ad6340055
parent 38361 b609d0b271fa
child 38363 af7f41a8a0a8
permissions -rw-r--r--
misc tuning and simplification;
wenzelm@36676
     1
/*  Title:      Pure/PIDE/command.scala
wenzelm@36676
     2
    Author:     Fabian Immler, TU Munich
wenzelm@36676
     3
    Author:     Makarius
wenzelm@36676
     4
wenzelm@36676
     5
Prover commands with semantic state.
wenzelm@36676
     6
*/
wenzelm@34407
     7
wenzelm@34871
     8
package isabelle
wenzelm@34318
     9
wenzelm@34451
    10
wenzelm@34699
    11
import scala.actors.Actor, Actor._
wenzelm@34497
    12
import scala.collection.mutable
wenzelm@34486
    13
wenzelm@34451
    14
wenzelm@34637
    15
object Command
wenzelm@34637
    16
{
wenzelm@34637
    17
  object Status extends Enumeration
wenzelm@34637
    18
  {
wenzelm@34318
    19
    val UNPROCESSED = Value("UNPROCESSED")
wenzelm@34318
    20
    val FINISHED = Value("FINISHED")
wenzelm@34318
    21
    val FAILED = Value("FAILED")
wenzelm@36990
    22
    val UNDEFINED = Value("UNDEFINED")
wenzelm@34318
    23
  }
wenzelm@34707
    24
wenzelm@37197
    25
  case class HighlightInfo(kind: String, sub_kind: Option[String]) {
wenzelm@37197
    26
    override def toString = kind
wenzelm@37197
    27
  }
wenzelm@34717
    28
  case class TypeInfo(ty: String)
wenzelm@34707
    29
  case class RefInfo(file: Option[String], line: Option[Int],
wenzelm@38355
    30
    command_id: Option[Document.Command_ID], offset: Option[Int])  // FIXME Command_ID vs. State_ID !?
wenzelm@38361
    31
wenzelm@38361
    32
wenzelm@38362
    33
wenzelm@38361
    34
  /** accumulated results from prover **/
wenzelm@38361
    35
wenzelm@38362
    36
  case class State(
wenzelm@38361
    37
    val command: Command,
wenzelm@38361
    38
    val status: Command.Status.Value,
wenzelm@38361
    39
    val forks: Int,
wenzelm@38361
    40
    val reverse_results: List[XML.Tree],
wenzelm@38362
    41
    val markup: Markup_Text)
wenzelm@38361
    42
  {
wenzelm@38361
    43
    def this(command: Command) =
wenzelm@38361
    44
      this(command, Command.Status.UNPROCESSED, 0, Nil, command.empty_markup)
wenzelm@38361
    45
wenzelm@38361
    46
wenzelm@38361
    47
    /* content */
wenzelm@38361
    48
wenzelm@38362
    49
    lazy val results = reverse_results.reverse
wenzelm@38361
    50
wenzelm@38362
    51
    def add_result(result: XML.Tree): State = copy(reverse_results = result :: reverse_results)
wenzelm@38361
    52
wenzelm@38362
    53
    def add_markup(node: Markup_Tree): State = copy(markup = markup + node)
wenzelm@38361
    54
wenzelm@38361
    55
wenzelm@38361
    56
    /* markup */
wenzelm@38361
    57
wenzelm@38361
    58
    lazy val highlight: Markup_Text =
wenzelm@38361
    59
    {
wenzelm@38362
    60
      markup.filter(_.info match {
wenzelm@38361
    61
        case Command.HighlightInfo(_, _) => true
wenzelm@38361
    62
        case _ => false
wenzelm@38361
    63
      })
wenzelm@38361
    64
    }
wenzelm@38361
    65
wenzelm@38361
    66
    private lazy val types: List[Markup_Node] =
wenzelm@38362
    67
      markup.filter(_.info match {
wenzelm@38361
    68
        case Command.TypeInfo(_) => true
wenzelm@38361
    69
        case _ => false }).flatten
wenzelm@38361
    70
wenzelm@38361
    71
    def type_at(pos: Int): Option[String] =
wenzelm@38361
    72
    {
wenzelm@38361
    73
      types.find(t => t.start <= pos && pos < t.stop) match {
wenzelm@38361
    74
        case Some(t) =>
wenzelm@38361
    75
          t.info match {
wenzelm@38361
    76
            case Command.TypeInfo(ty) => Some(command.source(t.start, t.stop) + " : " + ty)
wenzelm@38361
    77
            case _ => None
wenzelm@38361
    78
          }
wenzelm@38361
    79
        case None => None
wenzelm@38361
    80
      }
wenzelm@38361
    81
    }
wenzelm@38361
    82
wenzelm@38361
    83
    private lazy val refs: List[Markup_Node] =
wenzelm@38362
    84
      markup.filter(_.info match {
wenzelm@38361
    85
        case Command.RefInfo(_, _, _, _) => true
wenzelm@38361
    86
        case _ => false }).flatten
wenzelm@38361
    87
wenzelm@38361
    88
    def ref_at(pos: Int): Option[Markup_Node] =
wenzelm@38361
    89
      refs.find(t => t.start <= pos && pos < t.stop)
wenzelm@38361
    90
wenzelm@38361
    91
wenzelm@38361
    92
    /* message dispatch */
wenzelm@38361
    93
wenzelm@38361
    94
    def accumulate(message: XML.Tree): Command.State =
wenzelm@38361
    95
      message match {
wenzelm@38361
    96
        case XML.Elem(Markup(Markup.STATUS, _), elems) =>
wenzelm@38361
    97
          (this /: elems)((state, elem) =>
wenzelm@38361
    98
            elem match {
wenzelm@38362
    99
              case XML.Elem(Markup(Markup.UNPROCESSED, _), _) => state.copy(status = Command.Status.UNPROCESSED)
wenzelm@38362
   100
              case XML.Elem(Markup(Markup.FINISHED, _), _) => state.copy(status = Command.Status.FINISHED)
wenzelm@38362
   101
              case XML.Elem(Markup(Markup.FAILED, _), _) => state.copy(status = Command.Status.FAILED)
wenzelm@38362
   102
              case XML.Elem(Markup(Markup.FORKED, _), _) => state.copy(forks = state.forks + 1)
wenzelm@38362
   103
              case XML.Elem(Markup(Markup.JOINED, _), _) => state.copy(forks = state.forks - 1)
wenzelm@38361
   104
              case _ => System.err.println("Ignored status message: " + elem); state
wenzelm@38361
   105
            })
wenzelm@38361
   106
wenzelm@38361
   107
        case XML.Elem(Markup(Markup.REPORT, _), elems) =>
wenzelm@38361
   108
          (this /: elems)((state, elem) =>
wenzelm@38361
   109
            elem match {
wenzelm@38361
   110
              case XML.Elem(Markup(kind, atts), body) if Position.get_id(atts) == Some(command.id) =>
wenzelm@38361
   111
                atts match {
wenzelm@38361
   112
                  case Position.Range(begin, end) =>
wenzelm@38361
   113
                    if (kind == Markup.ML_TYPING) {
wenzelm@38361
   114
                      val info = Pretty.string_of(body, margin = 40)
wenzelm@38361
   115
                      state.add_markup(
wenzelm@38361
   116
                        command.markup_node(begin - 1, end - 1, Command.TypeInfo(info)))
wenzelm@38361
   117
                    }
wenzelm@38361
   118
                    else if (kind == Markup.ML_REF) {
wenzelm@38361
   119
                      body match {
wenzelm@38361
   120
                        case List(XML.Elem(Markup(Markup.ML_DEF, props), _)) =>
wenzelm@38362
   121
                          state.add_markup(
wenzelm@38362
   122
                            command.markup_node(
wenzelm@38362
   123
                              begin - 1, end - 1,
wenzelm@38362
   124
                              Command.RefInfo(
wenzelm@38362
   125
                                Position.get_file(props),
wenzelm@38362
   126
                                Position.get_line(props),
wenzelm@38362
   127
                                Position.get_id(props),
wenzelm@38362
   128
                                Position.get_offset(props))))
wenzelm@38361
   129
                        case _ => state
wenzelm@38361
   130
                      }
wenzelm@38361
   131
                    }
wenzelm@38361
   132
                    else {
wenzelm@38361
   133
                      state.add_markup(
wenzelm@38361
   134
                        command.markup_node(begin - 1, end - 1,
wenzelm@38361
   135
                          Command.HighlightInfo(kind, Markup.get_string(Markup.KIND, atts))))
wenzelm@38361
   136
                    }
wenzelm@38361
   137
                  case _ => state
wenzelm@38361
   138
                }
wenzelm@38361
   139
              case _ => System.err.println("Ignored report message: " + elem); state
wenzelm@38361
   140
            })
wenzelm@38361
   141
        case _ => add_result(message)
wenzelm@38361
   142
      }
wenzelm@38361
   143
  }
wenzelm@34318
   144
}
wenzelm@34318
   145
wenzelm@38361
   146
wenzelm@34697
   147
class Command(
wenzelm@38150
   148
    val id: Document.Command_ID,
wenzelm@37129
   149
    val span: Thy_Syntax.Span,
wenzelm@38220
   150
    val static_parent: Option[Command] = None)  // FIXME !?
wenzelm@34815
   151
  extends Session.Entity
wenzelm@34451
   152
{
wenzelm@34859
   153
  /* classification */
wenzelm@34500
   154
wenzelm@36012
   155
  def is_command: Boolean = !span.isEmpty && span.head.is_command
wenzelm@34865
   156
  def is_ignored: Boolean = span.forall(_.is_ignored)
wenzelm@34859
   157
  def is_malformed: Boolean = !is_command && !is_ignored
wenzelm@34859
   158
wenzelm@36012
   159
  def name: String = if (is_command) span.head.content else ""
wenzelm@37129
   160
  override def toString =
wenzelm@37373
   161
    id + "/" + (if (is_command) name else if (is_ignored) "IGNORED" else "MALFORMED")
wenzelm@34495
   162
wenzelm@34859
   163
wenzelm@34859
   164
  /* source text */
wenzelm@34451
   165
wenzelm@34859
   166
  val source: String = span.map(_.source).mkString
wenzelm@34859
   167
  def source(i: Int, j: Int): String = source.substring(i, j)
wenzelm@34859
   168
  def length: Int = source.length
wenzelm@34855
   169
wenzelm@34859
   170
  lazy val symbol_index = new Symbol.Index(source)
immler@34593
   171
wenzelm@34815
   172
wenzelm@34815
   173
  /* accumulated messages */
wenzelm@34815
   174
wenzelm@38361
   175
  @volatile protected var state = new Command.State(this)
wenzelm@38361
   176
  def current_state: Command.State = state
wenzelm@34815
   177
wenzelm@37129
   178
  private case class Consume(message: XML.Tree, forward: Command => Unit)
wenzelm@34832
   179
  private case object Assign
wenzelm@34815
   180
wenzelm@34815
   181
  private val accumulator = actor {
wenzelm@34832
   182
    var assigned = false
wenzelm@34815
   183
    loop {
wenzelm@34815
   184
      react {
wenzelm@37129
   185
        case Consume(message, forward) if !assigned =>
wenzelm@37129
   186
          val old_state = state
wenzelm@37178
   187
          state = old_state.accumulate(message)
wenzelm@37129
   188
          if (!(state eq old_state)) forward(static_parent getOrElse this)
wenzelm@34815
   189
wenzelm@34832
   190
        case Assign =>
wenzelm@34835
   191
          assigned = true  // single assignment
wenzelm@34832
   192
          reply(())
wenzelm@34815
   193
wenzelm@37189
   194
        case bad => System.err.println("Command accumulator: ignoring bad message " + bad)
wenzelm@34815
   195
      }
wenzelm@34815
   196
    }
wenzelm@34815
   197
  }
wenzelm@34815
   198
wenzelm@37129
   199
  def consume(message: XML.Tree, forward: Command => Unit)
wenzelm@37129
   200
  {
wenzelm@37129
   201
    accumulator ! Consume(message, forward)
wenzelm@37129
   202
  }
wenzelm@34815
   203
wenzelm@38150
   204
  def assign_state(state_id: Document.State_ID): Command =
wenzelm@34815
   205
  {
wenzelm@37129
   206
    val cmd = new Command(state_id, span, Some(this))
wenzelm@34832
   207
    accumulator !? Assign
wenzelm@34815
   208
    cmd.state = current_state
wenzelm@34815
   209
    cmd
wenzelm@34815
   210
  }
immler@34676
   211
immler@34676
   212
immler@34676
   213
  /* markup */
wenzelm@34508
   214
wenzelm@34859
   215
  lazy val empty_markup = new Markup_Text(Nil, source)
immler@34676
   216
wenzelm@34717
   217
  def markup_node(begin: Int, end: Int, info: Any): Markup_Tree =
wenzelm@34699
   218
  {
wenzelm@34703
   219
    val start = symbol_index.decode(begin)
wenzelm@34703
   220
    val stop = symbol_index.decode(end)
wenzelm@34717
   221
    new Markup_Tree(new Markup_Node(start, stop, info), Nil)
wenzelm@34500
   222
  }
immler@34676
   223
}