let rec to_string r =
          if Obj.is_int r
          then
            (let i : int = Obj.magic r
             in (string_of_int i) ^ (" | CstTag" ^ (string_of_int (i + 1))))
          else
            (let rec get_fields acc =
               function
               | 0 -> acc
               | n -> let n = n - 1 in get_fields ((Obj.field r n) :: acc) n in
             let rec is_list r =
               if Obj.is_int r
               then r = (Obj.repr 0)
               else
                 (let s = Obj.size r
                  and t = Obj.tag r
                  in (t = 0) && ((s = 2) && (is_list (Obj.field r 1)))) in
             let rec get_list r =
               if Obj.is_int r
               then []
               else
                 (let h = Obj.field r 0
                  and t = get_list (Obj.field r 1)
                  in h :: t) in
             let opaque name = "<" ^ (name ^ ">"in
             let s = Obj.size r
             and t = Obj.tag r
             in
               match t with
               | _ when is_list r ->
                   let fields = get_list r
                   in
                     "[" ^
                       ((String.concat "; " (List.map to_string fields)) ^
                          "]")
               | 0 ->
                   let fields = get_fields [] s
                   in
                     "(" ^
                       ((String.concat ", " (List.map to_string fields)) ^
                          ")")
               | x when x = Obj.lazy_tag -> opaque "lazy"
               | x when x = Obj.closure_tag -> opaque "closure"
               | x when x = Obj.object_tag ->
                   let fields = get_fields [] s in
                   let (_class, id, slots) =
                     (match fields with
                      | h :: h' :: t -> (h, h', t)
                      | _ -> assert false)
                   in
                     "Object #" ^
                       ((to_string id) ^
                          (" (" ^
                             ((String.concat ", " (List.map to_string slots))
                                ^ ")")))
               | x when x = Obj.infix_tag -> opaque "infix"
               | x when x = Obj.forward_tag -> opaque "forward"
               | x when x < Obj.no_scan_tag ->
                   let fields = get_fields [] s
                   in
                     "Tag" ^
                       ((string_of_int t) ^
                          (" (" ^
                             ((String.concat ", " (List.map to_string fields))
                                ^ ")")))
               | x when x = Obj.string_tag ->
                   "\"" ^ ((String.escaped (Obj.magic r : string)) ^ "\"")
               | x when x = Obj.double_tag ->
                   string_of_float (Obj.magic r : float)
               | x when x = Obj.abstract_tag -> opaque "abstract"
               | x when x = Obj.custom_tag -> opaque "custom"
               | x when x = Obj.final_tag -> opaque "final"
               | _ ->
                   failwith
                     ("ObjTools.to_string: unknown tag (" ^
                        ((string_of_int t) ^ ")")))