23 Perspective of command_id list |
23 Perspective of command_id list |
24 type edit = string * node_edit |
24 type edit = string * node_edit |
25 type state |
25 type state |
26 val init_state: state |
26 val init_state: state |
27 val define_command: command_id -> string -> string -> state -> state |
27 val define_command: command_id -> string -> string -> state -> state |
|
28 val remove_versions: version_id list -> state -> state |
28 val discontinue_execution: state -> unit |
29 val discontinue_execution: state -> unit |
29 val cancel_execution: state -> unit |
30 val cancel_execution: state -> unit |
30 val execute: version_id -> state -> state |
31 val start_execution: state -> unit |
31 val update: version_id -> version_id -> edit list -> state -> |
32 val update: version_id -> version_id -> edit list -> state -> |
32 (command_id * exec_id option) list * state |
33 (command_id * exec_id option) list * state |
33 val remove_versions: version_id list -> state -> state |
|
34 val state: unit -> state |
34 val state: unit -> state |
35 val change_state: (state -> state) -> unit |
35 val change_state: (state -> state) -> unit |
36 end; |
36 end; |
37 |
37 |
38 structure Document: DOCUMENT = |
38 structure Document: DOCUMENT = |
142 fun the_entry (Node {entries, ...}) id = |
142 fun the_entry (Node {entries, ...}) id = |
143 (case Entries.lookup entries id of |
143 (case Entries.lookup entries id of |
144 NONE => err_undef "command entry" id |
144 NONE => err_undef "command entry" id |
145 | SOME (exec, _) => exec); |
145 | SOME (exec, _) => exec); |
146 |
146 |
147 fun the_default_entry node (SOME id) = (id, (the_default (no_id, no_exec) (the_entry node id))) |
147 fun the_default_entry node (SOME id) = (id, the_default (no_id, no_exec) (the_entry node id)) |
148 | the_default_entry _ NONE = (no_id, (no_id, no_exec)); |
148 | the_default_entry _ NONE = (no_id, (no_id, no_exec)); |
149 |
149 |
150 fun update_entry id exec = |
150 fun update_entry id exec = |
151 map_entries (Entries.update (id, exec)); |
151 map_entries (Entries.update (id, exec)); |
152 |
152 |
218 |
218 |
219 val init_state = |
219 val init_state = |
220 make_state (Inttab.make [(no_id, empty_version)], Inttab.empty, |
220 make_state (Inttab.make [(no_id, empty_version)], Inttab.empty, |
221 (no_id, Future.new_group NONE, Unsynchronized.ref false)); |
221 (no_id, Future.new_group NONE, Unsynchronized.ref false)); |
222 |
222 |
|
223 fun execution_of (State {execution, ...}) = execution; |
|
224 |
223 |
225 |
224 (* document versions *) |
226 (* document versions *) |
225 |
227 |
226 fun define_version (id: version_id) version = |
228 fun define_version (id: version_id) version = |
227 map_state (fn (versions, commands, execution) => |
229 map_state (fn (versions, commands, _) => |
228 let val versions' = Inttab.update_new (id, version) versions |
230 let |
229 handle Inttab.DUP dup => err_dup "document version" dup |
231 val versions' = Inttab.update_new (id, version) versions |
230 in (versions', commands, execution) end); |
232 handle Inttab.DUP dup => err_dup "document version" dup; |
|
233 val execution' = (id, Future.new_group NONE, Unsynchronized.ref true); |
|
234 in (versions', commands, execution') end); |
231 |
235 |
232 fun the_version (State {versions, ...}) (id: version_id) = |
236 fun the_version (State {versions, ...}) (id: version_id) = |
233 (case Inttab.lookup versions id of |
237 (case Inttab.lookup versions id of |
234 NONE => err_undef "document version" id |
238 NONE => err_undef "document version" id |
235 | SOME version => version); |
239 | SOME version => version); |
260 fun the_command (State {commands, ...}) (id: command_id) = |
264 fun the_command (State {commands, ...}) (id: command_id) = |
261 (case Inttab.lookup commands id of |
265 (case Inttab.lookup commands id of |
262 NONE => err_undef "command" id |
266 NONE => err_undef "command" id |
263 | SOME command => command); |
267 | SOME command => command); |
264 |
268 |
265 |
|
266 (* document execution *) |
|
267 |
|
268 fun discontinue_execution (State {execution = (_, _, running), ...}) = running := false; |
|
269 |
|
270 fun cancel_execution (State {execution = (_, group, _), ...}) = Future.cancel_group group; |
|
271 fun execution_tasks (State {execution = (_, group, _), ...}) = Future.group_tasks group; |
|
272 |
|
273 end; |
269 end; |
274 |
270 |
275 |
271 fun remove_versions ids state = state |> map_state (fn (versions, _, execution) => |
276 |
272 let |
277 (** edit operations **) |
273 val _ = member (op =) ids (#1 execution) andalso |
278 |
274 error ("Attempt to remove execution version " ^ print_id (#1 execution)); |
279 (* execute *) |
275 |
280 |
276 val versions' = fold delete_version ids versions; |
281 local |
277 val commands' = |
282 |
278 (versions', Inttab.empty) |-> |
283 fun finished_theory node = |
279 Inttab.fold (fn (_, version) => nodes_of version |> |
284 (case Exn.capture (Command.memo_result o the) (get_result node) of |
280 Graph.fold (fn (_, (node, _)) => node |> |
285 Exn.Res (st, _) => can (Toplevel.end_theory Position.none) st |
281 iterate_entries (fn ((_, id), _) => |
286 | _ => false); |
282 SOME o Inttab.insert (K true) (id, the_command state id)))); |
287 |
283 in (versions', commands', execution) end); |
288 in |
284 |
289 |
285 |
290 fun execute version_id state = |
286 |
291 state |> map_state (fn (versions, commands, _) => |
287 (** document execution **) |
292 let |
288 |
293 val version = the_version state version_id; |
289 val discontinue_execution = execution_of #> (fn (_, _, running) => running := false); |
294 |
290 |
295 fun run node command_id exec = |
291 val cancel_execution = execution_of #> (fn (_, group, _) => Future.cancel_group group); |
296 let |
292 |
297 val (_, print) = Command.memo_eval exec; |
293 fun terminate_execution state = |
298 val _ = |
294 let |
299 if visible_command node command_id |
295 val (_, group, _) = execution_of state; |
300 then ignore (Lazy.future Future.default_params print) |
296 val _ = Future.cancel_group group; |
301 else (); |
297 in Future.join_tasks (Future.group_tasks group) end; |
302 in () end; |
298 |
303 |
299 fun start_execution state = |
304 val group = Future.new_group NONE; |
300 let |
305 val running = Unsynchronized.ref true; |
301 fun finished_theory node = |
306 |
302 (case Exn.capture (Command.memo_result o the) (get_result node) of |
307 val _ = |
303 Exn.Res (st, _) => can (Toplevel.end_theory Position.none) st |
308 nodes_of version |> Graph.schedule |
304 | _ => false); |
309 (fn deps => fn (name, node) => |
305 |
310 if not (visible_node node) andalso finished_theory node then |
306 fun run node command_id exec = |
311 Future.value () |
307 let |
312 else |
308 val (_, print) = Command.memo_eval exec; |
313 (singleton o Future.forks) |
309 val _ = |
314 {name = "theory:" ^ name, group = SOME (Future.new_group (SOME group)), |
310 if visible_command node command_id |
315 deps = map (Future.task_of o #2) deps, pri = ~2, interrupts = false} |
311 then ignore (Lazy.future Future.default_params print) |
316 (fn () => |
312 else (); |
317 iterate_entries (fn ((_, id), opt_exec) => fn () => |
313 in () end; |
318 (case opt_exec of |
314 |
319 SOME (_, exec) => if ! running then SOME (run node id exec) else NONE |
315 val (version_id, group, running) = execution_of state; |
320 | NONE => NONE)) node ())); |
316 val _ = |
321 |
317 nodes_of (the_version state version_id) |> Graph.schedule |
322 in (versions, commands, (version_id, group, running)) end); |
318 (fn deps => fn (name, node) => |
323 |
319 if not (visible_node node) andalso finished_theory node then |
324 end; |
320 Future.value () |
325 |
321 else |
326 |
322 (singleton o Future.forks) |
327 (* update *) |
323 {name = "theory:" ^ name, group = SOME (Future.new_group (SOME group)), |
|
324 deps = map (Future.task_of o #2) deps, pri = ~2, interrupts = false} |
|
325 (fn () => |
|
326 iterate_entries (fn ((_, id), opt_exec) => fn () => |
|
327 (case opt_exec of |
|
328 SOME (_, exec) => if ! running then SOME (run node id exec) else NONE |
|
329 | NONE => NONE)) node ())); |
|
330 in () end; |
|
331 |
|
332 |
|
333 |
|
334 (** document update **) |
328 |
335 |
329 local |
336 local |
330 |
337 |
331 fun stable_finished_theory node = |
338 fun stable_finished_theory node = |
332 is_some (Exn.get_res (Exn.capture (fn () => |
339 is_some (Exn.get_res (Exn.capture (fn () => |
517 in (command_execs, state') end; |
524 in (command_execs, state') end; |
518 |
525 |
519 end; |
526 end; |
520 |
527 |
521 |
528 |
522 (* remove versions *) |
|
523 |
|
524 fun remove_versions ids state = state |> map_state (fn (versions, _, execution) => |
|
525 let |
|
526 val _ = member (op =) ids (#1 execution) andalso |
|
527 error ("Attempt to remove execution version " ^ print_id (#1 execution)); |
|
528 |
|
529 val versions' = fold delete_version ids versions; |
|
530 val commands' = |
|
531 (versions', Inttab.empty) |-> |
|
532 Inttab.fold (fn (_, version) => nodes_of version |> |
|
533 Graph.fold (fn (_, (node, _)) => node |> |
|
534 iterate_entries (fn ((_, id), _) => |
|
535 SOME o Inttab.insert (K true) (id, the_command state id)))); |
|
536 in (versions', commands', execution) end); |
|
537 |
|
538 |
|
539 |
529 |
540 (** global state **) |
530 (** global state **) |
541 |
531 |
542 val global_state = Synchronized.var "Document" init_state; |
532 val global_state = Synchronized.var "Document" init_state; |
543 |
533 |