35 case object Startup extends Phase // transient |
35 case object Startup extends Phase // transient |
36 case object Failed extends Phase |
36 case object Failed extends Phase |
37 case object Ready extends Phase |
37 case object Ready extends Phase |
38 case object Shutdown extends Phase // transient |
38 case object Shutdown extends Phase // transient |
39 //}}} |
39 //}}} |
|
40 |
|
41 |
|
42 /* protocol handlers */ |
|
43 |
|
44 type Prover = Isabelle_Process with Protocol |
|
45 |
|
46 abstract class Protocol_Handler |
|
47 { |
|
48 def stop(prover: Prover): Unit = {} |
|
49 val functions: Map[String, (Prover, Isabelle_Process.Output) => Boolean] |
|
50 } |
|
51 |
|
52 class Protocol_Handlers( |
|
53 handlers: Map[String, Session.Protocol_Handler] = Map.empty, |
|
54 functions: Map[String, Isabelle_Process.Output => Boolean] = Map.empty) |
|
55 { |
|
56 def add(prover: Prover, name: String): Protocol_Handlers = |
|
57 { |
|
58 val (handlers1, functions1) = |
|
59 handlers.get(name) match { |
|
60 case Some(old_handler) => |
|
61 System.err.println("Redefining protocol handler: " + name) |
|
62 old_handler.stop(prover) |
|
63 (handlers - name, functions -- old_handler.functions.keys) |
|
64 case None => (handlers, functions) |
|
65 } |
|
66 |
|
67 val (handlers2, functions2) = |
|
68 try { |
|
69 val new_handler = Class.forName(name).newInstance.asInstanceOf[Protocol_Handler] |
|
70 val new_functions = |
|
71 for ((a, f) <- new_handler.functions.toList) yield |
|
72 (a, (output: Isabelle_Process.Output) => f(prover, output)) |
|
73 |
|
74 val dups = for ((a, _) <- new_functions if functions1.isDefinedAt(a)) yield a |
|
75 if (!dups.isEmpty) error("Duplicate protocol functions: " + commas_quote(dups)) |
|
76 |
|
77 (handlers1 + (name -> new_handler), functions1 ++ new_functions) |
|
78 } |
|
79 catch { |
|
80 case exn: Throwable => |
|
81 System.err.println("Failed to initialize protocol handler: " + |
|
82 name + "\n" + Exn.message(exn)) |
|
83 (handlers1, functions1) |
|
84 } |
|
85 |
|
86 new Protocol_Handlers(handlers2, functions2) |
|
87 } |
|
88 |
|
89 def invoke(output: Isabelle_Process.Output): Boolean = |
|
90 output.properties match { |
|
91 case Markup.Function(a) if functions.isDefinedAt(a) => |
|
92 try { functions(a)(output) } |
|
93 catch { |
|
94 case exn: Throwable => |
|
95 System.err.println("Failed invocation of protocol function: " + |
|
96 quote(a) + "\n" + Exn.message(exn)) |
|
97 false |
|
98 } |
|
99 case _ => false |
|
100 } |
|
101 } |
40 } |
102 } |
41 |
103 |
42 |
104 |
43 class Session(val thy_load: Thy_Load) |
105 class Session(val thy_load: Thy_Load) |
44 { |
106 { |
174 private case class Change( |
236 private case class Change( |
175 doc_edits: List[Document.Edit_Command], |
237 doc_edits: List[Document.Edit_Command], |
176 previous: Document.Version, |
238 previous: Document.Version, |
177 version: Document.Version) |
239 version: Document.Version) |
178 private case class Messages(msgs: List[Isabelle_Process.Message]) |
240 private case class Messages(msgs: List[Isabelle_Process.Message]) |
179 private case class Finished_Scala(id: String, tag: Invoke_Scala.Tag.Value, result: String) |
|
180 private case class Update_Options(options: Options) |
241 private case class Update_Options(options: Options) |
181 |
242 |
182 private val (_, session_actor) = Simple_Thread.actor("session_actor", daemon = true) |
243 private val (_, session_actor) = Simple_Thread.actor("session_actor", daemon = true) |
183 { |
244 { |
184 val this_actor = self |
245 val this_actor = self |
185 |
246 |
|
247 var protocol_handlers = new Session.Protocol_Handlers() |
|
248 |
186 var prune_next = System.currentTimeMillis() + prune_delay.ms |
249 var prune_next = System.currentTimeMillis() + prune_delay.ms |
187 |
|
188 var futures = Map.empty[String, java.util.concurrent.Future[Unit]] |
|
189 |
250 |
190 |
251 |
191 /* buffered prover messages */ |
252 /* buffered prover messages */ |
192 |
253 |
193 object receiver |
254 object receiver |
316 catch { |
377 catch { |
317 case _: Document.State.Fail => bad_output() |
378 case _: Document.State.Fail => bad_output() |
318 } |
379 } |
319 } |
380 } |
320 |
381 |
321 output.properties match { |
382 if (output.is_protocol) { |
322 |
383 val handled = protocol_handlers.invoke(output) |
323 case Position.Id(state_id) if !output.is_protocol => |
384 if (!handled) { |
324 accumulate(state_id, output.message) |
385 output.properties match { |
325 |
386 case Markup.Protocol_Handler(name) => |
326 case Protocol.Command_Timing(state_id, timing) if output.is_protocol => |
387 protocol_handlers = protocol_handlers.add(prover.get, name) |
327 val message = XML.elem(Markup.STATUS, List(XML.Elem(Markup.Timing(timing), Nil))) |
388 |
328 accumulate(state_id, prover.get.xml_cache.elem(message)) |
389 case Protocol.Command_Timing(state_id, timing) => |
329 |
390 val message = XML.elem(Markup.STATUS, List(XML.Elem(Markup.Timing(timing), Nil))) |
330 case Markup.Assign_Execs if output.is_protocol => |
391 accumulate(state_id, prover.get.xml_cache.elem(message)) |
331 XML.content(output.body) match { |
392 |
332 case Protocol.Assign(id, assign) => |
393 case Markup.Assign_Execs => |
333 try { |
394 XML.content(output.body) match { |
334 val cmds = global_state >>> (_.assign(id, assign)) |
395 case Protocol.Assign(id, assign) => |
335 delay_commands_changed.invoke(true, cmds) |
396 try { |
|
397 val cmds = global_state >>> (_.assign(id, assign)) |
|
398 delay_commands_changed.invoke(true, cmds) |
|
399 } |
|
400 catch { case _: Document.State.Fail => bad_output() } |
|
401 case _ => bad_output() |
336 } |
402 } |
337 catch { case _: Document.State.Fail => bad_output() } |
403 // FIXME separate timeout event/message!? |
|
404 if (prover.isDefined && System.currentTimeMillis() > prune_next) { |
|
405 val old_versions = global_state >>> (_.prune_history(prune_size)) |
|
406 if (!old_versions.isEmpty) prover.get.remove_versions(old_versions) |
|
407 prune_next = System.currentTimeMillis() + prune_delay.ms |
|
408 } |
|
409 |
|
410 case Markup.Removed_Versions => |
|
411 XML.content(output.body) match { |
|
412 case Protocol.Removed(removed) => |
|
413 try { |
|
414 global_state >> (_.removed_versions(removed)) |
|
415 } |
|
416 catch { case _: Document.State.Fail => bad_output() } |
|
417 case _ => bad_output() |
|
418 } |
|
419 |
|
420 case Markup.ML_Statistics(props) => |
|
421 statistics.event(Session.Statistics(props)) |
|
422 |
|
423 case Markup.Task_Statistics(props) => |
|
424 // FIXME |
|
425 |
338 case _ => bad_output() |
426 case _ => bad_output() |
339 } |
427 } |
340 // FIXME separate timeout event/message!? |
428 } |
341 if (prover.isDefined && System.currentTimeMillis() > prune_next) { |
429 } |
342 val old_versions = global_state >>> (_.prune_history(prune_size)) |
430 else { |
343 if (!old_versions.isEmpty) prover.get.remove_versions(old_versions) |
431 output.properties match { |
344 prune_next = System.currentTimeMillis() + prune_delay.ms |
432 case Position.Id(state_id) => |
345 } |
433 accumulate(state_id, output.message) |
346 |
434 |
347 case Markup.Removed_Versions if output.is_protocol => |
435 case _ if output.is_init => |
348 XML.content(output.body) match { |
436 phase = Session.Ready |
349 case Protocol.Removed(removed) => |
437 |
350 try { |
438 case Markup.Return_Code(rc) if output.is_exit => |
351 global_state >> (_.removed_versions(removed)) |
439 if (rc == 0) phase = Session.Inactive |
352 } |
440 else phase = Session.Failed |
353 catch { case _: Document.State.Fail => bad_output() } |
441 |
354 case _ => bad_output() |
442 case _ => bad_output() |
355 } |
443 } |
356 |
|
357 case Markup.Invoke_Scala(name, id) if output.is_protocol => |
|
358 futures += (id -> |
|
359 default_thread_pool.submit(() => |
|
360 { |
|
361 val arg = XML.content(output.body) |
|
362 val (tag, result) = Invoke_Scala.method(name, arg) |
|
363 this_actor ! Finished_Scala(id, tag, result) |
|
364 })) |
|
365 |
|
366 case Markup.Cancel_Scala(id) if output.is_protocol => |
|
367 futures.get(id) match { |
|
368 case Some(future) => |
|
369 future.cancel(true) |
|
370 this_actor ! Finished_Scala(id, Invoke_Scala.Tag.INTERRUPT, "") |
|
371 case None => |
|
372 } |
|
373 |
|
374 case Markup.ML_Statistics(props) if output.is_protocol => |
|
375 statistics.event(Session.Statistics(props)) |
|
376 |
|
377 case Markup.Task_Statistics(props) if output.is_protocol => |
|
378 // FIXME |
|
379 |
|
380 case _ if output.is_init => |
|
381 phase = Session.Ready |
|
382 |
|
383 case Markup.Return_Code(rc) if output.is_exit => |
|
384 if (rc == 0) phase = Session.Inactive |
|
385 else phase = Session.Failed |
|
386 |
|
387 case _ => bad_output() |
|
388 } |
444 } |
389 } |
445 } |
390 //}}} |
446 //}}} |
391 |
447 |
392 |
448 |