2016-02-18 07:11:59 -08:00
|
|
|
(**************************************************************************)
|
|
|
|
(* *)
|
|
|
|
(* OCaml *)
|
|
|
|
(* *)
|
|
|
|
(* Xavier Leroy and Jerome Vouillon, 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. *)
|
|
|
|
(* *)
|
|
|
|
(**************************************************************************)
|
1997-03-22 12:16:52 -08:00
|
|
|
|
|
|
|
(* To print values *)
|
|
|
|
|
|
|
|
open Misc
|
2000-03-06 14:12:09 -08:00
|
|
|
open Format
|
1997-03-22 12:16:52 -08:00
|
|
|
open Longident
|
|
|
|
open Path
|
|
|
|
open Types
|
2001-08-02 01:51:55 -07:00
|
|
|
open Outcometree
|
2018-06-26 13:03:45 -07:00
|
|
|
module Out_name = Printtyp.Out_name
|
1997-03-22 12:16:52 -08:00
|
|
|
|
1998-10-01 05:34:32 -07:00
|
|
|
module type OBJ =
|
1997-03-22 12:16:52 -08:00
|
|
|
sig
|
|
|
|
type t
|
2017-08-31 06:25:15 -07:00
|
|
|
val repr : 'a -> t
|
1997-03-22 12:16:52 -08:00
|
|
|
val obj : t -> 'a
|
|
|
|
val is_block : t -> bool
|
|
|
|
val tag : t -> int
|
|
|
|
val size : t -> int
|
|
|
|
val field : t -> int -> t
|
2017-08-31 06:25:15 -07:00
|
|
|
val double_array_tag : int
|
|
|
|
val double_field : t -> int -> float
|
1997-03-22 12:16:52 -08:00
|
|
|
end
|
|
|
|
|
2000-03-25 10:55:45 -08:00
|
|
|
module type EVALPATH =
|
|
|
|
sig
|
2012-07-10 08:03:11 -07:00
|
|
|
type valu
|
2018-02-08 09:51:47 -08:00
|
|
|
val eval_address: Env.address -> valu
|
2000-03-25 10:55:45 -08:00
|
|
|
exception Error
|
2012-07-10 08:03:11 -07:00
|
|
|
val same_value: valu -> valu -> bool
|
2000-03-25 10:55:45 -08:00
|
|
|
end
|
|
|
|
|
2014-12-06 09:11:04 -08:00
|
|
|
type ('a, 'b) gen_printer =
|
|
|
|
| Zero of 'b
|
|
|
|
| Succ of ('a -> ('a, 'b) gen_printer)
|
|
|
|
|
1997-03-22 12:16:52 -08:00
|
|
|
module type S =
|
|
|
|
sig
|
|
|
|
type t
|
2001-07-03 04:04:10 -07:00
|
|
|
val install_printer :
|
|
|
|
Path.t -> Types.type_expr -> (formatter -> t -> unit) -> unit
|
2014-12-06 09:11:04 -08:00
|
|
|
val install_generic_printer :
|
|
|
|
Path.t -> Path.t ->
|
|
|
|
(int -> (int -> t -> Outcometree.out_value,
|
|
|
|
t -> Outcometree.out_value) gen_printer) ->
|
|
|
|
unit
|
|
|
|
val install_generic_printer' :
|
|
|
|
Path.t -> Path.t ->
|
|
|
|
(formatter -> t -> unit,
|
|
|
|
formatter -> t -> unit) gen_printer ->
|
|
|
|
unit
|
1997-03-22 12:16:52 -08:00
|
|
|
val remove_printer : Path.t -> unit
|
2001-08-02 01:51:55 -07:00
|
|
|
val outval_of_untyped_exception : t -> Outcometree.out_value
|
|
|
|
val outval_of_value :
|
|
|
|
int -> int ->
|
|
|
|
(int -> t -> Types.type_expr -> Outcometree.out_value option) ->
|
|
|
|
Env.t -> t -> type_expr -> Outcometree.out_value
|
1997-03-22 12:16:52 -08:00
|
|
|
end
|
|
|
|
|
2014-12-13 07:33:48 -08:00
|
|
|
module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct
|
|
|
|
|
|
|
|
type t = O.t
|
|
|
|
|
|
|
|
module ObjTbl = Hashtbl.Make(struct
|
|
|
|
type t = O.t
|
2014-05-08 01:31:45 -07:00
|
|
|
let equal = (==)
|
|
|
|
let hash x =
|
|
|
|
try
|
|
|
|
Hashtbl.hash x
|
2016-03-09 02:40:16 -08:00
|
|
|
with _exn -> 0
|
2014-05-08 01:31:45 -07:00
|
|
|
end)
|
|
|
|
|
1997-03-22 12:16:52 -08:00
|
|
|
|
|
|
|
(* Given an exception value, we cannot recover its type,
|
|
|
|
hence we cannot print its arguments in general.
|
|
|
|
Here, we do a feeble attempt to print
|
|
|
|
integer, string and float arguments... *)
|
2001-08-02 01:51:55 -07:00
|
|
|
let outval_of_untyped_exception_args obj start_offset =
|
1998-10-01 05:34:32 -07:00
|
|
|
if O.size obj > start_offset then begin
|
2001-08-02 01:51:55 -07:00
|
|
|
let list = ref [] in
|
1998-10-01 05:34:32 -07:00
|
|
|
for i = start_offset to O.size obj - 1 do
|
|
|
|
let arg = O.field obj i in
|
|
|
|
if not (O.is_block arg) then
|
2001-08-02 01:51:55 -07:00
|
|
|
list := Oval_int (O.obj arg : int) :: !list
|
2000-03-25 10:55:45 -08:00
|
|
|
(* Note: this could be a char or a constant constructor... *)
|
2000-03-06 14:12:09 -08:00
|
|
|
else if O.tag arg = Obj.string_tag then
|
2001-08-02 01:51:55 -07:00
|
|
|
list :=
|
2017-05-11 04:57:08 -07:00
|
|
|
Oval_string ((O.obj arg : string), max_int, Ostr_string) :: !list
|
2000-03-06 14:12:09 -08:00
|
|
|
else if O.tag arg = Obj.double_tag then
|
2001-08-02 01:51:55 -07:00
|
|
|
list := Oval_float (O.obj arg : float) :: !list
|
1997-03-22 12:16:52 -08:00
|
|
|
else
|
2018-06-26 13:03:45 -07:00
|
|
|
list := Oval_constr (Oide_ident (Out_name.create "_"), []) :: !list
|
1997-03-22 12:16:52 -08:00
|
|
|
done;
|
2001-08-02 01:51:55 -07:00
|
|
|
List.rev !list
|
1997-03-22 12:16:52 -08:00
|
|
|
end
|
2001-08-02 01:51:55 -07:00
|
|
|
else []
|
1997-03-22 12:16:52 -08:00
|
|
|
|
2001-08-02 01:51:55 -07:00
|
|
|
let outval_of_untyped_exception bucket =
|
2013-10-23 07:28:31 -07:00
|
|
|
if O.tag bucket <> 0 then
|
2018-06-26 13:03:45 -07:00
|
|
|
let name = Out_name.create (O.obj (O.field bucket 0) : string) in
|
|
|
|
Oval_constr (Oide_ident name, [])
|
2013-10-23 07:28:31 -07:00
|
|
|
else
|
1998-10-01 05:34:32 -07:00
|
|
|
let name = (O.obj(O.field(O.field bucket 0) 0) : string) in
|
2001-08-02 01:51:55 -07:00
|
|
|
let args =
|
2003-06-19 08:53:53 -07:00
|
|
|
if (name = "Match_failure"
|
|
|
|
|| name = "Assert_failure"
|
|
|
|
|| name = "Undefined_recursive_module")
|
2001-08-02 01:51:55 -07:00
|
|
|
&& O.size bucket = 2
|
|
|
|
&& O.tag(O.field bucket 1) = 0
|
|
|
|
then outval_of_untyped_exception_args (O.field bucket 1) 0
|
|
|
|
else outval_of_untyped_exception_args bucket 1 in
|
2018-06-26 13:03:45 -07:00
|
|
|
Oval_constr (Oide_ident (Out_name.create name), args)
|
1997-12-09 01:12:30 -08:00
|
|
|
|
1997-03-22 12:16:52 -08:00
|
|
|
(* The user-defined printers. Also used for some builtin types. *)
|
|
|
|
|
2014-12-06 09:11:04 -08:00
|
|
|
type printer =
|
|
|
|
| Simple of Types.type_expr * (O.t -> Outcometree.out_value)
|
|
|
|
| Generic of Path.t * (int -> (int -> O.t -> Outcometree.out_value,
|
|
|
|
O.t -> Outcometree.out_value) gen_printer)
|
|
|
|
|
1997-03-22 12:16:52 -08:00
|
|
|
let printers = ref ([
|
2018-08-28 09:07:01 -07:00
|
|
|
( Pident(Ident.create_local "print_int"),
|
2014-12-06 09:11:04 -08:00
|
|
|
Simple (Predef.type_int,
|
|
|
|
(fun x -> Oval_int (O.obj x : int))) );
|
2018-08-28 09:07:01 -07:00
|
|
|
( Pident(Ident.create_local "print_float"),
|
2014-12-06 09:11:04 -08:00
|
|
|
Simple (Predef.type_float,
|
|
|
|
(fun x -> Oval_float (O.obj x : float))) );
|
2018-08-28 09:07:01 -07:00
|
|
|
( Pident(Ident.create_local "print_char"),
|
2014-12-06 09:11:04 -08:00
|
|
|
Simple (Predef.type_char,
|
|
|
|
(fun x -> Oval_char (O.obj x : char))) );
|
2018-08-28 09:07:01 -07:00
|
|
|
( Pident(Ident.create_local "print_int32"),
|
2014-12-06 09:11:04 -08:00
|
|
|
Simple (Predef.type_int32,
|
|
|
|
(fun x -> Oval_int32 (O.obj x : int32))) );
|
2018-08-28 09:07:01 -07:00
|
|
|
( Pident(Ident.create_local "print_nativeint"),
|
2014-12-06 09:11:04 -08:00
|
|
|
Simple (Predef.type_nativeint,
|
|
|
|
(fun x -> Oval_nativeint (O.obj x : nativeint))) );
|
2018-08-28 09:07:01 -07:00
|
|
|
( Pident(Ident.create_local "print_int64"),
|
2014-12-06 09:11:04 -08:00
|
|
|
Simple (Predef.type_int64,
|
|
|
|
(fun x -> Oval_int64 (O.obj x : int64)) ))
|
|
|
|
] : (Path.t * printer) list)
|
|
|
|
|
2017-02-10 08:45:02 -08:00
|
|
|
let exn_printer ppf path exn =
|
2017-08-12 13:24:41 -07:00
|
|
|
fprintf ppf "<printer %a raised an exception: %s>" Printtyp.path path
|
|
|
|
(Printexc.to_string exn)
|
2014-12-06 09:11:04 -08:00
|
|
|
|
2017-02-10 08:45:02 -08:00
|
|
|
let out_exn path exn =
|
|
|
|
Oval_printer (fun ppf -> exn_printer ppf path exn)
|
1997-03-22 12:16:52 -08:00
|
|
|
|
|
|
|
let install_printer path ty fn =
|
2000-03-06 14:12:09 -08:00
|
|
|
let print_val ppf obj =
|
2017-02-10 08:45:02 -08:00
|
|
|
try fn ppf obj with exn -> exn_printer ppf path exn in
|
2001-08-02 01:51:55 -07:00
|
|
|
let printer obj = Oval_printer (fun ppf -> print_val ppf obj) in
|
2014-12-06 09:11:04 -08:00
|
|
|
printers := (path, Simple (ty, printer)) :: !printers
|
|
|
|
|
2014-12-06 09:11:11 -08:00
|
|
|
let install_generic_printer function_path constr_path fn =
|
|
|
|
printers := (function_path, Generic (constr_path, fn)) :: !printers
|
2014-12-06 09:11:04 -08:00
|
|
|
|
2014-12-06 09:11:11 -08:00
|
|
|
let install_generic_printer' function_path ty_path fn =
|
2014-12-06 09:11:04 -08:00
|
|
|
let rec build gp depth =
|
|
|
|
match gp with
|
|
|
|
| Zero fn ->
|
|
|
|
let out_printer obj =
|
2014-12-06 09:11:11 -08:00
|
|
|
let printer ppf =
|
2017-02-10 08:45:02 -08:00
|
|
|
try fn ppf obj with exn -> exn_printer ppf function_path exn in
|
2014-12-06 09:11:04 -08:00
|
|
|
Oval_printer printer in
|
|
|
|
Zero out_printer
|
|
|
|
| Succ fn ->
|
|
|
|
let print_val fn_arg =
|
|
|
|
let print_arg ppf o =
|
|
|
|
!Oprint.out_value ppf (fn_arg (depth+1) o) in
|
|
|
|
build (fn print_arg) depth in
|
|
|
|
Succ print_val in
|
2014-12-06 09:11:11 -08:00
|
|
|
printers := (function_path, Generic (ty_path, build fn)) :: !printers
|
1997-03-22 12:16:52 -08:00
|
|
|
|
|
|
|
let remove_printer path =
|
|
|
|
let rec remove = function
|
2000-03-06 14:12:09 -08:00
|
|
|
| [] -> raise Not_found
|
2014-12-06 09:11:04 -08:00
|
|
|
| ((p, _) as printer) :: rem ->
|
1997-03-22 12:16:52 -08:00
|
|
|
if Path.same p path then rem else printer :: remove rem in
|
|
|
|
printers := remove !printers
|
|
|
|
|
|
|
|
(* Print a constructor or label, giving it the same prefix as the type
|
|
|
|
it comes from. Attempt to omit the prefix if the type comes from
|
|
|
|
a module that has been opened. *)
|
|
|
|
|
2018-10-12 02:20:21 -07:00
|
|
|
let tree_of_qualified find env ty_path name =
|
1997-03-22 12:16:52 -08:00
|
|
|
match ty_path with
|
2016-03-09 02:40:16 -08:00
|
|
|
| Pident _ ->
|
2001-08-02 01:51:55 -07:00
|
|
|
Oide_ident name
|
2018-02-08 09:51:47 -08:00
|
|
|
| Pdot(p, _s) ->
|
2018-10-12 02:20:21 -07:00
|
|
|
if
|
|
|
|
match (find (Lident (Out_name.print name)) env).desc with
|
|
|
|
| Tconstr(ty_path', _, _) -> Path.same ty_path ty_path'
|
|
|
|
| _ -> false
|
|
|
|
| exception Not_found -> false
|
2001-08-02 01:51:55 -07:00
|
|
|
then Oide_ident name
|
2018-06-26 13:03:45 -07:00
|
|
|
else Oide_dot (Printtyp.tree_of_path p, Out_name.print name)
|
2016-03-09 02:40:16 -08:00
|
|
|
| Papply _ ->
|
2001-08-04 03:08:19 -07:00
|
|
|
Printtyp.tree_of_path ty_path
|
1997-03-22 12:16:52 -08:00
|
|
|
|
2001-08-02 01:51:55 -07:00
|
|
|
let tree_of_constr =
|
|
|
|
tree_of_qualified
|
2018-10-12 02:20:21 -07:00
|
|
|
(fun lid env ->
|
|
|
|
(Env.find_constructor_by_name lid env).cstr_res)
|
1997-03-22 12:16:52 -08:00
|
|
|
|
2001-08-02 01:51:55 -07:00
|
|
|
and tree_of_label =
|
2018-10-12 02:20:21 -07:00
|
|
|
tree_of_qualified
|
|
|
|
(fun lid env ->
|
|
|
|
(Env.find_label_by_name lid env).lbl_res)
|
1997-03-22 12:16:52 -08:00
|
|
|
|
|
|
|
(* An abstract type *)
|
|
|
|
|
|
|
|
let abstract_type =
|
2018-09-13 02:37:08 -07:00
|
|
|
let id = Ident.create_local "abstract" in
|
|
|
|
let ty = Btype.newgenty (Tconstr (Pident id, [], ref Mnil)) in
|
2018-08-28 09:06:45 -07:00
|
|
|
ty
|
1997-03-22 12:16:52 -08:00
|
|
|
|
|
|
|
(* The main printing function *)
|
|
|
|
|
2001-08-02 01:51:55 -07:00
|
|
|
let outval_of_value max_steps max_depth check_depth env obj ty =
|
1997-03-22 12:16:52 -08:00
|
|
|
|
|
|
|
let printer_steps = ref max_steps in
|
|
|
|
|
2014-05-08 01:31:45 -07:00
|
|
|
let nested_values = ObjTbl.create 8 in
|
|
|
|
let nest_gen err f depth obj ty =
|
2014-12-13 07:33:48 -08:00
|
|
|
let repr = obj in
|
|
|
|
if not (O.is_block repr) then
|
2014-05-08 01:31:45 -07:00
|
|
|
f depth obj ty
|
|
|
|
else
|
|
|
|
if ObjTbl.mem nested_values repr then
|
|
|
|
err
|
|
|
|
else begin
|
|
|
|
ObjTbl.add nested_values repr ();
|
|
|
|
let ret = f depth obj ty in
|
|
|
|
ObjTbl.remove nested_values repr;
|
|
|
|
ret
|
|
|
|
end
|
|
|
|
in
|
|
|
|
|
|
|
|
let nest f = nest_gen (Oval_stuff "<cycle>") f in
|
|
|
|
|
2001-08-02 01:51:55 -07:00
|
|
|
let rec tree_of_val depth obj ty =
|
1997-03-22 12:16:52 -08:00
|
|
|
decr printer_steps;
|
2001-08-02 01:51:55 -07:00
|
|
|
if !printer_steps < 0 || depth < 0 then Oval_ellipsis
|
|
|
|
else begin
|
1997-03-22 12:16:52 -08:00
|
|
|
try
|
2014-12-06 09:11:04 -08:00
|
|
|
find_printer depth env ty obj
|
1997-03-22 12:16:52 -08:00
|
|
|
with Not_found ->
|
|
|
|
match (Ctype.repr ty).desc with
|
2011-09-22 02:05:42 -07:00
|
|
|
| Tvar _ | Tunivar _ ->
|
2001-08-02 01:51:55 -07:00
|
|
|
Oval_stuff "<poly>"
|
2016-03-09 02:40:16 -08:00
|
|
|
| Tarrow _ ->
|
2001-08-02 01:51:55 -07:00
|
|
|
Oval_stuff "<fun>"
|
1997-03-22 12:16:52 -08:00
|
|
|
| Ttuple(ty_list) ->
|
2001-08-02 01:51:55 -07:00
|
|
|
Oval_tuple (tree_of_val_list 0 depth obj ty_list)
|
|
|
|
| Tconstr(path, [ty_arg], _)
|
|
|
|
when Path.same path Predef.path_list ->
|
|
|
|
if O.is_block obj then
|
|
|
|
match check_depth depth obj ty with
|
|
|
|
Some x -> x
|
|
|
|
| None ->
|
2014-05-08 01:31:45 -07:00
|
|
|
let rec tree_of_conses tree_list depth obj ty_arg =
|
2001-08-02 01:51:55 -07:00
|
|
|
if !printer_steps < 0 || depth < 0 then
|
|
|
|
Oval_ellipsis :: tree_list
|
|
|
|
else if O.is_block obj then
|
|
|
|
let tree =
|
2014-05-08 01:31:45 -07:00
|
|
|
nest tree_of_val (depth - 1) (O.field obj 0) ty_arg
|
|
|
|
in
|
2001-08-02 01:51:55 -07:00
|
|
|
let next_obj = O.field obj 1 in
|
2014-05-08 01:31:45 -07:00
|
|
|
nest_gen (Oval_stuff "<cycle>" :: tree :: tree_list)
|
|
|
|
(tree_of_conses (tree :: tree_list))
|
|
|
|
depth next_obj ty_arg
|
2001-08-02 01:51:55 -07:00
|
|
|
else tree_list
|
|
|
|
in
|
2014-05-08 01:31:45 -07:00
|
|
|
Oval_list (List.rev (tree_of_conses [] depth obj ty_arg))
|
2001-08-02 01:51:55 -07:00
|
|
|
else
|
|
|
|
Oval_list []
|
|
|
|
| Tconstr(path, [ty_arg], _)
|
|
|
|
when Path.same path Predef.path_array ->
|
1998-10-01 05:34:32 -07:00
|
|
|
let length = O.size obj in
|
2001-08-02 01:51:55 -07:00
|
|
|
if length > 0 then
|
|
|
|
match check_depth depth obj ty with
|
|
|
|
Some x -> x
|
|
|
|
| None ->
|
|
|
|
let rec tree_of_items tree_list i =
|
|
|
|
if !printer_steps < 0 || depth < 0 then
|
|
|
|
Oval_ellipsis :: tree_list
|
|
|
|
else if i < length then
|
|
|
|
let tree =
|
2014-05-08 01:31:45 -07:00
|
|
|
nest tree_of_val (depth - 1) (O.field obj i) ty_arg
|
|
|
|
in
|
2001-08-02 01:51:55 -07:00
|
|
|
tree_of_items (tree :: tree_list) (i + 1)
|
|
|
|
else tree_list
|
|
|
|
in
|
|
|
|
Oval_array (List.rev (tree_of_items [] 0))
|
|
|
|
else
|
|
|
|
Oval_array []
|
2017-05-11 04:57:08 -07:00
|
|
|
|
|
|
|
| Tconstr(path, [], _)
|
|
|
|
when Path.same path Predef.path_string ->
|
|
|
|
Oval_string ((O.obj obj : string), !printer_steps, Ostr_string)
|
|
|
|
|
|
|
|
| Tconstr (path, [], _)
|
|
|
|
when Path.same path Predef.path_bytes ->
|
|
|
|
let s = Bytes.to_string (O.obj obj : bytes) in
|
|
|
|
Oval_string (s, !printer_steps, Ostr_bytes)
|
|
|
|
|
2002-01-20 09:39:10 -08:00
|
|
|
| Tconstr (path, [ty_arg], _)
|
|
|
|
when Path.same path Predef.path_lazy_t ->
|
2014-12-13 07:33:46 -08:00
|
|
|
let obj_tag = O.tag obj in
|
|
|
|
(* Lazy values are represented in three possible ways:
|
|
|
|
|
|
|
|
1. a lazy thunk that is not yet forced has tag
|
|
|
|
Obj.lazy_tag
|
|
|
|
|
|
|
|
2. a lazy thunk that has just been forced has tag
|
|
|
|
Obj.forward_tag; its first field is the forced
|
|
|
|
result, which we can print
|
|
|
|
|
|
|
|
3. when the GC moves a forced trunk with forward_tag,
|
|
|
|
or when a thunk is directly created from a value,
|
|
|
|
we get a third representation where the value is
|
|
|
|
directly exposed, without the Obj.forward_tag
|
|
|
|
(if its own tag is not ambiguous, that is neither
|
|
|
|
lazy_tag nor forward_tag)
|
|
|
|
|
|
|
|
Note that using Lazy.is_val and Lazy.force would be
|
|
|
|
unsafe, because they use the Obj.* functions rather
|
|
|
|
than the O.* functions of the functor argument, and
|
|
|
|
would thus crash if called from the toplevel
|
|
|
|
(debugger/printval instantiates Genprintval.Make with
|
|
|
|
an Obj module talking over a socket).
|
|
|
|
*)
|
|
|
|
if obj_tag = Obj.lazy_tag then Oval_stuff "<lazy>"
|
2014-11-23 01:17:59 -08:00
|
|
|
else begin
|
|
|
|
let forced_obj =
|
2014-12-13 07:33:46 -08:00
|
|
|
if obj_tag = Obj.forward_tag then O.field obj 0 else obj
|
|
|
|
in
|
2014-11-23 01:17:59 -08:00
|
|
|
(* calling oneself recursively on forced_obj risks
|
2014-12-13 07:33:46 -08:00
|
|
|
having a false positive for cycle detection;
|
|
|
|
indeed, in case (3) above, the value is stored
|
|
|
|
as-is instead of being wrapped in a forward
|
|
|
|
pointer. It means that, for (lazy "foo"), we have
|
2014-11-23 01:17:59 -08:00
|
|
|
forced_obj == obj
|
|
|
|
and it is easy to wrongly print (lazy <cycle>) in such
|
|
|
|
a case (PR#6669).
|
|
|
|
|
|
|
|
Unfortunately, there is a corner-case that *is*
|
2020-07-18 10:15:18 -07:00
|
|
|
a real cycle: using unboxed types one can define
|
|
|
|
|
|
|
|
type t = T : t Lazy.t -> t [@@unboxed]
|
|
|
|
let rec x = lazy (T x)
|
|
|
|
|
2014-11-23 01:17:59 -08:00
|
|
|
which creates a Forward_tagged block that points to
|
|
|
|
itself. For this reason, we still "nest"
|
|
|
|
(detect head cycles) on forward tags.
|
|
|
|
*)
|
2014-12-13 07:33:46 -08:00
|
|
|
let v =
|
|
|
|
if obj_tag = Obj.forward_tag
|
|
|
|
then nest tree_of_val depth forced_obj ty_arg
|
|
|
|
else tree_of_val depth forced_obj ty_arg
|
|
|
|
in
|
2018-06-26 13:03:45 -07:00
|
|
|
Oval_constr (Oide_ident (Out_name.create "lazy"), [v])
|
2014-11-23 01:17:59 -08:00
|
|
|
end
|
2014-05-04 16:08:45 -07:00
|
|
|
| Tconstr(path, ty_list, _) -> begin
|
|
|
|
try
|
1997-03-22 12:16:52 -08:00
|
|
|
let decl = Env.find_type path env in
|
2003-07-02 02:14:35 -07:00
|
|
|
match decl with
|
2000-03-06 14:12:09 -08:00
|
|
|
| {type_kind = Type_abstract; type_manifest = None} ->
|
2001-08-02 01:51:55 -07:00
|
|
|
Oval_stuff "<abstr>"
|
1997-03-22 12:16:52 -08:00
|
|
|
| {type_kind = Type_abstract; type_manifest = Some body} ->
|
2001-08-02 01:51:55 -07:00
|
|
|
tree_of_val depth obj
|
2020-04-10 04:56:16 -07:00
|
|
|
(instantiate_type env decl.type_params ty_list body)
|
2016-05-25 07:29:05 -07:00
|
|
|
| {type_kind = Type_variant constr_list; type_unboxed} ->
|
|
|
|
let unbx = type_unboxed.unboxed in
|
1997-03-22 12:16:52 -08:00
|
|
|
let tag =
|
2016-05-25 07:29:05 -07:00
|
|
|
if unbx then Cstr_unboxed
|
|
|
|
else if O.is_block obj
|
1998-10-01 05:34:32 -07:00
|
|
|
then Cstr_block(O.tag obj)
|
|
|
|
else Cstr_constant(O.obj obj) in
|
2013-09-27 03:54:55 -07:00
|
|
|
let {cd_id;cd_args;cd_res} =
|
1999-10-29 07:42:37 -07:00
|
|
|
Datarepr.find_constr_by_tag tag constr_list in
|
2012-07-30 11:04:46 -07:00
|
|
|
let type_params =
|
2013-09-27 03:54:55 -07:00
|
|
|
match cd_res with
|
2012-07-30 11:04:46 -07:00
|
|
|
Some t ->
|
|
|
|
begin match (Ctype.repr t).desc with
|
|
|
|
Tconstr (_,params,_) ->
|
|
|
|
params
|
|
|
|
| _ -> assert false end
|
|
|
|
| None -> decl.type_params
|
|
|
|
in
|
2014-10-14 08:51:30 -07:00
|
|
|
begin
|
|
|
|
match cd_args with
|
|
|
|
| Cstr_tuple l ->
|
|
|
|
let ty_args =
|
2020-04-10 04:56:16 -07:00
|
|
|
instantiate_types env type_params ty_list l in
|
2014-10-14 08:51:30 -07:00
|
|
|
tree_of_constr_with_args (tree_of_constr env path)
|
|
|
|
(Ident.name cd_id) false 0 depth obj
|
2016-05-25 07:29:05 -07:00
|
|
|
ty_args unbx
|
2014-10-14 08:51:30 -07:00
|
|
|
| Cstr_record lbls ->
|
|
|
|
let r =
|
|
|
|
tree_of_record_fields depth
|
|
|
|
env path type_params ty_list
|
2016-05-25 07:29:05 -07:00
|
|
|
lbls 0 obj unbx
|
2014-10-14 08:51:30 -07:00
|
|
|
in
|
|
|
|
Oval_constr(tree_of_constr env path
|
2018-06-26 13:03:45 -07:00
|
|
|
(Out_name.create (Ident.name cd_id)),
|
2014-10-14 08:51:30 -07:00
|
|
|
[ r ])
|
|
|
|
end
|
2007-10-09 03:29:37 -07:00
|
|
|
| {type_kind = Type_record(lbl_list, rep)} ->
|
2003-02-27 22:59:19 -08:00
|
|
|
begin match check_depth depth obj ty with
|
2001-08-02 01:51:55 -07:00
|
|
|
Some x -> x
|
|
|
|
| None ->
|
2014-04-01 04:46:00 -07:00
|
|
|
let pos =
|
|
|
|
match rep with
|
2018-02-08 09:51:47 -08:00
|
|
|
| Record_extension _ -> 1
|
2014-04-01 04:46:00 -07:00
|
|
|
| _ -> 0
|
2001-08-02 01:51:55 -07:00
|
|
|
in
|
2016-05-25 07:29:05 -07:00
|
|
|
let unbx =
|
|
|
|
match rep with Record_unboxed _ -> true | _ -> false
|
|
|
|
in
|
2014-10-14 08:51:30 -07:00
|
|
|
tree_of_record_fields depth
|
|
|
|
env path decl.type_params ty_list
|
2016-05-25 07:29:05 -07:00
|
|
|
lbl_list pos obj unbx
|
2003-02-27 22:59:19 -08:00
|
|
|
end
|
2014-05-04 16:08:45 -07:00
|
|
|
| {type_kind = Type_open} ->
|
2020-04-10 04:56:16 -07:00
|
|
|
tree_of_extension path ty_list depth obj
|
1997-03-22 12:16:52 -08:00
|
|
|
with
|
|
|
|
Not_found -> (* raised by Env.find_type *)
|
2001-08-02 01:51:55 -07:00
|
|
|
Oval_stuff "<abstr>"
|
1999-10-29 07:42:37 -07:00
|
|
|
| Datarepr.Constr_not_found -> (* raised by find_constr_by_tag *)
|
2001-08-02 01:51:55 -07:00
|
|
|
Oval_stuff "<unknown constructor>"
|
1997-03-22 12:16:52 -08:00
|
|
|
end
|
2000-01-07 08:47:25 -08:00
|
|
|
| Tvariant row ->
|
|
|
|
let row = Btype.row_repr row in
|
2001-08-02 01:51:55 -07:00
|
|
|
if O.is_block obj then
|
2000-01-07 08:47:25 -08:00
|
|
|
let tag : int = O.obj (O.field obj 0) in
|
2001-08-02 01:51:55 -07:00
|
|
|
let rec find = function
|
|
|
|
| (l, f) :: fields ->
|
|
|
|
if Btype.hash_variant l = tag then
|
|
|
|
match Btype.row_field_repr f with
|
2005-06-12 21:55:53 -07:00
|
|
|
| Rpresent(Some ty) | Reither(_,[ty],_,_) ->
|
2001-08-02 01:51:55 -07:00
|
|
|
let args =
|
2014-05-08 01:31:45 -07:00
|
|
|
nest tree_of_val (depth - 1) (O.field obj 1) ty
|
|
|
|
in
|
|
|
|
Oval_variant (l, Some args)
|
2001-08-02 01:51:55 -07:00
|
|
|
| _ -> find fields
|
|
|
|
else find fields
|
|
|
|
| [] -> Oval_stuff "<variant>" in
|
|
|
|
find row.row_fields
|
|
|
|
else
|
2000-01-07 08:47:25 -08:00
|
|
|
let tag : int = O.obj obj in
|
2001-08-02 01:51:55 -07:00
|
|
|
let rec find = function
|
|
|
|
| (l, _) :: fields ->
|
|
|
|
if Btype.hash_variant l = tag then
|
|
|
|
Oval_variant (l, None)
|
|
|
|
else find fields
|
|
|
|
| [] -> Oval_stuff "<variant>" in
|
|
|
|
find row.row_fields
|
1997-03-22 12:16:52 -08:00
|
|
|
| Tobject (_, _) ->
|
2001-08-02 01:51:55 -07:00
|
|
|
Oval_stuff "<obj>"
|
2000-01-07 08:47:25 -08:00
|
|
|
| Tsubst ty ->
|
2001-08-02 01:51:55 -07:00
|
|
|
tree_of_val (depth - 1) obj ty
|
1997-05-11 14:48:21 -07:00
|
|
|
| Tfield(_, _, _, _) | Tnil | Tlink _ ->
|
2001-08-02 01:51:55 -07:00
|
|
|
fatal_error "Printval.outval_of_value"
|
2002-04-18 00:27:47 -07:00
|
|
|
| Tpoly (ty, _) ->
|
|
|
|
tree_of_val (depth - 1) obj ty
|
2009-10-26 03:53:16 -07:00
|
|
|
| Tpackage _ ->
|
|
|
|
Oval_stuff "<module>"
|
2001-08-02 01:51:55 -07:00
|
|
|
end
|
1997-03-22 12:16:52 -08:00
|
|
|
|
2014-10-14 08:51:30 -07:00
|
|
|
and tree_of_record_fields depth env path type_params ty_list
|
2016-05-25 07:29:05 -07:00
|
|
|
lbl_list pos obj unboxed =
|
2014-10-14 08:51:30 -07:00
|
|
|
let rec tree_of_fields pos = function
|
|
|
|
| [] -> []
|
|
|
|
| {ld_id; ld_type} :: remainder ->
|
2020-04-10 04:56:16 -07:00
|
|
|
let ty_arg = instantiate_type env type_params ty_list ld_type in
|
2014-10-14 08:51:30 -07:00
|
|
|
let name = Ident.name ld_id in
|
|
|
|
(* PR#5722: print full module path only
|
|
|
|
for first record field *)
|
|
|
|
let lid =
|
2018-06-26 13:03:45 -07:00
|
|
|
if pos = 0 then tree_of_label env path (Out_name.create name)
|
|
|
|
else Oide_ident (Out_name.create name)
|
2014-10-14 08:51:30 -07:00
|
|
|
and v =
|
2017-08-31 06:25:15 -07:00
|
|
|
if unboxed then
|
|
|
|
tree_of_val (depth - 1) obj ty_arg
|
|
|
|
else begin
|
|
|
|
let fld =
|
|
|
|
if O.tag obj = O.double_array_tag then
|
|
|
|
O.repr (O.double_field obj pos)
|
|
|
|
else
|
|
|
|
O.field obj pos
|
|
|
|
in
|
|
|
|
nest tree_of_val (depth - 1) fld ty_arg
|
|
|
|
end
|
2014-10-14 08:51:30 -07:00
|
|
|
in
|
|
|
|
(lid, v) :: tree_of_fields (pos + 1) remainder
|
|
|
|
in
|
|
|
|
Oval_record (tree_of_fields pos lbl_list)
|
|
|
|
|
2001-08-02 01:51:55 -07:00
|
|
|
and tree_of_val_list start depth obj ty_list =
|
|
|
|
let rec tree_list i = function
|
|
|
|
| [] -> []
|
2000-03-06 14:12:09 -08:00
|
|
|
| ty :: ty_list ->
|
2014-05-08 01:31:45 -07:00
|
|
|
let tree = nest tree_of_val (depth - 1) (O.field obj i) ty in
|
2001-08-02 01:51:55 -07:00
|
|
|
tree :: tree_list (i + 1) ty_list in
|
|
|
|
tree_list start ty_list
|
|
|
|
|
|
|
|
and tree_of_constr_with_args
|
2016-05-25 07:29:05 -07:00
|
|
|
tree_of_cstr cstr_name inlined start depth obj ty_args unboxed =
|
2018-06-26 13:03:45 -07:00
|
|
|
let lid = tree_of_cstr (Out_name.create cstr_name) in
|
2014-03-31 05:20:22 -07:00
|
|
|
let args =
|
2016-05-25 07:29:05 -07:00
|
|
|
if inlined || unboxed then
|
2014-03-31 05:20:22 -07:00
|
|
|
match ty_args with
|
|
|
|
| [ty] -> [ tree_of_val (depth - 1) obj ty ]
|
|
|
|
| _ -> assert false
|
|
|
|
else
|
|
|
|
tree_of_val_list start depth obj ty_args
|
|
|
|
in
|
2001-08-02 01:51:55 -07:00
|
|
|
Oval_constr (lid, args)
|
|
|
|
|
2020-04-10 04:56:16 -07:00
|
|
|
and tree_of_extension type_path ty_list depth bucket =
|
2013-10-23 07:28:31 -07:00
|
|
|
let slot =
|
|
|
|
if O.tag bucket <> 0 then bucket
|
|
|
|
else O.field bucket 0
|
|
|
|
in
|
2013-10-18 06:00:58 -07:00
|
|
|
let name = (O.obj(O.field slot 0) : string) in
|
2000-03-25 10:55:45 -08:00
|
|
|
try
|
|
|
|
(* Attempt to recover the constructor description for the exn
|
|
|
|
from its name *)
|
2020-01-06 05:24:26 -08:00
|
|
|
let lid =
|
|
|
|
try Parse.longident (Lexing.from_string name) with
|
|
|
|
(* The syntactic class for extension constructor names
|
|
|
|
is an extended form of constructor "Longident.t"s
|
|
|
|
that also includes module application (e.g [F(X).A]) *)
|
|
|
|
| Syntaxerr.Error _ | Lexer.Error _ -> raise Not_found in
|
2018-10-12 02:20:21 -07:00
|
|
|
let cstr = Env.find_constructor_by_name lid env in
|
2000-03-25 10:55:45 -08:00
|
|
|
let path =
|
|
|
|
match cstr.cstr_tag with
|
2014-05-04 16:08:45 -07:00
|
|
|
Cstr_extension(p, _) -> p
|
|
|
|
| _ -> raise Not_found
|
|
|
|
in
|
2018-02-08 09:51:47 -08:00
|
|
|
let addr = Env.find_constructor_address path env in
|
2000-03-25 10:55:45 -08:00
|
|
|
(* Make sure this is the right exception and not an homonym,
|
2001-08-02 01:51:55 -07:00
|
|
|
by evaluating the exception found and comparing with the
|
|
|
|
identifier contained in the exception bucket *)
|
2018-02-08 09:51:47 -08:00
|
|
|
if not (EVP.same_value slot (EVP.eval_address addr))
|
2000-03-26 04:11:10 -08:00
|
|
|
then raise Not_found;
|
2020-04-10 04:56:16 -07:00
|
|
|
let type_params =
|
|
|
|
match (Ctype.repr cstr.cstr_res).desc with
|
|
|
|
Tconstr (_,params,_) ->
|
|
|
|
params
|
|
|
|
| _ -> assert false
|
|
|
|
in
|
|
|
|
let args = instantiate_types env type_params ty_list cstr.cstr_args in
|
2001-08-02 01:51:55 -07:00
|
|
|
tree_of_constr_with_args
|
2014-10-14 08:51:30 -07:00
|
|
|
(fun x -> Oide_ident x) name (cstr.cstr_inlined <> None)
|
|
|
|
1 depth bucket
|
2020-04-10 04:56:16 -07:00
|
|
|
args false
|
2000-03-25 10:55:45 -08:00
|
|
|
with Not_found | EVP.Error ->
|
2004-06-13 09:23:35 -07:00
|
|
|
match check_depth depth bucket ty with
|
2001-08-02 01:51:55 -07:00
|
|
|
Some x -> x
|
2014-05-04 16:08:45 -07:00
|
|
|
| None when Path.same type_path Predef.path_exn->
|
|
|
|
outval_of_untyped_exception bucket
|
|
|
|
| None ->
|
|
|
|
Oval_stuff "<extension>"
|
2001-08-02 01:51:55 -07:00
|
|
|
|
2020-04-10 04:56:16 -07:00
|
|
|
and instantiate_type env type_params ty_list ty =
|
|
|
|
try Ctype.apply env type_params ty ty_list
|
|
|
|
with Ctype.Cannot_apply -> abstract_type
|
|
|
|
|
|
|
|
and instantiate_types env type_params ty_list args =
|
|
|
|
List.map (instantiate_type env type_params ty_list) args
|
|
|
|
|
2014-12-06 09:11:04 -08:00
|
|
|
and find_printer depth env ty =
|
|
|
|
let rec find = function
|
|
|
|
| [] -> raise Not_found
|
2016-03-09 02:40:16 -08:00
|
|
|
| (_name, Simple (sch, printer)) :: remainder ->
|
2014-12-06 09:11:04 -08:00
|
|
|
if Ctype.moregeneral env false sch ty
|
|
|
|
then printer
|
|
|
|
else find remainder
|
2016-03-09 02:40:16 -08:00
|
|
|
| (_name, Generic (path, fn)) :: remainder ->
|
2014-12-06 09:11:04 -08:00
|
|
|
begin match (Ctype.expand_head env ty).desc with
|
|
|
|
| Tconstr (p, args, _) when Path.same p path ->
|
|
|
|
begin try apply_generic_printer path (fn depth) args
|
2017-02-10 08:45:02 -08:00
|
|
|
with exn -> (fun _obj -> out_exn path exn) end
|
2014-12-06 09:11:04 -08:00
|
|
|
| _ -> find remainder end in
|
|
|
|
find !printers
|
|
|
|
|
|
|
|
and apply_generic_printer path printer args =
|
|
|
|
match (printer, args) with
|
2017-08-12 13:24:41 -07:00
|
|
|
| (Zero fn, []) ->
|
|
|
|
(fun (obj : O.t)-> try fn obj with exn -> out_exn path exn)
|
2014-12-06 09:11:04 -08:00
|
|
|
| (Succ fn, arg :: args) ->
|
|
|
|
let printer = fn (fun depth obj -> tree_of_val depth obj arg) in
|
|
|
|
apply_generic_printer path printer args
|
|
|
|
| _ ->
|
2016-03-09 02:40:16 -08:00
|
|
|
(fun _obj ->
|
2014-12-06 09:11:04 -08:00
|
|
|
let printer ppf =
|
|
|
|
fprintf ppf "<internal error: incorrect arity for '%a'>"
|
|
|
|
Printtyp.path path in
|
|
|
|
Oval_printer printer)
|
|
|
|
|
|
|
|
|
2014-05-08 01:31:45 -07:00
|
|
|
in nest tree_of_val max_depth obj ty
|
2001-08-02 01:51:55 -07:00
|
|
|
|
1997-03-22 12:16:52 -08:00
|
|
|
end
|