19 |
19 |
20 case object Global_Settings |
20 case object Global_Settings |
21 case object Perspective |
21 case object Perspective |
22 case object Assignment |
22 case object Assignment |
23 case class Commands_Changed(set: Set[Command]) |
23 case class Commands_Changed(set: Set[Command]) |
|
24 |
|
25 sealed abstract class Phase |
|
26 case object Inactive extends Phase |
|
27 case object Startup extends Phase |
|
28 case object Exit extends Phase |
|
29 case object Ready extends Phase |
|
30 case object Shutdown extends Phase |
|
31 case object Terminated extends Phase |
24 } |
32 } |
25 |
33 |
26 |
34 |
27 class Session(system: Isabelle_System) |
35 class Session(system: Isabelle_System) |
28 { |
36 { |
38 val update_delay = 500 |
46 val update_delay = 500 |
39 |
47 |
40 |
48 |
41 /* pervasive event buses */ |
49 /* pervasive event buses */ |
42 |
50 |
|
51 val phase_changed = new Event_Bus[(Session.Phase, Session.Phase)] |
43 val global_settings = new Event_Bus[Session.Global_Settings.type] |
52 val global_settings = new Event_Bus[Session.Global_Settings.type] |
44 val raw_messages = new Event_Bus[Isabelle_Process.Result] |
53 val raw_messages = new Event_Bus[Isabelle_Process.Result] |
45 val commands_changed = new Event_Bus[Session.Commands_Changed] |
54 val commands_changed = new Event_Bus[Session.Commands_Changed] |
46 val perspective = new Event_Bus[Session.Perspective.type] |
55 val perspective = new Event_Bus[Session.Perspective.type] |
47 val assignments = new Event_Bus[Session.Assignment.type] |
56 val assignments = new Event_Bus[Session.Assignment.type] |
96 var finished = false |
105 var finished = false |
97 while (!finished) { |
106 while (!finished) { |
98 receiveWithin(flush_timeout) { |
107 receiveWithin(flush_timeout) { |
99 case command: Command => changed += command; invoke() |
108 case command: Command => changed += command; invoke() |
100 case TIMEOUT => flush() |
109 case TIMEOUT => flush() |
101 case Stop => finished = true |
110 case Stop => finished = true; reply(()) |
102 case bad => System.err.println("command_change_buffer: ignoring bad message " + bad) |
111 case bad => System.err.println("command_change_buffer: ignoring bad message " + bad) |
103 } |
112 } |
104 } |
113 } |
105 } |
114 } |
106 //}}} |
115 //}}} |
113 def current_syntax(): Outer_Syntax = syntax |
122 def current_syntax(): Outer_Syntax = syntax |
114 |
123 |
115 @volatile private var reverse_syslog = List[XML.Elem]() |
124 @volatile private var reverse_syslog = List[XML.Elem]() |
116 def syslog(): String = reverse_syslog.reverse.map(msg => XML.content(msg).mkString).mkString("\n") |
125 def syslog(): String = reverse_syslog.reverse.map(msg => XML.content(msg).mkString).mkString("\n") |
117 |
126 |
|
127 @volatile private var _phase: Session.Phase = Session.Inactive |
|
128 def phase = _phase |
|
129 def phase_=(new_phase: Session.Phase) |
|
130 { |
|
131 val old_phase = _phase |
|
132 _phase = new_phase |
|
133 phase_changed.event(old_phase, new_phase) |
|
134 } |
|
135 |
118 private val global_state = new Volatile(Document.State.init) |
136 private val global_state = new Volatile(Document.State.init) |
119 def current_state(): Document.State = global_state.peek() |
137 def current_state(): Document.State = global_state.peek() |
120 |
138 |
121 private case object Interrupt_Prover |
139 private case object Interrupt_Prover |
122 private case class Edit_Version(edits: List[Document.Node_Text_Edit]) |
140 private case class Edit_Version(edits: List[Document.Node_Text_Edit]) |
123 private case class Started(timeout: Int, args: List[String]) |
141 private case class Start(timeout: Int, args: List[String]) |
124 |
142 |
125 private val (_, session_actor) = Simple_Thread.actor("session_actor", daemon = true) |
143 private val (_, session_actor) = Simple_Thread.actor("session_actor", daemon = true) |
126 { |
144 { |
127 var prover: Isabelle_Process with Isar_Document = null |
145 var prover: Isabelle_Process with Isar_Document = null |
128 |
146 |
188 val st = global_state.change_yield(_.accumulate(state_id, result.message)) |
206 val st = global_state.change_yield(_.accumulate(state_id, result.message)) |
189 command_change_buffer ! st.command |
207 command_change_buffer ! st.command |
190 } |
208 } |
191 catch { case _: Document.State.Fail => bad_result(result) } |
209 catch { case _: Document.State.Fail => bad_result(result) } |
192 case _ => |
210 case _ => |
193 if (result.is_exit) prover = null // FIXME ?? |
211 if (result.is_syslog) { |
194 else if (result.is_syslog) reverse_syslog ::= result.message |
212 reverse_syslog ::= result.message |
|
213 if (result.is_ready) phase = Session.Ready |
|
214 else if (result.is_exit) phase = Session.Exit |
|
215 } |
195 else if (result.is_stdout) { } |
216 else if (result.is_stdout) { } |
196 else if (result.is_status) { |
217 else if (result.is_status) { |
197 result.body match { |
218 result.body match { |
198 case List(Isar_Document.Assign(id, edits)) => |
219 case List(Isar_Document.Assign(id, edits)) => |
199 try { |
220 try { |
211 } |
232 } |
212 } |
233 } |
213 //}}} |
234 //}}} |
214 |
235 |
215 |
236 |
216 /* prover startup */ |
237 /* main loop */ |
217 |
|
218 def startup_error(): String = |
|
219 { |
|
220 val buf = new StringBuilder |
|
221 while ( |
|
222 receiveWithin(0) { |
|
223 case result: Isabelle_Process.Result => |
|
224 if (result.is_system) { |
|
225 for (text <- XML.content(result.message)) |
|
226 buf.append(text) |
|
227 } |
|
228 true |
|
229 case TIMEOUT => false |
|
230 }) {} |
|
231 buf.toString |
|
232 } |
|
233 |
|
234 def prover_startup(timeout: Int): Option[String] = |
|
235 { |
|
236 receiveWithin(timeout) { |
|
237 case result: Isabelle_Process.Result if result.is_init => |
|
238 handle_result(result) |
|
239 while (receive { |
|
240 case result: Isabelle_Process.Result => |
|
241 handle_result(result); !result.is_ready |
|
242 }) {} |
|
243 None |
|
244 |
|
245 case result: Isabelle_Process.Result if result.is_exit => |
|
246 handle_result(result) |
|
247 Some(startup_error()) |
|
248 |
|
249 case TIMEOUT => // FIXME clarify |
|
250 prover.terminate; Some(startup_error()) |
|
251 } |
|
252 } |
|
253 |
|
254 |
|
255 /* main loop */ // FIXME proper shutdown |
|
256 |
238 |
257 var finished = false |
239 var finished = false |
258 while (!finished) { |
240 while (!finished) { |
259 receive { |
241 receive { |
260 case Interrupt_Prover => |
242 case Interrupt_Prover => |
261 if (prover != null) prover.interrupt |
243 if (prover != null) prover.interrupt |
262 |
244 |
263 case Edit_Version(edits) => |
245 case Edit_Version(edits) if prover != null => |
264 val previous = global_state.peek().history.tip.current |
246 val previous = global_state.peek().history.tip.current |
265 val result = Future.fork { Thy_Syntax.text_edits(Session.this, previous.join, edits) } |
247 val result = Future.fork { Thy_Syntax.text_edits(Session.this, previous.join, edits) } |
266 val change = global_state.change_yield(_.extend_history(previous, edits, result)) |
248 val change = global_state.change_yield(_.extend_history(previous, edits, result)) |
267 |
249 |
268 val this_actor = self |
250 val this_actor = self |
270 assignments.await { global_state.peek().is_assigned(previous.get_finished) } |
252 assignments.await { global_state.peek().is_assigned(previous.get_finished) } |
271 this_actor ! change }) |
253 this_actor ! change }) |
272 |
254 |
273 reply(()) |
255 reply(()) |
274 |
256 |
275 case change: Document.Change if prover != null => |
257 case change: Document.Change if prover != null => handle_change(change) |
276 handle_change(change) |
258 |
277 |
259 case result: Isabelle_Process.Result => handle_result(result) |
278 case result: Isabelle_Process.Result => |
260 |
279 handle_result(result) |
261 case Start(timeout, args) if prover == null => |
280 |
262 phase = Session.Startup |
281 case Started(timeout, args) => |
263 prover = new Isabelle_Process(system, timeout, self, args:_*) with Isar_Document |
282 if (prover == null) { |
264 |
283 prover = new Isabelle_Process(system, timeout, self, args:_*) with Isar_Document |
265 case Stop if phase == Session.Ready => |
284 val origin = sender |
266 global_state.change(_ => Document.State.init) // FIXME event bus!? |
285 val opt_err = prover_startup(timeout + 500) |
267 phase = Session.Shutdown |
286 if (opt_err.isDefined) prover = null |
268 prover.terminate |
287 origin ! opt_err |
269 phase = Session.Terminated |
288 } |
270 finished = true |
289 else reply(None) |
271 reply(()) |
290 |
|
291 case Stop => // FIXME synchronous!? |
|
292 if (prover != null) { |
|
293 global_state.change(_ => Document.State.init) |
|
294 prover.terminate |
|
295 prover = null |
|
296 } |
|
297 |
|
298 case TIMEOUT => // FIXME clarify |
|
299 |
272 |
300 case bad if prover != null => |
273 case bad if prover != null => |
301 System.err.println("session_actor: ignoring bad message " + bad) |
274 System.err.println("session_actor: ignoring bad message " + bad) |
302 } |
275 } |
303 } |
276 } |
305 |
278 |
306 |
279 |
307 |
280 |
308 /** main methods **/ |
281 /** main methods **/ |
309 |
282 |
310 def started(timeout: Int, args: List[String]): Option[String] = |
283 def start(timeout: Int, args: List[String]) { session_actor ! Start(timeout, args) } |
311 (session_actor !? Started(timeout, args)).asInstanceOf[Option[String]] |
284 |
312 |
285 def stop() { command_change_buffer !? Stop; session_actor !? Stop } |
313 def stop() { command_change_buffer ! Stop; session_actor ! Stop } |
|
314 |
286 |
315 def interrupt() { session_actor ! Interrupt_Prover } |
287 def interrupt() { session_actor ! Interrupt_Prover } |
316 |
288 |
317 def edit_version(edits: List[Document.Node_Text_Edit]) { session_actor !? Edit_Version(edits) } |
289 def edit_version(edits: List[Document.Node_Text_Edit]) { session_actor !? Edit_Version(edits) } |
318 |
290 |