35 val timing = Unsynchronized.ref false; |
35 val timing = Unsynchronized.ref false; |
36 fun timeit msg e = cond_timeit (! timing) msg e; |
36 fun timeit msg e = cond_timeit (! timing) msg e; |
37 |
37 |
38 |
38 |
39 |
39 |
40 |
|
41 |
|
42 |
|
43 (** document structure **) |
40 (** document structure **) |
44 |
41 |
45 fun err_dup kind id = error ("Duplicate " ^ kind ^ ": " ^ Document_ID.print id); |
42 fun err_dup kind id = error ("Duplicate " ^ kind ^ ": " ^ Document_ID.print id); |
46 fun err_undef kind id = error ("Undefined " ^ kind ^ ": " ^ Document_ID.print id); |
43 fun err_undef kind id = error ("Undefined " ^ kind ^ ": " ^ Document_ID.print id); |
47 |
44 |
283 type blob_digest = (string * string option) Exn.result; (*file node name, raw digest*) |
280 type blob_digest = (string * string option) Exn.result; (*file node name, raw digest*) |
284 |
281 |
285 type execution = |
282 type execution = |
286 {version_id: Document_ID.version, (*static version id*) |
283 {version_id: Document_ID.version, (*static version id*) |
287 execution_id: Document_ID.execution, (*dynamic execution id*) |
284 execution_id: Document_ID.execution, (*dynamic execution id*) |
288 delay_request: unit future, (*pending event timer request*) |
285 delay_request: unit future}; (*pending event timer request*) |
289 frontier: Future.task Symtab.table}; (*node name -> running execution task*) |
|
290 |
286 |
291 val no_execution: execution = |
287 val no_execution: execution = |
292 {version_id = Document_ID.none, execution_id = Document_ID.none, |
288 {version_id = Document_ID.none, |
293 delay_request = Future.value (), frontier = Symtab.empty}; |
289 execution_id = Document_ID.none, |
294 |
290 delay_request = Future.value ()}; |
295 fun new_execution version_id delay_request frontier : execution = |
291 |
296 {version_id = version_id, execution_id = Execution.start (), |
292 fun new_execution version_id delay_request : execution = |
297 delay_request = delay_request, frontier = frontier}; |
293 {version_id = version_id, |
|
294 execution_id = Execution.start (), |
|
295 delay_request = delay_request}; |
298 |
296 |
299 abstype state = State of |
297 abstype state = State of |
300 {versions: version Inttab.table, (*version id -> document content*) |
298 {versions: version Inttab.table, (*version id -> document content*) |
301 blobs: (SHA1.digest * string list) Symtab.table, (*raw digest -> digest, lines*) |
299 blobs: (SHA1.digest * string list) Symtab.table, (*raw digest -> digest, lines*) |
302 commands: (string * blob_digest list * Token.T list lazy) Inttab.table, |
300 commands: (string * blob_digest list * Token.T list lazy) Inttab.table, |
316 |
314 |
317 |
315 |
318 (* document versions *) |
316 (* document versions *) |
319 |
317 |
320 fun define_version version_id version = |
318 fun define_version version_id version = |
321 map_state (fn (versions, blobs, commands, {delay_request, frontier, ...}) => |
319 map_state (fn (versions, blobs, commands, {delay_request, ...}) => |
322 let |
320 let |
323 val versions' = Inttab.update_new (version_id, version) versions |
321 val versions' = Inttab.update_new (version_id, version) versions |
324 handle Inttab.DUP dup => err_dup "document version" dup; |
322 handle Inttab.DUP dup => err_dup "document version" dup; |
325 val execution' = new_execution version_id delay_request frontier; |
323 val execution' = new_execution version_id delay_request; |
326 in (versions', blobs, commands, execution') end); |
324 in (versions', blobs, commands, execution') end); |
327 |
325 |
328 fun the_version (State {versions, ...}) version_id = |
326 fun the_version (State {versions, ...}) version_id = |
329 (case Inttab.lookup versions version_id of |
327 (case Inttab.lookup versions version_id of |
330 NONE => err_undef "document version" version_id |
328 NONE => err_undef "document version" version_id |
406 (* document execution *) |
404 (* document execution *) |
407 |
405 |
408 fun start_execution state = state |> map_state (fn (versions, blobs, commands, execution) => |
406 fun start_execution state = state |> map_state (fn (versions, blobs, commands, execution) => |
409 timeit "Document.start_execution" (fn () => |
407 timeit "Document.start_execution" (fn () => |
410 let |
408 let |
411 val {version_id, execution_id, delay_request, frontier} = execution; |
409 val {version_id, execution_id, delay_request} = execution; |
412 |
410 |
413 val delay = seconds (Options.default_real "editor_execution_delay"); |
411 val delay = seconds (Options.default_real "editor_execution_delay"); |
414 |
412 |
415 val _ = Future.cancel delay_request; |
413 val _ = Future.cancel delay_request; |
416 val delay_request' = Event_Timer.future (Time.+ (Time.now (), delay)); |
414 val delay_request' = Event_Timer.future (Time.+ (Time.now (), delay)); |
417 |
415 |
418 val new_tasks = |
416 val _ = |
419 nodes_of (the_version state version_id) |> String_Graph.schedule |
417 nodes_of (the_version state version_id) |> String_Graph.schedule |
420 (fn deps => fn (name, node) => |
418 (fn deps => fn (name, node) => |
421 if visible_node node orelse pending_result node then |
419 if visible_node node orelse pending_result node then |
422 let |
420 let |
423 val more_deps = |
|
424 Future.task_of delay_request' :: the_list (Symtab.lookup frontier name); |
|
425 fun body () = |
421 fun body () = |
426 iterate_entries (fn (_, opt_exec) => fn () => |
422 iterate_entries (fn (_, opt_exec) => fn () => |
427 (case opt_exec of |
423 (case opt_exec of |
428 SOME exec => |
424 SOME exec => |
429 if Execution.is_running execution_id |
425 if Execution.is_running execution_id |
431 else NONE |
427 else NONE |
432 | NONE => NONE)) node () |
428 | NONE => NONE)) node () |
433 handle exn => if Exn.is_interrupt exn then () (*sic!*) else reraise exn; |
429 handle exn => if Exn.is_interrupt exn then () (*sic!*) else reraise exn; |
434 val future = |
430 val future = |
435 (singleton o Future.forks) |
431 (singleton o Future.forks) |
436 {name = "theory:" ^ name, group = SOME (Future.new_group NONE), |
432 {name = "theory:" ^ name, |
437 deps = more_deps @ map #2 (maps #2 deps), |
433 group = SOME (Future.new_group NONE), |
438 pri = 0, interrupts = false} body; |
434 deps = Future.task_of delay_request' :: maps #2 deps, |
439 in [(name, Future.task_of future)] end |
435 pri = 0, interrupts = false} body; |
|
436 in [Future.task_of future] end |
440 else []); |
437 else []); |
441 val frontier' = (fold o fold) Symtab.update new_tasks frontier; |
|
442 val execution' = |
438 val execution' = |
443 {version_id = version_id, execution_id = execution_id, |
439 {version_id = version_id, execution_id = execution_id, delay_request = delay_request'}; |
444 delay_request = delay_request', frontier = frontier'}; |
|
445 in (versions, blobs, commands, execution') end)); |
440 in (versions, blobs, commands, execution') end)); |
446 |
441 |
447 |
442 |
448 |
443 |
449 (** document update **) |
444 (** document update **) |