Blame browser/searchid.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 Location
Packit bd2e5d
open Longident
Packit bd2e5d
open Path
Packit bd2e5d
open Types
Packit bd2e5d
open Typedtree
Packit bd2e5d
open Env
Packit bd2e5d
open Btype
Packit bd2e5d
open Ctype
Packit bd2e5d
Packit bd2e5d
(* only empty here, but replaced by Pervasives later *)
Packit bd2e5d
let start_env = ref Env.empty
Packit bd2e5d
let module_list = ref []
Packit bd2e5d
Packit bd2e5d
type pkind =
Packit bd2e5d
    Pvalue
Packit bd2e5d
  | Ptype
Packit bd2e5d
  | Plabel
Packit bd2e5d
  | Pconstructor
Packit bd2e5d
  | Pmodule
Packit bd2e5d
  | Pmodtype
Packit bd2e5d
  | Pclass
Packit bd2e5d
  | Pcltype
Packit bd2e5d
Packit bd2e5d
let string_of_kind = function
Packit bd2e5d
    Pvalue -> "v"
Packit bd2e5d
  | Ptype -> "t"
Packit bd2e5d
  | Plabel -> "l"
Packit bd2e5d
  | Pconstructor -> "cn"
Packit bd2e5d
  | Pmodule -> "m"
Packit bd2e5d
  | Pmodtype -> "s"
Packit bd2e5d
  | Pclass -> "c"
Packit bd2e5d
  | Pcltype -> "ct"
Packit bd2e5d
Packit bd2e5d
let rec longident_of_path = function
Packit bd2e5d
    Pident id -> Lident (Ident.name id)
Packit bd2e5d
  | Pdot (path, s, _) -> Ldot (longident_of_path path, s)
Packit bd2e5d
  | Papply (p1, p2) -> Lapply (longident_of_path p1, longident_of_path p2)
Packit bd2e5d
Packit bd2e5d
let rec remove_prefix lid ~prefix =
Packit bd2e5d
  let rec remove_hd lid ~name =
Packit bd2e5d
  match lid with
Packit bd2e5d
    Ldot (Lident s1, s2) when s1 = name -> Lident s2
Packit bd2e5d
  | Ldot (l, s) -> Ldot (remove_hd ~name l, s)
Packit bd2e5d
  | _ -> raise Not_found
Packit bd2e5d
  in
Packit bd2e5d
  match prefix with
Packit bd2e5d
    [] -> lid
Packit bd2e5d
  | name :: prefix ->
Packit bd2e5d
    try remove_prefix ~prefix (remove_hd ~name lid)
Packit bd2e5d
    with Not_found -> lid
Packit bd2e5d
Packit bd2e5d
let rec permutations l = match l with
Packit bd2e5d
    [] | [_] -> [l]
Packit bd2e5d
  | [a;b] -> [l; [b;a]]
Packit bd2e5d
  | _ ->
Packit bd2e5d
  let _, perms =
Packit bd2e5d
    List.fold_left l ~init:(l,[]) ~f:
Packit bd2e5d
    begin fun (l, perms) a ->
Packit bd2e5d
      let l = List.tl l in
Packit bd2e5d
      l @ [a],
Packit bd2e5d
      List.map (permutations l) ~f:(fun l -> a :: l) @ perms
Packit bd2e5d
    end
Packit bd2e5d
  in perms
Packit bd2e5d
Packit bd2e5d
let rec choose n ~card:l =
Packit bd2e5d
  let len = List.length l in
Packit bd2e5d
  if n = len then [l] else
Packit bd2e5d
  if n = 1 then List.map l ~f:(fun x -> [x]) else
Packit bd2e5d
  if n = 0 then [[]] else
Packit bd2e5d
  if n > len then [] else
Packit bd2e5d
  match l with [] -> []
Packit bd2e5d
  | a :: l ->
Packit bd2e5d
    List.map (choose (n-1) ~card:l) ~f:(fun l -> a :: l)
Packit bd2e5d
    @ choose n ~card:l
Packit bd2e5d
Packit bd2e5d
let rec arr p ~card:n =
Packit bd2e5d
  if p = 0 then 1 else n * arr (p-1) ~card:(n-1)
Packit bd2e5d
Packit bd2e5d
let rec all_args ty =
Packit bd2e5d
  let ty = repr ty in
Packit bd2e5d
  match ty.desc with
Packit bd2e5d
    Tarrow(l, ty1, ty2, _) -> let (tl,ty) = all_args ty2 in ((l,ty1)::tl, ty)
Packit bd2e5d
  | _ -> ([], ty)
Packit bd2e5d
Packit bd2e5d
let rec equal ~prefix t1 t2 =
Packit bd2e5d
  match (repr t1).desc, (repr t2).desc with
Packit bd2e5d
    Tvar _, Tvar _ -> true
Packit bd2e5d
  | Tvariant row1, Tvariant row2 ->
Packit bd2e5d
      let row1 = row_repr row1 and row2 = row_repr row2 in
Packit bd2e5d
      let fields1 = filter_row_fields false row1.row_fields
Packit bd2e5d
      and fields2 = filter_row_fields false row1.row_fields
Packit bd2e5d
      in
Packit bd2e5d
      let r1, r2, pairs = merge_row_fields fields1 fields2 in
Packit bd2e5d
      row1.row_closed = row2.row_closed && r1 = [] && r2 = [] &&
Packit bd2e5d
      List.for_all pairs ~f:
Packit bd2e5d
           begin fun (_,f1,f2) ->
Packit bd2e5d
             match row_field_repr f1, row_field_repr f2 with
Packit bd2e5d
               Rpresent None, Rpresent None -> true
Packit bd2e5d
             | Rpresent(Some t1), Rpresent (Some t2) -> equal t1 t2 ~prefix
Packit bd2e5d
             | Reither(c1, tl1, _, _), Reither(c2, tl2, _, _) ->
Packit bd2e5d
                 c1 = c2 && List.length tl1 = List.length tl2 &&
Packit bd2e5d
                 List.for_all2 tl1 tl2 ~f:(equal ~prefix)
Packit bd2e5d
             | _ -> false
Packit bd2e5d
           end
Packit bd2e5d
  | Tarrow _, Tarrow _ ->
Packit bd2e5d
      let l1, t1 = all_args t1 and l2, t2 = all_args t2 in
Packit bd2e5d
      equal t1 t2 ~prefix &&
Packit bd2e5d
      List.length l1 = List.length l2 &&
Packit bd2e5d
      List.exists (permutations l1) ~f:
Packit bd2e5d
      begin fun l1 ->
Packit bd2e5d
        List.for_all2 l1 l2 ~f:
Packit bd2e5d
        begin fun (p1,t1) (p2,t2) ->
Packit bd2e5d
          (p1 = Nolabel || p1 = p2) && equal t1 t2 ~prefix
Packit bd2e5d
        end
Packit bd2e5d
      end
Packit bd2e5d
  | Ttuple l1, Ttuple l2 ->
Packit bd2e5d
      List.length l1 = List.length l2 &&
Packit bd2e5d
      List.for_all2 l1 l2 ~f:(equal ~prefix)
Packit bd2e5d
  | Tconstr (p1, l1, _), Tconstr (p2, l2, _) ->
Packit bd2e5d
      remove_prefix ~prefix (longident_of_path p1) = (longident_of_path p2)
Packit bd2e5d
      && List.length l1 = List.length l2
Packit bd2e5d
      && List.for_all2 l1 l2 ~f:(equal ~prefix)
Packit bd2e5d
  | _ -> false
Packit bd2e5d
Packit bd2e5d
let get_options = List.filter ~f:Btype.is_optional
Packit bd2e5d
Packit bd2e5d
let rec included ~prefix t1 t2 =
Packit bd2e5d
  match (repr t1).desc, (repr t2).desc with
Packit bd2e5d
    Tvar _, _ -> true
Packit bd2e5d
  | Tvariant row1, Tvariant row2 ->
Packit bd2e5d
      let row1 = row_repr row1 and row2 = row_repr row2 in
Packit bd2e5d
      let fields1 = filter_row_fields false row1.row_fields
Packit bd2e5d
      and fields2 = filter_row_fields false row2.row_fields
Packit bd2e5d
      in
Packit bd2e5d
      let r1, r2, pairs = merge_row_fields fields1 fields2 in
Packit bd2e5d
      r1 = [] &&
Packit bd2e5d
      List.for_all pairs ~f:
Packit bd2e5d
           begin fun (_,f1,f2) ->
Packit bd2e5d
             match row_field_repr f1, row_field_repr f2 with
Packit bd2e5d
               Rpresent None, Rpresent None -> true
Packit bd2e5d
             | Rpresent(Some t1), Rpresent (Some t2) -> included t1 t2 ~prefix
Packit bd2e5d
             | Reither(c1, tl1, _, _), Reither(c2, tl2, _, _) ->
Packit bd2e5d
                 c1 = c2 && List.length tl1 = List.length tl2 &&
Packit bd2e5d
                 List.for_all2 tl1 tl2 ~f:(included ~prefix)
Packit bd2e5d
             | _ -> false
Packit bd2e5d
           end
Packit bd2e5d
  | Tarrow _, Tarrow _ ->
Packit bd2e5d
      let l1, t1 = all_args t1 and l2, t2 = all_args t2 in
Packit bd2e5d
      included t1 t2 ~prefix &&
Packit bd2e5d
      let len1 = List.length l1 and len2 = List.length l2 in
Packit bd2e5d
      let l2 = if arr len1 ~card:len2 < 100 then l2 else
Packit bd2e5d
          let ll1 = get_options (fst (List.split l1)) in
Packit bd2e5d
          List.filter l2
Packit bd2e5d
          ~f:(fun (l,_) -> not (is_optional l) || List.mem l ll1)
Packit bd2e5d
      in
Packit bd2e5d
      len1 <= len2 &&
Packit bd2e5d
      List.exists (List2.flat_map ~f:permutations (choose len1 ~card:l2)) ~f:
Packit bd2e5d
      begin fun l2 ->
Packit bd2e5d
        List.for_all2 l1 l2 ~f:
Packit bd2e5d
        begin fun (p1,t1) (p2,t2) ->
Packit bd2e5d
          (p1 = Nolabel || p1 = p2) && included t1 t2 ~prefix
Packit bd2e5d
        end
Packit bd2e5d
      end
Packit bd2e5d
  | Ttuple l1, Ttuple l2 ->
Packit bd2e5d
      let len1 = List.length l1 in
Packit bd2e5d
      len1 <= List.length l2 &&
Packit bd2e5d
      List.exists (List2.flat_map ~f:permutations (choose len1 ~card:l2)) ~f:
Packit bd2e5d
      begin fun l2 ->
Packit bd2e5d
        List.for_all2 l1 l2 ~f:(included ~prefix)
Packit bd2e5d
      end
Packit bd2e5d
  | _, Ttuple _ -> included (newty (Ttuple [t1])) t2 ~prefix
Packit bd2e5d
  | Tconstr (p1, l1, _), Tconstr (p2, l2, _) ->
Packit bd2e5d
      remove_prefix ~prefix (longident_of_path p1) = (longident_of_path p2)
Packit bd2e5d
      && List.length l1 = List.length l2
Packit bd2e5d
      && List.for_all2 l1 l2 ~f:(included ~prefix)
Packit bd2e5d
  | _ -> false
Packit bd2e5d
Packit bd2e5d
let mklid = function
Packit bd2e5d
    [] -> raise (Invalid_argument "Searchid.mklid")
Packit bd2e5d
  | x :: l ->
Packit bd2e5d
      List.fold_left l ~init:(Lident x) ~f:(fun acc x -> Ldot (acc, x))
Packit bd2e5d
Packit bd2e5d
let mkpath = function
Packit bd2e5d
    [] -> raise (Invalid_argument "Searchid.mklid")
Packit bd2e5d
  | x :: l ->
Packit bd2e5d
      List.fold_left l ~init:(Pident (Ident.create x))
Packit bd2e5d
      ~f:(fun acc x -> Pdot (acc, x, 0))
Packit bd2e5d
Packit bd2e5d
let get_fields ~prefix ~sign self =
Packit bd2e5d
  (*let env = open_signature Fresh (mkpath prefix) sign !start_env in*)
Packit bd2e5d
  let env = add_signature sign !start_env in
Packit bd2e5d
  match (expand_head env self).desc with
Packit bd2e5d
    Tobject (ty_obj, _) ->
Packit bd2e5d
      let l,_ = flatten_fields ty_obj in l
Packit bd2e5d
  | _ -> []
Packit bd2e5d
Packit bd2e5d
let rec search_type_in_signature t ~sign ~prefix ~mode =
Packit bd2e5d
  let matches = match mode with
Packit bd2e5d
        `Included -> included t ~prefix
Packit bd2e5d
      | `Exact -> equal t ~prefix
Packit bd2e5d
  and lid_of_id id = mklid (prefix @ [Ident.name id]) in
Packit bd2e5d
  let constructor_matches = function
Packit bd2e5d
      Types.Cstr_tuple l -> List.exists l ~f:matches
Packit bd2e5d
    | Cstr_record l -> List.exists l ~f:(fun d -> matches d.Types.ld_type)
Packit bd2e5d
  in
Packit bd2e5d
  List2.flat_map sign ~f:
Packit bd2e5d
  begin fun item -> match item with
Packit bd2e5d
        Sig_value (id, vd) ->
Packit bd2e5d
          if matches vd.val_type then [lid_of_id id, Pvalue] else []
Packit bd2e5d
      | Sig_type (id, td, _) ->
Packit bd2e5d
          if
Packit bd2e5d
          matches (newconstr (Pident id) td.type_params) ||
Packit bd2e5d
          begin match td.type_manifest with
Packit bd2e5d
            None -> false
Packit bd2e5d
          | Some t -> matches t
Packit bd2e5d
          end ||
Packit bd2e5d
          begin match td.type_kind with
Packit bd2e5d
            Type_abstract
Packit bd2e5d
	  | Type_open -> false
Packit bd2e5d
          | Type_variant l ->
Packit bd2e5d
            List.exists l ~f:
Packit bd2e5d
            begin fun {Types.cd_args=args; cd_res=r} ->
Packit bd2e5d
              constructor_matches args  ||
Packit bd2e5d
              match r with None -> false | Some x -> matches x
Packit bd2e5d
            end
Packit bd2e5d
          | Type_record(l, rep) ->
Packit bd2e5d
            List.exists l ~f:(fun {Types.ld_type=t} -> matches t)
Packit bd2e5d
          end
Packit bd2e5d
          then [lid_of_id id, Ptype] else []
Packit bd2e5d
      | Sig_typext (id, l, _) ->
Packit bd2e5d
          if constructor_matches l.ext_args
Packit bd2e5d
          then [lid_of_id id, Pconstructor]
Packit bd2e5d
          else []
Packit bd2e5d
      | Sig_module (id, {md_type=Mty_signature sign}, _) ->
Packit bd2e5d
          search_type_in_signature t ~sign ~mode
Packit bd2e5d
            ~prefix:(prefix @ [Ident.name id])
Packit bd2e5d
      | Sig_module _ -> []
Packit bd2e5d
      | Sig_modtype _ -> []
Packit bd2e5d
      | Sig_class (id, cl, _) ->
Packit bd2e5d
          let self = self_type cl.cty_type in
Packit bd2e5d
          if matches self
Packit bd2e5d
          || (match cl.cty_new with None -> false | Some ty -> matches ty)
Packit bd2e5d
          (* || List.exists (get_fields ~prefix ~sign self)
Packit bd2e5d
              ~f:(fun (_,_,ty_field) -> matches ty_field) *)
Packit bd2e5d
          then [lid_of_id id, Pclass] else []
Packit bd2e5d
      | Sig_class_type (id, cl, _) ->
Packit bd2e5d
          let self = self_type cl.clty_type in
Packit bd2e5d
          if matches self
Packit bd2e5d
          (* || List.exists (get_fields ~prefix ~sign self)
Packit bd2e5d
              ~f:(fun (_,_,ty_field) -> matches ty_field) *)
Packit bd2e5d
          then [lid_of_id id, Pclass] else []
Packit bd2e5d
  end
Packit bd2e5d
Packit bd2e5d
let search_all_types t ~mode =
Packit bd2e5d
  let tl = match mode, t.desc with
Packit bd2e5d
      `Exact, _ -> [t]
Packit bd2e5d
    | `Included, Tarrow _ -> [t]
Packit bd2e5d
    | `Included, _ ->
Packit bd2e5d
      [t; newty(Tarrow(Nolabel,t,newvar(),Cok)); newty(Tarrow(Nolabel,newvar(),t,Cok))]
Packit bd2e5d
  in List2.flat_map !module_list ~f:
Packit bd2e5d
    begin fun modname ->
Packit bd2e5d
    let mlid = Lident modname in
Packit bd2e5d
    try match find_module (lookup_module ~load:true mlid !start_env) !start_env
Packit bd2e5d
    with {md_type=Mty_signature sign} ->
Packit bd2e5d
        List2.flat_map tl
Packit bd2e5d
          ~f:(search_type_in_signature ~sign ~prefix:[modname] ~mode)
Packit bd2e5d
    | _ -> []
Packit bd2e5d
    with Not_found | Env.Error _ -> []
Packit bd2e5d
    end
Packit bd2e5d
Packit bd2e5d
exception Error of int * int
Packit bd2e5d
Packit bd2e5d
let search_string_type text ~mode =
Packit bd2e5d
  try
Packit bd2e5d
    let sexp = Parse.interface (Lexing.from_string ("val z : " ^ text)) in
Packit bd2e5d
    let sign =
Packit bd2e5d
      try (Typemod.transl_signature !start_env sexp).sig_type with _ ->
Packit bd2e5d
      let env = List.fold_left !module_list ~init:!start_env ~f:
Packit bd2e5d
        begin fun acc m ->
Packit bd2e5d
          try open_pers_signature m acc with Env.Error _ -> acc
Packit bd2e5d
        end in
Packit bd2e5d
      try (Typemod.transl_signature env sexp).sig_type
Packit bd2e5d
      with Env.Error err -> []
Packit bd2e5d
      | Typemod.Error (l,_,_) ->
Packit bd2e5d
          let start_c = l.loc_start.Lexing.pos_cnum in
Packit bd2e5d
          let end_c = l.loc_end.Lexing.pos_cnum in
Packit bd2e5d
          raise (Error (start_c - 8, end_c - 8))
Packit bd2e5d
      | Typetexp.Error (l,_,_) ->
Packit bd2e5d
          let start_c = l.loc_start.Lexing.pos_cnum in
Packit bd2e5d
          let end_c = l.loc_end.Lexing.pos_cnum in
Packit bd2e5d
          raise (Error (start_c - 8, end_c - 8))
Packit bd2e5d
    in match sign with
Packit bd2e5d
        [ Sig_value (_, vd) ] ->
Packit bd2e5d
          search_all_types vd.val_type ~mode
Packit bd2e5d
      | _ -> []
Packit bd2e5d
  with
Packit bd2e5d
    Syntaxerr.Error(Syntaxerr.Unclosed(l,_,_,_)) ->
Packit bd2e5d
      let start_c = l.loc_start.Lexing.pos_cnum in
Packit bd2e5d
      let end_c = l.loc_end.Lexing.pos_cnum in
Packit bd2e5d
      raise (Error (start_c - 8, end_c - 8))
Packit bd2e5d
  | Syntaxerr.Error(Syntaxerr.Other l) ->
Packit bd2e5d
      let start_c = l.loc_start.Lexing.pos_cnum in
Packit bd2e5d
      let end_c = l.loc_end.Lexing.pos_cnum in
Packit bd2e5d
      raise (Error (start_c - 8, end_c - 8))
Packit bd2e5d
  | Lexer.Error (_, l) ->
Packit bd2e5d
      let start_c = l.loc_start.Lexing.pos_cnum in
Packit bd2e5d
      let end_c = l.loc_end.Lexing.pos_cnum in
Packit bd2e5d
      raise (Error (start_c - 8, end_c - 8))
Packit bd2e5d
Packit bd2e5d
let longident_of_string text =
Packit bd2e5d
  let exploded = ref [] and l = ref 0 in
Packit bd2e5d
  for i = 0 to String.length text - 2 do
Packit bd2e5d
    if text.[i] ='.' then
Packit bd2e5d
    (exploded := String.sub text ~pos:!l ~len:(i - !l) :: !exploded; l := i+1)
Packit bd2e5d
  done;
Packit bd2e5d
  let sym = String.sub text ~pos:!l ~len:(String.length text - !l) in
Packit bd2e5d
  let rec mklid = function
Packit bd2e5d
      [s] -> Lident s
Packit bd2e5d
    | s :: l -> Ldot (mklid l, s)
Packit bd2e5d
    | [] -> assert false in
Packit bd2e5d
  sym, fun l -> mklid (sym :: !exploded @ l)
Packit bd2e5d
Packit bd2e5d
Packit bd2e5d
let explode s =
Packit bd2e5d
  let l = ref [] in
Packit bd2e5d
  for i = String.length s - 1 downto 0 do
Packit bd2e5d
    l := s.[i] :: !l
Packit bd2e5d
  done; !l
Packit bd2e5d
Packit bd2e5d
let rec check_match ~pattern s =
Packit bd2e5d
  match pattern, s with
Packit bd2e5d
    [], [] -> true
Packit bd2e5d
  | '*'::l, l' -> check_match ~pattern:l l'
Packit bd2e5d
                  || check_match ~pattern:('?'::'*'::l) l'
Packit bd2e5d
  | '?'::l, _::l' -> check_match ~pattern:l l'
Packit bd2e5d
  | x::l, y::l' when x == y -> check_match ~pattern:l l'
Packit bd2e5d
  | _ -> false
Packit bd2e5d
Packit bd2e5d
let search_pattern_symbol text =
Packit bd2e5d
  if text = "" then [] else
Packit bd2e5d
  let pattern = explode text in
Packit bd2e5d
  let check i = check_match ~pattern (explode (Ident.name i)) in
Packit bd2e5d
  let l = List.map !module_list ~f:
Packit bd2e5d
    begin fun modname -> Lident modname,
Packit bd2e5d
    try match
Packit bd2e5d
      find_module (lookup_module ~load:true (Lident modname) !start_env)
Packit bd2e5d
	!start_env
Packit bd2e5d
    with {md_type=Mty_signature sign} ->
Packit bd2e5d
        List2.flat_map sign ~f:
Packit bd2e5d
          begin function
Packit bd2e5d
            Sig_value (i, _) when check i -> [i, Pvalue]
Packit bd2e5d
          | Sig_type (i, _, _) when check i -> [i, Ptype]
Packit bd2e5d
          | Sig_typext (i, _, _) when check i -> [i, Pconstructor]
Packit bd2e5d
          | Sig_module (i, _, _) when check i -> [i, Pmodule]
Packit bd2e5d
          | Sig_modtype (i, _) when check i -> [i, Pmodtype]
Packit bd2e5d
          | Sig_class (i, cl, _) when check i
Packit bd2e5d
            || List.exists
Packit bd2e5d
                (get_fields ~prefix:[modname] ~sign (self_type cl.cty_type))
Packit bd2e5d
                ~f:(fun (name,_,_) -> check_match ~pattern (explode name))
Packit bd2e5d
            -> [i, Pclass]
Packit bd2e5d
          | Sig_class_type (i, cl, _) when check i
Packit bd2e5d
            || List.exists
Packit bd2e5d
                (get_fields ~prefix:[modname] ~sign (self_type cl.clty_type))
Packit bd2e5d
                ~f:(fun (name,_,_) -> check_match ~pattern (explode name))
Packit bd2e5d
            -> [i, Pcltype]
Packit bd2e5d
          | _ -> []
Packit bd2e5d
          end
Packit bd2e5d
    | _ -> []
Packit bd2e5d
    with Env.Error _ -> []
Packit bd2e5d
    end
Packit bd2e5d
  in
Packit bd2e5d
  List2.flat_map l ~f:
Packit bd2e5d
    begin fun (m, l) ->
Packit bd2e5d
      List.map l ~f:(fun (i, p) -> Ldot (m, Ident.name i), p)
Packit bd2e5d
    end
Packit bd2e5d
Packit bd2e5d
(*
Packit bd2e5d
let is_pattern s =
Packit bd2e5d
  try for i = 0 to String.length s -1 do
Packit bd2e5d
      if s.[i] = '?' || s.[i] = '*' then raise Exit
Packit bd2e5d
    done; false
Packit bd2e5d
  with Exit -> true
Packit bd2e5d
*)
Packit bd2e5d
Packit bd2e5d
let search_string_symbol text =
Packit bd2e5d
  if text = "" then [] else
Packit bd2e5d
  let lid = snd (longident_of_string text) [] in
Packit bd2e5d
  let try_lookup f k =
Packit bd2e5d
    try let _ = f lid !start_env in [lid, k]
Packit bd2e5d
    with Not_found | Env.Error _ -> []
Packit bd2e5d
  in
Packit bd2e5d
  try_lookup lookup_constructor Pconstructor @
Packit bd2e5d
  try_lookup (lookup_module ~load:true) Pmodule @
Packit bd2e5d
  try_lookup lookup_modtype Pmodtype @
Packit bd2e5d
  try_lookup lookup_value Pvalue @
Packit bd2e5d
  try_lookup lookup_type Ptype @
Packit bd2e5d
  try_lookup lookup_label Plabel @
Packit bd2e5d
  try_lookup lookup_class Pclass
Packit bd2e5d
Packit bd2e5d
open Parsetree
Packit bd2e5d
Packit bd2e5d
let rec bound_variables pat =
Packit bd2e5d
  match pat.ppat_desc with
Packit bd2e5d
    Ppat_any | Ppat_constant _ | Ppat_type _ | Ppat_unpack _
Packit bd2e5d
  | Ppat_interval _ -> []
Packit bd2e5d
  | Ppat_var s -> [s.txt]
Packit bd2e5d
  | Ppat_alias (pat,s) -> s.txt :: bound_variables pat
Packit bd2e5d
  | Ppat_tuple l -> List2.flat_map l ~f:bound_variables
Packit bd2e5d
  | Ppat_construct (_,None) -> []
Packit bd2e5d
  | Ppat_construct (_,Some pat) -> bound_variables pat
Packit bd2e5d
  | Ppat_variant (_,None) -> []
Packit bd2e5d
  | Ppat_variant (_,Some pat) -> bound_variables pat
Packit bd2e5d
  | Ppat_record (l, _) ->
Packit bd2e5d
      List2.flat_map l ~f:(fun (_,pat) -> bound_variables pat)
Packit bd2e5d
  | Ppat_array l ->
Packit bd2e5d
      List2.flat_map l ~f:bound_variables
Packit bd2e5d
  | Ppat_or (pat1,pat2) ->
Packit bd2e5d
      bound_variables pat1 @ bound_variables pat2
Packit bd2e5d
  | Ppat_constraint (pat,_) -> bound_variables pat
Packit bd2e5d
  | Ppat_lazy pat -> bound_variables pat
Packit bd2e5d
  | Ppat_extension _ -> []
Packit bd2e5d
  | Ppat_exception pat -> bound_variables pat
Packit bd2e5d
  | Ppat_open (_, pat) -> bound_variables pat
Packit bd2e5d
Packit bd2e5d
let search_structure str ~name ~kind ~prefix =
Packit bd2e5d
  let loc = ref 0 in
Packit bd2e5d
  let rec search_module str ~prefix =
Packit bd2e5d
    match prefix with [] -> str
Packit bd2e5d
    | modu::prefix ->
Packit bd2e5d
        let str =
Packit bd2e5d
          List.fold_left ~init:[] str ~f:
Packit bd2e5d
            begin fun acc item ->
Packit bd2e5d
              match item.pstr_desc with
Packit bd2e5d
                Pstr_module x when x.pmb_name.txt = modu ->
Packit bd2e5d
                  loc := x.pmb_expr.pmod_loc.loc_start.Lexing.pos_cnum;
Packit bd2e5d
                  begin match x.pmb_expr.pmod_desc with
Packit bd2e5d
                    Pmod_structure str -> str
Packit bd2e5d
                  | _ -> []
Packit bd2e5d
                  end
Packit bd2e5d
              | _ -> acc
Packit bd2e5d
            end
Packit bd2e5d
        in search_module str ~prefix
Packit bd2e5d
  in
Packit bd2e5d
  List.iter (search_module str ~prefix) ~f:
Packit bd2e5d
    begin fun item ->
Packit bd2e5d
      if match item.pstr_desc with
Packit bd2e5d
        Pstr_value (_, l) when kind = Pvalue ->
Packit bd2e5d
          List.iter l ~f:
Packit bd2e5d
            begin fun {pvb_pat=pat} ->
Packit bd2e5d
              if List.mem name (bound_variables pat)
Packit bd2e5d
              then loc := pat.ppat_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
            end;
Packit bd2e5d
          false
Packit bd2e5d
      | Pstr_primitive vd when kind = Pvalue -> name = vd.pval_name.txt
Packit bd2e5d
      | Pstr_type (_, l) when kind = Ptype ->
Packit bd2e5d
          List.iter l ~f:
Packit bd2e5d
            begin fun td ->
Packit bd2e5d
              if td.ptype_name.txt = name
Packit bd2e5d
	      then loc := td.ptype_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
            end;
Packit bd2e5d
          false
Packit bd2e5d
      | Pstr_typext l when kind = Ptype ->
Packit bd2e5d
          List.iter l.ptyext_constructors ~f:
Packit bd2e5d
            begin fun td ->
Packit bd2e5d
              if td.pext_name.txt = name
Packit bd2e5d
	      then loc := td.pext_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
            end;
Packit bd2e5d
          false
Packit bd2e5d
      | Pstr_exception pcd when kind = Pconstructor -> name = pcd.pext_name.txt
Packit bd2e5d
      | Pstr_module x when kind = Pmodule -> name = x.pmb_name.txt
Packit bd2e5d
      | Pstr_modtype x when kind = Pmodtype -> name = x.pmtd_name.txt
Packit bd2e5d
      | Pstr_class l when kind = Pclass || kind = Ptype || kind = Pcltype ->
Packit bd2e5d
          List.iter l ~f:
Packit bd2e5d
            begin fun c ->
Packit bd2e5d
              if c.pci_name.txt = name
Packit bd2e5d
              then loc := c.pci_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
            end;
Packit bd2e5d
          false
Packit bd2e5d
      | Pstr_class_type l when kind = Pcltype || kind = Ptype ->
Packit bd2e5d
          List.iter l ~f:
Packit bd2e5d
            begin fun c ->
Packit bd2e5d
              if c.pci_name.txt = name
Packit bd2e5d
              then loc := c.pci_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
            end;
Packit bd2e5d
          false
Packit bd2e5d
      | _ -> false
Packit bd2e5d
      then loc := item.pstr_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
    end;
Packit bd2e5d
  !loc
Packit bd2e5d
Packit bd2e5d
let search_signature sign ~name ~kind ~prefix =
Packit bd2e5d
  ignore (name = "");
Packit bd2e5d
  ignore (prefix = [""]);
Packit bd2e5d
  let loc = ref 0 in
Packit bd2e5d
  let rec search_module_type  sign ~prefix =
Packit bd2e5d
    match prefix with [] -> sign
Packit bd2e5d
    | modu::prefix ->
Packit bd2e5d
        let sign =
Packit bd2e5d
          List.fold_left ~init:[] sign ~f:
Packit bd2e5d
            begin fun acc item ->
Packit bd2e5d
              match item.psig_desc with
Packit bd2e5d
                Psig_module pmd when pmd.pmd_name.txt = modu ->
Packit bd2e5d
                  loc := pmd.pmd_type.pmty_loc.loc_start.Lexing.pos_cnum;
Packit bd2e5d
                  begin match pmd.pmd_type.pmty_desc with
Packit bd2e5d
                    Pmty_signature sign -> sign
Packit bd2e5d
                  | _ -> []
Packit bd2e5d
                  end
Packit bd2e5d
              | _ -> acc
Packit bd2e5d
            end
Packit bd2e5d
        in search_module_type sign ~prefix
Packit bd2e5d
  in
Packit bd2e5d
  List.iter (search_module_type sign ~prefix) ~f:
Packit bd2e5d
    begin fun item ->
Packit bd2e5d
      if match item.psig_desc with
Packit bd2e5d
        Psig_value vd when kind = Pvalue -> name = vd.pval_name.txt
Packit bd2e5d
      | Psig_type (_, l) when kind = Ptype ->
Packit bd2e5d
          List.iter l ~f:
Packit bd2e5d
            begin fun td ->
Packit bd2e5d
              if td.ptype_name.txt = name
Packit bd2e5d
	      then loc := td.ptype_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
            end;
Packit bd2e5d
          false
Packit bd2e5d
      | Psig_typext l when kind = Pconstructor ->
Packit bd2e5d
          List.iter l.ptyext_constructors ~f:
Packit bd2e5d
            begin fun td ->
Packit bd2e5d
              if td.pext_name.txt = name
Packit bd2e5d
	      then loc := td.pext_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
            end;
Packit bd2e5d
          false
Packit bd2e5d
      | Psig_exception pcd when kind = Pconstructor -> name = pcd.pext_name.txt
Packit bd2e5d
      | Psig_module pmd when kind = Pmodule -> name = pmd.pmd_name.txt
Packit bd2e5d
      | Psig_modtype pmtd when kind = Pmodtype -> name = pmtd.pmtd_name.txt
Packit bd2e5d
      | Psig_class l when kind = Pclass || kind = Ptype || kind = Pcltype ->
Packit bd2e5d
          List.iter l ~f:
Packit bd2e5d
            begin fun c ->
Packit bd2e5d
              if c.pci_name.txt = name
Packit bd2e5d
              then loc := c.pci_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
            end;
Packit bd2e5d
          false
Packit bd2e5d
      | Psig_class_type l when kind = Ptype || kind = Pcltype ->
Packit bd2e5d
          List.iter l ~f:
Packit bd2e5d
            begin fun c ->
Packit bd2e5d
              if c.pci_name.txt = name
Packit bd2e5d
              then loc := c.pci_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
            end;
Packit bd2e5d
          false
Packit bd2e5d
      | _ -> false
Packit bd2e5d
      then loc := item.psig_loc.loc_start.Lexing.pos_cnum
Packit bd2e5d
    end;
Packit bd2e5d
  !loc