src/Pure/PIDE/document.ML
changeset 44674 bad4f9158c80
parent 44673 2fa51ac191bc
child 44675 f665a5d35a3d
equal deleted inserted replaced
44673:2fa51ac191bc 44674:bad4f9158c80
    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);
   276 
   276 
   277 
   277 
   278 (* commands *)
   278 (* commands *)
   279 
   279 
   280 fun define_command (id: command_id) name text =
   280 fun define_command (id: command_id) name text =
   281   map_state (fn (versions, commands, execs, execution) =>
   281   map_state (fn (versions, commands, execution) =>
   282     let
   282     let
   283       val id_string = print_id id;
   283       val id_string = print_id id;
   284       val future =
   284       val future =
   285         (singleton o Future.forks)
   285         (singleton o Future.forks)
   286           {name = "Document.define_command", group = SOME (Future.new_group NONE),
   286           {name = "Document.define_command", group = SOME (Future.new_group NONE),
   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