src/Pure/PIDE/command.scala
author wenzelm
Sun Aug 15 22:48:56 2010 +0200 (2010-08-15 ago)
changeset 38426 2858ec7b6dd8
parent 38415 f3220ef79d51
child 38427 7066fbd315ae
permissions -rw-r--r--
specific types Text.Offset and Text.Range;
minor tuning;
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@38363
    30
    command_id: Option[Document.Command_ID], offset: Option[Int])  // FIXME Command_ID vs. Exec_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
    /* content */
wenzelm@38361
    44
wenzelm@38362
    45
    lazy val results = reverse_results.reverse
wenzelm@38361
    46
wenzelm@38362
    47
    def add_result(result: XML.Tree): State = copy(reverse_results = result :: reverse_results)
wenzelm@38361
    48
wenzelm@38362
    49
    def add_markup(node: Markup_Tree): State = copy(markup = markup + node)
wenzelm@38361
    50
wenzelm@38361
    51
wenzelm@38361
    52
    /* markup */
wenzelm@38361
    53
wenzelm@38361
    54
    lazy val highlight: Markup_Text =
wenzelm@38361
    55
    {
wenzelm@38362
    56
      markup.filter(_.info match {
wenzelm@38361
    57
        case Command.HighlightInfo(_, _) => true
wenzelm@38361
    58
        case _ => false
wenzelm@38361
    59
      })
wenzelm@38361
    60
    }
wenzelm@38361
    61
wenzelm@38361
    62
    private lazy val types: List[Markup_Node] =
wenzelm@38362
    63
      markup.filter(_.info match {
wenzelm@38361
    64
        case Command.TypeInfo(_) => true
wenzelm@38361
    65
        case _ => false }).flatten
wenzelm@38361
    66
wenzelm@38426
    67
    def type_at(pos: Text.Offset): Option[String] =
wenzelm@38361
    68
    {
wenzelm@38426
    69
      types.find(t => t.range.start <= pos && pos < t.range.stop) match {
wenzelm@38361
    70
        case Some(t) =>
wenzelm@38361
    71
          t.info match {
wenzelm@38426
    72
            case Command.TypeInfo(ty) => Some(command.source(t.range) + " : " + ty)
wenzelm@38361
    73
            case _ => None
wenzelm@38361
    74
          }
wenzelm@38361
    75
        case None => None
wenzelm@38361
    76
      }
wenzelm@38361
    77
    }
wenzelm@38361
    78
wenzelm@38361
    79
    private lazy val refs: List[Markup_Node] =
wenzelm@38362
    80
      markup.filter(_.info match {
wenzelm@38361
    81
        case Command.RefInfo(_, _, _, _) => true
wenzelm@38361
    82
        case _ => false }).flatten
wenzelm@38361
    83
wenzelm@38426
    84
    def ref_at(pos: Text.Offset): Option[Markup_Node] =
wenzelm@38426
    85
      refs.find(t => t.range.start <= pos && pos < t.range.stop)
wenzelm@38361
    86
wenzelm@38361
    87
wenzelm@38361
    88
    /* message dispatch */
wenzelm@38361
    89
wenzelm@38361
    90
    def accumulate(message: XML.Tree): Command.State =
wenzelm@38361
    91
      message match {
wenzelm@38361
    92
        case XML.Elem(Markup(Markup.STATUS, _), elems) =>
wenzelm@38361
    93
          (this /: elems)((state, elem) =>
wenzelm@38361
    94
            elem match {
wenzelm@38362
    95
              case XML.Elem(Markup(Markup.UNPROCESSED, _), _) => state.copy(status = Command.Status.UNPROCESSED)
wenzelm@38362
    96
              case XML.Elem(Markup(Markup.FINISHED, _), _) => state.copy(status = Command.Status.FINISHED)
wenzelm@38362
    97
              case XML.Elem(Markup(Markup.FAILED, _), _) => state.copy(status = Command.Status.FAILED)
wenzelm@38362
    98
              case XML.Elem(Markup(Markup.FORKED, _), _) => state.copy(forks = state.forks + 1)
wenzelm@38362
    99
              case XML.Elem(Markup(Markup.JOINED, _), _) => state.copy(forks = state.forks - 1)
wenzelm@38361
   100
              case _ => System.err.println("Ignored status message: " + elem); state
wenzelm@38361
   101
            })
wenzelm@38361
   102
wenzelm@38361
   103
        case XML.Elem(Markup(Markup.REPORT, _), elems) =>
wenzelm@38361
   104
          (this /: elems)((state, elem) =>
wenzelm@38361
   105
            elem match {
wenzelm@38361
   106
              case XML.Elem(Markup(kind, atts), body) if Position.get_id(atts) == Some(command.id) =>
wenzelm@38361
   107
                atts match {
wenzelm@38361
   108
                  case Position.Range(begin, end) =>
wenzelm@38361
   109
                    if (kind == Markup.ML_TYPING) {
wenzelm@38361
   110
                      val info = Pretty.string_of(body, margin = 40)
wenzelm@38361
   111
                      state.add_markup(
wenzelm@38361
   112
                        command.markup_node(begin - 1, end - 1, Command.TypeInfo(info)))
wenzelm@38361
   113
                    }
wenzelm@38361
   114
                    else if (kind == Markup.ML_REF) {
wenzelm@38361
   115
                      body match {
wenzelm@38361
   116
                        case List(XML.Elem(Markup(Markup.ML_DEF, props), _)) =>
wenzelm@38362
   117
                          state.add_markup(
wenzelm@38362
   118
                            command.markup_node(
wenzelm@38362
   119
                              begin - 1, end - 1,
wenzelm@38362
   120
                              Command.RefInfo(
wenzelm@38362
   121
                                Position.get_file(props),
wenzelm@38362
   122
                                Position.get_line(props),
wenzelm@38362
   123
                                Position.get_id(props),
wenzelm@38362
   124
                                Position.get_offset(props))))
wenzelm@38361
   125
                        case _ => state
wenzelm@38361
   126
                      }
wenzelm@38361
   127
                    }
wenzelm@38361
   128
                    else {
wenzelm@38361
   129
                      state.add_markup(
wenzelm@38361
   130
                        command.markup_node(begin - 1, end - 1,
wenzelm@38361
   131
                          Command.HighlightInfo(kind, Markup.get_string(Markup.KIND, atts))))
wenzelm@38361
   132
                    }
wenzelm@38361
   133
                  case _ => state
wenzelm@38361
   134
                }
wenzelm@38361
   135
              case _ => System.err.println("Ignored report message: " + elem); state
wenzelm@38361
   136
            })
wenzelm@38361
   137
        case _ => add_result(message)
wenzelm@38361
   138
      }
wenzelm@38361
   139
  }
wenzelm@38367
   140
wenzelm@38367
   141
wenzelm@38367
   142
  /* unparsed dummy commands */
wenzelm@38367
   143
wenzelm@38367
   144
  def unparsed(source: String) =
wenzelm@38367
   145
    new Command(Document.NO_ID, List(Token(Token.Kind.UNPARSED, source)))
wenzelm@34318
   146
}
wenzelm@34318
   147
wenzelm@38361
   148
wenzelm@34697
   149
class Command(
wenzelm@38150
   150
    val id: Document.Command_ID,
wenzelm@38373
   151
    val span: List[Token])
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@38367
   159
  def is_unparsed = id == Document.NO_ID
wenzelm@38367
   160
wenzelm@36012
   161
  def name: String = if (is_command) span.head.content else ""
wenzelm@37129
   162
  override def toString =
wenzelm@37373
   163
    id + "/" + (if (is_command) name else if (is_ignored) "IGNORED" else "MALFORMED")
wenzelm@34495
   164
wenzelm@34859
   165
wenzelm@34859
   166
  /* source text */
wenzelm@34451
   167
wenzelm@34859
   168
  val source: String = span.map(_.source).mkString
wenzelm@38426
   169
  def source(range: Text.Range): String = source.substring(range.start, range.stop)
wenzelm@34859
   170
  def length: Int = source.length
wenzelm@34855
   171
wenzelm@34859
   172
  lazy val symbol_index = new Symbol.Index(source)
immler@34593
   173
wenzelm@34815
   174
immler@34676
   175
  /* markup */
wenzelm@34508
   176
wenzelm@34717
   177
  def markup_node(begin: Int, end: Int, info: Any): Markup_Tree =
wenzelm@34699
   178
  {
wenzelm@34703
   179
    val start = symbol_index.decode(begin)
wenzelm@34703
   180
    val stop = symbol_index.decode(end)
wenzelm@38426
   181
    new Markup_Tree(new Markup_Node(Text.Range(start, stop), info), Nil)
wenzelm@34500
   182
  }
wenzelm@38370
   183
wenzelm@38370
   184
wenzelm@38370
   185
  /* accumulated results */
wenzelm@38370
   186
wenzelm@38415
   187
  val empty_state: Command.State =
wenzelm@38370
   188
    Command.State(this, Command.Status.UNPROCESSED, 0, Nil, new Markup_Text(Nil, source))
immler@34676
   189
}