60 |
60 |
61 type node_header = (string * string list * (string * bool) list) Exn.result; |
61 type node_header = (string * string list * (string * bool) list) Exn.result; |
62 type perspective = (command_id -> bool) * command_id option; (*visible commands, last*) |
62 type perspective = (command_id -> bool) * command_id option; (*visible commands, last*) |
63 structure Entries = Linear_Set(type key = command_id val ord = int_ord); |
63 structure Entries = Linear_Set(type key = command_id val ord = int_ord); |
64 |
64 |
|
65 type exec = exec_id * (Toplevel.state * unit lazy) lazy; (*eval/print process*) |
|
66 val no_print = Lazy.value (); |
|
67 val no_exec = (no_id, Lazy.value (Toplevel.toplevel, no_print)); |
|
68 |
65 abstype node = Node of |
69 abstype node = Node of |
66 {touched: bool, |
70 {touched: bool, |
67 header: node_header, |
71 header: node_header, |
68 perspective: perspective, |
72 perspective: perspective, |
69 entries: exec_id option Entries.T, (*command entries with excecutions*) |
73 entries: exec option Entries.T, (*command entries with excecutions*) |
70 last_exec: command_id option, (*last command with exec state assignment*) |
74 last_exec: command_id option, (*last command with exec state assignment*) |
71 result: Toplevel.state lazy} |
75 result: Toplevel.state lazy} |
72 and version = Version of node Graph.T (*development graph wrt. static imports*) |
76 and version = Version of node Graph.T (*development graph wrt. static imports*) |
73 with |
77 with |
74 |
78 |
82 fun make_perspective command_ids : perspective = |
86 fun make_perspective command_ids : perspective = |
83 (Inttab.defined (Inttab.make (map (rpair ()) command_ids)), try List.last command_ids); |
87 (Inttab.defined (Inttab.make (map (rpair ()) command_ids)), try List.last command_ids); |
84 |
88 |
85 val no_header = Exn.Exn (ERROR "Bad theory header"); |
89 val no_header = Exn.Exn (ERROR "Bad theory header"); |
86 val no_perspective = make_perspective []; |
90 val no_perspective = make_perspective []; |
87 val no_print = Lazy.value (); |
|
88 val no_result = Lazy.value Toplevel.toplevel; |
91 val no_result = Lazy.value Toplevel.toplevel; |
89 |
92 |
90 val empty_node = make_node (false, no_header, no_perspective, Entries.empty, NONE, no_result); |
93 val empty_node = make_node (false, no_header, no_perspective, Entries.empty, NONE, no_result); |
91 val clear_node = map_node (fn (_, header, _, _, _, _) => |
94 val clear_node = map_node (fn (_, header, _, _, _, _) => |
92 (false, header, no_perspective, Entries.empty, NONE, no_result)); |
95 (false, header, no_perspective, Entries.empty, NONE, no_result)); |
155 fun the_entry (Node {entries, ...}) id = |
158 fun the_entry (Node {entries, ...}) id = |
156 (case Entries.lookup entries id of |
159 (case Entries.lookup entries id of |
157 NONE => err_undef "command entry" id |
160 NONE => err_undef "command entry" id |
158 | SOME (exec, _) => exec); |
161 | SOME (exec, _) => exec); |
159 |
162 |
160 fun the_default_entry node (SOME id) = the_default no_id (the_entry node id) |
163 fun the_default_entry node (SOME id) = (id, (the_default no_exec (the_entry node id))) |
161 | the_default_entry _ NONE = no_id; |
164 | the_default_entry _ NONE = (no_id, no_exec); |
162 |
165 |
163 fun update_entry id exec = |
166 fun update_entry id exec = |
164 map_entries (Entries.update (id, exec)); |
167 map_entries (Entries.update (id, exec)); |
165 |
168 |
166 fun reset_entry id node = |
169 fun reset_entry id node = |
236 (** global state -- document structure and execution process **) |
239 (** global state -- document structure and execution process **) |
237 |
240 |
238 abstype state = State of |
241 abstype state = State of |
239 {versions: version Inttab.table, (*version_id -> document content*) |
242 {versions: version Inttab.table, (*version_id -> document content*) |
240 commands: (string * Toplevel.transition future) Inttab.table, (*command_id -> name * transition*) |
243 commands: (string * Toplevel.transition future) Inttab.table, (*command_id -> name * transition*) |
241 execs: (command_id * (Toplevel.state * unit lazy) lazy) Inttab.table, |
|
242 (*exec_id -> command_id with eval/print process*) |
|
243 execution: version_id * Future.group} (*current execution process*) |
244 execution: version_id * Future.group} (*current execution process*) |
244 with |
245 with |
245 |
246 |
246 fun make_state (versions, commands, execs, execution) = |
247 fun make_state (versions, commands, execution) = |
247 State {versions = versions, commands = commands, execs = execs, execution = execution}; |
248 State {versions = versions, commands = commands, execution = execution}; |
248 |
249 |
249 fun map_state f (State {versions, commands, execs, execution}) = |
250 fun map_state f (State {versions, commands, execution}) = |
250 make_state (f (versions, commands, execs, execution)); |
251 make_state (f (versions, commands, execution)); |
251 |
252 |
252 val empty_commands = |
253 val empty_commands = (* FIXME no_id ??? *) |
253 Inttab.make [(no_id, (Toplevel.name_of Toplevel.empty, Future.value Toplevel.empty))]; |
254 Inttab.make [(no_id, (Toplevel.name_of Toplevel.empty, Future.value Toplevel.empty))]; |
254 val empty_execs = Inttab.make [(no_id, (no_id, Lazy.value (Toplevel.toplevel, no_print)))]; |
|
255 val empty_execution = (no_id, Future.new_group NONE); |
255 val empty_execution = (no_id, Future.new_group NONE); |
256 |
256 |
257 val init_state = |
257 val init_state = |
258 make_state (Inttab.make [(no_id, empty_version)], empty_commands, empty_execs, empty_execution); |
258 make_state (Inttab.make [(no_id, empty_version)], empty_commands, empty_execution); |
259 |
259 |
260 |
260 |
261 (* document versions *) |
261 (* document versions *) |
262 |
262 |
263 fun define_version (id: version_id) version = |
263 fun define_version (id: version_id) version = |
264 map_state (fn (versions, commands, execs, execution) => |
264 map_state (fn (versions, commands, execution) => |
265 let val versions' = Inttab.update_new (id, version) versions |
265 let val versions' = Inttab.update_new (id, version) versions |
266 handle Inttab.DUP dup => err_dup "document version" dup |
266 handle Inttab.DUP dup => err_dup "document version" dup |
267 in (versions', commands, execs, execution) end); |
267 in (versions', commands, execution) end); |
268 |
268 |
269 fun the_version (State {versions, ...}) (id: version_id) = |
269 fun the_version (State {versions, ...}) (id: version_id) = |
270 (case Inttab.lookup versions id of |
270 (case Inttab.lookup versions id of |
271 NONE => err_undef "document version" id |
271 NONE => err_undef "document version" id |
272 | SOME version => version); |
272 | SOME version => version); |
289 Position.setmp_thread_data (Position.id_only id_string) |
289 Position.setmp_thread_data (Position.id_only id_string) |
290 (fn () => Outer_Syntax.read_command (Position.id id_string) text) ()); |
290 (fn () => Outer_Syntax.read_command (Position.id id_string) text) ()); |
291 val commands' = |
291 val commands' = |
292 Inttab.update_new (id, (name, future)) commands |
292 Inttab.update_new (id, (name, future)) commands |
293 handle Inttab.DUP dup => err_dup "command" dup; |
293 handle Inttab.DUP dup => err_dup "command" dup; |
294 in (versions, commands', execs, execution) end); |
294 in (versions, commands', execution) end); |
295 |
295 |
296 fun the_command (State {commands, ...}) (id: command_id) = |
296 fun the_command (State {commands, ...}) (id: command_id) = |
297 (case Inttab.lookup commands id of |
297 (case Inttab.lookup commands id of |
298 NONE => err_undef "command" id |
298 NONE => err_undef "command" id |
299 | SOME command => command); |
299 | SOME command => command); |
300 |
|
301 |
|
302 (* command executions *) |
|
303 |
|
304 fun define_exec (exec_id, exec) = |
|
305 map_state (fn (versions, commands, execs, execution) => |
|
306 let val execs' = Inttab.update_new (exec_id, exec) execs |
|
307 handle Inttab.DUP dup => err_dup "command execution" dup |
|
308 in (versions, commands, execs', execution) end); |
|
309 |
|
310 fun the_exec (State {execs, ...}) exec_id = |
|
311 (case Inttab.lookup execs exec_id of |
|
312 NONE => err_undef "command execution" exec_id |
|
313 | SOME exec => exec); |
|
314 |
300 |
315 |
301 |
316 (* document execution *) |
302 (* document execution *) |
317 |
303 |
318 fun cancel_execution (State {execution, ...}) = Future.cancel_group (#2 execution); |
304 fun cancel_execution (State {execution, ...}) = Future.cancel_group (#2 execution); |
402 | SOME id => not (Keyword.is_theory_begin (#1 (the_command state id)))); |
388 | SOME id => not (Keyword.is_theory_begin (#1 (the_command state id)))); |
403 in (visible', initial') end; |
389 in (visible', initial') end; |
404 fun get_common ((prev, id), exec) (found, (_, flags)) = |
390 fun get_common ((prev, id), exec) (found, (_, flags)) = |
405 if found then NONE |
391 if found then NONE |
406 else |
392 else |
407 let val found' = is_none exec orelse exec <> lookup_entry node0 id |
393 let val found' = |
|
394 is_none exec orelse op <> (pairself (Option.map #1) (exec, lookup_entry node0 id)); |
408 in SOME (found', (prev, update_flags prev flags)) end; |
395 in SOME (found', (prev, update_flags prev flags)) end; |
409 val (found, (common, flags)) = |
396 val (found, (common, flags)) = |
410 iterate_entries get_common node (false, (NONE, (true, true))); |
397 iterate_entries get_common node (false, (NONE, (true, true))); |
411 in |
398 in |
412 if found then (common, flags) |
399 if found then (common, flags) |
415 in (last, update_flags last flags) end |
402 in (last, update_flags last flags) end |
416 end; |
403 end; |
417 |
404 |
418 fun illegal_init () = error "Illegal theory header after end of theory"; |
405 fun illegal_init () = error "Illegal theory header after end of theory"; |
419 |
406 |
420 fun new_exec state bad_init command_id' (execs, exec, init) = |
407 fun new_exec state bad_init command_id' (execs, command_exec, init) = |
421 if bad_init andalso is_none init then NONE |
408 if bad_init andalso is_none init then NONE |
422 else |
409 else |
423 let |
410 let |
424 val (name, tr0) = the_command state command_id' ||> Future.join; |
411 val (name, tr0) = the_command state command_id' ||> Future.join; |
425 val (modify_init, init') = |
412 val (modify_init, init') = |
428 else (I, init); |
415 else (I, init); |
429 val exec_id' = new_id (); |
416 val exec_id' = new_id (); |
430 val tr = tr0 |
417 val tr = tr0 |
431 |> modify_init |
418 |> modify_init |
432 |> Toplevel.put_id (print_id exec_id'); |
419 |> Toplevel.put_id (print_id exec_id'); |
433 val exec' = (command_id', Lazy.map (fn (st, _) => run_command tr st) (snd exec)); |
420 val exec' = snd (snd command_exec) |> Lazy.map (fn (st, _) => run_command tr st); |
434 in SOME ((exec_id', exec') :: execs, exec', init') end; |
421 val command_exec' = (command_id', (exec_id', exec')); |
|
422 in SOME (command_exec' :: execs, command_exec', init') end; |
435 |
423 |
436 fun make_required nodes = |
424 fun make_required nodes = |
437 let |
425 let |
438 val all_visible = |
426 val all_visible = |
439 Graph.fold (fn (a, (node, _)) => is_some (#2 (get_perspective node)) ? cons a) nodes [] |
427 Graph.fold (fn (a, (node, _)) => is_some (#2 (get_perspective node)) ? cons a) nodes [] |
493 (fn () => |
481 (fn () => |
494 let |
482 let |
495 val required = is_required name; |
483 val required = is_required name; |
496 val last_visible = #2 (get_perspective node); |
484 val last_visible = #2 (get_perspective node); |
497 val (common, (visible, initial)) = last_common state last_visible node0 node; |
485 val (common, (visible, initial)) = last_common state last_visible node0 node; |
498 val common_exec = the_exec state (the_default_entry node common); |
486 val common_command_exec = the_default_entry node common; |
499 |
487 |
500 val (execs, exec, _) = |
488 val (execs, (command_id, (_, exec)), _) = |
501 ([], common_exec, if initial then SOME init else NONE) |> |
489 ([], common_command_exec, if initial then SOME init else NONE) |> |
502 (visible orelse required) ? |
490 (visible orelse required) ? |
503 iterate_entries_after common |
491 iterate_entries_after common |
504 (fn ((prev, id), _) => fn res => |
492 (fn ((prev, id), _) => fn res => |
505 if not required andalso prev = last_visible then NONE |
493 if not required andalso prev = last_visible then NONE |
506 else new_exec state bad_init id res) node; |
494 else new_exec state bad_init id res) node; |
510 (fn ((_, id0), exec0) => fn res => |
498 (fn ((_, id0), exec0) => fn res => |
511 if is_none exec0 then NONE |
499 if is_none exec0 then NONE |
512 else if exists (fn (_, (id, _)) => id0 = id) execs then SOME res |
500 else if exists (fn (_, (id, _)) => id0 = id) execs then SOME res |
513 else SOME (id0 :: res)) node0 []; |
501 else SOME (id0 :: res)) node0 []; |
514 |
502 |
515 val last_exec = if #1 exec = no_id then NONE else SOME (#1 exec); |
503 val last_exec = if command_id = no_id then NONE else SOME command_id; |
516 val result = |
504 val result = |
517 if is_some (after_entry node last_exec) then no_result |
505 if is_some (after_entry node last_exec) then no_result |
518 else Lazy.map #1 (#2 exec); |
506 else Lazy.map #1 exec; |
519 |
507 |
520 val node' = node |
508 val node' = node |
521 |> fold reset_entry no_execs |
509 |> fold reset_entry no_execs |
522 |> fold (fn (exec_id, (id, _)) => update_entry id (SOME exec_id)) execs |
510 |> fold (fn (id, exec) => update_entry id (SOME exec)) execs |
523 |> set_last_exec last_exec |
511 |> set_last_exec last_exec |
524 |> set_result result |
512 |> set_result result |
525 |> set_touched false; |
513 |> set_touched false; |
526 in ((no_execs, execs, [(name, node')]), node') end) |
514 in ((no_execs, execs, [(name, node')]), node') end) |
527 end) |
515 end) |
528 |> Future.joins |> map #1; |
516 |> Future.joins |> map #1; |
529 |
517 |
530 val command_execs = |
518 val command_execs = |
531 map (rpair NONE) (maps #1 updated) @ |
519 map (rpair NONE) (maps #1 updated) @ |
532 map (fn (exec_id, (command_id, _)) => (command_id, SOME exec_id)) (maps #2 updated); |
520 map (fn (command_id, (exec_id, _)) => (command_id, SOME exec_id)) (maps #2 updated); |
533 val updated_nodes = maps #3 updated; |
521 val updated_nodes = maps #3 updated; |
534 val last_execs = map (fn (name, node) => (name, get_last_exec node)) updated_nodes; |
522 val last_execs = map (fn (name, node) => (name, get_last_exec node)) updated_nodes; |
535 |
523 |
536 val state' = state |
524 val state' = state |
537 |> fold (fold define_exec o #2) updated |
|
538 |> define_version new_id (fold put_node updated_nodes new_version); |
525 |> define_version new_id (fold put_node updated_nodes new_version); |
539 in ((command_execs, last_execs), state') end; |
526 in ((command_execs, last_execs), state') end; |
540 |
527 |
541 end; |
528 end; |
542 |
529 |
543 |
530 |
544 (* execute *) |
531 (* execute *) |
545 |
532 |
546 fun execute version_id state = |
533 fun execute version_id state = |
547 state |> map_state (fn (versions, commands, execs, _) => |
534 state |> map_state (fn (versions, commands, _) => |
548 let |
535 let |
549 val version = the_version state version_id; |
536 val version = the_version state version_id; |
550 |
537 |
551 fun force_exec _ NONE = () |
538 fun force_exec _ _ NONE = () |
552 | force_exec node (SOME exec_id) = |
539 | force_exec node command_id (SOME (_, exec)) = |
553 let |
540 let |
554 val (command_id, exec) = the_exec state exec_id; |
|
555 val (_, print) = Lazy.force exec; |
541 val (_, print) = Lazy.force exec; |
556 val _ = |
542 val _ = |
557 if #1 (get_perspective node) command_id |
543 if #1 (get_perspective node) command_id |
558 then ignore (Lazy.future Future.default_params print) |
544 then ignore (Lazy.future Future.default_params print) |
559 else (); |
545 else (); |
564 nodes_of version |> Graph.schedule |
550 nodes_of version |> Graph.schedule |
565 (fn deps => fn (name, node) => |
551 (fn deps => fn (name, node) => |
566 (singleton o Future.forks) |
552 (singleton o Future.forks) |
567 {name = "theory:" ^ name, group = SOME (Future.new_group (SOME group)), |
553 {name = "theory:" ^ name, group = SOME (Future.new_group (SOME group)), |
568 deps = map (Future.task_of o #2) deps, pri = 1, interrupts = false} |
554 deps = map (Future.task_of o #2) deps, pri = 1, interrupts = false} |
569 (iterate_entries (fn (_, exec) => fn () => SOME (force_exec node exec)) node)); |
555 (iterate_entries (fn ((_, id), exec) => fn () => |
570 |
556 SOME (force_exec node id exec)) node)); |
571 in (versions, commands, execs, (version_id, group)) end); |
557 |
|
558 in (versions, commands, (version_id, group)) end); |
572 |
559 |
573 |
560 |
574 (* remove versions *) |
561 (* remove versions *) |
575 |
562 |
576 fun remove_versions ids state = state |> map_state (fn (versions, _, _, execution) => |
563 fun remove_versions ids state = state |> map_state (fn (versions, _, execution) => |
577 let |
564 let |
578 val _ = member (op =) ids (#1 execution) andalso |
565 val _ = member (op =) ids (#1 execution) andalso |
579 error ("Attempt to remove execution version " ^ print_id (#1 execution)); |
566 error ("Attempt to remove execution version " ^ print_id (#1 execution)); |
580 |
567 |
581 val versions' = fold delete_version ids versions; |
568 val versions' = fold delete_version ids versions; |
582 val (commands', execs') = |
569 val commands' = |
583 (versions', (empty_commands, empty_execs)) |-> |
570 (versions', empty_commands) |-> |
584 Inttab.fold (fn (_, version) => nodes_of version |> |
571 Inttab.fold (fn (_, version) => nodes_of version |> |
585 Graph.fold (fn (_, (node, _)) => node |> |
572 Graph.fold (fn (_, (node, _)) => node |> |
586 iterate_entries (fn ((_, id), exec) => fn (commands, execs) => |
573 iterate_entries (fn ((_, id), _) => |
587 let |
574 SOME o Inttab.insert (K true) (id, the_command state id)))); |
588 val commands' = Inttab.insert (K true) (id, the_command state id) commands; |
575 in (versions', commands', execution) end); |
589 val execs' = |
|
590 (case exec of |
|
591 NONE => execs |
|
592 | SOME exec_id => Inttab.insert (K true) (exec_id, the_exec state exec_id) execs); |
|
593 in SOME (commands', execs') end))); |
|
594 in (versions', commands', execs', execution) end); |
|
595 |
576 |
596 |
577 |
597 |
578 |
598 (** global state **) |
579 (** global state **) |
599 |
580 |