src/Pure/Thy/thy_info.ML
changeset 23886 f40fba467384
parent 23871 0dd5696f58b6
child 23893 8babfcaaf129
equal deleted inserted replaced
23885:09254a1622e3 23886:f40fba467384
    36   val touch_child_thys: string -> unit
    36   val touch_child_thys: string -> unit
    37   val touch_all_thys: unit -> unit
    37   val touch_all_thys: unit -> unit
    38   val load_file: bool -> Path.T -> unit
    38   val load_file: bool -> Path.T -> unit
    39   val use: string -> unit
    39   val use: string -> unit
    40   val pretend_use_thy_only: string -> unit
    40   val pretend_use_thy_only: string -> unit
    41   val begin_theory: (Path.T list -> string -> string list ->
    41   val begin_theory: (Path.T -> string -> string list ->
    42       (Path.T * bool) list -> theory -> theory) ->
    42     (Path.T * bool) list -> theory -> theory) ->
    43     string -> string list -> (Path.T * bool) list -> bool -> theory
    43     string -> string list -> (Path.T * bool) list -> bool -> theory
    44   val end_theory: theory -> theory
    44   val end_theory: theory -> theory
    45   val finish: unit -> unit
    45   val finish: unit -> unit
    46   val register_theory: theory -> unit
    46   val register_theory: theory -> unit
    47   val pretty_theory: theory -> Pretty.T
    47   val pretty_theory: theory -> Pretty.T
    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);
   266       SOME (make_deps present outdated master (AList.update (op =) (path, SOME info) files)))
   270       SOME (make_deps present outdated master (AList.update (op =) (path, SOME info) files)))
   267   | provide _ _ _ NONE = NONE;
   271   | provide _ _ _ NONE = NONE;
   268 
   272 
   269 fun run_file path =
   273 fun run_file path =
   270   (case Option.map (Context.theory_name o Context.the_theory) (ML_Context.get_context ()) of
   274   (case Option.map (Context.theory_name o Context.the_theory) (ML_Context.get_context ()) of
   271     NONE => (ThyLoad.load_ml [] path; ())
   275     NONE => (ThyLoad.load_ml Path.current path; ())
   272   | SOME name =>
   276   | SOME name =>
   273       (case lookup_deps name of
   277       (case lookup_deps name of
   274         SOME deps =>
   278         SOME deps =>
   275           change_deps name (provide path name (ThyLoad.load_ml (master_path' deps) path))
   279           change_deps name (provide path name (ThyLoad.load_ml (master_dir' deps) path))
   276       | NONE => (ThyLoad.load_ml [] path; ())));
   280       | NONE => (ThyLoad.load_ml Path.current path; ())));
   277 
   281 
   278 in
   282 in
   279 
   283 
   280 fun load_file time path = Output.toplevel_errors (fn () =>
   284 fun load_file time path = Output.toplevel_errors (fn () =>
   281   if time then
   285   if time then
   296 (* load_thy *)
   300 (* load_thy *)
   297 
   301 
   298 fun required_by _ [] = ""
   302 fun required_by _ [] = ""
   299   | required_by s initiators = s ^ "(required by " ^ show_path (rev initiators) ^ ")";
   303   | required_by s initiators = s ^ "(required by " ^ show_path (rev initiators) ^ ")";
   300 
   304 
   301 fun load_thy really ml time initiators dirs name =
   305 fun load_thy really ml time initiators dir name =
   302   let
   306   let
   303     val _ =
   307     val _ =
   304       if really then priority ("Loading theory " ^ quote name ^ required_by " " initiators)
   308       if really then priority ("Loading theory " ^ quote name ^ required_by " " initiators)
   305       else priority ("Registering theory " ^ quote name);
   309       else priority ("Registering theory " ^ quote name);
   306 
   310 
   307     val _ = touch_thy name;
   311     val _ = touch_thy name;
   308     val master =
   312     val master =
   309       if really then ThyLoad.load_thy dirs name ml time
   313       if really then ThyLoad.load_thy dir name ml time
   310       else #1 (ThyLoad.deps_thy dirs name ml);
   314       else #1 (ThyLoad.deps_thy dir name ml);
   311 
   315 
   312     val files = get_files name;
   316     val files = get_files name;
   313     val missing_files = map_filter (fn (path, NONE) => SOME (Path.implode path) | _ => NONE) files;
   317     val missing_files = map_filter (fn (path, NONE) => SOME (Path.implode path) | _ => NONE) files;
   314   in
   318   in
   315     if null missing_files then ()
   319     if null missing_files then ()
   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'');