wenzelm@38483
|
1 |
/* Title: Pure/PIDE/isar_document.scala
|
wenzelm@38412
|
2 |
Author: Makarius
|
wenzelm@38412
|
3 |
|
wenzelm@38567
|
4 |
Protocol message formats for interactive Isar documents.
|
wenzelm@38412
|
5 |
*/
|
wenzelm@38412
|
6 |
|
wenzelm@38412
|
7 |
package isabelle
|
wenzelm@38412
|
8 |
|
wenzelm@38412
|
9 |
|
wenzelm@38412
|
10 |
object Isar_Document
|
wenzelm@38412
|
11 |
{
|
wenzelm@38567
|
12 |
/* document editing */
|
wenzelm@38412
|
13 |
|
wenzelm@38412
|
14 |
object Assign {
|
wenzelm@38414
|
15 |
def unapply(msg: XML.Tree)
|
wenzelm@38414
|
16 |
: Option[(Document.Version_ID, List[(Document.Command_ID, Document.Exec_ID)])] =
|
wenzelm@38412
|
17 |
msg match {
|
wenzelm@38414
|
18 |
case XML.Elem(Markup(Markup.ASSIGN, List((Markup.VERSION, Document.ID(id)))), edits) =>
|
wenzelm@38412
|
19 |
val id_edits = edits.map(Edit.unapply)
|
wenzelm@38414
|
20 |
if (id_edits.forall(_.isDefined)) Some((id, id_edits.map(_.get)))
|
wenzelm@38412
|
21 |
else None
|
wenzelm@38412
|
22 |
case _ => None
|
wenzelm@38412
|
23 |
}
|
wenzelm@38412
|
24 |
}
|
wenzelm@38412
|
25 |
|
wenzelm@38412
|
26 |
object Edit {
|
wenzelm@38412
|
27 |
def unapply(msg: XML.Tree): Option[(Document.Command_ID, Document.Exec_ID)] =
|
wenzelm@38412
|
28 |
msg match {
|
wenzelm@38414
|
29 |
case XML.Elem(
|
wenzelm@38414
|
30 |
Markup(Markup.EDIT,
|
wenzelm@38414
|
31 |
List((Markup.ID, Document.ID(i)), (Markup.EXEC, Document.ID(j)))), Nil) => Some((i, j))
|
wenzelm@38412
|
32 |
case _ => None
|
wenzelm@38412
|
33 |
}
|
wenzelm@38412
|
34 |
}
|
wenzelm@38567
|
35 |
|
wenzelm@38567
|
36 |
|
wenzelm@38567
|
37 |
/* toplevel transactions */
|
wenzelm@38567
|
38 |
|
wenzelm@38567
|
39 |
sealed abstract class Status
|
wenzelm@38567
|
40 |
case class Forked(forks: Int) extends Status
|
wenzelm@38567
|
41 |
case object Unprocessed extends Status
|
wenzelm@38567
|
42 |
case object Finished extends Status
|
wenzelm@38567
|
43 |
case object Failed extends Status
|
wenzelm@38567
|
44 |
|
wenzelm@38581
|
45 |
def command_status(markup: List[Markup]): Status =
|
wenzelm@38567
|
46 |
{
|
wenzelm@38567
|
47 |
val forks = (0 /: markup) {
|
wenzelm@38581
|
48 |
case (i, Markup(Markup.FORKED, _)) => i + 1
|
wenzelm@38581
|
49 |
case (i, Markup(Markup.JOINED, _)) => i - 1
|
wenzelm@38567
|
50 |
case (i, _) => i
|
wenzelm@38567
|
51 |
}
|
wenzelm@38567
|
52 |
if (forks != 0) Forked(forks)
|
wenzelm@38581
|
53 |
else if (markup.exists(_.name == Markup.FAILED)) Failed
|
wenzelm@38581
|
54 |
else if (markup.exists(_.name == Markup.FINISHED)) Finished
|
wenzelm@38567
|
55 |
else Unprocessed
|
wenzelm@38567
|
56 |
}
|
wenzelm@38887
|
57 |
|
wenzelm@38887
|
58 |
|
wenzelm@39441
|
59 |
/* result messages */
|
wenzelm@39439
|
60 |
|
wenzelm@39439
|
61 |
def clean_message(body: XML.Body): XML.Body =
|
wenzelm@39439
|
62 |
body filter { case XML.Elem(Markup(Markup.NO_REPORT, _), _) => false case _ => true } map
|
wenzelm@39439
|
63 |
{ case XML.Elem(markup, ts) => XML.Elem(markup, clean_message(ts)) case t => t }
|
wenzelm@39439
|
64 |
|
wenzelm@39441
|
65 |
def message_reports(msg: XML.Tree): List[XML.Elem] =
|
wenzelm@39441
|
66 |
msg match {
|
wenzelm@39441
|
67 |
case elem @ XML.Elem(Markup(Markup.REPORT, _), _) => List(elem)
|
wenzelm@39441
|
68 |
case XML.Elem(_, body) => body.flatMap(message_reports)
|
wenzelm@39441
|
69 |
case XML.Text(_) => Nil
|
wenzelm@39441
|
70 |
}
|
wenzelm@39441
|
71 |
|
wenzelm@39439
|
72 |
|
wenzelm@39511
|
73 |
/* specific messages */
|
wenzelm@39511
|
74 |
|
wenzelm@39625
|
75 |
def is_ready(msg: XML.Tree): Boolean =
|
wenzelm@39625
|
76 |
msg match {
|
wenzelm@39625
|
77 |
case XML.Elem(Markup(Markup.STATUS, _),
|
wenzelm@39625
|
78 |
List(XML.Elem(Markup(Markup.READY, _), _))) => true
|
wenzelm@39625
|
79 |
case _ => false
|
wenzelm@39625
|
80 |
}
|
wenzelm@39625
|
81 |
|
wenzelm@39625
|
82 |
def is_tracing(msg: XML.Tree): Boolean =
|
wenzelm@39622
|
83 |
msg match {
|
wenzelm@39622
|
84 |
case XML.Elem(Markup(Markup.TRACING, _), _) => true
|
wenzelm@39622
|
85 |
case _ => false
|
wenzelm@39622
|
86 |
}
|
wenzelm@39622
|
87 |
|
wenzelm@39511
|
88 |
def is_warning(msg: XML.Tree): Boolean =
|
wenzelm@39511
|
89 |
msg match {
|
wenzelm@39511
|
90 |
case XML.Elem(Markup(Markup.WARNING, _), _) => true
|
wenzelm@39511
|
91 |
case _ => false
|
wenzelm@39511
|
92 |
}
|
wenzelm@39511
|
93 |
|
wenzelm@39511
|
94 |
def is_error(msg: XML.Tree): Boolean =
|
wenzelm@39511
|
95 |
msg match {
|
wenzelm@39511
|
96 |
case XML.Elem(Markup(Markup.ERROR, _), _) => true
|
wenzelm@39511
|
97 |
case _ => false
|
wenzelm@39511
|
98 |
}
|
wenzelm@38887
|
99 |
|
wenzelm@39441
|
100 |
def is_state(msg: XML.Tree): Boolean =
|
wenzelm@39170
|
101 |
msg match {
|
wenzelm@39627
|
102 |
case XML.Elem(Markup(Markup.WRITELN, _),
|
wenzelm@39627
|
103 |
List(XML.Elem(Markup(Markup.STATE, _), _))) => true
|
wenzelm@39170
|
104 |
case _ => false
|
wenzelm@39170
|
105 |
}
|
wenzelm@39170
|
106 |
|
wenzelm@39511
|
107 |
|
wenzelm@39511
|
108 |
/* reported positions */
|
wenzelm@39511
|
109 |
|
wenzelm@39627
|
110 |
private val include_pos =
|
wenzelm@39627
|
111 |
Set(Markup.BINDING, Markup.ENTITY, Markup.REPORT, Markup.POSITION)
|
wenzelm@39441
|
112 |
|
wenzelm@39441
|
113 |
def message_positions(command: Command, message: XML.Elem): Set[Text.Range] =
|
wenzelm@38887
|
114 |
{
|
wenzelm@39441
|
115 |
def positions(set: Set[Text.Range], tree: XML.Tree): Set[Text.Range] =
|
wenzelm@38887
|
116 |
tree match {
|
wenzelm@39172
|
117 |
case XML.Elem(Markup(name, Position.Id_Range(id, raw_range)), body)
|
wenzelm@39172
|
118 |
if include_pos(name) && id == command.id =>
|
wenzelm@39172
|
119 |
val range = command.decode(raw_range).restrict(command.range)
|
wenzelm@39441
|
120 |
body.foldLeft(if (range.is_singularity) set else set + range)(positions)
|
wenzelm@39441
|
121 |
case XML.Elem(Markup(name, _), body) => body.foldLeft(set)(positions)
|
wenzelm@39042
|
122 |
case _ => set
|
wenzelm@38887
|
123 |
}
|
wenzelm@39441
|
124 |
val set = positions(Set.empty, message)
|
wenzelm@39170
|
125 |
if (set.isEmpty && !is_state(message))
|
wenzelm@39172
|
126 |
set ++ Position.Range.unapply(message.markup.properties).map(command.decode(_))
|
wenzelm@39042
|
127 |
else set
|
wenzelm@38887
|
128 |
}
|
wenzelm@38412
|
129 |
}
|
wenzelm@38412
|
130 |
|
wenzelm@38412
|
131 |
|
wenzelm@38412
|
132 |
trait Isar_Document extends Isabelle_Process
|
wenzelm@38412
|
133 |
{
|
wenzelm@38412
|
134 |
/* commands */
|
wenzelm@38412
|
135 |
|
wenzelm@38412
|
136 |
def define_command(id: Document.Command_ID, text: String): Unit =
|
wenzelm@38414
|
137 |
input("Isar_Document.define_command", Document.ID(id), text)
|
wenzelm@38412
|
138 |
|
wenzelm@38412
|
139 |
|
wenzelm@38417
|
140 |
/* document versions */
|
wenzelm@38412
|
141 |
|
wenzelm@38417
|
142 |
def edit_version(old_id: Document.Version_ID, new_id: Document.Version_ID,
|
wenzelm@44383
|
143 |
edits: List[Document.Edit_Command])
|
wenzelm@38412
|
144 |
{
|
wenzelm@44157
|
145 |
val edits_yxml =
|
wenzelm@43767
|
146 |
{ import XML.Encode._
|
wenzelm@44383
|
147 |
def id: T[Command] = (cmd => long(cmd.id))
|
wenzelm@44383
|
148 |
def encode: T[List[Document.Edit_Command]] =
|
wenzelm@44156
|
149 |
list(pair(string,
|
wenzelm@44156
|
150 |
variant(List(
|
wenzelm@44185
|
151 |
{ case Document.Node.Clear() => (Nil, Nil) },
|
wenzelm@44383
|
152 |
{ case Document.Node.Edits(a) => (Nil, list(pair(option(id), option(id)))(a)) },
|
wenzelm@44182
|
153 |
{ case Document.Node.Header(Exn.Res(Thy_Header(a, b, c))) =>
|
wenzelm@44185
|
154 |
(Nil, triple(string, list(string), list(pair(string, bool)))(a, b, c)) },
|
wenzelm@44182
|
155 |
{ case Document.Node.Header(Exn.Exn(e)) => (List(Exn.message(e)), Nil) }))))
|
wenzelm@44157
|
156 |
YXML.string_of_body(encode(edits)) }
|
wenzelm@38412
|
157 |
|
wenzelm@44157
|
158 |
input("Isar_Document.edit_version", Document.ID(old_id), Document.ID(new_id), edits_yxml)
|
wenzelm@38412
|
159 |
}
|
wenzelm@43748
|
160 |
|
wenzelm@43748
|
161 |
|
wenzelm@43748
|
162 |
/* method invocation service */
|
wenzelm@43748
|
163 |
|
wenzelm@43748
|
164 |
def invoke_scala(id: String, tag: Invoke_Scala.Tag.Value, res: String)
|
wenzelm@43748
|
165 |
{
|
wenzelm@43748
|
166 |
input("Isar_Document.invoke_scala", id, tag.toString, res)
|
wenzelm@43748
|
167 |
}
|
wenzelm@38412
|
168 |
}
|