src/Pure/PIDE/command.scala
author wenzelm
Thu Sep 01 13:34:45 2011 +0200 (2011-09-01)
changeset 44615 a4ff8a787202
parent 44607 274eff0ea12e
child 44959 9476c856c4b9
permissions -rw-r--r--
more abstract Document.Node.Name;
tuned signature;
     1 /*  Title:      Pure/PIDE/command.scala
     2     Author:     Fabian Immler, TU Munich
     3     Author:     Makarius
     4 
     5 Prover commands with semantic state.
     6 */
     7 
     8 package isabelle
     9 
    10 import java.lang.System
    11 
    12 import scala.collection.immutable.SortedMap
    13 
    14 
    15 object Command
    16 {
    17   /** accumulated results from prover **/
    18 
    19   sealed case class State(
    20     val command: Command,
    21     val status: List[Markup] = Nil,
    22     val results: SortedMap[Long, XML.Tree] = SortedMap.empty,
    23     val markup: Markup_Tree = Markup_Tree.empty)
    24   {
    25     /* content */
    26 
    27     def add_status(st: Markup): State = copy(status = st :: status)
    28     def add_markup(info: Text.Info[Any]): State = copy(markup = markup + info)
    29     def add_result(serial: Long, result: XML.Tree): State =
    30       copy(results = results + (serial -> result))
    31 
    32     def root_info: Text.Info[Any] =
    33       new Text.Info(command.range,
    34         XML.Elem(Markup(Markup.STATUS, Nil), status.reverse.map(XML.Elem(_, Nil))))
    35     def root_markup: Markup_Tree = markup + root_info
    36 
    37 
    38     /* message dispatch */
    39 
    40     def accumulate(message: XML.Elem): Command.State =
    41       message match {
    42         case XML.Elem(Markup(Markup.STATUS, _), msgs) =>
    43           (this /: msgs)((state, msg) =>
    44             msg match {
    45               case XML.Elem(markup, Nil) => state.add_status(markup)
    46               case _ => System.err.println("Ignored status message: " + msg); state
    47             })
    48 
    49         case XML.Elem(Markup(Markup.REPORT, _), msgs) =>
    50           (this /: msgs)((state, msg) =>
    51             msg match {
    52               case XML.Elem(Markup(name, atts @ Position.Id_Range(id, raw_range)), args)
    53               if id == command.id && command.range.contains(command.decode(raw_range)) =>
    54                 val range = command.decode(raw_range)
    55                 val props = Position.purge(atts)
    56                 val info = Text.Info[Any](range, XML.Elem(Markup(name, props), args))
    57                 state.add_markup(info)
    58               case _ =>
    59                 // FIXME System.err.println("Ignored report message: " + msg)
    60                 state
    61             })
    62         case XML.Elem(Markup(name, atts), body) =>
    63           atts match {
    64             case Markup.Serial(i) =>
    65               val result = XML.Elem(Markup(name, Position.purge(atts)), body)
    66               val st0 = add_result(i, result)
    67               val st1 =
    68                 if (Isar_Document.is_tracing(message)) st0
    69                 else
    70                   (st0 /: Isar_Document.message_positions(command, message))(
    71                     (st, range) => st.add_markup(Text.Info(range, result)))
    72               val st2 = (st1 /: Isar_Document.message_reports(message))(_ accumulate _)
    73               st2
    74             case _ => System.err.println("Ignored message without serial number: " + message); this
    75           }
    76       }
    77   }
    78 
    79 
    80   /* dummy commands */
    81 
    82   def unparsed(source: String): Command =
    83     new Command(Document.no_id, Document.Node.Name("", "", ""),
    84       List(Token(Token.Kind.UNPARSED, source)))
    85 
    86   def span(node_name: Document.Node.Name, toks: List[Token]): Command =
    87     new Command(Document.no_id, node_name, toks)
    88 
    89 
    90   /* perspective */
    91 
    92   object Perspective
    93   {
    94     val empty: Perspective = Perspective(Nil)
    95   }
    96 
    97   sealed case class Perspective(commands: List[Command])  // visible commands in canonical order
    98   {
    99     def same(that: Perspective): Boolean =
   100     {
   101       val cmds1 = this.commands
   102       val cmds2 = that.commands
   103       require(cmds1.forall(_.is_defined))
   104       require(cmds2.forall(_.is_defined))
   105       cmds1.length == cmds2.length &&
   106         (cmds1.iterator zip cmds2.iterator).forall({ case (c1, c2) => c1.id == c2.id })
   107     }
   108   }
   109 }
   110 
   111 
   112 class Command(
   113     val id: Document.Command_ID,
   114     val node_name: Document.Node.Name,
   115     val span: List[Token])
   116 {
   117   /* classification */
   118 
   119   def is_defined: Boolean = id != Document.no_id
   120 
   121   def is_command: Boolean = !span.isEmpty && span.head.is_command
   122   def is_ignored: Boolean = span.forall(_.is_ignored)
   123   def is_malformed: Boolean = !is_command && !is_ignored
   124 
   125   def name: String = if (is_command) span.head.content else ""
   126   override def toString =
   127     id + "/" + (if (is_command) name else if (is_ignored) "IGNORED" else "MALFORMED")
   128 
   129 
   130   /* source text */
   131 
   132   val source: String = span.map(_.source).mkString
   133   def source(range: Text.Range): String = source.substring(range.start, range.stop)
   134   def length: Int = source.length
   135 
   136   val newlines =
   137     (0 /: Symbol.iterator(source)) {
   138       case (n, s) => if (Symbol.is_physical_newline(s)) n + 1 else n }
   139 
   140   val range: Text.Range = Text.Range(0, length)
   141 
   142   lazy val symbol_index = new Symbol.Index(source)
   143   def decode(i: Text.Offset): Text.Offset = symbol_index.decode(i)
   144   def decode(r: Text.Range): Text.Range = symbol_index.decode(r)
   145 
   146 
   147   /* accumulated results */
   148 
   149   val empty_state: Command.State = Command.State(this)
   150 }