Blame browser/searchpos.ml

Packit bd2e5d
(*************************************************************************)
Packit bd2e5d
(*                                                                       *)
Packit bd2e5d
(*                         OCaml LablTk library                          *)
Packit bd2e5d
(*                                                                       *)
Packit bd2e5d
(*            Jacques Garrigue, Kyoto University RIMS                    *)
Packit bd2e5d
(*                                                                       *)
Packit bd2e5d
(*   Copyright 1999 Institut National de Recherche en Informatique et    *)
Packit bd2e5d
(*   en Automatique and Kyoto University.  All rights reserved.          *)
Packit bd2e5d
(*   This file is distributed under the terms of the GNU Library         *)
Packit bd2e5d
(*   General Public License, with the special exception on linking       *)
Packit bd2e5d
(*   described in file ../../../LICENSE.                                 *)
Packit bd2e5d
(*                                                                       *)
Packit bd2e5d
(*************************************************************************)
Packit bd2e5d
Packit bd2e5d
(* $Id$ *)
Packit bd2e5d
Packit bd2e5d
open Asttypes
Packit bd2e5d
open StdLabels
Packit bd2e5d
open Support
Packit bd2e5d
open Tk
Packit bd2e5d
open Jg_tk
Packit bd2e5d
open Parsetree
Packit bd2e5d
open Typedtree
Packit bd2e5d
open Types
Packit bd2e5d
open Location
Packit bd2e5d
open Longident
Packit bd2e5d
open Path
Packit bd2e5d
open Env
Packit bd2e5d
open Searchid
Packit bd2e5d
Packit bd2e5d
(* auxiliary functions *)
Packit bd2e5d
Packit bd2e5d
let (~!) = Jg_memo.fast ~f:Str.regexp
Packit bd2e5d
Packit bd2e5d
let lines_to_chars n ~text:s =
Packit bd2e5d
  let l = String.length s in
Packit bd2e5d
  let rec ltc n ~pos =
Packit bd2e5d
    if n = 1 || pos >= l then pos else
Packit bd2e5d
    if s.[pos] = '\n' then ltc (n-1) ~pos:(pos+1) else ltc n ~pos:(pos+1)
Packit bd2e5d
  in ltc n ~pos:0
Packit bd2e5d
Packit bd2e5d
let in_loc loc ~pos =
Packit bd2e5d
  loc.loc_ghost || pos >= loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
                   && pos < loc.loc_end.Lexing.pos_cnum
Packit bd2e5d
Packit bd2e5d
let le_loc loc1 loc2 =
Packit bd2e5d
  loc1.loc_start.Lexing.pos_cnum <= loc2.loc_start.Lexing.pos_cnum
Packit bd2e5d
  && loc1.loc_end.Lexing.pos_cnum >= loc2.loc_end.Lexing.pos_cnum
Packit bd2e5d
Packit bd2e5d
let add_found ~found sol ~env ~loc =
Packit bd2e5d
  if loc.loc_ghost then () else
Packit bd2e5d
  if List.exists !found ~f:(fun (_,_,loc') -> le_loc loc loc') then ()
Packit bd2e5d
  else found := (sol, env, loc) ::
Packit bd2e5d
    List.filter !found ~f:(fun (_,_,loc') -> not (le_loc loc' loc))
Packit bd2e5d
Packit bd2e5d
let observe ~ref ?init f x =
Packit bd2e5d
  let old = !ref in
Packit bd2e5d
  begin match init with None -> () | Some x -> ref := x end;
Packit bd2e5d
  try (f x : unit); let v = !ref in ref := old; v
Packit bd2e5d
  with exn -> ref := old; raise exn
Packit bd2e5d
Packit bd2e5d
let rec string_of_longident = function
Packit bd2e5d
    Lident s -> s
Packit bd2e5d
  | Ldot (id,s) -> string_of_longident id ^ "." ^ s
Packit bd2e5d
  | Lapply (id1, id2) ->
Packit bd2e5d
      string_of_longident id1 ^ "(" ^ string_of_longident id2 ^ ")"
Packit bd2e5d
Packit bd2e5d
let string_of_path p = string_of_longident (Searchid.longident_of_path p)
Packit bd2e5d
Packit bd2e5d
let parent_path = function
Packit bd2e5d
    Pdot (path, _, _) -> Some path
Packit bd2e5d
  | Pident _ | Papply _ -> None
Packit bd2e5d
Packit bd2e5d
let ident_of_path ~default = function
Packit bd2e5d
    Pident i -> i
Packit bd2e5d
  | Pdot (_, s, _) -> Ident.create s
Packit bd2e5d
  | Papply _ -> Ident.create default
Packit bd2e5d
Packit bd2e5d
let rec head_id = function
Packit bd2e5d
    Pident id -> id
Packit bd2e5d
  | Pdot (path,_,_) -> head_id path
Packit bd2e5d
  | Papply (path,_) -> head_id path (* wrong, but ... *)
Packit bd2e5d
Packit bd2e5d
let rec list_of_path = function
Packit bd2e5d
    Pident id -> [Ident.name id]
Packit bd2e5d
  | Pdot (path, s, _) -> list_of_path path @ [s]
Packit bd2e5d
  | Papply (path, _) -> list_of_path path (* wrong, but ... *)
Packit bd2e5d
Packit bd2e5d
(* a simple wrapper *)
Packit bd2e5d
Packit bd2e5d
class buffer ~size = object
Packit bd2e5d
  val buffer = Buffer.create size
Packit bd2e5d
  method out buf = Buffer.add_substring buffer buf
Packit bd2e5d
  method get = Buffer.contents buffer
Packit bd2e5d
end
Packit bd2e5d
Packit bd2e5d
(* Search in a signature *)
Packit bd2e5d
Packit bd2e5d
type skind = [`Type|`Class|`Module|`Modtype]
Packit bd2e5d
Packit bd2e5d
let found_sig = ref ([] : ((skind * Longident.t) * Env.t * Location.t) list)
Packit bd2e5d
let add_found_sig = add_found ~found:found_sig
Packit bd2e5d
Packit bd2e5d
let rec search_pos_type t ~pos ~env =
Packit bd2e5d
  if in_loc ~pos t.ptyp_loc then
Packit bd2e5d
  begin match t.ptyp_desc with
Packit bd2e5d
    Ptyp_any
Packit bd2e5d
  | Ptyp_var _ -> ()
Packit bd2e5d
  | Ptyp_variant(tl, _, _) ->
Packit bd2e5d
      List.iter tl ~f:
Packit bd2e5d
        begin function
Packit bd2e5d
            Rtag (_,_,_,tl) -> List.iter tl ~f:(search_pos_type ~pos ~env)
Packit bd2e5d
          | Rinherit st -> search_pos_type ~pos ~env st
Packit bd2e5d
        end
Packit bd2e5d
  | Ptyp_arrow (_, t1, t2) ->
Packit bd2e5d
      search_pos_type t1 ~pos ~env;
Packit bd2e5d
      search_pos_type t2 ~pos ~env
Packit bd2e5d
  | Ptyp_tuple tl ->
Packit bd2e5d
      List.iter tl ~f:(search_pos_type ~pos ~env)
Packit bd2e5d
  | Ptyp_constr (lid, tl) ->
Packit bd2e5d
      List.iter tl ~f:(search_pos_type ~pos ~env);
Packit bd2e5d
      add_found_sig (`Type, lid.txt) ~env ~loc:t.ptyp_loc
Packit bd2e5d
  | Ptyp_object (fl, _) ->
Packit bd2e5d
      List.iter fl ~f:
Packit bd2e5d
        (function Oinherit ty | Otag (_, _, ty) -> search_pos_type ty ~pos ~env)
Packit bd2e5d
  | Ptyp_class (lid, tl) ->
Packit bd2e5d
      List.iter tl ~f:(search_pos_type ~pos ~env);
Packit bd2e5d
      add_found_sig (`Type, lid.txt) ~env ~loc:t.ptyp_loc
Packit bd2e5d
  | Ptyp_alias (t, _)
Packit bd2e5d
  | Ptyp_poly (_, t) -> search_pos_type ~pos ~env t
Packit bd2e5d
  | Ptyp_package (_, stl) ->
Packit bd2e5d
     List.iter stl ~f:(fun (_, ty) -> search_pos_type ty ~pos ~env)
Packit bd2e5d
  | Ptyp_extension _ -> ()
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
let rec search_pos_class_type cl ~pos ~env =
Packit bd2e5d
  if in_loc cl.pcty_loc ~pos then
Packit bd2e5d
    begin match cl.pcty_desc with
Packit bd2e5d
      Pcty_constr (lid, _) ->
Packit bd2e5d
        add_found_sig (`Class, lid.txt) ~env ~loc:cl.pcty_loc
Packit bd2e5d
    | Pcty_signature  cl ->
Packit bd2e5d
        List.iter cl.pcsig_fields ~f: (fun fl ->
Packit bd2e5d
          begin match fl.pctf_desc with
Packit bd2e5d
              Pctf_inherit cty -> search_pos_class_type cty ~pos ~env
Packit bd2e5d
            | Pctf_val (_, _, _, ty)
Packit bd2e5d
            | Pctf_method (_, _, _, ty) ->
Packit bd2e5d
                if in_loc fl.pctf_loc ~pos then search_pos_type ty ~pos ~env
Packit bd2e5d
            | Pctf_constraint (ty1, ty2) ->
Packit bd2e5d
                if in_loc fl.pctf_loc ~pos then begin
Packit bd2e5d
                  search_pos_type ty1 ~pos ~env;
Packit bd2e5d
                  search_pos_type ty2 ~pos ~env
Packit bd2e5d
                end
Packit bd2e5d
	    | Pctf_attribute _
Packit bd2e5d
            | Pctf_extension _ -> ()
Packit bd2e5d
          end)
Packit bd2e5d
    | Pcty_arrow (_, ty, cty) ->
Packit bd2e5d
        search_pos_type ty ~pos ~env;
Packit bd2e5d
        search_pos_class_type cty ~pos ~env
Packit bd2e5d
    | Pcty_extension _ -> ()
Packit bd2e5d
    | Pcty_open (_, _, cty) ->
Packit bd2e5d
        search_pos_class_type cty ~pos ~env
Packit bd2e5d
    end
Packit bd2e5d
Packit bd2e5d
let search_pos_arguments ~pos ~env = function
Packit bd2e5d
    Pcstr_tuple l -> List.iter l ~f:(search_pos_type ~pos ~env)
Packit bd2e5d
  | Pcstr_record l -> List.iter l ~f:(fun ld -> search_pos_type ld.pld_type ~pos ~env)
Packit bd2e5d
Packit bd2e5d
let search_pos_constructor pcd ~pos ~env =
Packit bd2e5d
  if in_loc ~pos pcd.pcd_loc then begin
Packit bd2e5d
    Misc.may (search_pos_type ~pos ~env) pcd.pcd_res;
Packit bd2e5d
    search_pos_arguments ~pos ~env pcd.pcd_args
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
let search_pos_type_decl td ~pos ~env =
Packit bd2e5d
  if in_loc ~pos td.ptype_loc then begin
Packit bd2e5d
    begin match td.ptype_manifest with
Packit bd2e5d
      Some t -> search_pos_type t ~pos ~env
Packit bd2e5d
    | None -> ()
Packit bd2e5d
    end;
Packit bd2e5d
    let rec search_tkind = function
Packit bd2e5d
      Ptype_abstract
Packit bd2e5d
    | Ptype_open -> ()
Packit bd2e5d
    | Ptype_variant dl ->
Packit bd2e5d
        List.iter dl ~f:(search_pos_constructor ~pos ~env)
Packit bd2e5d
    | Ptype_record dl ->
Packit bd2e5d
        List.iter dl ~f:(fun pld -> search_pos_type pld.pld_type ~pos ~env) in
Packit bd2e5d
    search_tkind td.ptype_kind;
Packit bd2e5d
    List.iter td.ptype_cstrs ~f:
Packit bd2e5d
      begin fun (t1, t2, _) ->
Packit bd2e5d
        search_pos_type t1 ~pos ~env;
Packit bd2e5d
        search_pos_type t2 ~pos ~env
Packit bd2e5d
      end
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
let search_pos_extension ext ~pos ~env =
Packit bd2e5d
  begin match ext.pext_kind with
Packit bd2e5d
    Pext_decl (l, _) -> search_pos_arguments l ~pos ~env
Packit bd2e5d
  | Pext_rebind _ -> ()
Packit bd2e5d
  end
Packit bd2e5d
  
Packit bd2e5d
let rec search_pos_signature l ~pos ~env =
Packit bd2e5d
  ignore (
Packit bd2e5d
  List.fold_left l ~init:env ~f:
Packit bd2e5d
  begin fun env pt ->
Packit bd2e5d
    let env = match pt.psig_desc with
Packit bd2e5d
      Psig_open {popen_override=ovf; popen_lid=id} ->
Packit bd2e5d
        let path, mt = Typetexp.find_module env Location.none id.txt in
Packit bd2e5d
        begin match open_signature ovf path env with
Packit bd2e5d
          Some env -> env
Packit bd2e5d
        | None -> env
Packit bd2e5d
        end
Packit bd2e5d
    | sign_item ->
Packit bd2e5d
        try add_signature (Typemod.transl_signature env [pt]).sig_type env
Packit bd2e5d
        with Typemod.Error _ | Typeclass.Error _
Packit bd2e5d
        | Typetexp.Error _  | Typedecl.Error _ -> env
Packit bd2e5d
    in
Packit bd2e5d
    if in_loc ~pos pt.psig_loc then
Packit bd2e5d
      begin match pt.psig_desc with
Packit bd2e5d
        Psig_value desc -> search_pos_type desc.pval_type ~pos ~env
Packit bd2e5d
      | Psig_type (_, l) ->
Packit bd2e5d
          List.iter l ~f:(search_pos_type_decl ~pos ~env)
Packit bd2e5d
      | Psig_typext pty ->
Packit bd2e5d
	  List.iter pty.ptyext_constructors
Packit bd2e5d
	    ~f:(search_pos_extension ~pos ~env);
Packit bd2e5d
	  add_found_sig (`Type, pty.ptyext_path.txt) ~env ~loc:pt.psig_loc
Packit bd2e5d
      | Psig_exception ext ->
Packit bd2e5d
	  search_pos_extension ext ~pos ~env;
Packit bd2e5d
	  add_found_sig (`Type, Lident "exn") ~env ~loc:pt.psig_loc
Packit bd2e5d
      | Psig_module pmd ->
Packit bd2e5d
          search_pos_module pmd.pmd_type ~pos ~env
Packit bd2e5d
      | Psig_recmodule decls ->
Packit bd2e5d
          List.iter decls ~f:(fun pmd -> search_pos_module pmd.pmd_type ~pos ~env)
Packit bd2e5d
      | Psig_modtype {pmtd_type=Some t} ->
Packit bd2e5d
          search_pos_module t ~pos ~env
Packit bd2e5d
      | Psig_modtype _ -> ()
Packit bd2e5d
      | Psig_class l ->
Packit bd2e5d
          List.iter l
Packit bd2e5d
            ~f:(fun ci -> search_pos_class_type ci.pci_expr ~pos ~env)
Packit bd2e5d
      | Psig_class_type l ->
Packit bd2e5d
          List.iter l
Packit bd2e5d
            ~f:(fun ci -> search_pos_class_type ci.pci_expr ~pos ~env)
Packit bd2e5d
      (* The last cases should not happen in generated interfaces *)
Packit bd2e5d
      | Psig_open {popen_lid=lid} ->
Packit bd2e5d
        add_found_sig (`Module, lid.txt) ~env ~loc:pt.psig_loc
Packit bd2e5d
      | Psig_include {pincl_mod=t} -> search_pos_module t ~pos ~env
Packit bd2e5d
      | Psig_attribute _ | Psig_extension _ -> ()
Packit bd2e5d
      end;
Packit bd2e5d
    env
Packit bd2e5d
  end)
Packit bd2e5d
Packit bd2e5d
and search_pos_module m ~pos ~env =
Packit bd2e5d
  if in_loc m.pmty_loc ~pos then begin
Packit bd2e5d
    begin match m.pmty_desc with
Packit bd2e5d
      Pmty_ident lid -> add_found_sig (`Modtype, lid.txt) ~env ~loc:m.pmty_loc
Packit bd2e5d
    | Pmty_alias lid -> add_found_sig (`Module, lid.txt) ~env ~loc:m.pmty_loc
Packit bd2e5d
    | Pmty_signature sg -> search_pos_signature sg ~pos ~env
Packit bd2e5d
    | Pmty_functor (_ , m1, m2) ->
Packit bd2e5d
        Misc.may (search_pos_module ~pos ~env) m1;
Packit bd2e5d
        search_pos_module m2 ~pos ~env
Packit bd2e5d
    | Pmty_with (m, l) ->
Packit bd2e5d
        search_pos_module m ~pos ~env;
Packit bd2e5d
        List.iter l ~f:
Packit bd2e5d
          begin function
Packit bd2e5d
              Pwith_type (_, t) -> search_pos_type_decl t ~pos ~env
Packit bd2e5d
            | _ -> ()
Packit bd2e5d
          end
Packit bd2e5d
    | Pmty_typeof md ->
Packit bd2e5d
        ()   (* TODO? *)
Packit bd2e5d
    | Pmty_extension _ -> ()
Packit bd2e5d
    end
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
let search_pos_signature l ~pos ~env =
Packit bd2e5d
  observe ~ref:found_sig (search_pos_signature ~pos ~env) l
Packit bd2e5d
Packit bd2e5d
(* the module display machinery *)
Packit bd2e5d
Packit bd2e5d
type module_widgets =
Packit bd2e5d
    { mw_frame: Widget.frame Widget.widget;
Packit bd2e5d
      mw_title: Widget.label Widget.widget option;
Packit bd2e5d
      mw_detach: Widget.button Widget.widget;
Packit bd2e5d
      mw_edit: Widget.button Widget.widget;
Packit bd2e5d
      mw_intf: Widget.button Widget.widget }
Packit bd2e5d
Packit bd2e5d
let shown_modules = Hashtbl.create 17
Packit bd2e5d
let default_frame = ref None
Packit bd2e5d
let set_path = ref (fun _ ~sign -> assert false)
Packit bd2e5d
let filter_modules () =
Packit bd2e5d
  Hashtbl.iter
Packit bd2e5d
    (fun key data ->
Packit bd2e5d
      if not (Winfo.exists data.mw_frame) then
Packit bd2e5d
        Hashtbl.remove shown_modules key)
Packit bd2e5d
    shown_modules
Packit bd2e5d
let add_shown_module path ~widgets =
Packit bd2e5d
  Hashtbl.add shown_modules path widgets
Packit bd2e5d
let find_shown_module path =
Packit bd2e5d
  try
Packit bd2e5d
    filter_modules ();
Packit bd2e5d
    Hashtbl.find shown_modules path
Packit bd2e5d
  with Not_found ->
Packit bd2e5d
    match !default_frame with
Packit bd2e5d
      None -> raise Not_found
Packit bd2e5d
    | Some mw -> mw
Packit bd2e5d
Packit bd2e5d
let is_shown_module path =
Packit bd2e5d
  !default_frame <> None ||
Packit bd2e5d
  (filter_modules (); Hashtbl.mem shown_modules path)
Packit bd2e5d
Packit bd2e5d
(* Viewing a signature *)
Packit bd2e5d
Packit bd2e5d
(* Forward definitions of Viewer.view_defined and Editor.editor *)
Packit bd2e5d
let view_defined_ref = ref (fun lid ~env -> ())
Packit bd2e5d
let editor_ref = ref (fun ?file ?pos ?opendialog () -> ())
Packit bd2e5d
Packit bd2e5d
let edit_source ~file ~path ~sign =
Packit bd2e5d
  match sign with
Packit bd2e5d
    [item] ->
Packit bd2e5d
      let id, kind =
Packit bd2e5d
        match item with
Packit bd2e5d
          Sig_value (id, _) -> id, Pvalue
Packit bd2e5d
        | Sig_type (id, _, _) -> id, Ptype
Packit bd2e5d
        | Sig_typext (id, _, _) -> id, Pconstructor
Packit bd2e5d
        | Sig_module (id, _, _) -> id, Pmodule
Packit bd2e5d
        | Sig_modtype (id, _) -> id, Pmodtype
Packit bd2e5d
        | Sig_class (id, _, _) -> id, Pclass
Packit bd2e5d
        | Sig_class_type (id, _, _) -> id, Pcltype
Packit bd2e5d
      in
Packit bd2e5d
      let prefix = List.tl (list_of_path path) and name = Ident.name id in
Packit bd2e5d
      let pos =
Packit bd2e5d
        try
Packit bd2e5d
          let chan = open_in file in
Packit bd2e5d
          if Filename.check_suffix file ".ml" then
Packit bd2e5d
            let parsed = Parse.implementation (Lexing.from_channel chan) in
Packit bd2e5d
            close_in chan;
Packit bd2e5d
            Searchid.search_structure parsed ~name ~kind ~prefix
Packit bd2e5d
          else
Packit bd2e5d
            let parsed = Parse.interface (Lexing.from_channel chan) in
Packit bd2e5d
            close_in chan;
Packit bd2e5d
            Searchid.search_signature parsed ~name ~kind ~prefix
Packit bd2e5d
        with _ -> 0
Packit bd2e5d
      in !editor_ref ~file ~pos ()
Packit bd2e5d
  | _ -> !editor_ref ~file ()
Packit bd2e5d
Packit bd2e5d
(* List of windows to destroy by Close All *)
Packit bd2e5d
let top_widgets = ref []
Packit bd2e5d
Packit bd2e5d
let dummy_item =
Packit bd2e5d
  Sig_modtype (Ident.create "dummy",
Packit bd2e5d
               {mtd_type=None; mtd_attributes=[]; mtd_loc=Location.none})
Packit bd2e5d
Packit bd2e5d
let rec view_signature ?title ?path ?(env = !start_env) ?(detach=false) sign =
Packit bd2e5d
  let env =
Packit bd2e5d
    match path with None -> env
Packit bd2e5d
    | Some path ->
Packit bd2e5d
        match Env.open_signature Fresh path env with None -> env
Packit bd2e5d
        | Some env -> env
Packit bd2e5d
  in
Packit bd2e5d
  let title =
Packit bd2e5d
    match title, path with Some title, _ -> title
Packit bd2e5d
    | None, Some path -> string_of_path path
Packit bd2e5d
    | None, None -> "Signature"
Packit bd2e5d
  in
Packit bd2e5d
  let tl, tw, finish =
Packit bd2e5d
    try match path, !default_frame with
Packit bd2e5d
      None, Some ({mw_title=Some label} as mw) when not detach ->
Packit bd2e5d
        Button.configure mw.mw_detach
Packit bd2e5d
          ~command:(fun () -> view_signature sign ~title ~env ~detach:true);
Packit bd2e5d
        pack [mw.mw_detach] ~side:`Left;
Packit bd2e5d
        Pack.forget [mw.mw_edit; mw.mw_intf];
Packit bd2e5d
        List.iter ~f:destroy (Winfo.children mw.mw_frame);
Packit bd2e5d
        Label.configure label ~text:title;
Packit bd2e5d
        pack [label] ~fill:`X ~side:`Bottom;
Packit bd2e5d
        Jg_message.formatted ~title ~on:mw.mw_frame ~maxheight:15 ()
Packit bd2e5d
    | None, _ -> raise Not_found
Packit bd2e5d
    | Some path, _ ->
Packit bd2e5d
        let mw =
Packit bd2e5d
          try find_shown_module path
Packit bd2e5d
          with Not_found ->
Packit bd2e5d
            view_module path ~env;
Packit bd2e5d
            find_shown_module path
Packit bd2e5d
        in
Packit bd2e5d
        (try !set_path path ~sign with _ -> ());
Packit bd2e5d
        begin match mw.mw_title with None -> ()
Packit bd2e5d
        | Some label ->
Packit bd2e5d
            Label.configure label ~text:title;
Packit bd2e5d
            pack [label] ~fill:`X ~side:`Bottom
Packit bd2e5d
        end;
Packit bd2e5d
        Button.configure mw.mw_detach
Packit bd2e5d
          ~command:(fun () -> view_signature sign ~title ~env ~detach:true);
Packit bd2e5d
        pack [mw.mw_detach] ~side:`Left;
Packit bd2e5d
        let repack = ref false in
Packit bd2e5d
        List.iter2 [mw.mw_edit; mw.mw_intf] [".ml"; ".mli"] ~f:
Packit bd2e5d
          begin fun button ext ->
Packit bd2e5d
            try
Packit bd2e5d
              let id = head_id path in
Packit bd2e5d
              let file =
Packit bd2e5d
                Misc.find_in_path_uncap !Config.load_path
Packit bd2e5d
                  ((Ident.name id) ^ ext) in
Packit bd2e5d
              Button.configure button
Packit bd2e5d
                ~command:(fun () -> edit_source ~file ~path ~sign);
Packit bd2e5d
              if !repack then Pack.forget [button] else
Packit bd2e5d
              if not (Winfo.viewable button) then repack := true;
Packit bd2e5d
              pack [button] ~side:`Left
Packit bd2e5d
            with Not_found ->
Packit bd2e5d
              Pack.forget [button]
Packit bd2e5d
          end;
Packit bd2e5d
        let top = Winfo.toplevel mw.mw_frame in
Packit bd2e5d
        if not (Winfo.ismapped top) then Wm.deiconify top;
Packit bd2e5d
        List.iter ~f:destroy (Winfo.children mw.mw_frame);
Packit bd2e5d
        Jg_message.formatted ~title ~on:mw.mw_frame ~maxheight:15 ()
Packit bd2e5d
    with Not_found ->
Packit bd2e5d
      let tl, tw, finish = Jg_message.formatted ~title ~maxheight:15 () in
Packit bd2e5d
      top_widgets := tl :: !top_widgets;
Packit bd2e5d
      tl, tw, finish
Packit bd2e5d
  in
Packit bd2e5d
  Format.set_max_boxes 100;
Packit bd2e5d
  Printtyp.wrap_printing_env env
Packit bd2e5d
    (fun () -> Printtyp.signature Format.std_formatter sign);
Packit bd2e5d
  finish ();
Packit bd2e5d
  Lexical.init_tags tw;
Packit bd2e5d
  Lexical.tag tw;
Packit bd2e5d
  Text.configure tw ~state:`Disabled;
Packit bd2e5d
  let text = Jg_text.get_all tw in
Packit bd2e5d
  let pt =
Packit bd2e5d
      try Parse.interface (Lexing.from_string text)
Packit bd2e5d
      with Syntaxerr.Error e ->
Packit bd2e5d
        let l = Syntaxerr.location_of_error e in
Packit bd2e5d
        Jg_text.tag_and_see  tw ~start:(tpos l.loc_start.Lexing.pos_cnum)
Packit bd2e5d
          ~stop:(tpos l.loc_end.Lexing.pos_cnum) ~tag:"error"; []
Packit bd2e5d
      | Lexer.Error (_, l) ->
Packit bd2e5d
         let s = l.loc_start.Lexing.pos_cnum in
Packit bd2e5d
         let e = l.loc_end.Lexing.pos_cnum in
Packit bd2e5d
         Jg_text.tag_and_see tw ~start:(tpos s) ~stop:(tpos e) ~tag:"error"; []
Packit bd2e5d
  in
Packit bd2e5d
  Jg_bind.enter_focus tw;
Packit bd2e5d
  bind tw ~events:[`Modified([`Control], `KeyPressDetail"s")]
Packit bd2e5d
    ~action:(fun _ -> Jg_text.search_string tw);
Packit bd2e5d
  bind tw ~events:[`Modified([`Double], `ButtonPressDetail 1)]
Packit bd2e5d
    ~fields:[`MouseX;`MouseY] ~breakable:true
Packit bd2e5d
    ~action:(fun ev ->
Packit bd2e5d
      let `Linechar (l, c) =
Packit bd2e5d
        Text.index tw ~index:(`Atxy(ev.ev_MouseX,ev.ev_MouseY), []) in
Packit bd2e5d
      try
Packit bd2e5d
        match search_pos_signature pt ~pos:(lines_to_chars l ~text + c) ~env
Packit bd2e5d
        with [] -> break ()
Packit bd2e5d
        | ((kind, lid), env, loc) :: _ -> view_decl lid ~kind ~env
Packit bd2e5d
      with Not_found | Env.Error _ -> ());
Packit bd2e5d
  bind tw ~events:[`ButtonPressDetail 3] ~breakable:true
Packit bd2e5d
    ~fields:[`MouseX;`MouseY]
Packit bd2e5d
    ~action:(fun ev ->
Packit bd2e5d
      let x = ev.ev_MouseX and y = ev.ev_MouseY in
Packit bd2e5d
      let `Linechar (l, c) =
Packit bd2e5d
        Text.index tw ~index:(`Atxy(x,y), []) in
Packit bd2e5d
      try
Packit bd2e5d
        match search_pos_signature pt ~pos:(lines_to_chars l ~text + c) ~env
Packit bd2e5d
        with [] -> break ()
Packit bd2e5d
        | ((kind, lid), env, loc) :: _ ->
Packit bd2e5d
            let menu = view_decl_menu lid ~kind ~env ~parent:tw in
Packit bd2e5d
            let x = x + Winfo.rootx tw and y = y + Winfo.rooty tw - 10 in
Packit bd2e5d
            Menu.popup menu ~x ~y
Packit bd2e5d
      with Not_found -> ())
Packit bd2e5d
Packit bd2e5d
and view_signature_item sign ~path ~env =
Packit bd2e5d
  view_signature sign ~title:(string_of_path path)
Packit bd2e5d
    ?path:(parent_path path) ~env
Packit bd2e5d
Packit bd2e5d
and view_module path ~env =
Packit bd2e5d
  match find_module path env with
Packit bd2e5d
    {md_type=Mty_signature sign} ->
Packit bd2e5d
      !view_defined_ref (Searchid.longident_of_path path) ~env
Packit bd2e5d
  | modtype ->
Packit bd2e5d
      let id = ident_of_path path ~default:"M" in
Packit bd2e5d
      view_signature_item [Sig_module (id, modtype, Trec_not)] ~path ~env
Packit bd2e5d
Packit bd2e5d
and view_module_id id ~env =
Packit bd2e5d
  let path = lookup_module ~load:true id env in
Packit bd2e5d
  view_module path ~env
Packit bd2e5d
Packit bd2e5d
and view_type_decl path ~env =
Packit bd2e5d
  let td = find_type path env in
Packit bd2e5d
  try match td.type_manifest with None -> raise Not_found
Packit bd2e5d
    | Some ty -> match Ctype.repr ty with
Packit bd2e5d
        {desc = Tobject _} ->
Packit bd2e5d
          let clt = find_cltype path env in
Packit bd2e5d
          view_signature_item ~path ~env
Packit bd2e5d
            [Sig_class_type(ident_of_path path ~default:"ct", clt, Trec_first);
Packit bd2e5d
             dummy_item; dummy_item]
Packit bd2e5d
      | _ -> raise Not_found
Packit bd2e5d
  with Not_found ->
Packit bd2e5d
    view_signature_item ~path ~env
Packit bd2e5d
      [Sig_type(ident_of_path path ~default:"t", td, Trec_first)]
Packit bd2e5d
Packit bd2e5d
and view_type_id li ~env =
Packit bd2e5d
  let path = lookup_type li env in
Packit bd2e5d
  view_type_decl path ~env
Packit bd2e5d
Packit bd2e5d
and view_class_id li ~env =
Packit bd2e5d
  let path, cl = lookup_class li env in
Packit bd2e5d
  view_signature_item ~path ~env
Packit bd2e5d
     [Sig_class(ident_of_path path ~default:"c", cl, Trec_first);
Packit bd2e5d
      dummy_item; dummy_item; dummy_item]
Packit bd2e5d
Packit bd2e5d
and view_cltype_id li ~env =
Packit bd2e5d
  let path, clt = lookup_cltype li env in
Packit bd2e5d
  view_signature_item ~path ~env
Packit bd2e5d
     [Sig_class_type(ident_of_path path ~default:"ct", clt, Trec_first);
Packit bd2e5d
      dummy_item; dummy_item]
Packit bd2e5d
Packit bd2e5d
and view_modtype_id li ~env =
Packit bd2e5d
  let path, td = lookup_modtype li env in
Packit bd2e5d
  view_signature_item ~path ~env
Packit bd2e5d
    [Sig_modtype(ident_of_path path ~default:"S", td)]
Packit bd2e5d
Packit bd2e5d
and view_expr_type ?title ?path ?env ?(name="noname") t =
Packit bd2e5d
  let title =
Packit bd2e5d
    match title, path with Some title, _ -> title
Packit bd2e5d
    | None, Some path -> string_of_path path
Packit bd2e5d
    | None, None -> "Expression type"
Packit bd2e5d
  and path, id =
Packit bd2e5d
    match path with None -> None, Ident.create name
Packit bd2e5d
    | Some path -> parent_path path, ident_of_path path ~default:name
Packit bd2e5d
  in
Packit bd2e5d
  view_signature ~title ?path ?env
Packit bd2e5d
    [Sig_value (id, {val_type = t; val_kind = Val_reg; val_attributes=[];
Packit bd2e5d
                     val_loc = Location.none})]
Packit bd2e5d
Packit bd2e5d
and view_decl lid ~kind ~env =
Packit bd2e5d
  match kind with
Packit bd2e5d
    `Type -> view_type_id lid ~env
Packit bd2e5d
  | `Class -> view_class_id lid ~env
Packit bd2e5d
  | `Module -> view_module_id lid ~env
Packit bd2e5d
  | `Modtype -> view_modtype_id lid ~env
Packit bd2e5d
Packit bd2e5d
and view_decl_menu lid ~kind ~env ~parent =
Packit bd2e5d
  let path, kname =
Packit bd2e5d
    try match kind with
Packit bd2e5d
      `Type -> lookup_type lid env, "Type"
Packit bd2e5d
    | `Class -> fst (lookup_class lid env), "Class"
Packit bd2e5d
    | `Module -> lookup_module ~load:true lid env, "Module"
Packit bd2e5d
    | `Modtype -> fst (lookup_modtype lid env), "Module type"
Packit bd2e5d
    with Env.Error _ -> raise Not_found
Packit bd2e5d
  in
Packit bd2e5d
  let menu = Menu.create parent ~tearoff:false in
Packit bd2e5d
  let label = kname ^ " " ^ string_of_path path in
Packit bd2e5d
  begin match path with
Packit bd2e5d
    Pident _ ->
Packit bd2e5d
      Menu.add_command menu ~label ~state:`Disabled
Packit bd2e5d
  | _ ->
Packit bd2e5d
      Menu.add_command menu ~label
Packit bd2e5d
        ~command:(fun () -> view_decl lid ~kind ~env);
Packit bd2e5d
  end;
Packit bd2e5d
  if kind = `Type || kind = `Modtype then begin
Packit bd2e5d
    let buf = new buffer ~size:60 in
Packit bd2e5d
    let (fo,ff) = Format.get_formatter_output_functions ()
Packit bd2e5d
    and margin = Format.get_margin () in
Packit bd2e5d
    Format.set_formatter_output_functions buf#out (fun () -> ());
Packit bd2e5d
    Format.set_margin 60;
Packit bd2e5d
    Format.open_hbox ();
Packit bd2e5d
    Printtyp.wrap_printing_env env begin fun () ->
Packit bd2e5d
      if kind = `Type then
Packit bd2e5d
        Printtyp.type_declaration
Packit bd2e5d
          (ident_of_path path ~default:"t")
Packit bd2e5d
          Format.std_formatter
Packit bd2e5d
          (find_type path env)
Packit bd2e5d
      else
Packit bd2e5d
        Printtyp.modtype_declaration
Packit bd2e5d
          (ident_of_path path ~default:"S")
Packit bd2e5d
          Format.std_formatter
Packit bd2e5d
          (find_modtype path env)
Packit bd2e5d
    end;
Packit bd2e5d
    Format.close_box (); Format.print_flush ();
Packit bd2e5d
    Format.set_formatter_output_functions fo ff;
Packit bd2e5d
    Format.set_margin margin;
Packit bd2e5d
    let l = Str.split ~!"\n" buf#get in
Packit bd2e5d
    let font =
Packit bd2e5d
      let font =
Packit bd2e5d
        Option.get Widget.default_toplevel ~name:"font" ~clas:"Font" in
Packit bd2e5d
      if font = "" then "7x14" else font
Packit bd2e5d
    in
Packit bd2e5d
    (* Menu.add_separator menu; *)
Packit bd2e5d
    List.iter l
Packit bd2e5d
      ~f:(fun label -> Menu.add_command menu ~label ~font ~state:`Disabled)
Packit bd2e5d
  end;
Packit bd2e5d
  menu
Packit bd2e5d
Packit bd2e5d
(* search and view in a structure *)
Packit bd2e5d
Packit bd2e5d
type fkind = [
Packit bd2e5d
    `Exp of
Packit bd2e5d
      [`Expr|`Pat|`Const|`Val of Path.t|`Var of Path.t|`New of Path.t]
Packit bd2e5d
        * type_expr
Packit bd2e5d
  | `Class of Path.t * class_type
Packit bd2e5d
  | `Module of Path.t * module_type
Packit bd2e5d
]
Packit bd2e5d
Packit bd2e5d
let view_type kind ~env =
Packit bd2e5d
  match kind with
Packit bd2e5d
    `Exp (k, ty) ->
Packit bd2e5d
      begin match k with
Packit bd2e5d
        `Expr -> view_expr_type ty ~title:"Expression type" ~env
Packit bd2e5d
      | `Pat -> view_expr_type ty ~title:"Pattern type" ~env
Packit bd2e5d
      | `Const -> view_expr_type ty ~title:"Constant type" ~env
Packit bd2e5d
      | `Val path ->
Packit bd2e5d
          begin try
Packit bd2e5d
            let vd = find_value path env in
Packit bd2e5d
            view_signature_item ~path ~env
Packit bd2e5d
              [Sig_value(ident_of_path path ~default:"v", vd)]
Packit bd2e5d
          with Not_found ->
Packit bd2e5d
            view_expr_type ty ~path ~env
Packit bd2e5d
          end
Packit bd2e5d
      | `Var path ->
Packit bd2e5d
          let vd = find_value path env in
Packit bd2e5d
          view_expr_type vd.val_type ~env ~path ~title:"Variable type"
Packit bd2e5d
      | `New path ->
Packit bd2e5d
          let cl = find_class path env in
Packit bd2e5d
          view_signature_item ~path ~env
Packit bd2e5d
            [Sig_class(ident_of_path path ~default:"c", cl, Trec_first)]
Packit bd2e5d
      end
Packit bd2e5d
  | `Class (path, cty) ->
Packit bd2e5d
      let cld = { cty_params = []; cty_variance = []; cty_type = cty;
Packit bd2e5d
                  cty_path = path; cty_new = None; cty_loc = Location.none;
Packit bd2e5d
                  cty_attributes = []} in
Packit bd2e5d
      view_signature_item ~path ~env
Packit bd2e5d
        [Sig_class(ident_of_path path ~default:"c", cld, Trec_first)]
Packit bd2e5d
  | `Module (path, mty) ->
Packit bd2e5d
      match mty with
Packit bd2e5d
        Mty_signature sign -> view_signature sign ~path ~env
Packit bd2e5d
      | modtype ->
Packit bd2e5d
          let md =
Packit bd2e5d
	    {md_type = mty; md_attributes = []; md_loc = Location.none} in
Packit bd2e5d
          view_signature_item ~path ~env
Packit bd2e5d
            [Sig_module(ident_of_path path ~default:"M", md, Trec_not)]
Packit bd2e5d
Packit bd2e5d
let view_type_menu kind ~env ~parent =
Packit bd2e5d
  let title =
Packit bd2e5d
    match kind with
Packit bd2e5d
      `Exp (`Expr,_) -> "Expression :"
Packit bd2e5d
    | `Exp (`Pat, _) -> "Pattern :"
Packit bd2e5d
    | `Exp (`Const, _) -> "Constant :"
Packit bd2e5d
    | `Exp (`Val path, _) -> "Value " ^ string_of_path path ^ " :"
Packit bd2e5d
    | `Exp (`Var path, _) ->
Packit bd2e5d
        "Variable " ^ Ident.name (ident_of_path path ~default:"noname") ^ " :"
Packit bd2e5d
    | `Exp (`New path, _) -> "Class " ^ string_of_path path ^ " :"
Packit bd2e5d
    | `Class (path, _) -> "Class " ^ string_of_path path ^ " :"
Packit bd2e5d
    | `Module (path,_) -> "Module " ^ string_of_path path in
Packit bd2e5d
  let menu = Menu.create parent ~tearoff:false in
Packit bd2e5d
  begin match kind with
Packit bd2e5d
    `Exp((`Expr | `Pat | `Const | `Val (Pident _)),_)  ->
Packit bd2e5d
      Menu.add_command menu ~label:title ~state:`Disabled
Packit bd2e5d
  | `Exp _ | `Class _ | `Module _ ->
Packit bd2e5d
      Menu.add_command menu ~label:title
Packit bd2e5d
        ~command:(fun () -> view_type kind ~env)
Packit bd2e5d
  end;
Packit bd2e5d
  begin match kind with `Module _ | `Class _ -> ()
Packit bd2e5d
  | `Exp(_, ty) ->
Packit bd2e5d
      let buf = new buffer ~size:60 in
Packit bd2e5d
      let (fo,ff) = Format.get_formatter_output_functions ()
Packit bd2e5d
      and margin = Format.get_margin () in
Packit bd2e5d
      Format.set_formatter_output_functions buf#out ignore;
Packit bd2e5d
      Format.set_margin 60;
Packit bd2e5d
      Format.open_hbox ();
Packit bd2e5d
      Printtyp.reset ();
Packit bd2e5d
      Printtyp.mark_loops ty;
Packit bd2e5d
      Printtyp.wrap_printing_env env
Packit bd2e5d
        (fun () -> Printtyp.type_expr Format.std_formatter ty);
Packit bd2e5d
      Format.close_box (); Format.print_flush ();
Packit bd2e5d
      Format.set_formatter_output_functions fo ff;
Packit bd2e5d
      Format.set_margin margin;
Packit bd2e5d
      let l = Str.split ~!"\n" buf#get in
Packit bd2e5d
      let font =
Packit bd2e5d
        let font =
Packit bd2e5d
          Option.get Widget.default_toplevel ~name:"font" ~clas:"Font" in
Packit bd2e5d
        if font = "" then "7x14" else font
Packit bd2e5d
      in
Packit bd2e5d
      (* Menu.add_separator menu; *)
Packit bd2e5d
      List.iter l ~f:
Packit bd2e5d
        begin fun label -> match (Ctype.repr ty).desc with
Packit bd2e5d
          Tconstr (path,_,_) ->
Packit bd2e5d
            Menu.add_command menu ~label ~font
Packit bd2e5d
              ~command:(fun () -> view_type_decl path ~env)
Packit bd2e5d
        | Tvariant {row_name = Some (path, _)} ->
Packit bd2e5d
            Menu.add_command menu ~label ~font
Packit bd2e5d
              ~command:(fun () -> view_type_decl path ~env)
Packit bd2e5d
        | _ ->
Packit bd2e5d
            Menu.add_command menu ~label ~font ~state:`Disabled
Packit bd2e5d
        end
Packit bd2e5d
  end;
Packit bd2e5d
  menu
Packit bd2e5d
Packit bd2e5d
let found_str = ref ([] : (fkind * Env.t * Location.t) list)
Packit bd2e5d
let add_found_str = add_found ~found:found_str
Packit bd2e5d
Packit bd2e5d
let rec search_pos_structure ~pos str =
Packit bd2e5d
  List.iter str ~f:
Packit bd2e5d
  begin function str -> match str.str_desc with
Packit bd2e5d
    Tstr_eval (exp, _) -> search_pos_expr exp ~pos
Packit bd2e5d
  | Tstr_value (rec_flag, l) ->
Packit bd2e5d
      List.iter l ~f:
Packit bd2e5d
      begin fun {vb_pat=pat;vb_expr=exp} ->
Packit bd2e5d
        let env =
Packit bd2e5d
          if rec_flag = Asttypes.Recursive then exp.exp_env else Env.empty in
Packit bd2e5d
        search_pos_pat pat ~pos ~env;
Packit bd2e5d
        search_pos_expr exp ~pos
Packit bd2e5d
      end
Packit bd2e5d
  | Tstr_module mb -> search_pos_module_expr mb.mb_expr ~pos
Packit bd2e5d
  | Tstr_recmodule bindings ->
Packit bd2e5d
      List.iter bindings ~f:(fun mb -> search_pos_module_expr mb.mb_expr ~pos)
Packit bd2e5d
  | Tstr_class l ->
Packit bd2e5d
      List.iter l ~f:(fun (ci, _) -> search_pos_class_expr ci.ci_expr ~pos)
Packit bd2e5d
  | Tstr_include {incl_mod=m} -> search_pos_module_expr m ~pos
Packit bd2e5d
  | Tstr_primitive _
Packit bd2e5d
  | Tstr_type _
Packit bd2e5d
  | Tstr_typext _
Packit bd2e5d
  | Tstr_exception _
Packit bd2e5d
  | Tstr_modtype _
Packit bd2e5d
  | Tstr_open _
Packit bd2e5d
  | Tstr_class_type _
Packit bd2e5d
  | Tstr_attribute _
Packit bd2e5d
    -> ()
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
and search_pos_class_structure ~pos cls =
Packit bd2e5d
  List.iter cls.cstr_fields ~f:
Packit bd2e5d
    begin function cf -> match cf.cf_desc with
Packit bd2e5d
        Tcf_inherit (_, cl, _, _, _) ->
Packit bd2e5d
          search_pos_class_expr cl ~pos
Packit bd2e5d
      | Tcf_val (_, _, _, Tcfk_concrete (_, exp), _) -> search_pos_expr exp ~pos
Packit bd2e5d
      | Tcf_val _ -> ()
Packit bd2e5d
      | Tcf_method (_, _, Tcfk_concrete (_, exp)) -> search_pos_expr exp ~pos
Packit bd2e5d
      | Tcf_initializer exp -> search_pos_expr exp ~pos
Packit bd2e5d
      | Tcf_constraint _
Packit bd2e5d
      | Tcf_attribute _
Packit bd2e5d
      | Tcf_method _
Packit bd2e5d
        -> () (* TODO !!!!!!!!!!!!!!!!! *)
Packit bd2e5d
    end
Packit bd2e5d
Packit bd2e5d
and search_pos_class_expr ~pos cl =
Packit bd2e5d
  if in_loc cl.cl_loc ~pos then begin
Packit bd2e5d
    begin match cl.cl_desc with
Packit bd2e5d
      Tcl_ident (path, _, _) ->
Packit bd2e5d
        add_found_str (`Class (path, cl.cl_type))
Packit bd2e5d
          ~env:!start_env ~loc:cl.cl_loc
Packit bd2e5d
    | Tcl_structure cls ->
Packit bd2e5d
        search_pos_class_structure ~pos cls
Packit bd2e5d
    | Tcl_fun (_, pat, iel, cl, _) ->
Packit bd2e5d
        search_pos_pat pat ~pos ~env:pat.pat_env;
Packit bd2e5d
        List.iter iel ~f:(fun (_,_, exp) -> search_pos_expr exp ~pos);
Packit bd2e5d
        search_pos_class_expr cl ~pos
Packit bd2e5d
    | Tcl_apply (cl, el) ->
Packit bd2e5d
        search_pos_class_expr cl ~pos;
Packit bd2e5d
        List.iter el ~f:(fun (_, x) -> Misc.may (search_pos_expr ~pos) x)
Packit bd2e5d
    | Tcl_let (_, pel, iel, cl) ->
Packit bd2e5d
        List.iter pel ~f:
Packit bd2e5d
          begin fun {vb_pat=pat; vb_expr=exp} ->
Packit bd2e5d
            search_pos_pat pat ~pos ~env:exp.exp_env;
Packit bd2e5d
            search_pos_expr exp ~pos
Packit bd2e5d
          end;
Packit bd2e5d
        List.iter iel ~f:(fun (_,_, exp) -> search_pos_expr exp ~pos);
Packit bd2e5d
        search_pos_class_expr cl ~pos
Packit bd2e5d
    | Tcl_open (_, _, _, _, cl)
Packit bd2e5d
    | Tcl_constraint (cl, _, _, _, _) ->
Packit bd2e5d
        search_pos_class_expr cl ~pos
Packit bd2e5d
    end;
Packit bd2e5d
    add_found_str (`Class (Pident (Ident.create "c"), cl.cl_type))
Packit bd2e5d
      ~env:!start_env ~loc:cl.cl_loc
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
and search_case ~pos {c_lhs; c_guard; c_rhs} =
Packit bd2e5d
  search_pos_pat c_lhs ~pos ~env:c_rhs.exp_env;
Packit bd2e5d
  begin match c_guard with
Packit bd2e5d
  | None -> ()
Packit bd2e5d
  | Some g -> search_pos_expr g ~pos
Packit bd2e5d
  end;
Packit bd2e5d
  search_pos_expr c_rhs ~pos
Packit bd2e5d
Packit bd2e5d
and search_pos_expr ~pos exp =
Packit bd2e5d
  if in_loc exp.exp_loc ~pos then begin
Packit bd2e5d
  begin match exp.exp_desc with
Packit bd2e5d
    Texp_ident (path, _, _) ->
Packit bd2e5d
      add_found_str (`Exp(`Val path, exp.exp_type))
Packit bd2e5d
        ~env:exp.exp_env ~loc:exp.exp_loc
Packit bd2e5d
  | Texp_constant v ->
Packit bd2e5d
      add_found_str (`Exp(`Const, exp.exp_type))
Packit bd2e5d
        ~env:exp.exp_env ~loc:exp.exp_loc
Packit bd2e5d
  | Texp_let (_, expl, exp) ->
Packit bd2e5d
      List.iter expl ~f:
Packit bd2e5d
      begin fun {vb_pat=pat; vb_expr=exp'} ->
Packit bd2e5d
        search_pos_pat pat ~pos ~env:exp.exp_env;
Packit bd2e5d
        search_pos_expr exp' ~pos
Packit bd2e5d
      end;
Packit bd2e5d
      search_pos_expr exp ~pos
Packit bd2e5d
  | Texp_function {cases=l; _} ->
Packit bd2e5d
      List.iter l ~f:(search_case ~pos)
Packit bd2e5d
  | Texp_apply (exp, l) ->
Packit bd2e5d
      List.iter l ~f:(fun (_, x) -> Misc.may (search_pos_expr ~pos) x);
Packit bd2e5d
      search_pos_expr exp ~pos
Packit bd2e5d
  | Texp_match (exp, l, _, _) ->
Packit bd2e5d
      search_pos_expr exp ~pos;
Packit bd2e5d
      List.iter l ~f:(search_case ~pos)
Packit bd2e5d
  | Texp_try (exp, l) ->
Packit bd2e5d
      search_pos_expr exp ~pos;
Packit bd2e5d
      List.iter l ~f:(search_case ~pos)
Packit bd2e5d
  | Texp_tuple l -> List.iter l ~f:(search_pos_expr ~pos)
Packit bd2e5d
  | Texp_construct (_, _, l) -> List.iter l ~f:(search_pos_expr ~pos)
Packit bd2e5d
  | Texp_variant (_, None) -> ()
Packit bd2e5d
  | Texp_variant (_, Some exp) -> search_pos_expr exp ~pos
Packit bd2e5d
  | Texp_record {fields=l; extended_expression=opt} ->
Packit bd2e5d
      Array.iter l ~f:
Packit bd2e5d
        (function (_,Overridden(_,exp)) -> search_pos_expr exp ~pos | _ -> ());
Packit bd2e5d
      (match opt with None -> () | Some exp -> search_pos_expr exp ~pos)
Packit bd2e5d
  | Texp_field (exp, _, _) -> search_pos_expr exp ~pos
Packit bd2e5d
  | Texp_setfield (a, _, _, b) ->
Packit bd2e5d
      search_pos_expr a ~pos; search_pos_expr b ~pos
Packit bd2e5d
  | Texp_array l -> List.iter l ~f:(search_pos_expr ~pos)
Packit bd2e5d
  | Texp_ifthenelse (a, b, c) ->
Packit bd2e5d
      search_pos_expr a ~pos; search_pos_expr b ~pos;
Packit bd2e5d
      begin match c with None -> ()
Packit bd2e5d
      | Some exp -> search_pos_expr exp ~pos
Packit bd2e5d
      end
Packit bd2e5d
  | Texp_sequence (a,b) ->
Packit bd2e5d
      search_pos_expr a ~pos; search_pos_expr b ~pos
Packit bd2e5d
  | Texp_while (a,b) ->
Packit bd2e5d
      search_pos_expr a ~pos; search_pos_expr b ~pos
Packit bd2e5d
  | Texp_for (_, _, a, b, _, c) ->
Packit bd2e5d
      List.iter [a;b;c] ~f:(search_pos_expr ~pos)
Packit bd2e5d
  | Texp_send (exp, _, _) -> search_pos_expr exp ~pos
Packit bd2e5d
  | Texp_new (path, _, _) ->
Packit bd2e5d
      add_found_str (`Exp(`New path, exp.exp_type))
Packit bd2e5d
        ~env:exp.exp_env ~loc:exp.exp_loc
Packit bd2e5d
  | Texp_instvar (_, path, _) ->
Packit bd2e5d
      add_found_str (`Exp(`Var path, exp.exp_type))
Packit bd2e5d
        ~env:exp.exp_env ~loc:exp.exp_loc
Packit bd2e5d
  | Texp_setinstvar (_, path, _, exp) ->
Packit bd2e5d
      search_pos_expr exp ~pos;
Packit bd2e5d
      add_found_str (`Exp(`Var path, exp.exp_type))
Packit bd2e5d
        ~env:exp.exp_env ~loc:exp.exp_loc
Packit bd2e5d
  | Texp_override (_, l) ->
Packit bd2e5d
      List.iter l ~f:(fun (_, _, exp) -> search_pos_expr exp ~pos)
Packit bd2e5d
  | Texp_letmodule (id, _, modexp, exp) ->
Packit bd2e5d
      search_pos_module_expr modexp ~pos;
Packit bd2e5d
      search_pos_expr exp ~pos
Packit bd2e5d
  | Texp_assert exp ->
Packit bd2e5d
      search_pos_expr exp ~pos
Packit bd2e5d
  | Texp_lazy exp ->
Packit bd2e5d
      search_pos_expr exp ~pos
Packit bd2e5d
  | Texp_object (cls, _) ->
Packit bd2e5d
      search_pos_class_structure ~pos cls
Packit bd2e5d
  | Texp_pack modexp ->
Packit bd2e5d
      search_pos_module_expr modexp ~pos
Packit bd2e5d
  | Texp_unreachable ->
Packit bd2e5d
      ()
Packit bd2e5d
  | Texp_extension_constructor _ ->
Packit bd2e5d
      ()
Packit bd2e5d
  | Texp_letexception (_, exp) ->
Packit bd2e5d
      search_pos_expr exp ~pos
Packit bd2e5d
  end;
Packit bd2e5d
  add_found_str (`Exp(`Expr, exp.exp_type)) ~env:exp.exp_env ~loc:exp.exp_loc
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
and search_pos_pat ~pos ~env pat =
Packit bd2e5d
  if in_loc pat.pat_loc ~pos then begin
Packit bd2e5d
  begin match pat.pat_desc with
Packit bd2e5d
    Tpat_any -> ()
Packit bd2e5d
  | Tpat_var (id, _) ->
Packit bd2e5d
      add_found_str (`Exp(`Val (Pident id), pat.pat_type))
Packit bd2e5d
        ~env ~loc:pat.pat_loc
Packit bd2e5d
  | Tpat_alias (pat, _, _) -> search_pos_pat pat ~pos ~env
Packit bd2e5d
  | Tpat_lazy pat -> search_pos_pat pat ~pos ~env
Packit bd2e5d
  | Tpat_constant _ ->
Packit bd2e5d
      add_found_str (`Exp(`Const, pat.pat_type)) ~env ~loc:pat.pat_loc
Packit bd2e5d
  | Tpat_tuple l ->
Packit bd2e5d
      List.iter l ~f:(search_pos_pat ~pos ~env)
Packit bd2e5d
  | Tpat_construct (_, _, l) ->
Packit bd2e5d
      List.iter l ~f:(search_pos_pat ~pos ~env)
Packit bd2e5d
  | Tpat_variant (_, None, _) -> ()
Packit bd2e5d
  | Tpat_variant (_, Some pat, _) -> search_pos_pat pat ~pos ~env
Packit bd2e5d
  | Tpat_record (l, _) ->
Packit bd2e5d
      List.iter l ~f:(fun (_, _, pat) -> search_pos_pat pat ~pos ~env)
Packit bd2e5d
  | Tpat_array l ->
Packit bd2e5d
      List.iter l ~f:(search_pos_pat ~pos ~env)
Packit bd2e5d
  | Tpat_or (a, b, None) ->
Packit bd2e5d
      search_pos_pat a ~pos ~env; search_pos_pat b ~pos ~env
Packit bd2e5d
  | Tpat_or (_, _, Some _) ->
Packit bd2e5d
      ()
Packit bd2e5d
  end;
Packit bd2e5d
  add_found_str (`Exp(`Pat, pat.pat_type)) ~env ~loc:pat.pat_loc
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
and search_pos_module_expr ~pos (m :module_expr) =
Packit bd2e5d
  if in_loc m.mod_loc ~pos then begin
Packit bd2e5d
    begin match m.mod_desc with
Packit bd2e5d
      Tmod_ident (path, _) ->
Packit bd2e5d
        add_found_str (`Module (path, m.mod_type))
Packit bd2e5d
          ~env:m.mod_env ~loc:m.mod_loc
Packit bd2e5d
    | Tmod_structure str -> search_pos_structure str.str_items ~pos
Packit bd2e5d
    | Tmod_functor (_, _, _, m) -> search_pos_module_expr m ~pos
Packit bd2e5d
    | Tmod_apply (a, b, _) ->
Packit bd2e5d
        search_pos_module_expr a ~pos; search_pos_module_expr b ~pos
Packit bd2e5d
    | Tmod_constraint (m, _, _, _) -> search_pos_module_expr m ~pos
Packit bd2e5d
    | Tmod_unpack (e, _) -> search_pos_expr e ~pos
Packit bd2e5d
    end;
Packit bd2e5d
    add_found_str (`Module (Pident (Ident.create "M"), m.mod_type))
Packit bd2e5d
      ~env:m.mod_env ~loc:m.mod_loc
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
let search_pos_structure ~pos str =
Packit bd2e5d
  observe ~ref:found_str (search_pos_structure ~pos) str
Packit bd2e5d
Packit bd2e5d
open Stypes
Packit bd2e5d
Packit bd2e5d
let search_pos_ti ~pos = function
Packit bd2e5d
    Ti_pat p   -> search_pos_pat ~pos ~env:p.pat_env p
Packit bd2e5d
  | Ti_expr e  -> search_pos_expr ~pos e
Packit bd2e5d
  | Ti_class c -> search_pos_class_expr ~pos c
Packit bd2e5d
  | Ti_mod m   -> search_pos_module_expr ~pos m
Packit bd2e5d
  | _ -> ()
Packit bd2e5d
Packit bd2e5d
let rec search_pos_info ~pos = function
Packit bd2e5d
    [] -> []
Packit bd2e5d
  | ti :: l ->
Packit bd2e5d
      if in_loc ~pos (get_location ti)
Packit bd2e5d
      then observe ~ref:found_str (search_pos_ti ~pos) ti
Packit bd2e5d
      else  search_pos_info ~pos l