summaryrefslogtreecommitdiff
path: root/toplevel/mltop.ml
diff options
context:
space:
mode:
Diffstat (limited to 'toplevel/mltop.ml')
-rw-r--r--toplevel/mltop.ml447
1 files changed, 0 insertions, 447 deletions
diff --git a/toplevel/mltop.ml b/toplevel/mltop.ml
deleted file mode 100644
index b6690fe4..00000000
--- a/toplevel/mltop.ml
+++ /dev/null
@@ -1,447 +0,0 @@
-(************************************************************************)
-(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2016 *)
-(* \VV/ **************************************************************)
-(* // * This file is distributed under the terms of the *)
-(* * GNU Lesser General Public License Version 2.1 *)
-(************************************************************************)
-
-open CErrors
-open Util
-open Pp
-open Flags
-open Libobject
-open System
-
-(* Code to hook Coq into the ML toplevel -- depends on having the
- objective-caml compiler mostly visible. The functions implemented here are:
- \begin{itemize}
- \item [dir_ml_load name]: Loads the ML module fname from the current ML
- path.
- \item [dir_ml_use]: Directive #use of Ocaml toplevel
- \item [add_ml_dir]: Directive #directory of Ocaml toplevel
- \end{itemize}
-
- How to build an ML module interface with these functions.
- The idea is that the ML directory path is like the Coq directory
- path. So we can maintain the two in parallel.
- In the same way, we can use the "ml_env" as a kind of ML
- environment, which we freeze, unfreeze, and add things to just like
- to the other environments.
- Finally, we can create an object which is an ML module, and require
- that the "caching" of the ML module cause the loading of the
- associated ML file, if that file has not been yet loaded. Of
- course, the problem is how to record dependencies between ML
- modules.
- (I do not know of a solution to this problem, other than to
- put all the needed names into the ML Module object.) *)
-
-
-(* NB: this module relies on OCaml's Dynlink library. The bytecode version
- of Dynlink is always available, but there are some architectures
- with native compilation and no dynlink.cmxa. Instead of nasty IFDEF's
- here for hiding the calls to Dynlink, we now simply reject this rather
- rare situation during ./configure, and give instructions there about how
- to build a dummy dynlink.cmxa, cf. dev/dynlink.ml. *)
-
-(* This path is where we look for .cmo *)
-let coq_mlpath_copy = ref [Sys.getcwd ()]
-let keep_copy_mlpath path =
- let cpath = CUnix.canonical_path_name path in
- let filter path' = not (String.equal cpath path')
- in
- coq_mlpath_copy := cpath :: List.filter filter !coq_mlpath_copy
-
-(* If there is a toplevel under Coq *)
-type toplevel = {
- load_obj : string -> unit;
- use_file : string -> unit;
- add_dir : string -> unit;
- ml_loop : unit -> unit }
-
-(* Determines the behaviour of Coq with respect to ML files (compiled
- or not) *)
-type kind_load =
- | WithTop of toplevel
- | WithoutTop
-
-(* Must be always initialized *)
-let load = ref WithoutTop
-
-(* Are we in a native version of Coq? *)
-let is_native = Dynlink.is_native
-
-(* Sets and initializes a toplevel (if any) *)
-let set_top toplevel = load :=
- WithTop toplevel;
- Nativelib.load_obj := toplevel.load_obj
-
-(* Removes the toplevel (if any) *)
-let remove () =
- load := WithoutTop;
- Nativelib.load_obj := (fun x -> () : string -> unit)
-
-(* Tests if an Ocaml toplevel runs under Coq *)
-let is_ocaml_top () =
- match !load with
- | WithTop _ -> true
- |_ -> false
-
-(* Tests if we can load ML files *)
-let has_dynlink = Coq_config.has_natdynlink || not is_native
-
-(* Runs the toplevel loop of Ocaml *)
-let ocaml_toploop () =
- match !load with
- | WithTop t -> Printexc.catch t.ml_loop ()
- | _ -> ()
-
-(* Try to interpret load_obj's (internal) errors *)
-let report_on_load_obj_error exc =
- let x = Obj.repr exc in
- (* Try an horrible (fragile) hack to report on Symtable dynlink errors *)
- (* (we follow ocaml's Printexc.to_string decoding of exceptions) *)
- if Obj.is_block x && String.equal (Obj.magic (Obj.field (Obj.field x 0) 0)) "Symtable.Error"
- then
- let err_block = Obj.field x 1 in
- if Int.equal (Obj.tag err_block) 0 then
- (* Symtable.Undefined_global of string *)
- str "reference to undefined global " ++
- str (Obj.magic (Obj.field err_block 0))
- else str (Printexc.to_string exc)
- else str (Printexc.to_string exc)
-
-(* Dynamic loading of .cmo/.cma *)
-
-let ml_load s =
- match !load with
- | WithTop t ->
- (try t.load_obj s; s
- with
- | e when CErrors.noncritical e ->
- let e = CErrors.push e in
- match fst e with
- | (UserError _ | Failure _ | Not_found as u) -> Exninfo.iraise (u, snd e)
- | exc ->
- let msg = report_on_load_obj_error exc in
- errorlabstrm "Mltop.load_object" (str"Cannot link ml-object " ++
- str s ++ str" to Coq code (" ++ msg ++ str ")."))
- | WithoutTop ->
- try
- Dynlink.loadfile s; s
- with Dynlink.Error a ->
- errorlabstrm "Mltop.load_object"
- (strbrk "while loading " ++ str s ++
- strbrk ": " ++ str (Dynlink.error_message a))
-
-let dir_ml_load s =
- match !load with
- | WithTop _ -> ml_load s
- | WithoutTop ->
- let warn = Flags.is_verbose() in
- let _,gname = find_file_in_path ~warn !coq_mlpath_copy s in
- ml_load gname
-
-(* Dynamic interpretation of .ml *)
-let dir_ml_use s =
- match !load with
- | WithTop t -> t.use_file s
- | _ ->
- let moreinfo =
- if Dynlink.is_native then " Loading ML code works only in bytecode."
- else ""
- in
- errorlabstrm "Mltop.dir_ml_use" (str "Could not load ML code." ++ str moreinfo)
-
-(* Adds a path to the ML paths *)
-let add_ml_dir s =
- match !load with
- | WithTop t -> t.add_dir s; keep_copy_mlpath s
- | WithoutTop when has_dynlink -> keep_copy_mlpath s
- | _ -> ()
-
-(* For Rec Add ML Path (-R) *)
-let add_rec_ml_dir unix_path =
- List.iter (fun (lp,_) -> add_ml_dir lp) (all_subdirs ~unix_path)
-
-(* Adding files to Coq and ML loadpath *)
-
-let warn_cannot_use_directory =
- CWarnings.create ~name:"cannot-use-directory" ~category:"filesystem"
- (fun d ->
- str "Directory " ++ str d ++
- strbrk " cannot be used as a Coq identifier (skipped)")
-
-let convert_string d =
- try Names.Id.of_string d
- with UserError _ ->
- warn_cannot_use_directory d;
- raise Exit
-
-let warn_cannot_open_path =
- CWarnings.create ~name:"cannot-open-path" ~category:"filesystem"
- (fun unix_path -> str "Cannot open " ++ str unix_path)
-
-type add_ml = AddNoML | AddTopML | AddRecML
-
-let add_rec_path add_ml ~unix_path ~coq_root ~implicit =
- if exists_dir unix_path then
- let dirs = all_subdirs ~unix_path in
- let prefix = Names.DirPath.repr coq_root in
- let convert_dirs (lp, cp) =
- try
- let path = List.rev_map convert_string cp @ prefix in
- Some (lp, Names.DirPath.make path)
- with Exit -> None
- in
- let dirs = List.map_filter convert_dirs dirs in
- let () = match add_ml with
- | AddNoML -> ()
- | AddTopML -> add_ml_dir unix_path
- | AddRecML -> List.iter (fun (lp,_) -> add_ml_dir lp) dirs in
- let add (path, dir) =
- Loadpath.add_load_path path ~implicit dir in
- let () = List.iter add dirs in
- Loadpath.add_load_path unix_path ~implicit coq_root
- else
- warn_cannot_open_path unix_path
-
-(* convertit un nom quelconque en nom de fichier ou de module *)
-let mod_of_name name =
- if Filename.check_suffix name ".cmo" then
- Filename.chop_suffix name ".cmo"
- else
- name
-
-let get_ml_object_suffix name =
- if Filename.check_suffix name ".cmo" then
- Some ".cmo"
- else if Filename.check_suffix name ".cma" then
- Some ".cma"
- else if Filename.check_suffix name ".cmxs" then
- Some ".cmxs"
- else
- None
-
-let file_of_name name =
- let suffix = get_ml_object_suffix name in
- let fail s =
- errorlabstrm "Mltop.load_object"
- (str"File not found on loadpath : " ++ str s ++ str"\n" ++
- str"Loadpath: " ++ str(String.concat ":" !coq_mlpath_copy)) in
- if not (Filename.is_relative name) then
- if Sys.file_exists name then name else fail name
- else if is_native then
- let name = match suffix with
- | Some ((".cmo"|".cma") as suffix) ->
- (Filename.chop_suffix name suffix) ^ ".cmxs"
- | Some ".cmxs" -> name
- | _ -> name ^ ".cmxs"
- in
- if is_in_path !coq_mlpath_copy name then name else fail name
- else
- let (full, base) = match suffix with
- | Some ".cmo" | Some ".cma" -> true, name
- | Some ".cmxs" -> false, Filename.chop_suffix name ".cmxs"
- | _ -> false, name
- in
- if full then
- if is_in_path !coq_mlpath_copy base then base else fail base
- else
- let name = base ^ ".cma" in
- if is_in_path !coq_mlpath_copy name then name else
- let name = base ^ ".cmo" in
- if is_in_path !coq_mlpath_copy name then name else
- fail (base ^ ".cm[ao]")
-
-(** Is the ML code of the standard library placed into loadable plugins
- or statically compiled into coqtop ? For the moment this choice is
- made according to the presence of native dynlink : even if bytecode
- coqtop could always load plugins, we prefer to have uniformity between
- bytecode and native versions. *)
-
-(* [known_loaded_module] contains the names of the loaded ML modules
- * (linked or loaded with load_object). It is used not to load a
- * module twice. It is NOT the list of ML modules Coq knows. *)
-
-let known_loaded_modules = ref String.Map.empty
-
-let add_known_module mname path =
- if not (String.Map.mem mname !known_loaded_modules) ||
- String.Map.find mname !known_loaded_modules = None then
- known_loaded_modules := String.Map.add mname path !known_loaded_modules
-
-let module_is_known mname =
- String.Map.mem mname !known_loaded_modules
-
-let known_module_path mname =
- String.Map.find mname !known_loaded_modules
-
-(** A plugin is just an ML module with an initialization function. *)
-
-let known_loaded_plugins = ref String.Map.empty
-
-let add_known_plugin init name =
- add_known_module name None;
- known_loaded_plugins := String.Map.add name init !known_loaded_plugins
-
-let init_known_plugins () =
- String.Map.iter (fun _ f -> f()) !known_loaded_plugins
-
-(** Registering functions to be used at caching time, that is when the Declare
- ML module command is issued. *)
-
-let cache_objs = ref String.Map.empty
-
-let declare_cache_obj f name =
- let objs = try String.Map.find name !cache_objs with Not_found -> [] in
- let objs = f :: objs in
- cache_objs := String.Map.add name objs !cache_objs
-
-let perform_cache_obj name =
- let objs = try String.Map.find name !cache_objs with Not_found -> [] in
- let objs = List.rev objs in
- List.iter (fun f -> f ()) objs
-
-(** ml object = ml module or plugin *)
-
-let init_ml_object mname =
- try String.Map.find mname !known_loaded_plugins ()
- with Not_found -> ()
-
-let load_ml_object mname ?path fname=
- let path = match path with
- | None -> dir_ml_load fname
- | Some p -> ml_load p in
- add_known_module mname (Some path);
- init_ml_object mname;
- path
-
-let dir_ml_load m = ignore(dir_ml_load m)
-let add_known_module m = add_known_module m None
-let load_ml_object_raw fname = dir_ml_load (file_of_name fname)
-let load_ml_objects_raw_rex rex =
- List.iter (fun (_,fp) ->
- let name = file_of_name (Filename.basename fp) in
- try dir_ml_load name
- with e -> prerr_endline (Printexc.to_string e))
- (System.where_in_path_rex !coq_mlpath_copy rex)
-
-(* Summary of declared ML Modules *)
-
-(* List and not String.Set because order is important: most recent first. *)
-
-let loaded_modules = ref []
-let get_loaded_modules () = List.rev !loaded_modules
-let add_loaded_module md path =
- if not (List.mem_assoc md !loaded_modules) then
- loaded_modules := (md,path) :: !loaded_modules
-let reset_loaded_modules () = loaded_modules := []
-
-let if_verbose_load verb f name ?path fname =
- if not verb then f name ?path fname
- else
- let info = str "[Loading ML file " ++ str fname ++ str " ..." in
- try
- let path = f name ?path fname in
- Feedback.msg_info (info ++ str " done]");
- path
- with reraise ->
- Feedback.msg_info (info ++ str " failed]");
- raise reraise
-
-(** Load a module for the first time (i.e. dynlink it)
- or simulate its reload (i.e. doing nothing except maybe
- an initialization function). *)
-
-let trigger_ml_object verb cache reinit ?path name =
- if module_is_known name then begin
- if reinit then init_ml_object name;
- add_loaded_module name (known_module_path name);
- if cache then perform_cache_obj name
- end else if not has_dynlink then
- errorlabstrm "Mltop.trigger_ml_object"
- (str "Dynamic link not supported (module " ++ str name ++ str ")")
- else begin
- let file = file_of_name (Option.default name path) in
- let path =
- if_verbose_load (verb && is_verbose ()) load_ml_object name ?path file in
- add_loaded_module name (Some path);
- if cache then perform_cache_obj name
- end
-
-let load_ml_object n m = ignore(load_ml_object n m)
-
-let unfreeze_ml_modules x =
- reset_loaded_modules ();
- List.iter
- (fun (name,path) -> trigger_ml_object false false false ?path name) x
-
-let _ =
- Summary.declare_summary Summary.ml_modules
- { Summary.freeze_function = (fun _ -> get_loaded_modules ());
- Summary.unfreeze_function = unfreeze_ml_modules;
- Summary.init_function = reset_loaded_modules }
-
-(* Liboject entries of declared ML Modules *)
-
-type ml_module_object = {
- mlocal : Vernacexpr.locality_flag;
- mnames : string list
-}
-
-let cache_ml_objects (_,{mnames=mnames}) =
- let iter obj = trigger_ml_object true true true obj in
- List.iter iter mnames
-
-let load_ml_objects _ (_,{mnames=mnames}) =
- let iter obj = trigger_ml_object true false true obj in
- List.iter iter mnames
-
-let classify_ml_objects ({mlocal=mlocal} as o) =
- if mlocal then Dispose else Substitute o
-
-let inMLModule : ml_module_object -> obj =
- declare_object
- {(default_object "ML-MODULE") with
- cache_function = cache_ml_objects;
- load_function = load_ml_objects;
- subst_function = (fun (_,o) -> o);
- classify_function = classify_ml_objects }
-
-let declare_ml_modules local l =
- let l = List.map mod_of_name l in
- Lib.add_anonymous_leaf ~cache_first:false (inMLModule {mlocal=local; mnames=l})
-
-let print_ml_path () =
- let l = !coq_mlpath_copy in
- str"ML Load Path:" ++ fnl () ++ str" " ++
- hv 0 (prlist_with_sep fnl str l)
-
-(* Printing of loaded ML modules *)
-
-let print_ml_modules () =
- let l = get_loaded_modules () in
- str"Loaded ML Modules: " ++ pr_vertical_list str (List.map fst l)
-
-let print_gc () =
- let stat = Gc.stat () in
- let msg =
- str "minor words: " ++ real stat.Gc.minor_words ++ fnl () ++
- str "promoted words: " ++ real stat.Gc.promoted_words ++ fnl () ++
- str "major words: " ++ real stat.Gc.major_words ++ fnl () ++
- str "minor_collections: " ++ int stat.Gc.minor_collections ++ fnl () ++
- str "major_collections: " ++ int stat.Gc.major_collections ++ fnl () ++
- str "heap_words: " ++ int stat.Gc.heap_words ++ fnl () ++
- str "heap_chunks: " ++ int stat.Gc.heap_chunks ++ fnl () ++
- str "live_words: " ++ int stat.Gc.live_words ++ fnl () ++
- str "live_blocks: " ++ int stat.Gc.live_blocks ++ fnl () ++
- str "free_words: " ++ int stat.Gc.free_words ++ fnl () ++
- str "free_blocks: " ++ int stat.Gc.free_blocks ++ fnl () ++
- str "largest_free: " ++ int stat.Gc.largest_free ++ fnl () ++
- str "fragments: " ++ int stat.Gc.fragments ++ fnl () ++
- str "compactions: " ++ int stat.Gc.compactions ++ fnl () ++
- str "top_heap_words: " ++ int stat.Gc.top_heap_words ++ fnl () ++
- str "stack_size: " ++ int stat.Gc.stack_size
- in
- hv 0 msg