92 (* thy database *) |
92 (* thy database *) |
93 |
93 |
94 type master = (Path.T * File.ident) * (Path.T * File.ident) option; |
94 type master = (Path.T * File.ident) * (Path.T * File.ident) option; |
95 |
95 |
96 type deps = |
96 type deps = |
97 {present: bool, |
97 {present: bool, (*theory value present*) |
98 outdated: bool, |
98 outdated: bool, (*entry considered outdated*) |
99 master: master option, |
99 master: master option, (*master dependencies for thy + attached ML file*) |
100 files: (Path.T * (Path.T * File.ident) option) list}; |
100 files: (*auxiliary files: source path, physical path + identifier*) |
|
101 (Path.T * (Path.T * File.ident) option) list}; |
|
102 |
|
103 fun make_deps present outdated master files = |
|
104 {present = present, outdated = outdated, master = master, files = files}: deps; |
|
105 |
|
106 fun init_deps master files = SOME (make_deps false true master (map (rpair NONE) files)); |
101 |
107 |
102 fun master_idents (NONE: master option) = [] |
108 fun master_idents (NONE: master option) = [] |
103 | master_idents (SOME ((_, thy_id), NONE)) = [thy_id] |
109 | master_idents (SOME ((_, thy_id), NONE)) = [thy_id] |
104 | master_idents (SOME ((_, thy_id), SOME (_, ml_id))) = [thy_id, ml_id]; |
110 | master_idents (SOME ((_, thy_id), SOME (_, ml_id))) = [thy_id, ml_id]; |
105 |
111 |
106 fun master_path (m: master option) = map (Path.dir o fst o fst) (the_list m); |
112 fun master_dir (NONE: master option) = Path.current |
107 fun master_path' (d: deps option) = maps (master_path o #master) (the_list d); |
113 | master_dir (SOME ((path, _), _)) = Path.dir path; |
108 fun master_path'' d = maps master_path' (the_list d); |
114 |
109 |
115 fun master_dir' (d: deps option) = the_default Path.current (Option.map (master_dir o #master) d); |
110 fun make_deps present outdated master files = |
116 fun master_dir'' d = the_default Path.current (Option.map master_dir' d); |
111 {present = present, outdated = outdated, master = master, files = files}: deps; |
117 |
112 |
|
113 fun init_deps master files = SOME (make_deps false true master (map (rpair NONE) files)); |
|
114 |
118 |
115 type thy = deps option * theory option; |
119 type thy = deps option * theory option; |
116 |
120 |
117 local |
121 local |
118 val database = ref (Graph.empty: thy Graph.T); |
122 val database = ref (Graph.empty: thy Graph.T); |
324 |
328 |
325 fun base_name s = Path.implode (Path.base (Path.explode s)); |
329 fun base_name s = Path.implode (Path.base (Path.explode s)); |
326 |
330 |
327 local |
331 local |
328 |
332 |
329 fun check_ml master (path, info) = |
333 fun check_ml master (src_path, info) = |
330 let val info' = |
334 let val info' = |
331 (case info of NONE => NONE |
335 (case info of NONE => NONE |
332 | SOME (_, id) => |
336 | SOME (_, id) => |
333 (case ThyLoad.check_ml (master_path master) path of NONE => NONE |
337 (case ThyLoad.check_ml (master_dir master) src_path of NONE => NONE |
334 | SOME (path', id') => if id <> id' then NONE else SOME (path', id'))) |
338 | SOME (path', id') => if id <> id' then NONE else SOME (path', id'))) |
335 in (path, info') end; |
339 in (src_path, info') end; |
336 |
340 |
337 fun check_deps ml strict dirs name = |
341 fun check_deps ml strict dir name = |
338 (case lookup_deps name of |
342 (case lookup_deps name of |
339 NONE => |
343 NONE => |
340 let val (master, (parents, files)) = ThyLoad.deps_thy dirs name ml |>> SOME |
344 let val (master, (parents, files)) = ThyLoad.deps_thy dir name ml |>> SOME |
341 in (false, (init_deps master files, parents)) end |
345 in (false, (init_deps master files, parents)) end |
342 | SOME NONE => (true, (NONE, get_parents name)) |
346 | SOME NONE => (true, (NONE, get_parents name)) |
343 | SOME (deps as SOME {present, outdated, master, files}) => |
347 | SOME (deps as SOME {present, outdated, master, files}) => |
344 if present andalso not strict then (true, (deps, get_parents name)) |
348 if present andalso not strict then (true, (deps, get_parents name)) |
345 else |
349 else |
346 let val (master', (parents', files')) = ThyLoad.deps_thy dirs name ml |>> SOME in |
350 let val (master', (parents', files')) = ThyLoad.deps_thy dir name ml |>> SOME in |
347 if master_idents master <> master_idents master' |
351 if master_idents master <> master_idents master' |
348 then (false, (init_deps master' files', parents')) |
352 then (false, (init_deps master' files', parents')) |
349 else |
353 else |
350 let |
354 let |
351 val checked_files = map (check_ml master') files; |
355 val checked_files = map (check_ml master') files; |
352 val current = not outdated andalso forall (is_some o snd) checked_files; |
356 val current = not outdated andalso forall (is_some o snd) checked_files; |
353 val deps' = SOME (make_deps present (not current) master' checked_files); |
357 val deps' = SOME (make_deps present (not current) master' checked_files); |
354 in (current, (deps', parents')) end |
358 in (current, (deps', parents')) end |
355 end); |
359 end); |
356 |
360 |
357 fun require_thy really ml time strict keep_strict initiators dirs str visited = |
361 fun require_thy really ml time strict keep_strict initiators dir str visited = |
358 let |
362 let |
359 val path = Path.expand (Path.explode str); |
363 val path = Path.expand (Path.explode str); |
360 val name = Path.implode (Path.base path); |
364 val name = Path.implode (Path.base path); |
361 val dirs' = Path.dir path :: dirs; |
365 val dir1 = Path.append dir (Path.dir path); |
362 val _ = member (op =) initiators name andalso error (cycle_msg initiators); |
366 val _ = member (op =) initiators name andalso error (cycle_msg initiators); |
363 in |
367 in |
364 if known_thy name andalso is_finished name orelse member (op =) visited name |
368 if known_thy name andalso is_finished name orelse member (op =) visited name |
365 then ((true, name), visited) |
369 then ((true, name), visited) |
366 else |
370 else |
367 let |
371 let |
368 val (current, (deps, parents)) = check_deps ml strict dirs' name |
372 val (current, (deps, parents)) = check_deps ml strict dir1 name |
369 handle ERROR msg => cat_error msg |
373 handle ERROR msg => cat_error msg |
370 (loader_msg "the error(s) above occurred while examining theory" [name] ^ |
374 (loader_msg "the error(s) above occurred while examining theory" [name] ^ |
371 (if null initiators then "" else required_by "\n" initiators)); |
375 (if null initiators then "" else required_by "\n" initiators)); |
372 |
376 |
373 val dirs'' = master_path' deps @ dirs; |
377 val dir2 = Path.append dir (master_dir' deps); |
374 val req_parent = require_thy true true time (strict andalso keep_strict) keep_strict |
378 val req_parent = require_thy true true time (strict andalso keep_strict) keep_strict |
375 (name :: initiators) dirs''; |
379 (name :: initiators) dir2; |
376 val (parent_results, visited') = fold_map req_parent parents (name :: visited); |
380 val (parent_results, visited') = fold_map req_parent parents (name :: visited); |
377 |
381 |
378 val all_current = current andalso forall fst parent_results; |
382 val all_current = current andalso forall fst parent_results; |
379 val thy = if all_current orelse not really then SOME (get_theory name) else NONE; |
383 val thy = if all_current orelse not really then SOME (get_theory name) else NONE; |
380 val _ = change_thys (update_node name (map base_name parents) (deps, thy)); |
384 val _ = change_thys (update_node name (map base_name parents) (deps, thy)); |
381 val _ = |
385 val _ = |
382 if all_current then () |
386 if all_current then () |
383 else load_thy really ml (time orelse ! Output.timing) initiators dirs' name; |
387 else load_thy really ml (time orelse ! Output.timing) initiators dir1 name; |
384 in ((all_current, name), visited') end |
388 in ((all_current, name), visited') end |
385 end; |
389 end; |
386 |
390 |
387 fun gen_use_thy' req dirs s = Output.toplevel_errors (fn () => |
391 fun gen_use_thy' req dir s = Output.toplevel_errors (fn () => |
388 let val ((_, name), _) = req [] dirs s [] |
392 let val ((_, name), _) = req [] dir s [] |
389 in ML_Context.set_context (SOME (Context.Theory (get_theory name))) end) (); |
393 in ML_Context.set_context (SOME (Context.Theory (get_theory name))) end) (); |
390 |
394 |
391 fun gen_use_thy req = gen_use_thy' req []; |
395 fun gen_use_thy req = gen_use_thy' req Path.current; |
392 |
396 |
393 fun warn_finished f name = (check_unfinished warning name; f name); |
397 fun warn_finished f name = (check_unfinished warning name; f name); |
394 |
398 |
395 in |
399 in |
396 |
400 |
427 end; |
431 end; |
428 |
432 |
429 fun begin_theory present name parents uses int = |
433 fun begin_theory present name parents uses int = |
430 let |
434 let |
431 val bparents = map base_name parents; |
435 val bparents = map base_name parents; |
432 val dirs' = master_path'' (lookup_deps name); |
436 val dir = master_dir'' (lookup_deps name); |
433 val dirs = dirs' @ [Path.current]; |
|
434 val _ = check_unfinished error name; |
437 val _ = check_unfinished error name; |
435 val _ = List.app ((if int then quiet_update_thy else weak_use_thy) dirs) parents; |
438 val _ = List.app ((if int then quiet_update_thy else weak_use_thy) dir) parents; |
436 val _ = check_uses name uses; |
439 val _ = check_uses name uses; |
437 |
440 |
438 val theory = Theory.begin_theory name (map get_theory bparents); |
441 val theory = Theory.begin_theory name (map get_theory bparents); |
439 val deps = |
442 val deps = |
440 if known_thy name then get_deps name |
443 if known_thy name then get_deps name |
441 else (init_deps NONE (map #1 uses)); |
444 else (init_deps NONE (map #1 uses)); |
442 val uses_now = map_filter (fn (x, true) => SOME x | _ => NONE) uses; |
445 val uses_now = map_filter (fn (x, true) => SOME x | _ => NONE) uses; |
443 |
446 |
444 val _ = change_thys (update_node name bparents (deps, SOME (Theory.copy theory))); |
447 val _ = change_thys (update_node name bparents (deps, SOME (Theory.copy theory))); |
445 val theory' = theory |> present dirs' name bparents uses; |
448 val theory' = theory |> present dir name bparents uses; |
446 val _ = put_theory name (Theory.copy theory'); |
449 val _ = put_theory name (Theory.copy theory'); |
447 val ((), theory'') = |
450 val ((), theory'') = |
448 ML_Context.pass_context (Context.Theory theory') (List.app (load_file false)) uses_now |
451 ML_Context.pass_context (Context.Theory theory') (List.app (load_file false)) uses_now |
449 ||> Context.the_theory; |
452 ||> Context.the_theory; |
450 val _ = put_theory name (Theory.copy theory''); |
453 val _ = put_theory name (Theory.copy theory''); |