13 type exec_id = id |
13 type exec_id = id |
14 val no_id: id |
14 val no_id: id |
15 val new_id: unit -> id |
15 val new_id: unit -> id |
16 val parse_id: string -> id |
16 val parse_id: string -> id |
17 val print_id: id -> string |
17 val print_id: id -> string |
18 type node_header = (string * string list * string list) Exn.result |
18 type node_header = (string * string list * (string * bool) list) Exn.result |
19 datatype node_edit = |
19 datatype node_edit = |
20 Remove | |
20 Clear | |
21 Edits of (command_id option * command_id option) list | |
21 Edits of (command_id option * command_id option) list | |
22 Header of node_header |
22 Header of node_header |
23 type edit = string * node_edit |
23 type edit = string * node_edit |
24 type state |
24 type state |
25 val init_state: state |
25 val init_state: state |
53 |
53 |
54 |
54 |
55 |
55 |
56 (** document structure **) |
56 (** document structure **) |
57 |
57 |
58 type node_header = (string * string list * string list) Exn.result; |
58 type node_header = (string * string list * (string * bool) list) Exn.result; |
59 structure Entries = Linear_Set(type key = command_id val ord = int_ord); |
59 structure Entries = Linear_Set(type key = command_id val ord = int_ord); |
60 |
60 |
61 abstype node = Node of |
61 abstype node = Node of |
62 {header: node_header, |
62 {header: node_header, |
63 entries: exec_id option Entries.T, (*command entries with excecutions*) |
63 entries: exec_id option Entries.T, (*command entries with excecutions*) |
80 |
80 |
81 fun get_last (Node {last, ...}) = last; |
81 fun get_last (Node {last, ...}) = last; |
82 fun set_last last = map_node (fn (header, entries, _) => (header, entries, last)); |
82 fun set_last last = map_node (fn (header, entries, _) => (header, entries, last)); |
83 |
83 |
84 val empty_node = make_node (Exn.Exn (ERROR "Bad theory header"), Entries.empty, no_id); |
84 val empty_node = make_node (Exn.Exn (ERROR "Bad theory header"), Entries.empty, no_id); |
85 val empty_version = Version Graph.empty; |
85 val clear_node = map_node (fn (header, _, _) => (header, Entries.empty, no_id)); |
|
86 |
|
87 fun get_node nodes name = Graph.get_node nodes name handle Graph.UNDEF _ => empty_node; |
|
88 fun remove_node name nodes = Graph.del_node name nodes handle Graph.UNDEF _ => nodes; |
|
89 fun update_node name f = Graph.default_node (name, empty_node) #> Graph.map_node name f; |
86 |
90 |
87 |
91 |
88 (* node edits and associated executions *) |
92 (* node edits and associated executions *) |
89 |
93 |
90 datatype node_edit = |
94 datatype node_edit = |
91 Remove | |
95 Clear | |
92 Edits of (command_id option * command_id option) list | |
96 Edits of (command_id option * command_id option) list | |
93 Header of node_header; |
97 Header of node_header; |
94 |
98 |
95 type edit = string * node_edit; |
99 type edit = string * node_edit; |
96 |
100 |
112 | (id, NONE) => Entries.delete_after id #> reset_after id); |
116 | (id, NONE) => Entries.delete_after id #> reset_after id); |
113 |
117 |
114 |
118 |
115 (* version operations *) |
119 (* version operations *) |
116 |
120 |
|
121 val empty_version = Version Graph.empty; |
|
122 |
117 fun nodes_of (Version nodes) = nodes; |
123 fun nodes_of (Version nodes) = nodes; |
|
124 val node_of = get_node o nodes_of; |
118 val node_names_of = Graph.keys o nodes_of; |
125 val node_names_of = Graph.keys o nodes_of; |
119 |
126 |
120 fun get_node version name = Graph.get_node (nodes_of version) name |
127 fun cycle_msg names = "Cyclic dependency of " ^ space_implode " via " (map quote names); |
121 handle Graph.UNDEF _ => empty_node; |
|
122 |
|
123 fun update_node name f = |
|
124 Graph.default_node (name, empty_node) #> Graph.map_node name f; |
|
125 |
128 |
126 fun edit_nodes (name, node_edit) (Version nodes) = |
129 fun edit_nodes (name, node_edit) (Version nodes) = |
127 Version |
130 Version |
128 (case node_edit of |
131 (case node_edit of |
129 Remove => perhaps (try (Graph.del_node name)) nodes |
132 Clear => update_node name clear_node nodes |
130 | Edits edits => update_node name (edit_node edits) nodes |
133 | Edits edits => update_node name (edit_node edits) nodes |
131 (* FIXME maintain deps; cycles!? *) |
134 | Header header => |
132 | Header header => update_node name (set_header header) nodes); |
135 let |
|
136 val node = get_node nodes name; |
|
137 val nodes' = Graph.new_node (name, node) (remove_node name nodes); |
|
138 val parents = |
|
139 (case header of Exn.Res (_, parents, _) => parents | _ => []) |
|
140 |> filter (can (Graph.get_node nodes')); |
|
141 val (header', nodes'') = |
|
142 (header, Graph.add_deps_acyclic (name, parents) nodes') |
|
143 handle Graph.CYCLES cs => (Exn.Exn (ERROR (cat_lines (map cycle_msg cs))), nodes'); |
|
144 in Graph.map_node name (set_header header') nodes'' end); |
133 |
145 |
134 fun put_node name node (Version nodes) = |
146 fun put_node name node (Version nodes) = |
135 Version (nodes |
147 Version (nodes |
136 |> Graph.default_node (name, empty_node) |
148 |> Graph.default_node (name, empty_node) |
137 |> Graph.map_node name (K node)); |
149 |> Graph.map_node name (K node)); |
212 NONE => err_undef "command execution" id |
224 NONE => err_undef "command execution" id |
213 | SOME exec => exec); |
225 | SOME exec => exec); |
214 |
226 |
215 fun get_theory state version_id pos name = |
227 fun get_theory state version_id pos name = |
216 let |
228 let |
217 val last = get_last (get_node (the_version state version_id) name); |
229 val last = get_last (node_of (the_version state version_id) name); |
218 val st = |
230 val st = |
219 (case Lazy.peek (the_exec state last) of |
231 (case Lazy.peek (the_exec state last) of |
220 SOME result => #2 (Exn.release result) |
232 SOME result => #2 (Exn.release result) |
221 | NONE => error ("Unfinished execution for theory " ^ quote name)); |
233 | NONE => error ("Unfinished execution for theory " ^ quote name ^ Position.str_of pos)); |
222 in Toplevel.end_theory pos st end; |
234 in Toplevel.end_theory pos st end; |
223 |
235 |
224 |
236 |
225 (* document execution *) |
237 (* document execution *) |
226 |
238 |
261 | errs => (errs, NONE)) |
273 | errs => (errs, NONE)) |
262 | NONE => ([ML_Compiler.exn_message Runtime.TERMINATE], NONE)); |
274 | NONE => ([ML_Compiler.exn_message Runtime.TERMINATE], NONE)); |
263 |
275 |
264 in |
276 in |
265 |
277 |
266 fun run_command node_name raw_tr st = |
278 fun run_command (node_name, node_header) raw_tr st = |
267 (case |
279 let |
268 (case Toplevel.init_of raw_tr of |
280 val is_init = Toplevel.is_init raw_tr; |
269 SOME _ => |
281 val tr = |
270 Exn.capture (fn () => |
282 if is_init then |
271 let val master_dir = Path.dir (Path.explode node_name); (* FIXME move to Scala side *) |
283 raw_tr |> Toplevel.modify_init (fn _ => |
272 in Toplevel.modify_master (SOME master_dir) raw_tr end) () |
284 let |
273 | NONE => Exn.Res raw_tr) of |
285 (* FIXME get theories from document state *) |
274 Exn.Res tr => |
286 (* FIXME provide files via Scala layer *) |
275 let |
287 val (name, imports, uses) = Exn.release node_header; |
276 val is_init = is_some (Toplevel.init_of tr); |
288 val master = SOME (Path.dir (Path.explode node_name)); |
277 val is_proof = Keyword.is_proof (Toplevel.name_of tr); |
289 in Thy_Info.toplevel_begin_theory master name imports (map (apfst Path.explode) uses) end) |
278 val do_print = not is_init andalso (Toplevel.print_of tr orelse is_proof); |
290 else raw_tr; |
279 |
291 |
280 val start = Timing.start (); |
292 val is_proof = Keyword.is_proof (Toplevel.name_of tr); |
281 val (errs, result) = |
293 val do_print = not is_init andalso (Toplevel.print_of tr orelse is_proof); |
282 if Toplevel.is_toplevel st andalso not is_init then ([], SOME st) |
294 |
283 else run (is_init orelse is_proof) (Toplevel.set_print false tr) st; |
295 val start = Timing.start (); |
284 val _ = timing tr (Timing.result start); |
296 val (errs, result) = |
285 val _ = List.app (Toplevel.error_msg tr) errs; |
297 if Toplevel.is_toplevel st andalso not is_init then ([], SOME st) |
286 val res = |
298 else run (is_init orelse is_proof) (Toplevel.set_print false tr) st; |
287 (case result of |
299 val _ = timing tr (Timing.result start); |
288 NONE => (Toplevel.status tr Markup.failed; (false, st)) |
300 val _ = List.app (Toplevel.error_msg tr) errs; |
289 | SOME st' => |
301 in |
290 (Toplevel.status tr Markup.finished; |
302 (case result of |
291 proof_status tr st'; |
303 NONE => (Toplevel.status tr Markup.failed; (false, st)) |
292 if do_print then async_state tr st' else (); |
304 | SOME st' => |
293 (true, st'))); |
305 (Toplevel.status tr Markup.finished; |
294 in res end |
306 proof_status tr st'; |
295 | Exn.Exn exn => |
307 if do_print then async_state tr st' else (); |
296 if Exn.is_interrupt exn then reraise exn |
308 (true, st'))) |
297 else |
309 end; |
298 (Toplevel.error_msg raw_tr (ML_Compiler.exn_message exn); |
|
299 Toplevel.status raw_tr Markup.failed; |
|
300 (false, Toplevel.toplevel))); |
|
301 |
310 |
302 end; |
311 end; |
303 |
312 |
304 |
313 |
305 |
314 |
313 fun is_changed node' ((_, id), exec) = |
322 fun is_changed node' ((_, id), exec) = |
314 (case try (the_entry node') id of |
323 (case try (the_entry node') id of |
315 NONE => true |
324 NONE => true |
316 | SOME exec' => exec' <> exec); |
325 | SOME exec' => exec' <> exec); |
317 |
326 |
318 fun new_exec name (id: command_id) (exec_id, updates, state) = |
327 fun new_exec node_info (id: command_id) (exec_id, updates, state) = |
319 let |
328 let |
320 val exec = the_exec state exec_id; |
329 val exec = the_exec state exec_id; |
321 val exec_id' = new_id (); |
330 val exec_id' = new_id (); |
322 val future_tr = the_command state id; |
331 val future_tr = the_command state id; |
323 val exec' = |
332 val exec' = |
324 Lazy.lazy (fn () => |
333 Lazy.lazy (fn () => |
325 let |
334 let |
326 val st = #2 (Lazy.force exec); |
335 val st = #2 (Lazy.force exec); |
327 val exec_tr = Toplevel.put_id (print_id exec_id') (Future.join future_tr); |
336 val exec_tr = Toplevel.put_id (print_id exec_id') (Future.join future_tr); |
328 in run_command name exec_tr st end); |
337 in run_command node_info exec_tr st end); |
329 val state' = define_exec exec_id' exec' state; |
338 val state' = define_exec exec_id' exec' state; |
330 in (exec_id', (id, exec_id') :: updates, state') end; |
339 in (exec_id', (id, exec_id') :: updates, state') end; |
331 |
340 |
332 in |
341 in |
333 |
342 |
336 val old_version = the_version state old_id; |
345 val old_version = the_version state old_id; |
337 val _ = Time.now (); (* FIXME odd workaround for polyml-5.4.0/x86_64 *) |
346 val _ = Time.now (); (* FIXME odd workaround for polyml-5.4.0/x86_64 *) |
338 val new_version = fold edit_nodes edits old_version; |
347 val new_version = fold edit_nodes edits old_version; |
339 |
348 |
340 fun update_node name (rev_updates, version, st) = |
349 fun update_node name (rev_updates, version, st) = |
341 let val node = get_node version name in |
350 let |
342 (case first_entry NONE (is_changed (get_node old_version name)) node of |
351 val node = node_of version name; |
|
352 val header = get_header node; |
|
353 in |
|
354 (case first_entry NONE (is_changed (node_of old_version name)) node of |
343 NONE => (rev_updates, version, st) |
355 NONE => (rev_updates, version, st) |
344 | SOME ((prev, id), _) => |
356 | SOME ((prev, id), _) => |
345 let |
357 let |
346 val prev_exec = |
358 val prev_exec = |
347 (case prev of |
359 (case prev of |
348 NONE => no_id |
360 NONE => no_id |
349 | SOME prev_id => the_default no_id (the_entry node prev_id)); |
361 | SOME prev_id => the_default no_id (the_entry node prev_id)); |
350 val (last, rev_upds, st') = |
362 val (last, rev_upds, st') = |
351 fold_entries (SOME id) (new_exec name o #2 o #1) node (prev_exec, [], st); |
363 fold_entries (SOME id) (new_exec (name, header) o #2 o #1) node (prev_exec, [], st); |
352 val node' = node |> fold update_entry rev_upds |> set_last last; |
364 val node' = node |> fold update_entry rev_upds |> set_last last; |
353 in (rev_upds @ rev_updates, put_node name node' version, st') end) |
365 in (rev_upds @ rev_updates, put_node name node' version, st') end) |
354 end; |
366 end; |
355 |
367 |
356 (* FIXME proper node deps *) |
368 (* FIXME Graph.schedule *) |
357 val (rev_updates, new_version', state') = |
369 val (rev_updates, new_version', state') = |
358 fold update_node (node_names_of new_version) ([], new_version, state); |
370 fold update_node (node_names_of new_version) ([], new_version, state); |
359 val state'' = define_version new_id new_version' state'; |
371 val state'' = define_version new_id new_version' state'; |
360 |
372 |
361 val _ = join_commands state''; (* FIXME async!? *) |
373 val _ = join_commands state''; (* FIXME async!? *) |
378 Future.forks |
390 Future.forks |
379 {name = "Document.execute", group = NONE, deps = [], pri = 1, interrupts = true} |
391 {name = "Document.execute", group = NONE, deps = [], pri = 1, interrupts = true} |
380 [fn () => |
392 [fn () => |
381 node_names_of version |> List.app (fn name => |
393 node_names_of version |> List.app (fn name => |
382 fold_entries NONE (fn (_, exec) => fn () => force_exec exec) |
394 fold_entries NONE (fn (_, exec) => fn () => force_exec exec) |
383 (get_node version name) ())]; |
395 (node_of version name) ())]; |
384 |
396 |
385 in (versions, commands, execs, execution') end); |
397 in (versions, commands, execs, execution') end); |
386 |
398 |
387 |
399 |
388 |
400 |