86 |> add_deps name parents; |
86 |> add_deps name parents; |
87 |
87 |
88 |
88 |
89 (* thy database *) |
89 (* thy database *) |
90 |
90 |
91 type master = (Path.T * File.ident) * (Path.T * File.ident) option; |
|
92 |
|
93 type deps = |
91 type deps = |
94 {update_time: int, (*symbolic time of update; negative value means outdated*) |
92 {update_time: int, (*symbolic time of update; negative value means outdated*) |
95 master: master option, (*master dependencies for thy + attached ML file*) |
93 master: (Path.T * File.ident) option, (*master dependencies for thy file*) |
96 text: string list, (*source text for thy*) |
94 text: string list, (*source text for thy*) |
97 parents: string list, (*source specification of parents (partially qualified)*) |
95 parents: string list, (*source specification of parents (partially qualified)*) |
98 files: (*auxiliary files: source path, physical path + identifier*) |
96 (*auxiliary files: source path, physical path + identifier*) |
99 (Path.T * (Path.T * File.ident) option) list}; |
97 files: (Path.T * (Path.T * File.ident) option) list}; |
100 |
98 |
101 fun make_deps update_time master text parents files : deps = |
99 fun make_deps update_time master text parents files : deps = |
102 {update_time = update_time, master = master, text = text, parents = parents, files = files}; |
100 {update_time = update_time, master = master, text = text, parents = parents, files = files}; |
103 |
101 |
104 fun init_deps master text parents files = |
102 fun init_deps master text parents files = |
105 SOME (make_deps ~1 master text parents (map (rpair NONE) files)); |
103 SOME (make_deps ~1 master text parents (map (rpair NONE) files)); |
106 |
104 |
107 fun master_idents (NONE: master option) = [] |
105 fun master_dir NONE = Path.current |
108 | master_idents (SOME ((_, thy_id), NONE)) = [thy_id] |
106 | master_dir (SOME (path, _)) = Path.dir path; |
109 | master_idents (SOME ((_, thy_id), SOME (_, ml_id))) = [thy_id, ml_id]; |
|
110 |
|
111 fun master_dir (NONE: master option) = Path.current |
|
112 | master_dir (SOME ((path, _), _)) = Path.dir path; |
|
113 |
107 |
114 fun master_dir' (d: deps option) = the_default Path.current (Option.map (master_dir o #master) d); |
108 fun master_dir' (d: deps option) = the_default Path.current (Option.map (master_dir o #master) d); |
115 fun master_dir'' d = the_default Path.current (Option.map master_dir' d); |
109 fun master_dir'' d = the_default Path.current (Option.map master_dir' d); |
116 |
110 |
117 fun base_name s = Path.implode (Path.base (Path.explode s)); |
111 fun base_name s = Path.implode (Path.base (Path.explode s)); |
162 |
156 |
163 fun loaded_files name = |
157 fun loaded_files name = |
164 (case get_deps name of |
158 (case get_deps name of |
165 NONE => [] |
159 NONE => [] |
166 | SOME {master, files, ...} => |
160 | SOME {master, files, ...} => |
167 (case master of SOME ((thy_path, _), _) => [thy_path] | NONE => []) @ |
161 (case master of SOME (thy_path, _) => [thy_path] | NONE => []) @ |
168 (map_filter (Option.map #1 o #2) files)); |
162 (map_filter (Option.map #1 o #2) files)); |
169 |
163 |
170 fun get_parents name = |
164 fun get_parents name = |
171 thy_graph Graph.imm_preds name handle Graph.UNDEF _ => |
165 thy_graph Graph.imm_preds name handle Graph.UNDEF _ => |
172 error (loader_msg "nothing known about theory" [name]); |
166 error (loader_msg "nothing known about theory" [name]); |
225 |
219 |
226 fun check_files name = |
220 fun check_files name = |
227 let |
221 let |
228 val files = (case get_deps name of SOME {files, ...} => files | NONE => []); |
222 val files = (case get_deps name of SOME {files, ...} => files | NONE => []); |
229 val missing_files = map_filter (fn (path, NONE) => SOME (Path.implode path) | _ => NONE) files; |
223 val missing_files = map_filter (fn (path, NONE) => SOME (Path.implode path) | _ => NONE) files; |
230 val _ = |
224 val _ = null missing_files orelse |
231 if null missing_files then () |
225 error (loader_msg "unresolved dependencies of theory" [name] ^ |
232 else warning (loader_msg "unresolved dependencies of theory" [name] ^ |
|
233 " on file(s): " ^ commas_quote missing_files); |
226 " on file(s): " ^ commas_quote missing_files); |
234 in files end; |
227 in () end; |
235 |
228 |
236 |
229 |
237 (* maintain update_time *) |
230 (* maintain update_time *) |
238 |
231 |
239 local |
232 local |
308 (* load_thy *) |
301 (* load_thy *) |
309 |
302 |
310 fun required_by _ [] = "" |
303 fun required_by _ [] = "" |
311 | required_by s initiators = s ^ "(required by " ^ show_path (rev initiators) ^ ")"; |
304 | required_by s initiators = s ^ "(required by " ^ show_path (rev initiators) ^ ")"; |
312 |
305 |
313 fun load_thy ml time upd_time initiators dir name = |
306 fun load_thy time upd_time initiators dir name = |
314 let |
307 let |
315 val _ = priority ("Loading theory " ^ quote name ^ required_by " " initiators); |
308 val _ = priority ("Loading theory " ^ quote name ^ required_by " " initiators); |
316 val (pos, text, files) = |
309 val (pos, text, files) = |
317 (case get_deps name of |
310 (case get_deps name of |
318 SOME {master = SOME ((master_path, _), _), text as _ :: _, files, ...} => |
311 SOME {master = SOME (master_path, _), text as _ :: _, files, ...} => |
319 (Position.path master_path, text, files) |
312 (Position.path master_path, text, files) |
320 | _ => error (loader_msg "corrupted dependency information" [name])); |
313 | _ => error (loader_msg "corrupted dependency information" [name])); |
321 val _ = touch_thy name; |
314 val _ = touch_thy name; |
322 val _ = CRITICAL (fn () => |
315 val _ = CRITICAL (fn () => |
323 change_deps name (Option.map (fn {master, text, parents, files, ...} => |
316 change_deps name (Option.map (fn {master, text, parents, files, ...} => |
324 make_deps upd_time master text parents files))); |
317 make_deps upd_time master text parents files))); |
325 val _ = ThyLoad.load_thy dir name pos text ml (time orelse ! Output.timing); |
318 val _ = ThyLoad.load_thy dir name pos text (time orelse ! Output.timing); |
326 val _ = check_files name; |
|
327 in |
319 in |
328 CRITICAL (fn () => |
320 CRITICAL (fn () => |
329 (change_deps name |
321 (change_deps name |
330 (Option.map (fn {update_time, master, parents, files, ...} => |
322 (Option.map (fn {update_time, master, parents, files, ...} => |
331 make_deps update_time master [] parents files)); |
323 make_deps update_time master [] parents files)); |
347 |
339 |
348 fun check_deps dir name = |
340 fun check_deps dir name = |
349 (case lookup_deps name of |
341 (case lookup_deps name of |
350 SOME NONE => (true, NONE, get_parents name) |
342 SOME NONE => (true, NONE, get_parents name) |
351 | NONE => |
343 | NONE => |
352 let val {master, text, imports = parents, uses = files} = ThyLoad.deps_thy dir name true |
344 let val {master, text, imports = parents, uses = files} = ThyLoad.deps_thy dir name |
353 in (false, init_deps (SOME master) text parents files, parents) end |
345 in (false, init_deps (SOME master) text parents files, parents) end |
354 | SOME (deps as SOME {update_time, master, text, parents, files}) => |
346 | SOME (deps as SOME {update_time, master, text, parents, files}) => |
355 let val master' as SOME ((thy_path, _), _) = SOME (ThyLoad.check_thy dir name true) in |
347 let |
356 if master_idents master <> master_idents master' |
348 val (thy_path, thy_id) = ThyLoad.check_thy dir name; |
357 then |
349 val master' = SOME (thy_path, thy_id); |
|
350 in |
|
351 if Option.map #2 master <> SOME thy_id then |
358 let val {text = text', imports = parents', uses = files', ...} = |
352 let val {text = text', imports = parents', uses = files', ...} = |
359 ThyLoad.deps_thy dir name true; |
353 ThyLoad.deps_thy dir name; |
360 in (false, init_deps master' text' parents' files', parents') end |
354 in (false, init_deps master' text' parents' files', parents') end |
361 else |
355 else |
362 let |
356 let |
363 val files' = map (check_ml master') files; |
357 val files' = map (check_ml master') files; |
364 val current = update_time >= 0 andalso forall (is_some o snd) files'; |
358 val current = update_time >= 0 andalso forall (is_some o snd) files'; |
399 val _ = change_thys (new_deps name parent_names (deps, theory)); |
393 val _ = change_thys (new_deps name parent_names (deps, theory)); |
400 |
394 |
401 val upd_time = serial (); |
395 val upd_time = serial (); |
402 val tasks_graph'' = tasks_graph' |> new_deps name parent_names |
396 val tasks_graph'' = tasks_graph' |> new_deps name parent_names |
403 (if all_current then Task.Finished |
397 (if all_current then Task.Finished |
404 else Task.Task (fn () => load_thy true time upd_time initiators dir' name)); |
398 else Task.Task (fn () => load_thy time upd_time initiators dir' name)); |
405 val tasks_len'' = if all_current then tasks_len' else tasks_len' + 1; |
399 val tasks_len'' = if all_current then tasks_len' else tasks_len' + 1; |
406 in (all_current, (tasks_graph'', tasks_len'')) end) |
400 in (all_current, (tasks_graph'', tasks_len'')) end) |
407 end; |
401 end; |
408 |
402 |
409 end; |
403 end; |
482 end; |
476 end; |
483 |
477 |
484 |
478 |
485 (* begin / end theory *) |
479 (* begin / end theory *) |
486 |
480 |
487 fun check_uses name uses = |
|
488 let val illegal = map (fn ext => Path.ext ext (Path.basic name)) ("" :: ThyLoad.ml_exts) in |
|
489 (case find_first (member (op =) illegal o Path.base o Path.expand o #1) uses of |
|
490 NONE => () |
|
491 | SOME (path, _) => error ("Illegal use of theory ML file: " ^ quote (Path.implode path))) |
|
492 end; |
|
493 |
|
494 fun begin_theory name parents uses int = |
481 fun begin_theory name parents uses int = |
495 let |
482 let |
496 val parent_names = map base_name parents; |
483 val parent_names = map base_name parents; |
497 val dir = master_dir'' (lookup_deps name); |
484 val dir = master_dir'' (lookup_deps name); |
498 val _ = check_unfinished error name; |
485 val _ = check_unfinished error name; |
499 val _ = if int then use_thys_dir dir parents else (); |
486 val _ = if int then use_thys_dir dir parents else (); |
500 (* FIXME tmp *) |
487 (* FIXME tmp *) |
501 val _ = CRITICAL (fn () => |
488 val _ = CRITICAL (fn () => |
502 ML_Context.set_context (SOME (Context.Theory (get_theory (List.last parent_names))))); |
489 ML_Context.set_context (SOME (Context.Theory (get_theory (List.last parent_names))))); |
503 val _ = check_uses name uses; |
|
504 |
490 |
505 val theory = Theory.begin_theory name (map get_theory parent_names); |
491 val theory = Theory.begin_theory name (map get_theory parent_names); |
506 |
492 |
507 val deps = |
493 val deps = |
508 if known_thy name then get_deps name |
494 if known_thy name then get_deps name |
533 val _ = priority ("Registering theory " ^ quote name); |
520 val _ = priority ("Registering theory " ^ quote name); |
534 val _ = get_theory name; |
521 val _ = get_theory name; |
535 val _ = map get_theory (get_parents name); |
522 val _ = map get_theory (get_parents name); |
536 val _ = check_unfinished error name; |
523 val _ = check_unfinished error name; |
537 val _ = touch_thy name; |
524 val _ = touch_thy name; |
538 val files = check_files name; |
525 val master = #master (ThyLoad.deps_thy Path.current name); |
539 val master = #master (ThyLoad.deps_thy Path.current name false); |
|
540 val upd_time = serial (); |
526 val upd_time = serial (); |
541 in |
527 in |
542 CRITICAL (fn () => |
528 CRITICAL (fn () => |
543 (change_deps name |
529 (change_deps name (Option.map |
544 (Option.map (fn {parents, ...} => make_deps upd_time (SOME master) [] parents files)); |
530 (fn {parents, files, ...} => make_deps upd_time (SOME master) [] parents files)); |
545 perform Update name)) |
531 perform Update name)) |
546 end; |
532 end; |
547 |
533 |
548 fun register_theory theory = |
534 fun register_theory theory = |
549 let |
535 let |