berghofe@3604: (* Title: Pure/Thy/thy_info.ML wenzelm@6211: Author: Markus Wenzel, TU Muenchen berghofe@3604: wenzelm@15801: Main part of theory loader database, including handling of theory and wenzelm@15801: file dependencies. wenzelm@3976: *) berghofe@3604: berghofe@3604: signature THY_INFO = berghofe@3604: sig wenzelm@7099: datatype action = Update | Outdate | Remove wenzelm@7099: val str_of_action: action -> string wenzelm@7099: val add_hook: (action -> string -> unit) -> unit wenzelm@26614: val get_names: unit -> string list wenzelm@7910: val known_thy: string -> bool wenzelm@7935: val check_known_thy: string -> bool wenzelm@7935: val if_known_thy: (string -> unit) -> string -> unit wenzelm@7288: val lookup_theory: string -> theory option wenzelm@6211: val get_theory: string -> theory wenzelm@19547: val the_theory: string -> theory -> theory wenzelm@24563: val is_finished: string -> bool wenzelm@26983: val master_directory: string -> Path.T wenzelm@24080: val loaded_files: string -> Path.T list wenzelm@23871: val get_parents: string -> string list wenzelm@27495: val touch_thy: string -> unit wenzelm@7910: val touch_child_thys: string -> unit wenzelm@32126: val thy_ord: theory * theory -> order wenzelm@29422: val remove_thy: string -> unit wenzelm@29422: val kill_thy: string -> unit wenzelm@25013: val provide_file: Path.T -> string -> unit wenzelm@7941: val load_file: bool -> Path.T -> unit wenzelm@26494: val exec_file: bool -> Path.T -> Context.generic -> Context.generic wenzelm@6241: val use: string -> unit wenzelm@24057: val time_use: string -> unit wenzelm@24057: val use_thys: string list -> unit wenzelm@24057: val use_thy: string -> unit wenzelm@24057: val time_use_thy: string -> unit wenzelm@23900: val begin_theory: string -> string list -> (Path.T * bool) list -> bool -> theory wenzelm@27579: val end_theory: theory -> unit wenzelm@24080: val register_thy: string -> unit wenzelm@24080: val register_theory: theory -> unit wenzelm@6666: val finish: unit -> unit berghofe@3604: end; berghofe@3604: wenzelm@37216: structure Thy_Info: THY_INFO = berghofe@3604: struct berghofe@3604: wenzelm@7099: (** theory loader actions and hooks **) wenzelm@7099: wenzelm@7099: datatype action = Update | Outdate | Remove; wenzelm@7099: val str_of_action = fn Update => "Update" | Outdate => "Outdate" | Remove => "Remove"; wenzelm@7099: wenzelm@7099: local wenzelm@32738: val hooks = Unsynchronized.ref ([]: (action -> string -> unit) list); wenzelm@7099: in wenzelm@32738: fun add_hook f = CRITICAL (fn () => Unsynchronized.change hooks (cons f)); skalberg@15570: fun perform action name = List.app (fn f => (try (fn () => f action name) (); ())) (! hooks); wenzelm@7099: end; wenzelm@7099: wenzelm@7099: wenzelm@7099: wenzelm@6211: (** thy database **) wenzelm@3976: wenzelm@6211: (* messages *) berghofe@3604: wenzelm@23871: fun loader_msg txt [] = "Theory loader: " ^ txt wenzelm@23871: | loader_msg txt names = "Theory loader: " ^ txt ^ " " ^ commas_quote names; berghofe@3604: wenzelm@6211: val show_path = space_implode " via " o map quote; wenzelm@9332: fun cycle_msg names = loader_msg ("cyclic dependency of " ^ show_path names) []; berghofe@3604: berghofe@3604: wenzelm@6666: (* derived graph operations *) berghofe@3604: wenzelm@9327: fun add_deps name parents G = Graph.add_deps_acyclic (name, parents) G wenzelm@9332: handle Graph.CYCLES namess => error (cat_lines (map cycle_msg namess)); berghofe@3604: wenzelm@7952: fun upd_deps name entry G = wenzelm@19473: fold (fn parent => Graph.del_edge (parent, name)) (Graph.imm_preds G name) G wenzelm@7952: |> Graph.map_node name (K entry); berghofe@3604: wenzelm@23967: fun new_deps name parents entry G = wenzelm@7952: (if can (Graph.get_node G) name then upd_deps name entry G else Graph.new_node (name, entry) G) wenzelm@7952: |> add_deps name parents; berghofe@3604: berghofe@3604: wenzelm@6211: (* thy database *) berghofe@3604: wenzelm@6211: type deps = wenzelm@24190: {update_time: int, (*symbolic time of update; negative value means outdated*) wenzelm@24190: master: (Path.T * File.ident) option, (*master dependencies for thy file*) wenzelm@24190: text: string list, (*source text for thy*) wenzelm@24190: parents: string list, (*source specification of parents (partially qualified)*) wenzelm@24190: (*auxiliary files: source path, physical path + identifier*) wenzelm@24190: files: (Path.T * (Path.T * File.ident) option) list}; wenzelm@23886: wenzelm@24151: fun make_deps update_time master text parents files : deps = wenzelm@24151: {update_time = update_time, master = master, text = text, parents = parents, files = files}; wenzelm@23886: wenzelm@24068: fun init_deps master text parents files = wenzelm@24151: SOME (make_deps ~1 master text parents (map (rpair NONE) files)); wenzelm@23871: wenzelm@24190: fun master_dir NONE = Path.current wenzelm@24190: | master_dir (SOME (path, _)) = Path.dir path; berghofe@3604: wenzelm@23886: fun master_dir' (d: deps option) = the_default Path.current (Option.map (master_dir o #master) d); wenzelm@23886: fun master_dir'' d = the_default Path.current (Option.map master_dir' d); berghofe@3604: wenzelm@23967: fun base_name s = Path.implode (Path.base (Path.explode s)); wenzelm@23967: wenzelm@7211: wenzelm@6362: type thy = deps option * theory option; berghofe@3604: wenzelm@6211: local wenzelm@32738: val database = Unsynchronized.ref (Graph.empty: thy Graph.T); wenzelm@6211: in wenzelm@6362: fun get_thys () = ! database; wenzelm@32738: fun change_thys f = CRITICAL (fn () => Unsynchronized.change database f); berghofe@3604: end; wenzelm@5209: wenzelm@5209: wenzelm@6211: (* access thy graph *) wenzelm@6211: wenzelm@6211: fun thy_graph f x = f (get_thys ()) x; wenzelm@9417: wenzelm@23967: fun get_names () = Graph.topological_order (get_thys ()); wenzelm@6211: wenzelm@6211: wenzelm@6211: (* access thy *) wenzelm@6211: wenzelm@7935: fun lookup_thy name = skalberg@15531: SOME (thy_graph Graph.get_node name) handle Graph.UNDEF _ => NONE; wenzelm@7935: wenzelm@16047: val known_thy = is_some o lookup_thy; wenzelm@7935: fun check_known_thy name = known_thy name orelse (warning ("Unknown theory " ^ quote name); false); wenzelm@7935: fun if_known_thy f name = if check_known_thy name then f name else (); wenzelm@6211: wenzelm@6211: fun get_thy name = wenzelm@6211: (case lookup_thy name of skalberg@15531: SOME thy => thy skalberg@15531: | NONE => error (loader_msg "nothing known about theory" [name])); wenzelm@6211: wenzelm@23939: fun change_thy name f = CRITICAL (fn () => wenzelm@23939: (get_thy name; change_thys (Graph.map_node name f))); wenzelm@6211: wenzelm@6211: wenzelm@6211: (* access deps *) wenzelm@6211: skalberg@15570: val lookup_deps = Option.map #1 o lookup_thy; wenzelm@6211: val get_deps = #1 o get_thy; wenzelm@6211: fun change_deps name f = change_thy name (fn (deps, x) => (f deps, x)); wenzelm@6211: wenzelm@26983: val is_finished = is_none o get_deps; wenzelm@26983: val master_directory = master_dir' o get_deps; wenzelm@7191: wenzelm@7191: fun loaded_files name = wenzelm@7191: (case get_deps name of skalberg@15531: NONE => [] skalberg@15531: | SOME {master, files, ...} => wenzelm@24190: (case master of SOME (thy_path, _) => [thy_path] | NONE => []) @ wenzelm@19482: (map_filter (Option.map #1 o #2) files)); wenzelm@6211: wenzelm@23871: fun get_parents name = wenzelm@23967: thy_graph Graph.imm_preds name handle Graph.UNDEF _ => berghofe@6654: error (loader_msg "nothing known about theory" [name]); berghofe@6654: wenzelm@6211: wenzelm@6211: (* access theory *) wenzelm@6211: wenzelm@7687: fun lookup_theory name = wenzelm@7687: (case lookup_thy name of skalberg@15531: SOME (_, SOME thy) => SOME thy skalberg@15531: | _ => NONE); wenzelm@7288: wenzelm@6211: fun get_theory name = wenzelm@7288: (case lookup_theory name of wenzelm@23871: SOME theory => theory wenzelm@6211: | _ => error (loader_msg "undefined theory entry for" [name])); wenzelm@6211: wenzelm@19547: fun the_theory name thy = wenzelm@19547: if Context.theory_name thy = name then thy wenzelm@19547: else get_theory name; wenzelm@19547: wenzelm@6211: wenzelm@6211: wenzelm@6211: (** thy operations **) wenzelm@6211: wenzelm@24080: (* check state *) wenzelm@24080: wenzelm@24080: fun check_unfinished fail name = wenzelm@24080: if known_thy name andalso is_finished name then wenzelm@24080: fail (loader_msg "cannot update finished theory" [name]) wenzelm@24080: else (); wenzelm@24080: wenzelm@24080: fun check_files name = wenzelm@24080: let wenzelm@24080: val files = (case get_deps name of SOME {files, ...} => files | NONE => []); wenzelm@24080: val missing_files = map_filter (fn (path, NONE) => SOME (Path.implode path) | _ => NONE) files; wenzelm@24190: val _ = null missing_files orelse wenzelm@24190: error (loader_msg "unresolved dependencies of theory" [name] ^ wenzelm@24080: " on file(s): " ^ commas_quote missing_files); wenzelm@24190: in () end; wenzelm@24080: wenzelm@24080: wenzelm@24151: (* maintain update_time *) wenzelm@6211: wenzelm@7099: local wenzelm@7099: wenzelm@6241: fun is_outdated name = wenzelm@6241: (case lookup_deps name of wenzelm@24151: SOME (SOME {update_time, ...}) => update_time < 0 wenzelm@6241: | _ => false); wenzelm@6211: wenzelm@25013: fun unfinished name = wenzelm@24186: if is_finished name then (warning (loader_msg "tried to touch finished theory" [name]); NONE) wenzelm@24186: else SOME name; wenzelm@24186: wenzelm@24186: in wenzelm@24186: wenzelm@6241: fun outdate_thy name = wenzelm@7099: if is_finished name orelse is_outdated name then () wenzelm@23939: else CRITICAL (fn () => wenzelm@24151: (change_deps name (Option.map (fn {master, text, parents, files, ...} => wenzelm@24151: make_deps ~1 master text parents files)); perform Outdate name)); wenzelm@7099: wenzelm@7910: fun touch_thys names = wenzelm@25013: List.app outdate_thy (thy_graph Graph.all_succs (map_filter unfinished names)); wenzelm@7910: wenzelm@7910: fun touch_thy name = touch_thys [name]; wenzelm@7910: fun touch_child_thys name = touch_thys (thy_graph Graph.imm_succs name); wenzelm@6241: wenzelm@7099: end; wenzelm@6211: wenzelm@6211: wenzelm@32126: (* management data *) wenzelm@32126: wenzelm@33522: structure Management_Data = Theory_Data wenzelm@32126: ( wenzelm@32126: type T = wenzelm@32126: Task_Queue.group option * (*worker thread group*) wenzelm@32126: int; (*abstract update time*) wenzelm@32126: val empty = (NONE, 0); wenzelm@32126: fun extend _ = empty; wenzelm@33522: fun merge _ = empty; wenzelm@32126: ); wenzelm@32126: wenzelm@32126: val thy_ord = int_ord o pairself (#2 o Management_Data.get); wenzelm@32126: wenzelm@32126: wenzelm@32126: (* pending proofs *) wenzelm@29434: wenzelm@29434: fun join_thy name = wenzelm@29434: (case lookup_theory name of wenzelm@32126: NONE => () wenzelm@29434: | SOME thy => PureThy.join_proofs thy); wenzelm@29434: wenzelm@29434: fun cancel_thy name = wenzelm@29434: (case lookup_theory name of wenzelm@29434: NONE => () wenzelm@32126: | SOME thy => wenzelm@32126: (case #1 (Management_Data.get thy) of wenzelm@32126: NONE => () wenzelm@32126: | SOME group => Future.cancel_group group)); wenzelm@29434: wenzelm@29434: wenzelm@29422: (* remove theory *) wenzelm@29422: wenzelm@29422: fun remove_thy name = wenzelm@29422: if is_finished name then error (loader_msg "cannot remove finished theory" [name]) wenzelm@29422: else wenzelm@29434: let wenzelm@29434: val succs = thy_graph Graph.all_succs [name]; wenzelm@29434: val _ = List.app cancel_thy succs; wenzelm@29434: val _ = priority (loader_msg "removing" succs); wenzelm@29434: val _ = CRITICAL (fn () => wenzelm@29434: (List.app (perform Remove) succs; change_thys (Graph.del_nodes succs))); wenzelm@29434: in () end; wenzelm@29422: wenzelm@29422: val kill_thy = if_known_thy remove_thy; wenzelm@29422: wenzelm@29422: wenzelm@7941: (* load_file *) wenzelm@6211: wenzelm@7191: local wenzelm@7191: wenzelm@32801: fun provide path name info (SOME {update_time, master, text, parents, files}) = wenzelm@23871: (if AList.defined (op =) files path then () wenzelm@7941: else warning (loader_msg "undeclared dependency of theory" [name] ^ wenzelm@21858: " on file: " ^ quote (Path.implode path)); wenzelm@24151: SOME (make_deps update_time master text parents wenzelm@24151: (AList.update (op =) (path, SOME info) files))) skalberg@15531: | provide _ _ _ NONE = NONE; wenzelm@7941: wenzelm@7941: fun run_file path = wenzelm@26415: (case Option.map (Context.theory_name o Context.the_theory) (Context.thread_data ()) of wenzelm@37216: NONE => (Thy_Load.load_ml Path.current path; ()) wenzelm@23871: | SOME name => wenzelm@23871: (case lookup_deps name of wenzelm@23871: SOME deps => wenzelm@37216: change_deps name (provide path name (Thy_Load.load_ml (master_dir' deps) path)) wenzelm@37216: | NONE => (Thy_Load.load_ml Path.current path; ()))); wenzelm@6211: wenzelm@7191: in wenzelm@7191: wenzelm@25013: fun provide_file path name = wenzelm@25013: let wenzelm@26983: val dir = master_directory name; wenzelm@25013: val _ = check_unfinished error name; wenzelm@25013: in wenzelm@37216: (case Thy_Load.check_file dir path of wenzelm@25013: SOME path_info => change_deps name (provide path name path_info) wenzelm@25013: | NONE => error ("Could not find file " ^ quote (Path.implode path))) wenzelm@25013: end; wenzelm@25013: wenzelm@24057: fun load_file time path = wenzelm@7941: if time then wenzelm@21858: let val name = Path.implode path in wenzelm@7244: timeit (fn () => wenzelm@9778: (priority ("\n**** Starting file " ^ quote name ^ " ****"); wenzelm@9036: run_file path; wenzelm@9778: priority ("**** Finished file " ^ quote name ^ " ****\n"))) wenzelm@7244: end wenzelm@24057: else run_file path; wenzelm@7941: wenzelm@26494: fun exec_file time path = ML_Context.exec (fn () => load_file time path); wenzelm@26494: wenzelm@21858: val use = load_file false o Path.explode; wenzelm@21858: val time_use = load_file true o Path.explode; wenzelm@7191: wenzelm@7191: end; wenzelm@6233: wenzelm@6233: wenzelm@7099: (* load_thy *) wenzelm@7099: wenzelm@9490: fun required_by _ [] = "" wenzelm@9490: | required_by s initiators = s ^ "(required by " ^ show_path (rev initiators) ^ ")"; wenzelm@7099: wenzelm@27843: fun load_thy time upd_time initiators name = wenzelm@7099: let wenzelm@24080: val _ = priority ("Loading theory " ^ quote name ^ required_by " " initiators); wenzelm@32801: val (pos, text, _) = wenzelm@24068: (case get_deps name of wenzelm@24190: SOME {master = SOME (master_path, _), text as _ :: _, files, ...} => wenzelm@26881: (Path.position master_path, text, files) wenzelm@24068: | _ => error (loader_msg "corrupted dependency information" [name])); wenzelm@7099: val _ = touch_thy name; wenzelm@24151: val _ = CRITICAL (fn () => wenzelm@24151: change_deps name (Option.map (fn {master, text, parents, files, ...} => wenzelm@24151: make_deps upd_time master text parents files))); wenzelm@36953: val after_load = Outer_Syntax.load_thy name pos text (time orelse ! Output.timing); wenzelm@29429: val _ = wenzelm@29429: CRITICAL (fn () => wenzelm@29429: (change_deps name wenzelm@29429: (Option.map (fn {update_time, master, parents, files, ...} => wenzelm@29429: make_deps update_time master [] parents files)); wenzelm@29429: perform Update name)); wenzelm@29429: in after_load end; wenzelm@7099: wenzelm@7099: wenzelm@24209: (* scheduling loader tasks *) wenzelm@24209: wenzelm@29429: datatype task = Task of (unit -> unit -> unit) | Finished | Running; wenzelm@24209: fun task_finished Finished = true | task_finished _ = false; wenzelm@24209: wenzelm@29119: local wenzelm@29119: wenzelm@32823: fun schedule_futures task_graph = uninterruptible (fn _ => fn () => wenzelm@28194: let wenzelm@28194: val tasks = Graph.topological_order task_graph |> map_filter (fn name => wenzelm@28194: (case Graph.get_node task_graph name of Task body => SOME (name, body) | _ => NONE)); wenzelm@28194: wenzelm@32077: val par_proofs = ! parallel_proofs >= 1; wenzelm@29442: wenzelm@29429: fun fork (name, body) tab = wenzelm@28194: let wenzelm@29005: val deps = Graph.imm_preds task_graph name wenzelm@29005: |> map_filter (fn parent => wenzelm@29005: (case Symtab.lookup tab parent of SOME future => SOME (parent, future) | NONE => NONE)); wenzelm@29005: fun failed (parent, future) = if can Future.join future then NONE else SOME parent; wenzelm@29005: wenzelm@29442: val future = Future.fork_deps (map #2 deps) (fn () => wenzelm@29005: (case map_filter failed deps of wenzelm@29005: [] => body () wenzelm@29005: | bad => error (loader_msg wenzelm@29005: ("failed to load " ^ quote name ^ " (unresolved " ^ commas_quote bad ^ ")") []))); wenzelm@29442: val future' = wenzelm@29442: if par_proofs then future wenzelm@29442: else Future.map (fn after_load => (after_load (); fn () => ())) future; wenzelm@29442: in Symtab.update (name, future') tab end; wenzelm@29005: wenzelm@29429: val futures = fold fork tasks Symtab.empty; wenzelm@29005: wenzelm@34260: val failed = tasks |> maps (fn (name, _) => wenzelm@29429: let wenzelm@29429: val after_load = Future.join (the (Symtab.lookup futures name)); wenzelm@32126: val _ = join_thy name; wenzelm@29429: val _ = after_load (); wenzelm@34260: in [] end handle exn => [(name, exn)]) |> rev; wenzelm@29429: wenzelm@34260: val _ = List.app (kill_thy o #1) failed; wenzelm@34260: val _ = Exn.release_all (map (Exn.Exn o #2) failed); wenzelm@34260: in () end) (); wenzelm@29429: wenzelm@29429: fun schedule_seq tasks = wenzelm@29429: Graph.topological_order tasks wenzelm@30322: |> List.app (fn name => wenzelm@30322: (case Graph.get_node tasks name of wenzelm@30322: Task body => wenzelm@30322: let val after_load = body () wenzelm@31545: in after_load () handle exn => (kill_thy name; reraise exn) end wenzelm@30322: | _ => ())); wenzelm@28194: wenzelm@24209: in wenzelm@24209: wenzelm@32801: fun schedule_tasks tasks = wenzelm@29119: if not (Multithreading.enabled ()) then schedule_seq tasks wenzelm@29119: else if Multithreading.self_critical () then wenzelm@24209: (warning (loader_msg "no multithreading within critical section" []); wenzelm@24209: schedule_seq tasks) wenzelm@29119: else schedule_futures tasks; wenzelm@24209: wenzelm@24209: end; wenzelm@24209: wenzelm@24209: wenzelm@23967: (* require_thy -- checking database entries wrt. the file-system *) berghofe@15065: wenzelm@7211: local wenzelm@6211: wenzelm@23886: fun check_ml master (src_path, info) = wenzelm@23871: let val info' = wenzelm@23871: (case info of NONE => NONE wenzelm@23871: | SOME (_, id) => wenzelm@37216: (case Thy_Load.check_ml (master_dir master) src_path of NONE => NONE wenzelm@23871: | SOME (path', id') => if id <> id' then NONE else SOME (path', id'))) wenzelm@23886: in (src_path, info') end; wenzelm@6211: wenzelm@24175: fun check_deps dir name = wenzelm@23871: (case lookup_deps name of wenzelm@23893: SOME NONE => (true, NONE, get_parents name) wenzelm@23893: | NONE => wenzelm@37216: let val {master, text, imports = parents, uses = files} = Thy_Load.deps_thy dir name wenzelm@24068: in (false, init_deps (SOME master) text parents files, parents) end wenzelm@32801: | SOME (SOME {update_time, master, text, parents, files}) => wenzelm@24190: let wenzelm@37216: val (thy_path, thy_id) = Thy_Load.check_thy dir name; wenzelm@24190: val master' = SOME (thy_path, thy_id); wenzelm@24190: in wenzelm@24190: if Option.map #2 master <> SOME thy_id then wenzelm@24175: let val {text = text', imports = parents', uses = files', ...} = wenzelm@37216: Thy_Load.deps_thy dir name; wenzelm@24175: in (false, init_deps master' text' parents' files', parents') end wenzelm@24175: else wenzelm@24175: let wenzelm@24186: val files' = map (check_ml master') files; wenzelm@24307: val current = update_time >= 0 andalso can get_theory name wenzelm@24307: andalso forall (is_some o snd) files'; wenzelm@24175: val update_time' = if current then update_time else ~1; wenzelm@25030: val deps' = SOME (make_deps update_time' master' text parents files'); wenzelm@24175: in (current, deps', parents) end wenzelm@24175: end); wenzelm@6211: wenzelm@25030: fun read_text (SOME {update_time, master = master as SOME (path, _), text = _, parents, files}) = wenzelm@25030: SOME (make_deps update_time master (explode (File.read path)) parents files); wenzelm@25030: wenzelm@23967: in wenzelm@23967: wenzelm@24175: fun require_thys time initiators dir strs tasks = wenzelm@24186: fold_map (require_thy time initiators dir) strs tasks |>> forall I wenzelm@24175: and require_thy time initiators dir str tasks = wenzelm@6211: let wenzelm@21858: val path = Path.expand (Path.explode str); wenzelm@21858: val name = Path.implode (Path.base path); wenzelm@23893: val dir' = Path.append dir (Path.dir path); wenzelm@23871: val _ = member (op =) initiators name andalso error (cycle_msg initiators); wenzelm@7066: in wenzelm@32801: (case try (Graph.get_node tasks) name of wenzelm@24209: SOME task => (task_finished task, tasks) wenzelm@23967: | NONE => wenzelm@23967: let wenzelm@24175: val (current, deps, parents) = check_deps dir' name wenzelm@23967: handle ERROR msg => cat_error msg wenzelm@23967: (loader_msg "the error(s) above occurred while examining theory" [name] ^ wenzelm@23967: required_by "\n" initiators); wenzelm@23967: val parent_names = map base_name parents; wenzelm@6211: wenzelm@32801: val (parents_current, tasks_graph') = wenzelm@24175: require_thys time (name :: initiators) wenzelm@24175: (Path.append dir (master_dir' deps)) parents tasks; wenzelm@23871: wenzelm@23967: val all_current = current andalso parents_current; wenzelm@24186: val _ = if not all_current andalso known_thy name then outdate_thy name else (); wenzelm@25030: val entry = wenzelm@25030: if all_current then (deps, SOME (get_theory name)) wenzelm@25030: else (read_text deps, NONE); wenzelm@25030: val _ = change_thys (new_deps name parent_names entry); wenzelm@23967: wenzelm@24151: val upd_time = serial (); wenzelm@23974: val tasks_graph'' = tasks_graph' |> new_deps name parent_names wenzelm@24209: (if all_current then Finished wenzelm@27843: else Task (fn () => load_thy time upd_time initiators name)); wenzelm@32801: in (all_current, tasks_graph'') end) wenzelm@7066: end; wenzelm@6484: wenzelm@23967: end; wenzelm@23967: wenzelm@23967: wenzelm@24209: (* use_thy etc. *) wenzelm@23967: wenzelm@23967: local wenzelm@23967: wenzelm@24057: fun gen_use_thy' req dir arg = wenzelm@32801: schedule_tasks (snd (req [] dir arg Graph.empty)); wenzelm@6211: wenzelm@23893: fun gen_use_thy req str = wenzelm@23893: let val name = base_name str in wenzelm@23893: check_unfinished warning name; wenzelm@25994: gen_use_thy' req Path.current str wenzelm@23893: end; wenzelm@7244: wenzelm@7211: in wenzelm@7211: wenzelm@24186: val use_thys_dir = gen_use_thy' (require_thys false); wenzelm@24186: val use_thys = use_thys_dir Path.current; wenzelm@24186: val use_thy = gen_use_thy (require_thy false); wenzelm@24186: val time_use_thy = gen_use_thy (require_thy true); wenzelm@6211: wenzelm@7211: end; wenzelm@7211: wenzelm@6241: wenzelm@7066: (* begin / end theory *) wenzelm@6211: wenzelm@23900: fun begin_theory name parents uses int = wenzelm@6211: let wenzelm@23893: val parent_names = map base_name parents; wenzelm@23886: val dir = master_dir'' (lookup_deps name); wenzelm@7244: val _ = check_unfinished error name; wenzelm@24186: val _ = if int then use_thys_dir dir parents else (); wenzelm@17365: wenzelm@24151: val theory = Theory.begin_theory name (map get_theory parent_names); wenzelm@23900: wenzelm@7952: val deps = wenzelm@7952: if known_thy name then get_deps name wenzelm@24068: else init_deps NONE [] parents (map #1 uses); wenzelm@23967: val _ = change_thys (new_deps name parent_names (deps, NONE)); wenzelm@23900: wenzelm@24151: val update_time = (case deps of NONE => 0 | SOME {update_time, ...} => update_time); wenzelm@24563: val update_time = if update_time > 0 then update_time else serial (); wenzelm@24563: val theory' = theory wenzelm@32126: |> Management_Data.put (Future.worker_group (), update_time) wenzelm@24563: |> Present.begin_theory update_time dir uses; wenzelm@24151: wenzelm@19482: val uses_now = map_filter (fn (x, true) => SOME x | _ => NONE) uses; wenzelm@28292: val theory'' = wenzelm@28292: fold (fn x => Context.theory_map (exec_file false x) o Theory.checkpoint) uses_now theory'; wenzelm@24151: in theory'' end; wenzelm@7244: wenzelm@6211: fun end_theory theory = wenzelm@7099: let wenzelm@16454: val name = Context.theory_name theory; wenzelm@24190: val _ = check_files name; wenzelm@16504: val theory' = Theory.end_theory theory; wenzelm@23900: val _ = change_thy name (fn (deps, _) => (deps, SOME theory')); wenzelm@27579: in () end; wenzelm@6211: wenzelm@6211: wenzelm@24080: (* register existing theories *) wenzelm@6211: wenzelm@24080: fun register_thy name = wenzelm@24080: let wenzelm@24080: val _ = priority ("Registering theory " ^ quote name); wenzelm@24563: val thy = get_theory name; wenzelm@24096: val _ = map get_theory (get_parents name); wenzelm@24096: val _ = check_unfinished error name; wenzelm@24080: val _ = touch_thy name; wenzelm@37216: val master = #master (Thy_Load.deps_thy Path.current name); wenzelm@32126: val upd_time = #2 (Management_Data.get thy); wenzelm@24080: in wenzelm@24080: CRITICAL (fn () => wenzelm@24190: (change_deps name (Option.map wenzelm@24190: (fn {parents, files, ...} => make_deps upd_time (SOME master) [] parents files)); wenzelm@24080: perform Update name)) wenzelm@24080: end; wenzelm@6211: wenzelm@6211: fun register_theory theory = wenzelm@6211: let wenzelm@16454: val name = Context.theory_name theory; wenzelm@6211: val parents = Theory.parents_of theory; wenzelm@16454: val parent_names = map Context.theory_name parents; wenzelm@6211: wenzelm@6211: fun err txt bads = wenzelm@23871: error (loader_msg txt bads ^ "\ncannot register theory " ^ quote name); wenzelm@6211: wenzelm@6666: val nonfinished = filter_out is_finished parent_names; wenzelm@6211: fun get_variant (x, y_name) = skalberg@15531: if Theory.eq_thy (x, get_theory y_name) then NONE skalberg@15531: else SOME y_name; wenzelm@19482: val variants = map_filter get_variant (parents ~~ parent_names); wenzelm@6211: wenzelm@6211: fun register G = skalberg@15531: (Graph.new_node (name, (NONE, SOME theory)) G wenzelm@9327: handle Graph.DUP _ => err "duplicate theory entry" []) wenzelm@6211: |> add_deps name parent_names; wenzelm@6211: in wenzelm@6666: if not (null nonfinished) then err "non-finished parent theories" nonfinished wenzelm@6211: else if not (null variants) then err "different versions of parent theories" variants wenzelm@23939: else CRITICAL (fn () => (change_thys register; perform Update name)) wenzelm@6211: end; wenzelm@6211: wenzelm@24080: wenzelm@24080: (* finish all theories *) wenzelm@24080: wenzelm@28976: fun finish () = change_thys (Graph.map_nodes (fn (_, entry) => (NONE, entry))); wenzelm@24080: wenzelm@6211: end;