| author | wenzelm | 
| Wed, 17 Aug 2011 13:14:20 +0200 | |
| changeset 44236 | b73b7832b384 | 
| parent 44225 | a8f921e6484f | 
| child 44298 | b8f8488704e2 | 
| permissions | -rw-r--r-- | 
| 36676 | 1 | /* Title: Pure/System/session.scala | 
| 2 | Author: Makarius | |
| 38221 | 3 | Options: :folding=explicit:collapseFolds=1: | 
| 36676 | 4 | |
| 43651 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 5 | Main Isabelle/Scala session, potentially with running prover process. | 
| 36676 | 6 | */ | 
| 34777 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 7 | |
| 34871 
e596a0b71f3c
incorporate "proofdocument" part into main Isabelle/Pure.jar -- except for html_panel.scala, which depends on external library (Lobo/Cobra browser);
 wenzelm parents: 
34859diff
changeset | 8 | package isabelle | 
| 34777 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 9 | |
| 43520 
cec9b95fa35d
explicit import java.lang.System to prevent odd scope problems;
 wenzelm parents: 
43443diff
changeset | 10 | import java.lang.System | 
| 34777 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 11 | |
| 34820 
a8ba6cde13e9
basic setup for synchronous / modal (!) prover startup;
 wenzelm parents: 
34819diff
changeset | 12 | import scala.actors.TIMEOUT | 
| 38226 
9d8848d70b0a
maintain editor history independently of Swing thread, which is potentially a bottle-neck or might be unavailable (e.g. in batch mode);
 wenzelm parents: 
38222diff
changeset | 13 | import scala.actors.Actor | 
| 34777 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 14 | import scala.actors.Actor._ | 
| 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 15 | |
| 34815 
6bae73cd8e33
unified Command and Command_State, eliminated separate Accumulator;
 wenzelm parents: 
34813diff
changeset | 16 | |
| 34791 | 17 | object Session | 
| 18 | {
 | |
| 43716 | 19 | /* file store */ | 
| 43645 | 20 | |
| 21 | abstract class File_Store | |
| 22 |   {
 | |
| 44163 | 23 | def append(master_dir: String, path: Path): String | 
| 24 | def require(file: String): Unit | |
| 43645 | 25 | } | 
| 26 | ||
| 27 | ||
| 34813 
f0107bc96961
more explicit modeling of Command and Command_State as Session.Entity;
 wenzelm parents: 
34810diff
changeset | 28 | /* events */ | 
| 
f0107bc96961
more explicit modeling of Command and Command_State as Session.Entity;
 wenzelm parents: 
34810diff
changeset | 29 | |
| 43716 | 30 |   //{{{
 | 
| 34791 | 31 | case object Global_Settings | 
| 37849 | 32 | case object Perspective | 
| 38849 
2f198d107aef
session_actor: await state assigment of previous change before signalling current change, and avoid crash in overrun situations;
 wenzelm parents: 
38848diff
changeset | 33 | case object Assignment | 
| 38360 | 34 | case class Commands_Changed(set: Set[Command]) | 
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 35 | |
| 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 36 | sealed abstract class Phase | 
| 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 37 | case object Inactive extends Phase | 
| 39701 | 38 | case object Startup extends Phase // transient | 
| 39 | case object Failed extends Phase | |
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 40 | case object Ready extends Phase | 
| 39701 | 41 | case object Shutdown extends Phase // transient | 
| 43716 | 42 | //}}} | 
| 34791 | 43 | } | 
| 44 | ||
| 34777 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 45 | |
| 43661 
39fdbd814c7f
quasi-static Isabelle_System -- reduced tendency towards "functorial style";
 wenzelm parents: 
43660diff
changeset | 46 | class Session(val file_store: Session.File_Store) | 
| 34777 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 47 | {
 | 
| 37849 | 48 | /* real time parameters */ // FIXME properties or settings (!?) | 
| 49 | ||
| 43716 | 50 | val input_delay = Time.seconds(0.3) // user input (e.g. text edits, cursor movement) | 
| 51 | val output_delay = Time.seconds(0.1) // prover output (markup, common messages) | |
| 52 | val update_delay = Time.seconds(0.5) // GUI layout updates | |
| 37849 | 53 | |
| 54 | ||
| 34809 | 55 | /* pervasive event buses */ | 
| 56 | ||
| 57 | val global_settings = new Event_Bus[Session.Global_Settings.type] | |
| 37849 | 58 | val perspective = new Event_Bus[Session.Perspective.type] | 
| 38849 
2f198d107aef
session_actor: await state assigment of previous change before signalling current change, and avoid crash in overrun situations;
 wenzelm parents: 
38848diff
changeset | 59 | val assignments = new Event_Bus[Session.Assignment.type] | 
| 43716 | 60 | val commands_changed = new Event_Bus[Session.Commands_Changed] | 
| 61 | val phase_changed = new Event_Bus[Session.Phase] | |
| 43721 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43720diff
changeset | 62 | val raw_messages = new Event_Bus[Isabelle_Process.Message] | 
| 43716 | 63 | |
| 34809 | 64 | |
| 65 | ||
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 66 | /** buffered command changes (delay_first discipline) **/ | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 67 | |
| 43716 | 68 |   //{{{
 | 
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 69 | private case object Stop | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 70 | |
| 39572 | 71 | private val (_, command_change_buffer) = | 
| 72 |     Simple_Thread.actor("command_change_buffer", daemon = true)
 | |
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 73 |   {
 | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 74 | var changed: Set[Command] = Set() | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 75 | var flush_time: Option[Long] = None | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 76 | |
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 77 | def flush_timeout: Long = | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 78 |       flush_time match {
 | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 79 | case None => 5000L | 
| 40848 
8662b9b1f123
more abstract/uniform handling of time, preferring seconds as Double;
 wenzelm parents: 
40566diff
changeset | 80 | case Some(time) => (time - System.currentTimeMillis()) max 0 | 
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 81 | } | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 82 | |
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 83 | def flush() | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 84 |     {
 | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 85 | if (!changed.isEmpty) commands_changed.event(Session.Commands_Changed(changed)) | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 86 | changed = Set() | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 87 | flush_time = None | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 88 | } | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 89 | |
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 90 | def invoke() | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 91 |     {
 | 
| 40848 
8662b9b1f123
more abstract/uniform handling of time, preferring seconds as Double;
 wenzelm parents: 
40566diff
changeset | 92 | val now = System.currentTimeMillis() | 
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 93 |       flush_time match {
 | 
| 40848 
8662b9b1f123
more abstract/uniform handling of time, preferring seconds as Double;
 wenzelm parents: 
40566diff
changeset | 94 | case None => flush_time = Some(now + output_delay.ms) | 
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 95 | case Some(time) => if (now >= time) flush() | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 96 | } | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 97 | } | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 98 | |
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 99 | var finished = false | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 100 |     while (!finished) {
 | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 101 |       receiveWithin(flush_timeout) {
 | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 102 | case command: Command => changed += command; invoke() | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 103 | case TIMEOUT => flush() | 
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 104 | case Stop => finished = true; reply(()) | 
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 105 |         case bad => System.err.println("command_change_buffer: ignoring bad message " + bad)
 | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 106 | } | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 107 | } | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 108 | } | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 109 | //}}} | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 110 | |
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 111 | |
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 112 | |
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 113 | /** main protocol actor **/ | 
| 34809 | 114 | |
| 43651 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 115 | /* global state */ | 
| 43644 | 116 | |
| 43716 | 117 | @volatile var verbose: Boolean = false | 
| 118 | ||
| 119 | @volatile private var loaded_theories: Set[String] = Set() | |
| 43673 
29eb1cd29961
Thy_Info.dependencies: ignore already loaded theories, according to initial prover session status;
 wenzelm parents: 
43662diff
changeset | 120 | |
| 43695 
5130dfe1b7be
simplified Symbol based on lazy Symbol.Interpretation -- reduced odd "functorial style";
 wenzelm parents: 
43673diff
changeset | 121 | @volatile private var syntax = new Outer_Syntax | 
| 38569 | 122 | def current_syntax(): Outer_Syntax = syntax | 
| 34809 | 123 | |
| 39626 
a5d0bcfb95a3
manage persistent syslog via Session, not Isabelle_Process;
 wenzelm parents: 
39625diff
changeset | 124 | @volatile private var reverse_syslog = List[XML.Elem]() | 
| 39629 | 125 |   def syslog(): String = reverse_syslog.reverse.map(msg => XML.content(msg).mkString).mkString("\n")
 | 
| 39626 
a5d0bcfb95a3
manage persistent syslog via Session, not Isabelle_Process;
 wenzelm parents: 
39625diff
changeset | 126 | |
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 127 | @volatile private var _phase: Session.Phase = Session.Inactive | 
| 39633 | 128 | private def phase_=(new_phase: Session.Phase) | 
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 129 |   {
 | 
| 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 130 | _phase = new_phase | 
| 39701 | 131 | phase_changed.event(new_phase) | 
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 132 | } | 
| 43716 | 133 | def phase = _phase | 
| 43553 | 134 | def is_ready: Boolean = phase == Session.Ready | 
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 135 | |
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 136 | private val global_state = new Volatile(Document.State.init) | 
| 43719 | 137 | def current_state(): Document.State = global_state() | 
| 34816 
d33312514220
maintain generic session entities -- cover commands, states, etc. (but not yet documents);
 wenzelm parents: 
34815diff
changeset | 138 | |
| 43716 | 139 | def snapshot(name: String, pending_edits: List[Text.Edit]): Document.Snapshot = | 
| 43719 | 140 | global_state().snapshot(name, pending_edits) | 
| 43716 | 141 | |
| 43651 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 142 | |
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 143 | /* theory files */ | 
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 144 | |
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 145 | val thy_load = new Thy_Load | 
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 146 |   {
 | 
| 43673 
29eb1cd29961
Thy_Info.dependencies: ignore already loaded theories, according to initial prover session status;
 wenzelm parents: 
43662diff
changeset | 147 | override def is_loaded(name: String): Boolean = | 
| 
29eb1cd29961
Thy_Info.dependencies: ignore already loaded theories, according to initial prover session status;
 wenzelm parents: 
43662diff
changeset | 148 | loaded_theories.contains(name) | 
| 
29eb1cd29961
Thy_Info.dependencies: ignore already loaded theories, according to initial prover session status;
 wenzelm parents: 
43662diff
changeset | 149 | |
| 44159 | 150 | override def check_thy(dir: Path, name: String): (String, Thy_Header) = | 
| 43651 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 151 |     {
 | 
| 43661 
39fdbd814c7f
quasi-static Isabelle_System -- reduced tendency towards "functorial style";
 wenzelm parents: 
43660diff
changeset | 152 | val file = Isabelle_System.platform_file(dir + Thy_Header.thy_path(name)) | 
| 43652 | 153 |       if (!file.exists || !file.isFile) error("No such file: " + quote(file.toString))
 | 
| 43651 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 154 | val text = Standard_System.read_file(file) | 
| 43661 
39fdbd814c7f
quasi-static Isabelle_System -- reduced tendency towards "functorial style";
 wenzelm parents: 
43660diff
changeset | 155 | val header = Thy_Header.read(text) | 
| 43651 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 156 | (text, header) | 
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 157 | } | 
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 158 | } | 
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 159 | |
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 160 | val thy_info = new Thy_Info(thy_load) | 
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 161 | |
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 162 | |
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 163 | /* actor messages */ | 
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: 
43649diff
changeset | 164 | |
| 43716 | 165 | private case class Start(timeout: Time, args: List[String]) | 
| 166 | private case object Interrupt | |
| 44182 | 167 | private case class Init_Node( | 
| 168 | name: String, master_dir: String, header: Document.Node_Header, text: String) | |
| 169 | private case class Edit_Node( | |
| 170 | name: String, master_dir: String, header: Document.Node_Header, edits: List[Text.Edit]) | |
| 43722 | 171 | private case class Change_Node( | 
| 172 | name: String, | |
| 173 | doc_edits: List[Document.Edit_Command], | |
| 174 | previous: Document.Version, | |
| 175 | version: Document.Version) | |
| 41534 | 176 | |
| 39572 | 177 |   private val (_, session_actor) = Simple_Thread.actor("session_actor", daemon = true)
 | 
| 38639 
f642faca303e
main session actor as independent thread, to avoid starvation via regular worker pool;
 wenzelm parents: 
38569diff
changeset | 178 |   {
 | 
| 43648 | 179 | val this_actor = self | 
| 43649 | 180 | var prover: Option[Isabelle_Process with Isar_Document] = None | 
| 34809 | 181 | |
| 182 | ||
| 43716 | 183 | /* incoming edits */ | 
| 184 | ||
| 44182 | 185 | def handle_edits(name: String, master_dir: String, | 
| 186 | header: Document.Node_Header, edits: List[Document.Node.Edit[Text.Edit]]) | |
| 43716 | 187 |     //{{{
 | 
| 188 |     {
 | |
| 189 | val syntax = current_syntax() | |
| 43719 | 190 | val previous = global_state().history.tip.version | 
| 44185 | 191 | |
| 44222 
9d5ef6cd4ee1
use full .thy file name as node name, which makes MiscUtilities.resolveSymlinks/File.getCanonicalPath more predictable;
 wenzelm parents: 
44185diff
changeset | 192 | def norm_import(s: String): String = | 
| 
9d5ef6cd4ee1
use full .thy file name as node name, which makes MiscUtilities.resolveSymlinks/File.getCanonicalPath more predictable;
 wenzelm parents: 
44185diff
changeset | 193 |       {
 | 
| 44225 
a8f921e6484f
more robust Thy_Header.base_name, with minimal assumptions about path syntax;
 wenzelm parents: 
44222diff
changeset | 194 | val name = Thy_Header.base_name(s) | 
| 44222 
9d5ef6cd4ee1
use full .thy file name as node name, which makes MiscUtilities.resolveSymlinks/File.getCanonicalPath more predictable;
 wenzelm parents: 
44185diff
changeset | 195 | if (thy_load.is_loaded(name)) name | 
| 
9d5ef6cd4ee1
use full .thy file name as node name, which makes MiscUtilities.resolveSymlinks/File.getCanonicalPath more predictable;
 wenzelm parents: 
44185diff
changeset | 196 | else file_store.append(master_dir, Thy_Header.thy_path(Path.explode(s))) | 
| 
9d5ef6cd4ee1
use full .thy file name as node name, which makes MiscUtilities.resolveSymlinks/File.getCanonicalPath more predictable;
 wenzelm parents: 
44185diff
changeset | 197 | } | 
| 
9d5ef6cd4ee1
use full .thy file name as node name, which makes MiscUtilities.resolveSymlinks/File.getCanonicalPath more predictable;
 wenzelm parents: 
44185diff
changeset | 198 | def norm_use(s: String): String = file_store.append(master_dir, Path.explode(s)) | 
| 
9d5ef6cd4ee1
use full .thy file name as node name, which makes MiscUtilities.resolveSymlinks/File.getCanonicalPath more predictable;
 wenzelm parents: 
44185diff
changeset | 199 | val norm_header = Document.Node.norm_header[Text.Edit](norm_import, norm_use, header) | 
| 
9d5ef6cd4ee1
use full .thy file name as node name, which makes MiscUtilities.resolveSymlinks/File.getCanonicalPath more predictable;
 wenzelm parents: 
44185diff
changeset | 200 | |
| 44185 | 201 | val text_edits = (name, norm_header) :: edits.map(edit => (name, edit)) | 
| 202 |       val result = Future.fork { Thy_Syntax.text_edits(syntax, previous.join, text_edits) }
 | |
| 43722 | 203 | val change = | 
| 44185 | 204 | global_state.change_yield(_.extend_history(previous, text_edits, result.map(_._2))) | 
| 43716 | 205 | |
| 43722 | 206 |       result.map {
 | 
| 44157 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 207 | case (doc_edits, _) => | 
| 43722 | 208 |           assignments.await { global_state().is_assigned(previous.get_finished) }
 | 
| 44157 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 209 | this_actor ! Change_Node(name, doc_edits, previous.join, change.version.join) | 
| 43722 | 210 | } | 
| 43716 | 211 | } | 
| 212 | //}}} | |
| 213 | ||
| 214 | ||
| 215 | /* resulting changes */ | |
| 34809 | 216 | |
| 43722 | 217 | def handle_change(change: Change_Node) | 
| 38221 | 218 |     //{{{
 | 
| 34809 | 219 |     {
 | 
| 43722 | 220 | val previous = change.previous | 
| 221 | val version = change.version | |
| 222 | val name = change.name | |
| 223 | val doc_edits = change.doc_edits | |
| 38366 
fea82d1add74
simplified/clarified Change: transition prev --edits--> result, based on futures;
 wenzelm parents: 
38365diff
changeset | 224 | |
| 43719 | 225 | var former_assignment = global_state().the_assignment(previous).get_finished | 
| 38370 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 226 |       for {
 | 
| 44156 | 227 | (name, Document.Node.Edits(cmd_edits)) <- doc_edits // FIXME proper coverage!? | 
| 38370 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 228 | (prev, None) <- cmd_edits | 
| 38417 | 229 | removed <- previous.nodes(name).commands.get_after(prev) | 
| 38370 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 230 | } former_assignment -= removed | 
| 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 231 | |
| 43720 | 232 | def id_command(command: Command): Document.Command_ID = | 
| 233 |       {
 | |
| 234 |         if (global_state().lookup_command(command.id).isEmpty) {
 | |
| 235 | global_state.change(_.define_command(command)) | |
| 236 | prover.get.define_command(command.id, Symbol.encode(command.source)) | |
| 237 | } | |
| 238 | command.id | |
| 239 | } | |
| 38150 
67fc24df3721
simplified/refined document model: collection of named nodes, without proper dependencies yet;
 wenzelm parents: 
37849diff
changeset | 240 | val id_edits = | 
| 43722 | 241 |         doc_edits map {
 | 
| 44156 | 242 | case (name, edit) => | 
| 243 |             (name, edit.map({ case (c1, c2) => (c1.map(id_command), c2.map(id_command)) }))
 | |
| 38150 
67fc24df3721
simplified/refined document model: collection of named nodes, without proper dependencies yet;
 wenzelm parents: 
37849diff
changeset | 244 | } | 
| 43722 | 245 | |
| 39698 | 246 | global_state.change(_.define_version(version, former_assignment)) | 
| 44157 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 247 | prover.get.edit_version(previous.id, version.id, id_edits) | 
| 34809 | 248 | } | 
| 38221 | 249 | //}}} | 
| 34809 | 250 | |
| 251 | ||
| 252 | /* prover results */ | |
| 253 | ||
| 254 | def handle_result(result: Isabelle_Process.Result) | |
| 38221 | 255 |     //{{{
 | 
| 34809 | 256 |     {
 | 
| 43716 | 257 | def bad_result(result: Isabelle_Process.Result) | 
| 258 |       {
 | |
| 259 | if (verbose) | |
| 260 |           System.err.println("Ignoring prover result: " + result.message.toString)
 | |
| 261 | } | |
| 262 | ||
| 38722 
ba31936497c2
organized markup properties via apply/unapply patterns;
 wenzelm parents: 
38639diff
changeset | 263 |       result.properties match {
 | 
| 43748 | 264 | case Position.Id(state_id) if !result.is_raw => | 
| 38370 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 265 |           try {
 | 
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 266 | val st = global_state.change_yield(_.accumulate(state_id, result.message)) | 
| 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 267 | command_change_buffer ! st.command | 
| 38370 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 268 | } | 
| 43748 | 269 |           catch {
 | 
| 270 | case _: Document.State.Fail => bad_result(result) | |
| 271 | } | |
| 272 | case Markup.Invoke_Scala(name, id) if result.is_raw => | |
| 273 |           Future.fork {
 | |
| 274 | val arg = XML.content(result.body).mkString | |
| 275 | val (tag, res) = Invoke_Scala.method(name, arg) | |
| 276 | prover.get.invoke_scala(id, tag, res) | |
| 277 | } | |
| 38722 
ba31936497c2
organized markup properties via apply/unapply patterns;
 wenzelm parents: 
38639diff
changeset | 278 | case _ => | 
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 279 |           if (result.is_syslog) {
 | 
| 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 280 | reverse_syslog ::= result.message | 
| 40533 
e38e80686ce5
somewhat adhoc replacement for 'thus' and 'hence';
 wenzelm parents: 
40479diff
changeset | 281 |             if (result.is_ready) {
 | 
| 43716 | 282 | // FIXME move to ML side (!?) | 
| 40533 
e38e80686ce5
somewhat adhoc replacement for 'thus' and 'hence';
 wenzelm parents: 
40479diff
changeset | 283 |               syntax += ("hence", Keyword.PRF_ASM_GOAL, "then have")
 | 
| 
e38e80686ce5
somewhat adhoc replacement for 'thus' and 'hence';
 wenzelm parents: 
40479diff
changeset | 284 |               syntax += ("thus", Keyword.PRF_ASM_GOAL, "then show")
 | 
| 
e38e80686ce5
somewhat adhoc replacement for 'thus' and 'hence';
 wenzelm parents: 
40479diff
changeset | 285 | phase = Session.Ready | 
| 
e38e80686ce5
somewhat adhoc replacement for 'thus' and 'hence';
 wenzelm parents: 
40479diff
changeset | 286 | } | 
| 39701 | 287 | else if (result.is_exit && phase == Session.Startup) phase = Session.Failed | 
| 39696 | 288 | else if (result.is_exit) phase = Session.Inactive | 
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 289 | } | 
| 39626 
a5d0bcfb95a3
manage persistent syslog via Session, not Isabelle_Process;
 wenzelm parents: 
39625diff
changeset | 290 |           else if (result.is_stdout) { }
 | 
| 39625 | 291 |           else if (result.is_status) {
 | 
| 38370 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 292 |             result.body match {
 | 
| 38417 | 293 | case List(Isar_Document.Assign(id, edits)) => | 
| 38849 
2f198d107aef
session_actor: await state assigment of previous change before signalling current change, and avoid crash in overrun situations;
 wenzelm parents: 
38848diff
changeset | 294 |                 try {
 | 
| 38882 
e1fb3bbc22ab
Document state assignment indicates command change;
 wenzelm parents: 
38850diff
changeset | 295 | val cmds: List[Command] = global_state.change_yield(_.assign(id, edits)) | 
| 
e1fb3bbc22ab
Document state assignment indicates command change;
 wenzelm parents: 
38850diff
changeset | 296 | for (cmd <- cmds) command_change_buffer ! cmd | 
| 38849 
2f198d107aef
session_actor: await state assigment of previous change before signalling current change, and avoid crash in overrun situations;
 wenzelm parents: 
38848diff
changeset | 297 | assignments.event(Session.Assignment) | 
| 
2f198d107aef
session_actor: await state assigment of previous change before signalling current change, and avoid crash in overrun situations;
 wenzelm parents: 
38848diff
changeset | 298 | } | 
| 38414 
49f1f657adc2
more basic Markup.parse_int/print_int (using signed_string_of_int) (ML);
 wenzelm parents: 
38413diff
changeset | 299 |                 catch { case _: Document.State.Fail => bad_result(result) }
 | 
| 38370 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 300 | case List(Keyword.Command_Decl(name, kind)) => syntax += (name, kind) | 
| 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 301 | case List(Keyword.Keyword_Decl(name)) => syntax += name | 
| 43673 
29eb1cd29961
Thy_Info.dependencies: ignore already loaded theories, according to initial prover session status;
 wenzelm parents: 
43662diff
changeset | 302 | case List(Thy_Info.Loaded_Theory(name)) => loaded_theories += name | 
| 39625 | 303 | case _ => bad_result(result) | 
| 38370 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 304 | } | 
| 
8b15d0f98962
explicit Document.State value, instead of individual state variables in Session, Command, Document;
 wenzelm parents: 
38366diff
changeset | 305 | } | 
| 39625 | 306 | else bad_result(result) | 
| 43748 | 307 | } | 
| 34809 | 308 | } | 
| 38221 | 309 | //}}} | 
| 34809 | 310 | |
| 34820 
a8ba6cde13e9
basic setup for synchronous / modal (!) prover startup;
 wenzelm parents: 
34819diff
changeset | 311 | |
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 312 | /* main loop */ | 
| 34809 | 313 | |
| 43716 | 314 |     //{{{
 | 
| 38639 
f642faca303e
main session actor as independent thread, to avoid starvation via regular worker pool;
 wenzelm parents: 
38569diff
changeset | 315 | var finished = false | 
| 
f642faca303e
main session actor as independent thread, to avoid starvation via regular worker pool;
 wenzelm parents: 
38569diff
changeset | 316 |     while (!finished) {
 | 
| 
f642faca303e
main session actor as independent thread, to avoid starvation via regular worker pool;
 wenzelm parents: 
38569diff
changeset | 317 |       receive {
 | 
| 43649 | 318 | case Start(timeout, args) if prover.isEmpty => | 
| 39701 | 319 |           if (phase == Session.Inactive || phase == Session.Failed) {
 | 
| 320 | phase = Session.Startup | |
| 43661 
39fdbd814c7f
quasi-static Isabelle_System -- reduced tendency towards "functorial style";
 wenzelm parents: 
43660diff
changeset | 321 | prover = Some(new Isabelle_Process(timeout, this_actor, args:_*) with Isar_Document) | 
| 39701 | 322 | } | 
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 323 | |
| 39701 | 324 | case Stop => | 
| 325 |           if (phase == Session.Ready) {
 | |
| 326 | global_state.change(_ => Document.State.init) // FIXME event bus!? | |
| 327 | phase = Session.Shutdown | |
| 43649 | 328 | prover.get.terminate | 
| 43717 | 329 | prover = None | 
| 39701 | 330 | phase = Session.Inactive | 
| 331 | } | |
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 332 | finished = true | 
| 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 333 | reply(()) | 
| 38850 
5c3e5c548f12
session_actor: ignore spurious TIMEOUT (again) -- probably stemming from earlier use of receiveWithin;
 wenzelm parents: 
38849diff
changeset | 334 | |
| 43717 | 335 | case Interrupt if prover.isDefined => | 
| 336 | prover.get.interrupt | |
| 43716 | 337 | |
| 44182 | 338 | case Init_Node(name, master_dir, header, text) if prover.isDefined => | 
| 43716 | 339 | // FIXME compare with existing node | 
| 44182 | 340 | handle_edits(name, master_dir, header, | 
| 44185 | 341 | List(Document.Node.Clear(), Document.Node.Edits(List(Text.Edit.insert(0, text))))) | 
| 43716 | 342 | reply(()) | 
| 343 | ||
| 44182 | 344 | case Edit_Node(name, master_dir, header, text_edits) if prover.isDefined => | 
| 345 | handle_edits(name, master_dir, header, List(Document.Node.Edits(text_edits))) | |
| 43718 | 346 | reply(()) | 
| 347 | ||
| 43722 | 348 | case change: Change_Node if prover.isDefined => | 
| 349 | handle_change(change) | |
| 43716 | 350 | |
| 43721 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43720diff
changeset | 351 | case input: Isabelle_Process.Input => | 
| 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43720diff
changeset | 352 | raw_messages.event(input) | 
| 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43720diff
changeset | 353 | |
| 43716 | 354 | case result: Isabelle_Process.Result => | 
| 355 | handle_result(result) | |
| 43721 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43720diff
changeset | 356 | raw_messages.event(result) | 
| 43716 | 357 | |
| 43717 | 358 |         case bad => System.err.println("session_actor: ignoring bad message " + bad)
 | 
| 34777 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 359 | } | 
| 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 360 | } | 
| 43716 | 361 | //}}} | 
| 34777 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 362 | } | 
| 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 363 | |
| 34809 | 364 | |
| 43716 | 365 | /* actions */ | 
| 34809 | 366 | |
| 40848 
8662b9b1f123
more abstract/uniform handling of time, preferring seconds as Double;
 wenzelm parents: 
40566diff
changeset | 367 |   def start(timeout: Time, args: List[String]) { session_actor ! Start(timeout, args) }
 | 
| 34820 
a8ba6cde13e9
basic setup for synchronous / modal (!) prover startup;
 wenzelm parents: 
34819diff
changeset | 368 | |
| 39630 
44181423183a
explicit Session.Phase indication with associated event bus;
 wenzelm parents: 
39629diff
changeset | 369 |   def stop() { command_change_buffer !? Stop; session_actor !? Stop }
 | 
| 38841 
4df7b76249a0
include Document.History in Document.State -- just one universal session state maintained by main actor;
 wenzelm parents: 
38722diff
changeset | 370 | |
| 43716 | 371 |   def interrupt() { session_actor ! Interrupt }
 | 
| 43648 | 372 | |
| 44182 | 373 | def init_node(name: String, master_dir: String, header: Document.Node_Header, text: String) | 
| 374 |   { session_actor !? Init_Node(name, master_dir, header, text) }
 | |
| 38221 | 375 | |
| 44182 | 376 | def edit_node(name: String, master_dir: String, header: Document.Node_Header, edits: List[Text.Edit]) | 
| 377 |   { session_actor !? Edit_Node(name, master_dir, header, edits) }
 | |
| 34777 
91d6089cef88
class Session models full session, with or without prover process (cf. heaps, browser_info);
 wenzelm parents: diff
changeset | 378 | } |