ocaml/debugger/loadprinter.ml

138 lines
4.3 KiB
OCaml
Raw Normal View History

(***********************************************************************)
(* *)
(* Objective Caml *)
(* *)
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 1997 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
(***********************************************************************)
(* $Id$ *)
(* Loading and installation of user-defined printer functions *)
open Misc
open Debugger_config
open Path
open Types
(* Error report *)
type error =
Load_failure of Dynlink.error
| Unbound_identifier of Longident.t
| Unavailable_module of string * Longident.t
| Wrong_type of Longident.t
| No_active_printer of Longident.t
exception Error of error
(* Symtable has global state, and normally holds the symbol table
for the debuggee. We need to switch it temporarily to the
symbol table for the debugger. *)
let debugger_symtable = ref (None: Symtable.global_map option)
let use_debugger_symtable fn arg =
let old_symtable = Symtable.current_state() in
begin match !debugger_symtable with
None ->
Symtable.init_toplevel();
debugger_symtable := Some(Symtable.current_state())
| Some st ->
Symtable.restore_state st
end;
try
fn arg;
debugger_symtable := Some(Symtable.current_state());
Symtable.restore_state old_symtable
with exn ->
Symtable.restore_state old_symtable;
raise exn
(* Load a .cmo or .cma file *)
let loadfile filename =
if !debugger_symtable = None then begin
Dynlink.add_interfaces stdlib_units [Config.standard_library];
Dynlink.allow_unsafe_modules true
end;
try
use_debugger_symtable Dynlink.loadfile filename
with Dynlink.Error e ->
raise(Error(Load_failure e))
(* Return the value referred to by a path (as in toplevel/topdirs) *)
(* Note: evaluation proceeds in the debugger memory space, not in
the debuggee. *)
let rec eval_path = function
Pident id -> Symtable.get_global_value id
| Pdot(p, s, pos) -> Obj.field (eval_path p) pos
| Papply(p1, p2) -> fatal_error "Loadprinter.eval_path"
(* Install, remove a printer (as in toplevel/topdirs) *)
let find_printer_type lid =
try
let (path, desc) = Env.lookup_value lid Env.empty in
Ctype.init_def(Ident.current_time());
Ctype.begin_def();
let ty_arg = Ctype.newvar() in
Ctype.unify Env.empty
(Ctype.newty (Tarrow(ty_arg, Ctype.instance Predef.type_unit)))
(Ctype.instance desc.val_type);
Ctype.end_def();
Ctype.generalize ty_arg;
(ty_arg, path)
with
Not_found -> raise(Error(Unbound_identifier lid))
| Ctype.Unify _ -> raise(Error(Wrong_type lid))
let install_printer lid =
let (ty_arg, path) = find_printer_type lid in
let v =
try
use_debugger_symtable eval_path path
with Symtable.Error(Symtable.Undefined_global s) ->
raise(Error(Unavailable_module(s, lid))) in
Printval.install_printer path ty_arg (Obj.magic v : Obj.t -> unit)
let remove_printer lid =
let (ty_arg, path) = find_printer_type lid in
try
Printval.remove_printer path
with Not_found ->
raise(Error(No_active_printer lid))
(* Error report *)
open Format
let report_error error =
open_hovbox 0;
begin match error with
Load_failure e ->
print_string "Error during code loading:"; print_space();
print_string (Dynlink.error_message e)
| Unbound_identifier lid ->
print_string "Unbound identifier ";
Printtyp.longident lid
| Unavailable_module(md, lid) ->
print_string "The debugger does not contain the code for";
print_space(); Printtyp.longident lid; print_string "."; print_space();
print_string "Please load an implementation of ";
print_string md; print_string " first."
| Wrong_type lid ->
Printtyp.longident lid;
print_string " has the wrong type for a printing function."
| No_active_printer lid ->
Printtyp.longident lid;
print_string " is not currently active as a printing function."
end;
close_box(); print_newline()