store exports within PIDE command state;
authorwenzelm
Mon, 07 May 2018 17:11:01 +0200
changeset 68101 0699a0bacc50
parent 68097 5f3cffe16311
child 68102 813b5d0904c6
store exports within PIDE command state; Markup.Export.unapply: proper NAME;
src/Pure/PIDE/command.scala
src/Pure/PIDE/document.scala
src/Pure/PIDE/markup.ML
src/Pure/PIDE/markup.scala
src/Pure/PIDE/session.scala
src/Pure/Thy/export.ML
src/Pure/Thy/export.scala
--- a/src/Pure/PIDE/command.scala	Sun May 06 23:59:14 2018 +0100
+++ b/src/Pure/PIDE/command.scala	Mon May 07 17:11:01 2018 +0200
@@ -28,7 +28,7 @@
   object Results
   {
     type Entry = (Long, XML.Tree)
-    val empty = new Results(SortedMap.empty)
+    val empty: Results = new Results(SortedMap.empty)
     def make(args: TraversableOnce[Results.Entry]): Results = (empty /: args)(_ + _)
     def merge(args: TraversableOnce[Results]): Results = (empty /: args)(_ ++ _)
 
@@ -68,7 +68,39 @@
   }
 
 
-  /* markup */
+  /* exports */
+
+  object Exports
+  {
+    type Entry = (Long, Export.Entry)
+    val empty: Exports = new Exports(SortedMap.empty)
+    def merge(args: TraversableOnce[Exports]): Exports = (empty /: args)(_ ++ _)
+  }
+
+  final class Exports private(private val rep: SortedMap[Long, Export.Entry])
+  {
+    def iterator: Iterator[Exports.Entry] = rep.iterator
+
+    def + (entry: Exports.Entry): Exports =
+      if (rep.isDefinedAt(entry._1)) this
+      else new Exports(rep + entry)
+
+    def ++ (other: Exports): Exports =
+      if (this eq other) this
+      else if (rep.isEmpty) other
+      else (this /: other.iterator)(_ + _)
+
+    override def hashCode: Int = rep.hashCode
+    override def equals(that: Any): Boolean =
+      that match {
+        case other: Exports => rep == other.rep
+        case _ => false
+      }
+    override def toString: String = iterator.mkString("Exports(", ", ", ")")
+  }
+
+
+  /* markups */
 
   object Markup_Index
   {
@@ -175,6 +207,9 @@
     def merge_results(states: List[State]): Results =
       Results.merge(states.map(_.results))
 
+    def merge_exports(states: List[State]): Exports =
+      Exports.merge(states.map(_.exports))
+
     def merge_markups(states: List[State]): Markups =
       Markups.merge(states.map(_.markups))
 
@@ -183,7 +218,8 @@
       Markup_Tree.merge(states.map(_.markup(index)), range, elements)
 
     def merge(command: Command, states: List[State]): State =
-      State(command, states.flatMap(_.status), merge_results(states), merge_markups(states))
+      State(command, states.flatMap(_.status), merge_results(states),
+        merge_exports(states), merge_markups(states))
 
 
     /* XML data representation */
@@ -213,7 +249,7 @@
       val blobs_info: Blobs_Info =
         (blobs_names.map(name => Exn.Res((node_name(name), None)): Blob), blobs_index)
       val command = Command(id, node_name(node), blobs_info, span)
-      State(command, status, results, markups)
+      State(command, status, results, Exports.empty, markups)
     }
   }
 
@@ -221,6 +257,7 @@
     command: Command,
     status: List[Markup] = Nil,
     results: Results = Results.empty,
+    exports: Exports = Exports.empty,
     markups: Markups = Markups.empty)
   {
     lazy val consolidated: Boolean =
@@ -245,7 +282,7 @@
     {
       val markups1 = markups.redirect(other_command.id)
       if (markups1.is_empty) None
-      else Some(new State(other_command, Nil, Results.empty, markups1))
+      else Some(new State(other_command, markups = markups1))
     }
 
     private def add_status(st: Markup): State =
@@ -254,6 +291,9 @@
     private def add_result(entry: Results.Entry): State =
       copy(results = results + entry)
 
+    def add_export(entry: Exports.Entry): State =
+      copy(exports = exports + entry)
+
     private def add_markup(
       status: Boolean, chunk_name: Symbol.Text_Chunk.Name, m: Text.Markup): State =
     {
@@ -342,7 +382,7 @@
               Output.warning("Ignored message without serial number: " + message)
               this
           }
-    }
+      }
   }
 
 
--- a/src/Pure/PIDE/document.scala	Sun May 06 23:59:14 2018 +0100
+++ b/src/Pure/PIDE/document.scala	Mon May 07 17:11:01 2018 +0200
@@ -721,6 +721,22 @@
       }
     }
 
+    def add_export(id: Document_ID.Generic, entry: Command.Exports.Entry): (Command.State, State) =
+    {
+      execs.get(id) match {
+        case Some(st) =>
+          val new_st = st.add_export(entry)
+          (new_st, copy(execs = execs + (id -> new_st)))
+        case None =>
+          commands.get(id) match {
+            case Some(st) =>
+              val new_st = st.add_export(entry)
+              (new_st, copy(commands = commands + (id -> new_st)))
+            case None => fail
+          }
+      }
+    }
+
     def assign(id: Document_ID.Version, update: Assign_Update): (List[Command], State) =
     {
       val version = the_version(id)
--- a/src/Pure/PIDE/markup.ML	Sun May 06 23:59:14 2018 +0100
+++ b/src/Pure/PIDE/markup.ML	Mon May 07 17:11:01 2018 +0200
@@ -203,7 +203,8 @@
   val command_timing: Properties.entry
   val theory_timing: Properties.entry
   val exportN: string
-  type export_args = {id: string option, theory_name: string, name: string, compress: bool}
+  type export_args =
+    {id: string option, serial: serial, theory_name: string, name: string, compress: bool}
   val export: export_args -> Properties.T
   val loading_theory: string -> Properties.T
   val dest_loading_theory: Properties.T -> string option
@@ -642,9 +643,10 @@
 val theory_timing = (functionN, "theory_timing");
 
 val exportN = "export";
-type export_args = {id: string option, theory_name: string, name: string, compress: bool}
-fun export ({id, theory_name, name, compress}: export_args) =
-  [(functionN, exportN), (idN, the_default "" id),
+type export_args =
+  {id: string option, serial: serial, theory_name: string, name: string, compress: bool}
+fun export ({id, serial, theory_name, name, compress}: export_args) =
+  [(functionN, exportN), (idN, the_default "" id), (serialN, Value.print_int serial),
     ("theory_name", theory_name), (nameN, name), ("compress", Value.print_bool compress)];
 
 fun loading_theory name = [("function", "loading_theory"), ("name", name)];
--- a/src/Pure/PIDE/markup.scala	Sun May 06 23:59:14 2018 +0100
+++ b/src/Pure/PIDE/markup.scala	Mon May 07 17:11:01 2018 +0200
@@ -571,7 +571,8 @@
   val EXPORT = "export"
   object Export
   {
-    sealed case class Args(id: Option[String], theory_name: String, name: String, compress: Boolean)
+    sealed case class Args(
+      id: Option[String], serial: Long, theory_name: String, name: String, compress: Boolean)
 
     val THEORY_NAME = "theory_name"
     val COMPRESS = "compress"
@@ -579,16 +580,26 @@
     def dest_inline(props: Properties.T): Option[(Args, Bytes)] =
       props match {
         case
-          List((THEORY_NAME, theory_name), (NAME, name), (COMPRESS, Value.Boolean(compress)),
-            (EXPORT, hex)) => Some((Args(None, theory_name, name, compress), Bytes.hex(hex)))
+          List(
+            (SERIAL, Value.Long(serial)),
+            (THEORY_NAME, theory_name),
+            (NAME, name),
+            (COMPRESS, Value.Boolean(compress)),
+            (EXPORT, hex)) =>
+          Some((Args(None, serial, theory_name, name, compress), Bytes.hex(hex)))
         case _ => None
       }
 
     def unapply(props: Properties.T): Option[Args] =
       props match {
-        case List((FUNCTION, EXPORT), (ID, id),
-          (THEORY_NAME, theory_name), (PATH, name), (COMPRESS, Value.Boolean(compress))) =>
-            Some(Args(proper_string(id), theory_name, name, compress))
+        case List(
+            (FUNCTION, EXPORT),
+            (ID, id),
+            (SERIAL, Value.Long(serial)),
+            (THEORY_NAME, theory_name),
+            (NAME, name),
+            (COMPRESS, Value.Boolean(compress))) =>
+          Some(Args(proper_string(id), serial, theory_name, name, compress))
         case _ => None
       }
   }
--- a/src/Pure/PIDE/session.scala	Sun May 06 23:59:14 2018 +0100
+++ b/src/Pure/PIDE/session.scala	Mon May 07 17:11:01 2018 +0200
@@ -191,6 +191,7 @@
   private case object Stop
   private case class Cancel_Exec(exec_id: Document_ID.Exec)
   private case class Protocol_Command(name: String, args: List[String])
+  private case class Add_Export(args: Markup.Export.Args, bytes: Bytes, output: Prover.Output)
   private case class Update_Options(options: Options)
   private case object Consolidate_Execution
   private case object Prune_History
@@ -400,25 +401,26 @@
 
     /* prover output */
 
+    def bad_output(output: Prover.Output)
+    {
+      if (verbose)
+        Output.warning("Ignoring bad prover output: " + output.message.toString)
+    }
+
+    def change_command(f: Document.State => (Command.State, Document.State), output: Prover.Output)
+    {
+      try {
+        val st = global_state.change_result(f)
+        change_buffer.invoke(false, List(st.command))
+      }
+      catch { case _: Document.State.Fail => bad_output(output) }
+    }
+
     def handle_output(output: Prover.Output)
     //{{{
     {
-      def bad_output()
-      {
-        if (verbose)
-          Output.warning("Ignoring bad prover output: " + output.message.toString)
-      }
-
-      def accumulate(state_id: Document_ID.Generic, message: XML.Elem)
-      {
-        try {
-          val st = global_state.change_result(_.accumulate(state_id, message, xml_cache))
-          change_buffer.invoke(false, List(st.command))
-        }
-        catch {
-          case _: Document.State.Fail => bad_output()
-        }
-      }
+      def accumulate(state_id: Document_ID.Generic, message: XML.Elem): Unit =
+        change_command(_.accumulate(state_id, message, xml_cache), output)
 
       output match {
         case msg: Prover.Protocol_Output =>
@@ -435,8 +437,12 @@
               case Protocol.Theory_Timing(_, _) =>
                 // FIXME
 
-              case Markup.Export(_) =>
-                // FIXME
+              case Markup.Export(args)
+              if args.id.isDefined && Value.Long.unapply(args.id.get).isDefined =>
+                if (args.compress) {
+                  Future.fork { manager.send(Add_Export(args, msg.bytes.compress(), output)) }
+                }
+                else manager.send(Add_Export(args, msg.bytes, output))
 
               case Markup.Assign_Update =>
                 msg.text match {
@@ -446,8 +452,8 @@
                       change_buffer.invoke(true, cmds)
                       manager.send(Session.Change_Flush)
                     }
-                    catch { case _: Document.State.Fail => bad_output() }
-                  case _ => bad_output()
+                    catch { case _: Document.State.Fail => bad_output(output) }
+                  case _ => bad_output(output)
                 }
                 delay_prune.invoke()
 
@@ -458,8 +464,8 @@
                       global_state.change(_.removed_versions(removed))
                       manager.send(Session.Change_Flush)
                     }
-                    catch { case _: Document.State.Fail => bad_output() }
-                  case _ => bad_output()
+                    catch { case _: Document.State.Fail => bad_output(output) }
+                  case _ => bad_output(output)
                 }
 
               case Markup.ML_Statistics(props) =>
@@ -468,7 +474,7 @@
               case Markup.Task_Statistics(props) =>
                 // FIXME
 
-              case _ => bad_output()
+              case _ => bad_output(output)
             }
           }
         case _ =>
@@ -556,6 +562,11 @@
           case Protocol_Command(name, args) if prover.defined =>
             prover.get.protocol_command(name, args:_*)
 
+          case Add_Export(args, bytes, output) =>
+            val id = Value.Long.parse(args.id.get)
+            val entry = (args.serial, Export.make_entry("", args, bytes))
+            change_command(_.add_export(id, entry), output)
+
           case change: Session.Change if prover.defined =>
             val state = global_state.value
             if (!state.removing_versions && state.is_assigned(change.previous))
--- a/src/Pure/Thy/export.ML	Sun May 06 23:59:14 2018 +0100
+++ b/src/Pure/Thy/export.ML	Mon May 07 17:11:01 2018 +0200
@@ -16,6 +16,7 @@
 fun gen_export compress thy name output =
   (Output.try_protocol_message o Markup.export)
    {id = Position.get_id (Position.thread_data ()),
+    serial = serial (),
     theory_name = Context.theory_long_name thy,
     name = name,
     compress = compress} [output];
--- a/src/Pure/Thy/export.scala	Sun May 06 23:59:14 2018 +0100
+++ b/src/Pure/Thy/export.scala	Mon May 07 17:11:01 2018 +0200
@@ -58,6 +58,12 @@
     }
   }
 
+  def make_entry(session_name: String, args: Markup.Export.Args, body: Bytes): Entry =
+  {
+    val bytes = if (args.compress) body.compress() else body
+    Entry(session_name, args.theory_name, args.name, args.compress, bytes)
+  }
+
   def read_entry(db: SQL.Database, session_name: String, theory_name: String, name: String): Entry =
   {
     val select =
@@ -104,9 +110,9 @@
     {
       consumer.send(
         if (args.compress)
-          Future.fork(Entry(session_name, args.theory_name, args.name, true, body.compress()))
+          Future.fork(make_entry(session_name, args, body))
         else
-          Future.value(Entry(session_name, args.theory_name, args.name, false, body)))
+          Future.value(make_entry(session_name, args, body)))
     }
 
     def shutdown(close: Boolean = false): List[String] =