2016-02-18 07:11:59 -08:00
|
|
|
(**************************************************************************)
|
|
|
|
(* *)
|
|
|
|
(* OCaml *)
|
|
|
|
(* *)
|
|
|
|
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
|
|
|
|
(* *)
|
|
|
|
(* Copyright 1996 Institut National de Recherche en Informatique et *)
|
|
|
|
(* en Automatique. *)
|
|
|
|
(* *)
|
|
|
|
(* All rights reserved. This file is distributed under the terms of *)
|
|
|
|
(* the GNU Lesser General Public License version 2.1, with the *)
|
|
|
|
(* special exception on linking described in the file LICENSE. *)
|
|
|
|
(* *)
|
|
|
|
(**************************************************************************)
|
1995-08-09 08:06:35 -07:00
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
(* Toplevel directives *)
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
open Format
|
1995-05-04 03:15:53 -07:00
|
|
|
open Misc
|
|
|
|
open Longident
|
1996-09-23 04:32:19 -07:00
|
|
|
open Types
|
2006-05-11 08:50:53 -07:00
|
|
|
open Cmo_format
|
1995-09-14 04:53:55 -07:00
|
|
|
open Trace
|
1995-05-04 03:15:53 -07:00
|
|
|
open Toploop
|
|
|
|
|
2000-04-10 07:59:29 -07:00
|
|
|
(* The standard output formatter *)
|
|
|
|
let std_out = std_formatter
|
2000-03-06 14:12:09 -08:00
|
|
|
|
2015-12-25 10:51:20 -08:00
|
|
|
(* Directive sections (used in #help) *)
|
|
|
|
let section_general = "General"
|
|
|
|
let section_run = "Loading code"
|
|
|
|
let section_env = "Environment queries"
|
|
|
|
|
|
|
|
let section_print = "Pretty-printing"
|
|
|
|
let section_trace = "Tracing"
|
|
|
|
let section_options = "Compiler options"
|
|
|
|
|
|
|
|
let section_undocumented = "Undocumented"
|
|
|
|
|
|
|
|
(* we will print the sections in the first list,
|
|
|
|
then all user-defined sections,
|
|
|
|
then the sections in the second list,
|
|
|
|
then all undocumented directives *)
|
|
|
|
let order_of_sections =
|
|
|
|
([
|
|
|
|
section_general;
|
|
|
|
section_run;
|
|
|
|
section_env;
|
|
|
|
], [
|
|
|
|
section_print;
|
|
|
|
section_trace;
|
|
|
|
section_options;
|
|
|
|
|
|
|
|
section_undocumented;
|
|
|
|
])
|
2016-02-11 04:34:48 -08:00
|
|
|
(* Do not forget to keep the directives synchronized with the manual in
|
|
|
|
manual/manual/cmds/top.etex *)
|
2015-12-25 10:51:20 -08:00
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
(* To quit *)
|
|
|
|
|
2020-10-05 00:46:20 -07:00
|
|
|
let dir_quit () = raise (Compenv.Exit_with_status 0)
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "quit" (Directive_none dir_quit)
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_general;
|
|
|
|
doc = "Exit the toplevel.";
|
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
(* To add a directory to the load path *)
|
|
|
|
|
|
|
|
let dir_directory s =
|
2001-08-28 07:47:48 -07:00
|
|
|
let d = expand_directory Config.standard_library s in
|
2018-09-18 06:49:18 -07:00
|
|
|
Dll.add_path [d];
|
|
|
|
let dir = Load_path.Dir.create d in
|
|
|
|
Load_path.add dir;
|
|
|
|
toplevel_env :=
|
|
|
|
Stdlib.String.Set.fold
|
|
|
|
(fun name env ->
|
|
|
|
Env.add_persistent_structure (Ident.create_persistent name) env)
|
|
|
|
(Env.persistent_structures_of_dir dir)
|
|
|
|
!toplevel_env
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "directory" (Directive_string dir_directory)
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_run;
|
2016-02-16 04:23:31 -08:00
|
|
|
doc = "Add the given directory to search path for source and compiled \
|
|
|
|
files.";
|
2015-12-25 10:51:20 -08:00
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2012-07-07 04:40:33 -07:00
|
|
|
(* To remove a directory from the load path *)
|
|
|
|
let dir_remove_directory s =
|
|
|
|
let d = expand_directory Config.standard_library s in
|
2018-09-18 06:49:18 -07:00
|
|
|
let keep id =
|
|
|
|
match Load_path.find_uncap (Ident.name id ^ ".cmi") with
|
|
|
|
| exception Not_found -> true
|
|
|
|
| fn -> Filename.dirname fn <> d
|
|
|
|
in
|
|
|
|
toplevel_env := Env.filter_non_loaded_persistent keep !toplevel_env;
|
|
|
|
Load_path.remove_dir s;
|
2012-07-07 04:40:33 -07:00
|
|
|
Dll.remove_path [d]
|
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "remove_directory" (Directive_string dir_remove_directory)
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_run;
|
|
|
|
doc = "Remove the given directory from the search path.";
|
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
(* To change the current directory *)
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_cd s = Sys.chdir s
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "cd" (Directive_string dir_cd)
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_run;
|
|
|
|
doc = "Change the current working directory.";
|
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
(* Load in-core a .cmo file *)
|
|
|
|
|
1996-02-18 06:46:22 -08:00
|
|
|
exception Load_failed
|
|
|
|
|
2002-11-17 08:42:12 -08:00
|
|
|
let check_consistency ppf filename cu =
|
2019-01-23 14:08:22 -08:00
|
|
|
try Env.import_crcs ~source:filename cu.cu_imports
|
2019-01-07 07:48:03 -08:00
|
|
|
with Persistent_env.Consistbl.Inconsistency {
|
|
|
|
unit_name = name;
|
|
|
|
inconsistent_source = user;
|
|
|
|
original_source = auth;
|
|
|
|
} ->
|
2002-11-17 08:42:12 -08:00
|
|
|
fprintf ppf "@[<hv 0>The files %s@ and %s@ \
|
|
|
|
disagree over interface %s@]@."
|
|
|
|
user auth name;
|
|
|
|
raise Load_failed
|
2000-03-26 07:50:58 -08:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let load_compunit ic filename ppf compunit =
|
2000-03-26 07:50:58 -08:00
|
|
|
check_consistency ppf filename compunit;
|
1996-02-18 06:46:22 -08:00
|
|
|
seek_in ic compunit.cu_pos;
|
1996-05-28 05:43:41 -07:00
|
|
|
let code_size = compunit.cu_codesize + 8 in
|
2018-04-13 08:11:23 -07:00
|
|
|
let code = LongString.create code_size in
|
|
|
|
LongString.input_bytes_into code ic compunit.cu_codesize;
|
|
|
|
LongString.set code compunit.cu_codesize (Char.chr Opcodes.opRETURN);
|
2018-04-13 09:09:03 -07:00
|
|
|
LongString.blit_string "\000\000\000\001\000\000\000" 0
|
|
|
|
code (compunit.cu_codesize + 1) 7;
|
1996-02-18 06:46:22 -08:00
|
|
|
let initial_symtable = Symtable.current_state() in
|
|
|
|
Symtable.patch_object code compunit.cu_reloc;
|
|
|
|
Symtable.update_global_table();
|
2015-02-08 06:10:12 -08:00
|
|
|
let events =
|
|
|
|
if compunit.cu_debug = 0 then [| |]
|
|
|
|
else begin
|
|
|
|
seek_in ic compunit.cu_debug;
|
|
|
|
[| input_value ic |]
|
|
|
|
end in
|
1996-02-18 06:46:22 -08:00
|
|
|
begin try
|
2001-02-12 06:32:38 -08:00
|
|
|
may_trace := true;
|
2018-04-13 09:36:20 -07:00
|
|
|
let _bytecode, closure = Meta.reify_bytecode code events None in
|
2018-04-13 08:11:23 -07:00
|
|
|
ignore (closure ());
|
2001-02-12 06:32:38 -08:00
|
|
|
may_trace := false;
|
1996-02-18 06:46:22 -08:00
|
|
|
with exn ->
|
2015-02-08 06:10:12 -08:00
|
|
|
record_backtrace ();
|
2001-02-12 06:32:38 -08:00
|
|
|
may_trace := false;
|
1996-02-18 06:46:22 -08:00
|
|
|
Symtable.restore_state initial_symtable;
|
2000-03-06 14:12:09 -08:00
|
|
|
print_exception_outcome ppf exn;
|
1996-02-18 06:46:22 -08:00
|
|
|
raise Load_failed
|
|
|
|
end
|
|
|
|
|
2011-12-13 09:50:08 -08:00
|
|
|
let rec load_file recursive ppf name =
|
2013-09-04 08:12:37 -07:00
|
|
|
let filename =
|
2018-09-18 06:49:18 -07:00
|
|
|
try Some (Load_path.find name) with Not_found -> None
|
2013-09-04 08:12:37 -07:00
|
|
|
in
|
2011-12-14 03:04:06 -08:00
|
|
|
match filename with
|
|
|
|
| None -> fprintf ppf "Cannot find file %s.@." name; false
|
|
|
|
| Some filename ->
|
|
|
|
let ic = open_in_bin filename in
|
2018-07-25 07:23:07 -07:00
|
|
|
Misc.try_finally
|
2015-12-23 13:40:21 -08:00
|
|
|
~always:(fun () -> close_in ic)
|
2018-07-25 07:23:07 -07:00
|
|
|
(fun () -> really_load_file recursive ppf name filename ic)
|
2011-12-14 03:04:06 -08:00
|
|
|
|
|
|
|
and really_load_file recursive ppf name filename ic =
|
2014-04-29 04:56:17 -07:00
|
|
|
let buffer = really_input_string ic (String.length Config.cmo_magic_number) in
|
1995-05-04 03:15:53 -07:00
|
|
|
try
|
2011-12-14 03:04:06 -08:00
|
|
|
if buffer = Config.cmo_magic_number then begin
|
|
|
|
let compunit_pos = input_binary_int ic in (* Go to descriptor *)
|
|
|
|
seek_in ic compunit_pos;
|
|
|
|
let cu : compilation_unit = input_value ic in
|
|
|
|
if recursive then
|
|
|
|
List.iter
|
|
|
|
(function
|
2013-09-04 08:12:37 -07:00
|
|
|
| (Reloc_getglobal id, _)
|
|
|
|
when not (Symtable.is_global_defined id) ->
|
2011-12-14 03:04:06 -08:00
|
|
|
let file = Ident.name id ^ ".cmo" in
|
2018-09-18 06:49:18 -07:00
|
|
|
begin match Load_path.find_uncap file with
|
|
|
|
| exception Not_found -> ()
|
|
|
|
| file ->
|
2013-09-04 08:12:37 -07:00
|
|
|
if not (load_file recursive ppf file) then raise Load_failed
|
2011-12-14 03:04:06 -08:00
|
|
|
end
|
|
|
|
| _ -> ()
|
|
|
|
)
|
|
|
|
cu.cu_reloc;
|
|
|
|
load_compunit ic filename ppf cu;
|
|
|
|
true
|
|
|
|
end else
|
1996-02-18 06:46:22 -08:00
|
|
|
if buffer = Config.cma_magic_number then begin
|
|
|
|
let toc_pos = input_binary_int ic in (* Go to table of contents *)
|
|
|
|
seek_in ic toc_pos;
|
2001-08-28 07:47:48 -07:00
|
|
|
let lib = (input_value ic : library) in
|
2004-07-13 05:25:21 -07:00
|
|
|
List.iter
|
|
|
|
(fun dllib ->
|
|
|
|
let name = Dll.extract_dll_name dllib in
|
2006-09-28 14:36:38 -07:00
|
|
|
try Dll.open_dlls Dll.For_execution [name]
|
2004-07-13 05:25:21 -07:00
|
|
|
with Failure reason ->
|
|
|
|
fprintf ppf
|
|
|
|
"Cannot load required shared library %s.@.Reason: %s.@."
|
|
|
|
name reason;
|
|
|
|
raise Load_failed)
|
|
|
|
lib.lib_dllibs;
|
2002-02-07 18:56:04 -08:00
|
|
|
List.iter (load_compunit ic filename ppf) lib.lib_units;
|
|
|
|
true
|
|
|
|
end else begin
|
|
|
|
fprintf ppf "File %s is not a bytecode object file.@." name;
|
|
|
|
false
|
|
|
|
end
|
2011-12-14 03:04:06 -08:00
|
|
|
with Load_failed -> false
|
2002-02-07 18:56:04 -08:00
|
|
|
|
2011-12-13 09:50:08 -08:00
|
|
|
let dir_load ppf name = ignore (load_file false ppf name)
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "load" (Directive_string (dir_load std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_run;
|
|
|
|
doc = "Load in memory a bytecode object, produced by ocamlc.";
|
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2011-12-13 09:50:08 -08:00
|
|
|
let dir_load_rec ppf name = ignore (load_file true ppf name)
|
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "load_rec"
|
|
|
|
(Directive_string (dir_load_rec std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_run;
|
|
|
|
doc = "As #load, but loads dependencies recursively.";
|
|
|
|
}
|
2011-12-13 09:50:08 -08:00
|
|
|
|
|
|
|
let load_file = load_file false
|
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
(* Load commands from a file *)
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_use ppf name = ignore(Toploop.use_file ppf name)
|
2020-03-16 10:48:41 -07:00
|
|
|
let dir_use_output ppf name = ignore(Toploop.use_output ppf name)
|
2012-11-18 08:16:50 -08:00
|
|
|
let dir_mod_use ppf name = ignore(Toploop.mod_use_file ppf name)
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "use" (Directive_string (dir_use std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_run;
|
|
|
|
doc = "Read, compile and execute source phrases from the given file.";
|
|
|
|
}
|
2015-12-25 09:29:43 -08:00
|
|
|
|
2020-03-16 10:48:41 -07:00
|
|
|
let _ = add_directive "use_output" (Directive_string (dir_use_output std_out))
|
|
|
|
{
|
|
|
|
section = section_run;
|
|
|
|
doc = "Execute a command and read, compile and execute source phrases \
|
|
|
|
from its output.";
|
|
|
|
}
|
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "mod_use" (Directive_string (dir_mod_use std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_run;
|
|
|
|
doc = "Usage is identical to #use but #mod_use \
|
|
|
|
wraps the contents in a module.";
|
|
|
|
}
|
2015-12-25 09:29:43 -08:00
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
(* Install, remove a printer *)
|
|
|
|
|
2014-12-06 09:11:07 -08:00
|
|
|
let filter_arrow ty =
|
|
|
|
let ty = Ctype.expand_head !toplevel_env ty in
|
|
|
|
match ty.desc with
|
|
|
|
| Tarrow (lbl, l, r, _) when not (Btype.is_optional lbl) -> Some (l, r)
|
|
|
|
| _ -> None
|
|
|
|
|
|
|
|
let rec extract_last_arrow desc =
|
|
|
|
match filter_arrow desc with
|
|
|
|
| None -> raise (Ctype.Unify [])
|
|
|
|
| Some (_, r as res) ->
|
|
|
|
try extract_last_arrow r
|
|
|
|
with Ctype.Unify _ -> res
|
|
|
|
|
|
|
|
let extract_target_type ty = fst (extract_last_arrow ty)
|
|
|
|
let extract_target_parameters ty =
|
|
|
|
let ty = extract_target_type ty |> Ctype.expand_head !toplevel_env in
|
|
|
|
match ty.desc with
|
|
|
|
| Tconstr (path, (_ :: _ as args), _)
|
|
|
|
when Ctype.all_distinct_vars !toplevel_env args -> Some (path, args)
|
|
|
|
| _ -> None
|
|
|
|
|
2001-07-03 04:04:10 -07:00
|
|
|
type 'a printer_type_new = Format.formatter -> 'a -> unit
|
|
|
|
type 'a printer_type_old = 'a -> unit
|
|
|
|
|
2014-12-06 09:11:09 -08:00
|
|
|
let printer_type ppf typename =
|
2016-05-12 00:56:34 -07:00
|
|
|
let printer_type =
|
2018-10-12 02:20:21 -07:00
|
|
|
match
|
|
|
|
Env.find_type_by_name
|
|
|
|
(Ldot(Lident "Topdirs", typename)) !toplevel_env
|
|
|
|
with
|
|
|
|
| path, _ -> path
|
|
|
|
| exception Not_found ->
|
|
|
|
fprintf ppf "Cannot find type Topdirs.%s.@." typename;
|
|
|
|
raise Exit
|
|
|
|
in
|
2014-12-06 09:11:09 -08:00
|
|
|
printer_type
|
|
|
|
|
2016-03-09 02:40:16 -08:00
|
|
|
let match_simple_printer_type desc printer_type =
|
2014-12-06 09:11:09 -08:00
|
|
|
Ctype.begin_def();
|
|
|
|
let ty_arg = Ctype.newvar() in
|
|
|
|
Ctype.unify !toplevel_env
|
|
|
|
(Ctype.newconstr printer_type [ty_arg])
|
2018-07-24 08:17:53 -07:00
|
|
|
(Ctype.instance desc.val_type);
|
2014-12-06 09:11:09 -08:00
|
|
|
Ctype.end_def();
|
|
|
|
Ctype.generalize ty_arg;
|
|
|
|
(ty_arg, None)
|
|
|
|
|
2016-03-09 02:40:16 -08:00
|
|
|
let match_generic_printer_type desc path args printer_type =
|
2014-12-06 09:11:09 -08:00
|
|
|
Ctype.begin_def();
|
|
|
|
let args = List.map (fun _ -> Ctype.newvar ()) args in
|
|
|
|
let ty_target = Ctype.newty (Tconstr (path, args, ref Mnil)) in
|
|
|
|
let ty_args =
|
|
|
|
List.map (fun ty_var -> Ctype.newconstr printer_type [ty_var]) args in
|
|
|
|
let ty_expected =
|
|
|
|
List.fold_right
|
2015-09-11 04:58:31 -07:00
|
|
|
(fun ty_arg ty -> Ctype.newty (Tarrow (Asttypes.Nolabel, ty_arg, ty,
|
|
|
|
Cunknown)))
|
2014-12-06 09:11:09 -08:00
|
|
|
ty_args (Ctype.newconstr printer_type [ty_target]) in
|
|
|
|
Ctype.unify !toplevel_env
|
|
|
|
ty_expected
|
2018-07-24 08:17:53 -07:00
|
|
|
(Ctype.instance desc.val_type);
|
2014-12-06 09:11:09 -08:00
|
|
|
Ctype.end_def();
|
|
|
|
Ctype.generalize ty_expected;
|
|
|
|
if not (Ctype.all_distinct_vars !toplevel_env args) then
|
|
|
|
raise (Ctype.Unify []);
|
|
|
|
(ty_expected, Some (path, ty_args))
|
|
|
|
|
|
|
|
let match_printer_type ppf desc =
|
|
|
|
let printer_type_new = printer_type ppf "printer_type_new" in
|
|
|
|
let printer_type_old = printer_type ppf "printer_type_old" in
|
2015-07-29 15:19:24 -07:00
|
|
|
try
|
2016-03-09 02:40:16 -08:00
|
|
|
(match_simple_printer_type desc printer_type_new, false)
|
2015-07-29 15:19:24 -07:00
|
|
|
with Ctype.Unify _ ->
|
|
|
|
try
|
2016-03-09 02:40:16 -08:00
|
|
|
(match_simple_printer_type desc printer_type_old, true)
|
2015-07-29 15:19:24 -07:00
|
|
|
with Ctype.Unify _ as exn ->
|
|
|
|
match extract_target_parameters desc.val_type with
|
|
|
|
| None -> raise exn
|
|
|
|
| Some (path, args) ->
|
2016-03-09 02:40:16 -08:00
|
|
|
(match_generic_printer_type desc path args printer_type_new,
|
2015-07-29 15:19:24 -07:00
|
|
|
false)
|
2001-07-03 04:04:10 -07:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let find_printer_type ppf lid =
|
2018-10-12 02:20:21 -07:00
|
|
|
match Env.find_value_by_name lid !toplevel_env with
|
|
|
|
| (path, desc) -> begin
|
|
|
|
match match_printer_type ppf desc with
|
|
|
|
| (ty_arg, is_old_style) -> (ty_arg, path, is_old_style)
|
|
|
|
| exception Ctype.Unify _ ->
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "%a has a wrong type for a printing function.@."
|
1995-05-04 03:15:53 -07:00
|
|
|
Printtyp.longident lid;
|
2000-03-06 14:12:09 -08:00
|
|
|
raise Exit
|
2018-10-12 02:20:21 -07:00
|
|
|
end
|
|
|
|
| exception Not_found ->
|
|
|
|
fprintf ppf "Unbound value %a.@." Printtyp.longident lid;
|
|
|
|
raise Exit
|
2010-01-22 04:48:24 -08:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_install_printer ppf lid =
|
1995-05-04 03:15:53 -07:00
|
|
|
try
|
2014-12-06 09:11:07 -08:00
|
|
|
let ((ty_arg, ty), path, is_old_style) =
|
|
|
|
find_printer_type ppf lid in
|
2018-02-08 09:51:47 -08:00
|
|
|
let v = eval_value_path !toplevel_env path in
|
2014-12-06 09:11:07 -08:00
|
|
|
match ty with
|
|
|
|
| None ->
|
|
|
|
let print_function =
|
|
|
|
if is_old_style then
|
2016-03-09 02:40:16 -08:00
|
|
|
(fun _formatter repr -> Obj.obj v (Obj.obj repr))
|
2014-12-06 09:11:07 -08:00
|
|
|
else
|
|
|
|
(fun formatter repr -> Obj.obj v formatter (Obj.obj repr)) in
|
|
|
|
install_printer path ty_arg print_function
|
|
|
|
| Some (ty_path, ty_args) ->
|
|
|
|
let rec build v = function
|
|
|
|
| [] ->
|
|
|
|
let print_function =
|
|
|
|
if is_old_style then
|
2016-03-09 02:40:16 -08:00
|
|
|
(fun _formatter repr -> Obj.obj v (Obj.obj repr))
|
2014-12-06 09:11:07 -08:00
|
|
|
else
|
|
|
|
(fun formatter repr -> Obj.obj v formatter (Obj.obj repr)) in
|
|
|
|
Zero print_function
|
|
|
|
| _ :: args ->
|
|
|
|
Succ
|
|
|
|
(fun fn -> build ((Obj.obj v : _ -> Obj.t) fn) args) in
|
|
|
|
install_generic_printer' path ty_path (build v ty_args)
|
2000-03-06 14:12:09 -08:00
|
|
|
with Exit -> ()
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_remove_printer ppf lid =
|
1995-05-04 03:15:53 -07:00
|
|
|
try
|
2016-03-09 02:40:16 -08:00
|
|
|
let (_ty_arg, path, _is_old_style) = find_printer_type ppf lid in
|
1997-03-22 12:16:52 -08:00
|
|
|
begin try
|
2000-11-07 05:18:20 -08:00
|
|
|
remove_printer path
|
1997-03-22 12:16:52 -08:00
|
|
|
with Not_found ->
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "No printer named %a.@." Printtyp.longident lid
|
1997-03-22 12:16:52 -08:00
|
|
|
end
|
2000-03-06 14:12:09 -08:00
|
|
|
with Exit -> ()
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "install_printer"
|
|
|
|
(Directive_ident (dir_install_printer std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_print;
|
|
|
|
doc = "Registers a printer for values of a certain type.";
|
|
|
|
}
|
2015-12-25 09:29:43 -08:00
|
|
|
|
|
|
|
let _ = add_directive "remove_printer"
|
|
|
|
(Directive_ident (dir_remove_printer std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_print;
|
|
|
|
doc = "Remove the named function from the table of toplevel printers.";
|
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
(* The trace *)
|
|
|
|
|
2003-12-31 06:20:40 -08:00
|
|
|
external current_environment: unit -> Obj.t = "caml_get_current_environment"
|
1995-05-04 03:15:53 -07:00
|
|
|
|
1998-09-07 00:55:38 -07:00
|
|
|
let tracing_function_ptr =
|
|
|
|
get_code_pointer
|
|
|
|
(Obj.repr (fun arg -> Trace.print_trace (current_environment()) arg))
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_trace ppf lid =
|
2018-10-12 02:20:21 -07:00
|
|
|
match Env.find_value_by_name lid !toplevel_env with
|
|
|
|
| (path, desc) -> begin
|
|
|
|
(* Check if this is a primitive *)
|
|
|
|
match desc.val_kind with
|
|
|
|
| Val_prim _ ->
|
|
|
|
fprintf ppf "%a is an external function and cannot be traced.@."
|
|
|
|
Printtyp.longident lid
|
|
|
|
| _ ->
|
|
|
|
let clos = eval_value_path !toplevel_env path in
|
|
|
|
(* Nothing to do if it's not a closure *)
|
|
|
|
if Obj.is_block clos
|
|
|
|
&& (Obj.tag clos = Obj.closure_tag || Obj.tag clos = Obj.infix_tag)
|
|
|
|
&& (match Ctype.(repr (expand_head !toplevel_env desc.val_type))
|
|
|
|
with {desc=Tarrow _} -> true | _ -> false)
|
|
|
|
then begin
|
|
|
|
match is_traced clos with
|
|
|
|
| Some opath ->
|
|
|
|
fprintf ppf "%a is already traced (under the name %a).@."
|
|
|
|
Printtyp.path path
|
|
|
|
Printtyp.path opath
|
|
|
|
| None ->
|
|
|
|
(* Instrument the old closure *)
|
|
|
|
traced_functions :=
|
|
|
|
{ path = path;
|
|
|
|
closure = clos;
|
|
|
|
actual_code = get_code_pointer clos;
|
|
|
|
instrumented_fun =
|
|
|
|
instrument_closure !toplevel_env lid ppf desc.val_type }
|
|
|
|
:: !traced_functions;
|
|
|
|
(* Redirect the code field of the closure to point
|
|
|
|
to the instrumentation function *)
|
|
|
|
set_code_pointer clos tracing_function_ptr;
|
|
|
|
fprintf ppf "%a is now traced.@." Printtyp.longident lid
|
|
|
|
end else fprintf ppf "%a is not a function.@." Printtyp.longident lid
|
|
|
|
end
|
|
|
|
| exception Not_found ->
|
|
|
|
fprintf ppf "Unbound value %a.@." Printtyp.longident lid
|
2000-03-06 14:12:09 -08:00
|
|
|
|
|
|
|
let dir_untrace ppf lid =
|
2018-10-12 02:20:21 -07:00
|
|
|
match Env.find_value_by_name lid !toplevel_env with
|
|
|
|
| (path, _desc) ->
|
|
|
|
let rec remove = function
|
|
|
|
| [] ->
|
|
|
|
fprintf ppf "%a was not traced.@." Printtyp.longident lid;
|
|
|
|
[]
|
|
|
|
| f :: rem ->
|
|
|
|
if Path.same f.path path then begin
|
|
|
|
set_code_pointer f.closure f.actual_code;
|
|
|
|
fprintf ppf "%a is no longer traced.@." Printtyp.longident lid;
|
|
|
|
rem
|
|
|
|
end else f :: remove rem in
|
|
|
|
traced_functions := remove !traced_functions
|
|
|
|
| exception Not_found ->
|
|
|
|
fprintf ppf "Unbound value %a.@." Printtyp.longident lid
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_untrace_all ppf () =
|
1995-05-04 03:15:53 -07:00
|
|
|
List.iter
|
1995-09-14 04:53:55 -07:00
|
|
|
(fun f ->
|
2004-05-09 02:01:00 -07:00
|
|
|
set_code_pointer f.closure f.actual_code;
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "%a is no longer traced.@." Printtyp.path f.path)
|
1995-09-14 04:53:55 -07:00
|
|
|
!traced_functions;
|
|
|
|
traced_functions := []
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2000-08-23 10:13:09 -07:00
|
|
|
let parse_warnings ppf iserr s =
|
|
|
|
try Warnings.parse_options iserr s
|
2000-03-06 14:12:09 -08:00
|
|
|
with Arg.Bad err -> fprintf ppf "%s.@." err
|
|
|
|
|
2014-04-17 02:24:14 -07:00
|
|
|
(* Typing information *)
|
|
|
|
|
|
|
|
let trim_signature = function
|
|
|
|
Mty_signature sg ->
|
|
|
|
Mty_signature
|
|
|
|
(List.map
|
|
|
|
(function
|
2018-04-08 01:51:15 -07:00
|
|
|
Sig_module (id, pres, md, rs, priv) ->
|
2018-07-21 05:04:53 -07:00
|
|
|
let attribute =
|
|
|
|
Ast_helper.Attr.mk
|
|
|
|
(Location.mknoloc "...")
|
|
|
|
(Parsetree.PStr [])
|
|
|
|
in
|
2018-02-08 09:51:47 -08:00
|
|
|
Sig_module (id, pres, {md with md_attributes =
|
|
|
|
attribute :: md.md_attributes},
|
2018-04-08 01:51:15 -07:00
|
|
|
rs, priv)
|
2014-04-17 02:24:14 -07:00
|
|
|
(*| Sig_modtype (id, Modtype_manifest mty) ->
|
|
|
|
Sig_modtype (id, Modtype_manifest (trim_modtype mty))*)
|
|
|
|
| item -> item)
|
|
|
|
sg)
|
|
|
|
| mty -> mty
|
|
|
|
|
2014-04-28 01:04:43 -07:00
|
|
|
let show_prim to_sig ppf lid =
|
|
|
|
let env = !Toploop.toplevel_env in
|
|
|
|
let loc = Location.none in
|
|
|
|
try
|
|
|
|
let s =
|
|
|
|
match lid with
|
|
|
|
| Longident.Lident s -> s
|
2014-04-17 02:24:14 -07:00
|
|
|
| Longident.Ldot (_,s) -> s
|
|
|
|
| Longident.Lapply _ ->
|
|
|
|
fprintf ppf "Invalid path %a@." Printtyp.longident lid;
|
|
|
|
raise Exit
|
|
|
|
in
|
2014-04-28 01:04:43 -07:00
|
|
|
let id = Ident.create_persistent s in
|
|
|
|
let sg = to_sig env loc id lid in
|
2018-03-26 17:25:28 -07:00
|
|
|
Printtyp.wrap_printing_env ~error:false env
|
2015-01-29 18:02:28 -08:00
|
|
|
(fun () -> fprintf ppf "@[%a@]@." Printtyp.signature sg)
|
2014-04-17 02:24:14 -07:00
|
|
|
with
|
|
|
|
| Not_found ->
|
|
|
|
fprintf ppf "@[Unknown element.@]@."
|
2014-04-28 01:04:43 -07:00
|
|
|
| Exit -> ()
|
|
|
|
|
|
|
|
let all_show_funs = ref []
|
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let reg_show_prim name to_sig doc =
|
2014-04-28 01:04:43 -07:00
|
|
|
all_show_funs := to_sig :: !all_show_funs;
|
2015-12-25 09:29:43 -08:00
|
|
|
add_directive
|
|
|
|
name
|
|
|
|
(Directive_ident (show_prim to_sig std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_env;
|
|
|
|
doc;
|
|
|
|
}
|
2014-04-28 01:04:43 -07:00
|
|
|
|
|
|
|
let () =
|
|
|
|
reg_show_prim "show_val"
|
|
|
|
(fun env loc id lid ->
|
2018-10-12 02:20:21 -07:00
|
|
|
let _path, desc = Env.lookup_value ~loc lid env in
|
2018-04-08 01:51:15 -07:00
|
|
|
[ Sig_value (id, desc, Exported) ]
|
2014-04-28 01:04:43 -07:00
|
|
|
)
|
2015-12-25 09:29:43 -08:00
|
|
|
"Print the signature of the corresponding value."
|
2014-04-28 01:04:43 -07:00
|
|
|
|
|
|
|
let () =
|
|
|
|
reg_show_prim "show_type"
|
|
|
|
(fun env loc id lid ->
|
2018-10-12 02:20:21 -07:00
|
|
|
let _path, desc = Env.lookup_type ~loc lid env in
|
2020-08-05 03:00:19 -07:00
|
|
|
[ Sig_type (id, desc, Trec_not, Exported) ]
|
2014-04-28 01:04:43 -07:00
|
|
|
)
|
2015-12-25 09:29:43 -08:00
|
|
|
"Print the signature of the corresponding type constructor."
|
2014-04-28 01:04:43 -07:00
|
|
|
|
2019-10-31 12:33:22 -07:00
|
|
|
(* Each registered show_prim function is called in turn
|
|
|
|
* and any output produced is sent to std_out.
|
|
|
|
* Two show_prim functions are needed for constructors,
|
|
|
|
* one for exception constructors and another for
|
|
|
|
* non-exception constructors (normal and extensible variants). *)
|
|
|
|
let is_exception_constructor env type_expr =
|
|
|
|
Ctype.equal env true [type_expr] [Predef.type_exn]
|
|
|
|
|
|
|
|
let is_extension_constructor = function
|
|
|
|
| Cstr_extension _ -> true
|
|
|
|
| _ -> false
|
|
|
|
|
|
|
|
let () =
|
|
|
|
(* This show_prim function will only show constructor types
|
|
|
|
* that are not also exception types. *)
|
|
|
|
reg_show_prim "show_constructor"
|
|
|
|
(fun env loc id lid ->
|
|
|
|
let desc = Env.lookup_constructor ~loc Env.Positive lid env in
|
|
|
|
if is_exception_constructor env desc.cstr_res then
|
|
|
|
raise Not_found;
|
|
|
|
let path =
|
|
|
|
match Ctype.repr desc.cstr_res with
|
|
|
|
| {desc=Tconstr(path, _, _)} -> path
|
|
|
|
| _ -> raise Not_found
|
|
|
|
in
|
|
|
|
let type_decl = Env.find_type path env in
|
|
|
|
if is_extension_constructor desc.cstr_tag then
|
|
|
|
let ret_type =
|
|
|
|
if desc.cstr_generalized then Some desc.cstr_res
|
|
|
|
else None
|
|
|
|
in
|
|
|
|
let ext =
|
|
|
|
{ ext_type_path = path;
|
|
|
|
ext_type_params = type_decl.type_params;
|
|
|
|
ext_args = Cstr_tuple desc.cstr_args;
|
|
|
|
ext_ret_type = ret_type;
|
|
|
|
ext_private = Asttypes.Public;
|
2019-08-20 01:53:05 -07:00
|
|
|
ext_loc = desc.cstr_loc;
|
|
|
|
ext_attributes = desc.cstr_attributes;
|
|
|
|
ext_uid = desc.cstr_uid; }
|
2019-10-31 12:33:22 -07:00
|
|
|
in
|
|
|
|
[Sig_typext (id, ext, Text_first, Exported)]
|
|
|
|
else
|
|
|
|
(* make up a fake Ident.t as type_decl : Types.type_declaration
|
|
|
|
* does not have an Ident.t yet. Ident.create_presistent is a
|
|
|
|
* good choice because it has no side-effects.
|
|
|
|
* *)
|
|
|
|
let type_id = Ident.create_persistent (Path.name path) in
|
|
|
|
[ Sig_type (type_id, type_decl, Trec_first, Exported) ]
|
|
|
|
)
|
|
|
|
"Print the signature of the corresponding value constructor."
|
|
|
|
|
2014-04-28 01:04:43 -07:00
|
|
|
let () =
|
|
|
|
reg_show_prim "show_exception"
|
|
|
|
(fun env loc id lid ->
|
2018-10-12 02:20:21 -07:00
|
|
|
let desc = Env.lookup_constructor ~loc Env.Positive lid env in
|
2019-10-31 12:33:22 -07:00
|
|
|
if not (is_exception_constructor env desc.cstr_res) then
|
2014-05-04 16:08:45 -07:00
|
|
|
raise Not_found;
|
|
|
|
let ret_type =
|
|
|
|
if desc.cstr_generalized then Some Predef.type_exn
|
|
|
|
else None
|
|
|
|
in
|
|
|
|
let ext =
|
|
|
|
{ ext_type_path = Predef.path_exn;
|
|
|
|
ext_type_params = [];
|
2014-10-14 08:51:30 -07:00
|
|
|
ext_args = Cstr_tuple desc.cstr_args;
|
2014-05-04 16:08:45 -07:00
|
|
|
ext_ret_type = ret_type;
|
|
|
|
ext_private = Asttypes.Public;
|
2019-08-20 01:53:05 -07:00
|
|
|
ext_loc = desc.cstr_loc;
|
|
|
|
ext_attributes = desc.cstr_attributes;
|
|
|
|
ext_uid = desc.cstr_uid;
|
|
|
|
}
|
2014-05-04 16:08:45 -07:00
|
|
|
in
|
2018-04-08 01:51:15 -07:00
|
|
|
[Sig_typext (id, ext, Text_exception, Exported)]
|
2014-04-28 01:04:43 -07:00
|
|
|
)
|
2015-12-25 09:29:43 -08:00
|
|
|
"Print the signature of the corresponding exception."
|
2014-04-28 01:04:43 -07:00
|
|
|
|
|
|
|
let () =
|
|
|
|
reg_show_prim "show_module"
|
|
|
|
(fun env loc id lid ->
|
2018-10-12 02:20:21 -07:00
|
|
|
let rec accum_aliases md acc =
|
2016-03-21 12:25:13 -07:00
|
|
|
let acc =
|
2018-02-08 09:51:47 -08:00
|
|
|
Sig_module (id, Mp_present,
|
|
|
|
{md with md_type = trim_signature md.md_type},
|
2018-04-08 01:51:15 -07:00
|
|
|
Trec_not, Exported) :: acc in
|
2016-03-21 12:25:13 -07:00
|
|
|
match md.md_type with
|
2018-10-12 02:20:21 -07:00
|
|
|
| Mty_alias path ->
|
|
|
|
let md = Env.find_module path env in
|
|
|
|
accum_aliases md acc
|
2016-03-21 12:25:13 -07:00
|
|
|
| Mty_ident _ | Mty_signature _ | Mty_functor _ ->
|
|
|
|
List.rev acc
|
|
|
|
in
|
2018-10-12 02:20:21 -07:00
|
|
|
let _, md = Env.lookup_module ~loc lid env in
|
|
|
|
accum_aliases md []
|
2014-04-28 01:04:43 -07:00
|
|
|
)
|
2015-12-25 09:29:43 -08:00
|
|
|
"Print the signature of the corresponding module."
|
2014-04-28 01:04:43 -07:00
|
|
|
|
|
|
|
let () =
|
|
|
|
reg_show_prim "show_module_type"
|
|
|
|
(fun env loc id lid ->
|
2018-10-12 02:20:21 -07:00
|
|
|
let _path, desc = Env.lookup_modtype ~loc lid env in
|
2018-04-08 01:51:15 -07:00
|
|
|
[ Sig_modtype (id, desc, Exported) ]
|
2014-04-28 01:04:43 -07:00
|
|
|
)
|
2015-12-25 09:29:43 -08:00
|
|
|
"Print the signature of the corresponding module type."
|
2014-04-28 01:04:43 -07:00
|
|
|
|
|
|
|
let () =
|
|
|
|
reg_show_prim "show_class"
|
|
|
|
(fun env loc id lid ->
|
2018-10-12 02:20:21 -07:00
|
|
|
let _path, desc = Env.lookup_class ~loc lid env in
|
2018-04-08 01:51:15 -07:00
|
|
|
[ Sig_class (id, desc, Trec_not, Exported) ]
|
2014-04-28 01:04:43 -07:00
|
|
|
)
|
2015-12-25 09:29:43 -08:00
|
|
|
"Print the signature of the corresponding class."
|
2014-04-28 01:04:43 -07:00
|
|
|
|
|
|
|
let () =
|
|
|
|
reg_show_prim "show_class_type"
|
|
|
|
(fun env loc id lid ->
|
2018-10-12 02:20:21 -07:00
|
|
|
let _path, desc = Env.lookup_cltype ~loc lid env in
|
2018-04-08 01:51:15 -07:00
|
|
|
[ Sig_class_type (id, desc, Trec_not, Exported) ]
|
2014-04-28 01:04:43 -07:00
|
|
|
)
|
2015-12-25 09:29:43 -08:00
|
|
|
"Print the signature of the corresponding class type."
|
2014-04-28 01:04:43 -07:00
|
|
|
|
|
|
|
let show env loc id lid =
|
|
|
|
let sg =
|
|
|
|
List.fold_left
|
|
|
|
(fun sg f -> try (f env loc id lid) @ sg with _ -> sg)
|
|
|
|
[] !all_show_funs
|
|
|
|
in
|
|
|
|
if sg = [] then raise Not_found else sg
|
|
|
|
|
|
|
|
let () =
|
2015-12-25 09:29:43 -08:00
|
|
|
add_directive "show" (Directive_ident (show_prim show std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_env;
|
|
|
|
doc = "Print the signatures of components \
|
2017-05-08 06:16:28 -07:00
|
|
|
from any of the categories below.";
|
2015-12-25 10:51:20 -08:00
|
|
|
}
|
2015-12-25 09:29:43 -08:00
|
|
|
|
|
|
|
let _ = add_directive "trace"
|
|
|
|
(Directive_ident (dir_trace std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_trace;
|
|
|
|
doc = "All calls to the function \
|
|
|
|
named function-name will be traced.";
|
|
|
|
}
|
2015-12-25 09:29:43 -08:00
|
|
|
|
|
|
|
let _ = add_directive "untrace"
|
|
|
|
(Directive_ident (dir_untrace std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_trace;
|
|
|
|
doc = "Stop tracing the given function.";
|
|
|
|
}
|
2014-04-17 02:24:14 -07:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "untrace_all"
|
|
|
|
(Directive_none (dir_untrace_all std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_trace;
|
|
|
|
doc = "Stop tracing all functions traced so far.";
|
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
(* Control the printing of values *)
|
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "print_depth"
|
|
|
|
(Directive_int(fun n -> max_printer_depth := n))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_print;
|
|
|
|
doc = "Limit the printing of values to a maximal depth of n.";
|
|
|
|
}
|
2015-12-25 09:29:43 -08:00
|
|
|
|
|
|
|
let _ = add_directive "print_length"
|
|
|
|
(Directive_int(fun n -> max_printer_steps := n))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_print;
|
|
|
|
doc = "Limit the number of value nodes printed to at most n.";
|
|
|
|
}
|
1999-12-03 02:26:08 -08:00
|
|
|
|
|
|
|
(* Set various compiler flags *)
|
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "labels"
|
|
|
|
(Directive_bool(fun b -> Clflags.classic := not b))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_options;
|
|
|
|
doc = "Choose whether to ignore labels in function types.";
|
|
|
|
}
|
1999-12-03 02:26:08 -08:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "principal"
|
|
|
|
(Directive_bool(fun b -> Clflags.principal := b))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_options;
|
|
|
|
doc = "Make sure that all types are derived in a principal way.";
|
|
|
|
}
|
2002-06-18 23:11:21 -07:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "rectypes"
|
|
|
|
(Directive_none(fun () -> Clflags.recursive_types := true))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_options;
|
|
|
|
doc = "Allow arbitrary recursive types during type-checking.";
|
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "ppx"
|
|
|
|
(Directive_string(fun s -> Clflags.all_ppx := s :: !Clflags.all_ppx))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_options;
|
|
|
|
doc = "After parsing, pipe the abstract \
|
|
|
|
syntax tree through the preprocessor command.";
|
|
|
|
}
|
2014-05-30 05:10:06 -07:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "warnings"
|
|
|
|
(Directive_string (parse_warnings std_out false))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_options;
|
|
|
|
doc = "Enable or disable warnings according to the argument.";
|
|
|
|
}
|
2000-08-23 10:13:09 -07:00
|
|
|
|
2015-12-25 09:29:43 -08:00
|
|
|
let _ = add_directive "warn_error"
|
|
|
|
(Directive_string (parse_warnings std_out true))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_options;
|
|
|
|
doc = "Treat as errors the warnings enabled by the argument.";
|
|
|
|
}
|
|
|
|
|
|
|
|
(* #help directive *)
|
|
|
|
|
|
|
|
let directive_sections () =
|
|
|
|
let sections = Hashtbl.create 10 in
|
|
|
|
let add_dir name dir =
|
|
|
|
let section, doc =
|
|
|
|
match Hashtbl.find directive_info_table name with
|
|
|
|
| { section; doc } -> section, Some doc
|
|
|
|
| exception Not_found -> "Undocumented", None
|
|
|
|
in
|
|
|
|
Hashtbl.replace sections section
|
|
|
|
((name, dir, doc)
|
|
|
|
:: (try Hashtbl.find sections section with Not_found -> []))
|
2015-12-25 09:29:43 -08:00
|
|
|
in
|
2015-12-25 10:51:20 -08:00
|
|
|
Hashtbl.iter add_dir directive_table;
|
|
|
|
let take_section section =
|
|
|
|
if not (Hashtbl.mem sections section) then (section, [])
|
|
|
|
else begin
|
|
|
|
let section_dirs =
|
|
|
|
Hashtbl.find sections section
|
|
|
|
|> List.sort (fun (n1, _, _) (n2, _, _) -> String.compare n1 n2) in
|
|
|
|
Hashtbl.remove sections section;
|
|
|
|
(section, section_dirs)
|
|
|
|
end
|
|
|
|
in
|
|
|
|
let before, after = order_of_sections in
|
|
|
|
let sections_before = List.map take_section before in
|
|
|
|
let sections_after = List.map take_section after in
|
|
|
|
let sections_user =
|
|
|
|
Hashtbl.fold (fun section _ acc -> section::acc) sections []
|
|
|
|
|> List.sort String.compare
|
|
|
|
|> List.map take_section in
|
|
|
|
sections_before @ sections_user @ sections_after
|
|
|
|
|
|
|
|
let print_directive ppf (name, directive, doc) =
|
2015-12-25 09:29:43 -08:00
|
|
|
let param = match directive with
|
|
|
|
| Directive_none _ -> ""
|
|
|
|
| Directive_string _ -> " <str>"
|
|
|
|
| Directive_int _ -> " <int>"
|
|
|
|
| Directive_bool _ -> " <bool>"
|
|
|
|
| Directive_ident _ -> " <ident>" in
|
2015-12-25 10:51:20 -08:00
|
|
|
match doc with
|
2016-03-09 02:40:16 -08:00
|
|
|
| None -> fprintf ppf "#%s%s@." name param
|
2015-12-25 10:51:20 -08:00
|
|
|
| Some doc ->
|
2016-03-09 02:40:16 -08:00
|
|
|
fprintf ppf "@[<hov 2>#%s%s@\n%a@]@."
|
2015-12-25 10:51:20 -08:00
|
|
|
name param
|
|
|
|
Format.pp_print_text doc
|
|
|
|
|
|
|
|
let print_section ppf (section, directives) =
|
|
|
|
if directives <> [] then begin
|
|
|
|
fprintf ppf "%30s%s@." "" section;
|
|
|
|
List.iter (print_directive ppf) directives;
|
|
|
|
fprintf ppf "@.";
|
|
|
|
end
|
2015-12-25 09:29:43 -08:00
|
|
|
|
|
|
|
let print_directives ppf () =
|
2015-12-25 10:51:20 -08:00
|
|
|
List.iter (print_section ppf) (directive_sections ())
|
2015-12-25 09:29:43 -08:00
|
|
|
|
|
|
|
let _ = add_directive "help"
|
|
|
|
(Directive_none (print_directives std_out))
|
2015-12-25 10:51:20 -08:00
|
|
|
{
|
|
|
|
section = section_general;
|
|
|
|
doc = "Prints a list of all available directives, with \
|
|
|
|
corresponding argument type if appropriate.";
|
|
|
|
}
|