src/Pure/PIDE/protocol.scala
author wenzelm
Fri Apr 21 14:09:03 2017 +0200 (2017-04-21 ago)
changeset 65532 febfd9f78bd4
parent 65471 05e5bffcf1d8
child 66382 6392766f3c25
permissions -rw-r--r--
eliminated default_qualifier: just a constant;
wenzelm@45709
     1
/*  Title:      Pure/PIDE/protocol.scala
wenzelm@38412
     2
    Author:     Makarius
wenzelm@38412
     3
wenzelm@45709
     4
Protocol message formats for interactive proof documents.
wenzelm@38412
     5
*/
wenzelm@38412
     6
wenzelm@38412
     7
package isabelle
wenzelm@38412
     8
wenzelm@38412
     9
wenzelm@45709
    10
object Protocol
wenzelm@38412
    11
{
wenzelm@38567
    12
  /* document editing */
wenzelm@38412
    13
wenzelm@52563
    14
  object Assign_Update
wenzelm@44476
    15
  {
wenzelm@52563
    16
    def unapply(text: String): Option[(Document_ID.Version, Document.Assign_Update)] =
wenzelm@44661
    17
      try {
wenzelm@44661
    18
        import XML.Decode._
wenzelm@65345
    19
        Some(pair(long, list(pair(long, list(long))))(Symbol.decode_yxml(text)))
wenzelm@44661
    20
      }
wenzelm@44661
    21
      catch {
wenzelm@44661
    22
        case ERROR(_) => None
wenzelm@51987
    23
        case _: XML.Error => None
wenzelm@38412
    24
      }
wenzelm@38412
    25
  }
wenzelm@38567
    26
wenzelm@44676
    27
  object Removed
wenzelm@44676
    28
  {
wenzelm@52530
    29
    def unapply(text: String): Option[List[Document_ID.Version]] =
wenzelm@44676
    30
      try {
wenzelm@44676
    31
        import XML.Decode._
wenzelm@65345
    32
        Some(list(long)(Symbol.decode_yxml(text)))
wenzelm@44676
    33
      }
wenzelm@44676
    34
      catch {
wenzelm@44676
    35
        case ERROR(_) => None
wenzelm@51987
    36
        case _: XML.Error => None
wenzelm@44676
    37
      }
wenzelm@44676
    38
  }
wenzelm@44676
    39
wenzelm@38567
    40
wenzelm@46209
    41
  /* command status */
wenzelm@38567
    42
wenzelm@56359
    43
  object Status
wenzelm@56359
    44
  {
wenzelm@56359
    45
    def make(markup_iterator: Iterator[Markup]): Status =
wenzelm@56359
    46
    {
wenzelm@56359
    47
      var touched = false
wenzelm@56359
    48
      var accepted = false
wenzelm@56395
    49
      var warned = false
wenzelm@56359
    50
      var failed = false
wenzelm@56359
    51
      var forks = 0
wenzelm@56359
    52
      var runs = 0
wenzelm@56359
    53
      for (markup <- markup_iterator) {
wenzelm@56359
    54
        markup.name match {
wenzelm@56359
    55
          case Markup.ACCEPTED => accepted = true
wenzelm@56359
    56
          case Markup.FORKED => touched = true; forks += 1
wenzelm@56359
    57
          case Markup.JOINED => forks -= 1
wenzelm@56359
    58
          case Markup.RUNNING => touched = true; runs += 1
wenzelm@56359
    59
          case Markup.FINISHED => runs -= 1
wenzelm@59203
    60
          case Markup.WARNING | Markup.LEGACY => warned = true
wenzelm@56395
    61
          case Markup.FAILED | Markup.ERROR => failed = true
wenzelm@56359
    62
          case _ =>
wenzelm@56359
    63
        }
wenzelm@56359
    64
      }
wenzelm@56395
    65
      Status(touched, accepted, warned, failed, forks, runs)
wenzelm@56359
    66
    }
wenzelm@56359
    67
wenzelm@56359
    68
    val empty = make(Iterator.empty)
wenzelm@56359
    69
wenzelm@56359
    70
    def merge(status_iterator: Iterator[Status]): Status =
wenzelm@56359
    71
      if (status_iterator.hasNext) {
wenzelm@56359
    72
        val status0 = status_iterator.next
wenzelm@56359
    73
        (status0 /: status_iterator)(_ + _)
wenzelm@56359
    74
      }
wenzelm@56359
    75
      else empty
wenzelm@56359
    76
  }
wenzelm@56359
    77
wenzelm@46166
    78
  sealed case class Status(
wenzelm@56352
    79
    private val touched: Boolean,
wenzelm@56352
    80
    private val accepted: Boolean,
wenzelm@56395
    81
    private val warned: Boolean,
wenzelm@56352
    82
    private val failed: Boolean,
wenzelm@56352
    83
    forks: Int,
wenzelm@56352
    84
    runs: Int)
wenzelm@38567
    85
  {
wenzelm@56359
    86
    def + (that: Status): Status =
wenzelm@56395
    87
      Status(
wenzelm@56395
    88
        touched || that.touched,
wenzelm@56395
    89
        accepted || that.accepted,
wenzelm@56395
    90
        warned || that.warned,
wenzelm@56395
    91
        failed || that.failed,
wenzelm@56395
    92
        forks + that.forks,
wenzelm@56395
    93
        runs + that.runs)
wenzelm@56359
    94
wenzelm@49036
    95
    def is_unprocessed: Boolean = accepted && !failed && (!touched || (forks != 0 && runs == 0))
wenzelm@49036
    96
    def is_running: Boolean = runs != 0
wenzelm@56474
    97
    def is_warned: Boolean = warned
wenzelm@56474
    98
    def is_failed: Boolean = failed
wenzelm@49039
    99
    def is_finished: Boolean = !failed && touched && forks == 0 && runs == 0
wenzelm@46166
   100
  }
wenzelm@46166
   101
wenzelm@56395
   102
  val proper_status_elements =
wenzelm@56743
   103
    Markup.Elements(Markup.ACCEPTED, Markup.FORKED, Markup.JOINED, Markup.RUNNING,
wenzelm@55646
   104
      Markup.FINISHED, Markup.FAILED)
wenzelm@55646
   105
wenzelm@56395
   106
  val liberal_status_elements =
wenzelm@59203
   107
    proper_status_elements + Markup.WARNING + Markup.LEGACY + Markup.ERROR
wenzelm@55646
   108
wenzelm@46209
   109
wenzelm@51818
   110
  /* command timing */
wenzelm@51818
   111
wenzelm@51818
   112
  object Command_Timing
wenzelm@51818
   113
  {
wenzelm@52531
   114
    def unapply(props: Properties.T): Option[(Document_ID.Generic, isabelle.Timing)] =
wenzelm@51818
   115
      props match {
wenzelm@51818
   116
        case (Markup.FUNCTION, Markup.COMMAND_TIMING) :: args =>
wenzelm@51818
   117
          (args, args) match {
wenzelm@51818
   118
            case (Position.Id(id), Markup.Timing_Properties(timing)) => Some((id, timing))
wenzelm@51818
   119
            case _ => None
wenzelm@51818
   120
          }
wenzelm@51818
   121
        case _ => None
wenzelm@51818
   122
      }
wenzelm@51818
   123
  }
wenzelm@51818
   124
wenzelm@51818
   125
wenzelm@46209
   126
  /* node status */
wenzelm@46209
   127
wenzelm@46688
   128
  sealed case class Node_Status(
wenzelm@56474
   129
    unprocessed: Int, running: Int, warned: Int, failed: Int, finished: Int)
wenzelm@44866
   130
  {
wenzelm@56474
   131
    def total: Int = unprocessed + running + warned + failed + finished
wenzelm@44866
   132
  }
wenzelm@44613
   133
wenzelm@44613
   134
  def node_status(
wenzelm@44613
   135
    state: Document.State, version: Document.Version, node: Document.Node): Node_Status =
wenzelm@44613
   136
  {
wenzelm@44613
   137
    var unprocessed = 0
wenzelm@44613
   138
    var running = 0
wenzelm@46688
   139
    var warned = 0
wenzelm@44613
   140
    var failed = 0
wenzelm@56474
   141
    var finished = 0
wenzelm@56356
   142
    for (command <- node.commands.iterator) {
wenzelm@56355
   143
      val states = state.command_states(version, command)
wenzelm@56359
   144
      val status = Status.merge(states.iterator.map(_.protocol_status))
wenzelm@56355
   145
wenzelm@56299
   146
      if (status.is_running) running += 1
wenzelm@57843
   147
      else if (status.is_failed) failed += 1
wenzelm@56395
   148
      else if (status.is_warned) warned += 1
wenzelm@56395
   149
      else if (status.is_finished) finished += 1
wenzelm@56299
   150
      else unprocessed += 1
wenzelm@56299
   151
    }
wenzelm@56474
   152
    Node_Status(unprocessed, running, warned, failed, finished)
wenzelm@44613
   153
  }
wenzelm@44613
   154
wenzelm@38887
   155
wenzelm@51533
   156
  /* node timing */
wenzelm@51533
   157
wenzelm@51533
   158
  sealed case class Node_Timing(total: Double, commands: Map[Command, Double])
wenzelm@51533
   159
wenzelm@51533
   160
  val empty_node_timing = Node_Timing(0.0, Map.empty)
wenzelm@51533
   161
wenzelm@51533
   162
  def node_timing(
wenzelm@51533
   163
    state: Document.State,
wenzelm@51533
   164
    version: Document.Version,
wenzelm@51533
   165
    node: Document.Node,
wenzelm@51533
   166
    threshold: Double): Node_Timing =
wenzelm@51533
   167
  {
wenzelm@51533
   168
    var total = 0.0
wenzelm@51533
   169
    var commands = Map.empty[Command, Double]
wenzelm@51533
   170
    for {
wenzelm@51533
   171
      command <- node.commands.iterator
wenzelm@56299
   172
      st <- state.command_states(version, command)
wenzelm@56356
   173
    } {
wenzelm@56356
   174
      val command_timing =
wenzelm@51533
   175
        (0.0 /: st.status)({
wenzelm@51533
   176
          case (timing, Markup.Timing(t)) => timing + t.elapsed.seconds
wenzelm@51533
   177
          case (timing, _) => timing
wenzelm@51533
   178
        })
wenzelm@51533
   179
      total += command_timing
wenzelm@51533
   180
      if (command_timing >= threshold) commands += (command -> command_timing)
wenzelm@51533
   181
    }
wenzelm@51533
   182
    Node_Timing(total, commands)
wenzelm@51533
   183
  }
wenzelm@51533
   184
wenzelm@51533
   185
wenzelm@39441
   186
  /* result messages */
wenzelm@39439
   187
wenzelm@50500
   188
  def is_result(msg: XML.Tree): Boolean =
wenzelm@50500
   189
    msg match {
wenzelm@50500
   190
      case XML.Elem(Markup(Markup.RESULT, _), _) => true
wenzelm@50500
   191
      case _ => false
wenzelm@50500
   192
    }
wenzelm@50500
   193
wenzelm@50157
   194
  def is_tracing(msg: XML.Tree): Boolean =
wenzelm@39622
   195
    msg match {
wenzelm@50201
   196
      case XML.Elem(Markup(Markup.TRACING, _), _) => true
wenzelm@50201
   197
      case XML.Elem(Markup(Markup.TRACING_MESSAGE, _), _) => true
wenzelm@39622
   198
      case _ => false
wenzelm@39622
   199
    }
wenzelm@39622
   200
wenzelm@59184
   201
  def is_state(msg: XML.Tree): Boolean =
wenzelm@50500
   202
    msg match {
wenzelm@59184
   203
      case XML.Elem(Markup(Markup.STATE, _), _) => true
wenzelm@59184
   204
      case XML.Elem(Markup(Markup.STATE_MESSAGE, _), _) => true
wenzelm@59184
   205
      case _ => false
wenzelm@59184
   206
    }
wenzelm@59184
   207
wenzelm@59184
   208
  def is_information(msg: XML.Tree): Boolean =
wenzelm@59184
   209
    msg match {
wenzelm@59184
   210
      case XML.Elem(Markup(Markup.INFORMATION, _), _) => true
wenzelm@59184
   211
      case XML.Elem(Markup(Markup.INFORMATION_MESSAGE, _), _) => true
wenzelm@50500
   212
      case _ => false
wenzelm@50500
   213
    }
wenzelm@50500
   214
wenzelm@39511
   215
  def is_warning(msg: XML.Tree): Boolean =
wenzelm@39511
   216
    msg match {
wenzelm@50201
   217
      case XML.Elem(Markup(Markup.WARNING, _), _) => true
wenzelm@50201
   218
      case XML.Elem(Markup(Markup.WARNING_MESSAGE, _), _) => true
wenzelm@39511
   219
      case _ => false
wenzelm@39511
   220
    }
wenzelm@39511
   221
wenzelm@59203
   222
  def is_legacy(msg: XML.Tree): Boolean =
wenzelm@59203
   223
    msg match {
wenzelm@59203
   224
      case XML.Elem(Markup(Markup.LEGACY, _), _) => true
wenzelm@59203
   225
      case XML.Elem(Markup(Markup.LEGACY_MESSAGE, _), _) => true
wenzelm@59203
   226
      case _ => false
wenzelm@59203
   227
    }
wenzelm@59203
   228
wenzelm@39511
   229
  def is_error(msg: XML.Tree): Boolean =
wenzelm@39511
   230
    msg match {
wenzelm@50201
   231
      case XML.Elem(Markup(Markup.ERROR, _), _) => true
wenzelm@50201
   232
      case XML.Elem(Markup(Markup.ERROR_MESSAGE, _), _) => true
wenzelm@39511
   233
      case _ => false
wenzelm@39511
   234
    }
wenzelm@38887
   235
wenzelm@56495
   236
  def is_inlined(msg: XML.Tree): Boolean =
wenzelm@56495
   237
    !(is_result(msg) || is_tracing(msg) || is_state(msg))
wenzelm@56495
   238
wenzelm@50500
   239
wenzelm@60882
   240
  /* breakpoints */
wenzelm@60882
   241
wenzelm@60882
   242
  object ML_Breakpoint
wenzelm@60882
   243
  {
wenzelm@60882
   244
    def unapply(tree: XML.Tree): Option[Long] =
wenzelm@60882
   245
    tree match {
wenzelm@60882
   246
      case XML.Elem(Markup(Markup.ML_BREAKPOINT, Markup.Serial(breakpoint)), _) => Some(breakpoint)
wenzelm@60882
   247
      case _ => None
wenzelm@60882
   248
    }
wenzelm@60882
   249
  }
wenzelm@60882
   250
wenzelm@60882
   251
wenzelm@50500
   252
  /* dialogs */
wenzelm@50500
   253
wenzelm@50500
   254
  object Dialog_Args
wenzelm@50500
   255
  {
wenzelm@52531
   256
    def unapply(props: Properties.T): Option[(Document_ID.Generic, Long, String)] =
wenzelm@50500
   257
      (props, props, props) match {
wenzelm@50500
   258
        case (Position.Id(id), Markup.Serial(serial), Markup.Result(result)) =>
wenzelm@50500
   259
          Some((id, serial, result))
wenzelm@50500
   260
        case _ => None
wenzelm@50500
   261
      }
wenzelm@50500
   262
  }
wenzelm@50500
   263
wenzelm@50500
   264
  object Dialog
wenzelm@50500
   265
  {
wenzelm@52531
   266
    def unapply(tree: XML.Tree): Option[(Document_ID.Generic, Long, String)] =
wenzelm@50500
   267
      tree match {
wenzelm@50500
   268
        case XML.Elem(Markup(Markup.DIALOG, Dialog_Args(id, serial, result)), _) =>
wenzelm@50500
   269
          Some((id, serial, result))
wenzelm@50500
   270
        case _ => None
wenzelm@50500
   271
      }
wenzelm@50500
   272
  }
wenzelm@50500
   273
wenzelm@50500
   274
  object Dialog_Result
wenzelm@50500
   275
  {
wenzelm@52531
   276
    def apply(id: Document_ID.Generic, serial: Long, result: String): XML.Elem =
wenzelm@50501
   277
    {
wenzelm@50501
   278
      val props = Position.Id(id) ::: Markup.Serial(serial)
wenzelm@50501
   279
      XML.Elem(Markup(Markup.RESULT, props), List(XML.Text(result)))
wenzelm@50501
   280
    }
wenzelm@50500
   281
wenzelm@50501
   282
    def unapply(tree: XML.Tree): Option[String] =
wenzelm@50500
   283
      tree match {
wenzelm@50501
   284
        case XML.Elem(Markup(Markup.RESULT, _), List(XML.Text(result))) => Some(result)
wenzelm@50500
   285
        case _ => None
wenzelm@50500
   286
      }
wenzelm@50500
   287
  }
wenzelm@38412
   288
}
wenzelm@38412
   289
wenzelm@38412
   290
wenzelm@57916
   291
trait Protocol
wenzelm@38412
   292
{
wenzelm@57916
   293
  /* protocol commands */
wenzelm@57916
   294
wenzelm@57916
   295
  def protocol_command_bytes(name: String, args: Bytes*): Unit
wenzelm@57916
   296
  def protocol_command(name: String, args: String*): Unit
wenzelm@57916
   297
wenzelm@57916
   298
wenzelm@56387
   299
  /* options */
wenzelm@56387
   300
wenzelm@56387
   301
  def options(opts: Options): Unit =
wenzelm@65345
   302
    protocol_command("Prover.options", Symbol.encode_yxml(opts.encode))
wenzelm@56387
   303
wenzelm@56387
   304
wenzelm@65470
   305
  /* session base */
wenzelm@65470
   306
wenzelm@65470
   307
  private def encode_table(table: List[(String, String)]): String =
wenzelm@65470
   308
  {
wenzelm@65470
   309
    import XML.Encode._
wenzelm@65470
   310
    Symbol.encode_yxml(list(pair(string, string))(table))
wenzelm@65470
   311
  }
wenzelm@65470
   312
wenzelm@65470
   313
  def session_base(resources: Resources): Unit =
wenzelm@65470
   314
    protocol_command("Prover.session_base",
wenzelm@65470
   315
      encode_table(resources.session_base.global_theories.toList),
wenzelm@65471
   316
      encode_table(resources.session_base.loaded_theories.toList),
wenzelm@65470
   317
      encode_table(resources.session_base.dest_known_theories))
wenzelm@65470
   318
wenzelm@65470
   319
wenzelm@56387
   320
  /* interned items */
wenzelm@54519
   321
wenzelm@56335
   322
  def define_blob(digest: SHA1.Digest, bytes: Bytes): Unit =
wenzelm@56387
   323
    protocol_command_bytes("Document.define_blob", Bytes(digest.toString), bytes)
wenzelm@38412
   324
wenzelm@59671
   325
  def define_command(command: Command)
wenzelm@54519
   326
  {
wenzelm@54519
   327
    val blobs_yxml =
wenzelm@61376
   328
    {
wenzelm@61376
   329
      import XML.Encode._
wenzelm@54519
   330
      val encode_blob: T[Command.Blob] =
wenzelm@54519
   331
        variant(List(
wenzelm@54526
   332
          { case Exn.Res((a, b)) =>
wenzelm@65345
   333
              (Nil, pair(string, option(string))((a.node, b.map(p => p._1.toString)))) },
wenzelm@65345
   334
          { case Exn.Exn(e) => (Nil, string(Exn.message(e))) }))
wenzelm@59085
   335
wenzelm@65345
   336
      Symbol.encode_yxml(pair(list(encode_blob), int)(command.blobs, command.blobs_index))
wenzelm@54519
   337
    }
wenzelm@59085
   338
wenzelm@59085
   339
    val toks = command.span.content
wenzelm@59085
   340
    val toks_yxml =
wenzelm@61376
   341
    {
wenzelm@61376
   342
      import XML.Encode._
wenzelm@64617
   343
      val encode_tok: T[Token] = (tok => pair(int, int)((tok.kind.id, Symbol.length(tok.source))))
wenzelm@65345
   344
      Symbol.encode_yxml(list(encode_tok)(toks))
wenzelm@59085
   345
    }
wenzelm@59085
   346
wenzelm@52582
   347
    protocol_command("Document.define_command",
wenzelm@65345
   348
      (Document_ID(command.id) :: Symbol.encode(command.span.name) :: blobs_yxml :: toks_yxml ::
wenzelm@65345
   349
        toks.map(tok => Symbol.encode(tok.source))): _*)
wenzelm@54519
   350
  }
wenzelm@38412
   351
wenzelm@38412
   352
wenzelm@52931
   353
  /* execution */
wenzelm@52931
   354
wenzelm@52931
   355
  def discontinue_execution(): Unit =
wenzelm@52931
   356
    protocol_command("Document.discontinue_execution")
wenzelm@38412
   357
wenzelm@52931
   358
  def cancel_exec(id: Document_ID.Exec): Unit =
wenzelm@52931
   359
    protocol_command("Document.cancel_exec", Document_ID(id))
wenzelm@52931
   360
wenzelm@52931
   361
wenzelm@52931
   362
  /* document versions */
wenzelm@47343
   363
wenzelm@52530
   364
  def update(old_id: Document_ID.Version, new_id: Document_ID.Version,
wenzelm@44383
   365
    edits: List[Document.Edit_Command])
wenzelm@38412
   366
  {
wenzelm@44157
   367
    val edits_yxml =
wenzelm@61376
   368
    {
wenzelm@61376
   369
      import XML.Encode._
wenzelm@44383
   370
      def id: T[Command] = (cmd => long(cmd.id))
wenzelm@46737
   371
      def encode_edit(name: Document.Node.Name)
wenzelm@52849
   372
          : T[Document.Node.Edit[Command.Edit, Command.Perspective]] =
wenzelm@44979
   373
        variant(List(
wenzelm@44979
   374
          { case Document.Node.Edits(a) => (Nil, list(pair(option(id), option(id)))(a)) },
wenzelm@48707
   375
          { case Document.Node.Deps(header) =>
wenzelm@60992
   376
              val master_dir = File.standard_url(name.master_dir)
wenzelm@59695
   377
              val imports = header.imports.map({ case (a, _) => a.node })
wenzelm@65387
   378
              val keywords =
wenzelm@65387
   379
                header.keywords.map({ case (a, Keyword.Spec(b, c, d)) => (a, ((b, c), d)) })
wenzelm@44979
   380
              (Nil,
wenzelm@65345
   381
                pair(string, pair(string, pair(list(string), pair(list(pair(string,
wenzelm@65345
   382
                    pair(pair(string, list(string)), list(string)))), list(string)))))(
wenzelm@65445
   383
                (master_dir, (name.theory, (imports, (keywords, header.errors)))))) },
wenzelm@52849
   384
          { case Document.Node.Perspective(a, b, c) =>
wenzelm@52849
   385
              (bool_atom(a) :: b.commands.map(cmd => long_atom(cmd.id)),
wenzelm@65345
   386
                list(pair(id, pair(string, list(string))))(c.dest)) }))
wenzelm@48705
   387
      def encode_edits: T[List[Document.Edit_Command]] = list((node_edit: Document.Edit_Command) =>
wenzelm@44979
   388
      {
wenzelm@44979
   389
        val (name, edit) = node_edit
wenzelm@65345
   390
        pair(string, encode_edit(name))(name.node, edit)
wenzelm@44979
   391
      })
wenzelm@65345
   392
      Symbol.encode_yxml(encode_edits(edits)) }
wenzelm@52582
   393
    protocol_command("Document.update", Document_ID(old_id), Document_ID(new_id), edits_yxml)
wenzelm@38412
   394
  }
wenzelm@43748
   395
wenzelm@44673
   396
  def remove_versions(versions: List[Document.Version])
wenzelm@44673
   397
  {
wenzelm@44673
   398
    val versions_yxml =
wenzelm@59364
   399
    { import XML.Encode._
wenzelm@65345
   400
      Symbol.encode_yxml(list(long)(versions.map(_.id))) }
wenzelm@52582
   401
    protocol_command("Document.remove_versions", versions_yxml)
wenzelm@44673
   402
  }
wenzelm@44673
   403
wenzelm@43748
   404
wenzelm@50498
   405
  /* dialog via document content */
wenzelm@50498
   406
wenzelm@52931
   407
  def dialog_result(serial: Long, result: String): Unit =
wenzelm@63805
   408
    protocol_command("Document.dialog_result", Value.Long(serial), result)
wenzelm@38412
   409
}