185 lines
6.3 KiB
OCaml
185 lines
6.3 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* OCaml *)
|
|
(* *)
|
|
(* Fabrice Le Fessant, INRIA Saclay *)
|
|
(* *)
|
|
(* Copyright 2012 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. *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
(* Generate an .annot file from a .cmt file. *)
|
|
|
|
open Asttypes
|
|
open Typedtree
|
|
open Tast_iterator
|
|
|
|
let variables_iterator scope =
|
|
let super = default_iterator in
|
|
let pat sub (type k) (p : k general_pattern) =
|
|
begin match p.pat_desc with
|
|
| Tpat_var (id, _) | Tpat_alias (_, id, _) ->
|
|
Stypes.record (Stypes.An_ident (p.pat_loc,
|
|
Ident.name id,
|
|
Annot.Idef scope))
|
|
| _ -> ()
|
|
end;
|
|
super.pat sub p
|
|
in
|
|
{super with pat}
|
|
|
|
let bind_variables scope =
|
|
let iter = variables_iterator scope in
|
|
fun p -> iter.pat iter p
|
|
|
|
let bind_bindings scope bindings =
|
|
let o = bind_variables scope in
|
|
List.iter (fun x -> o x.vb_pat) bindings
|
|
|
|
let bind_cases l =
|
|
List.iter
|
|
(fun {c_lhs; c_guard; c_rhs} ->
|
|
let loc =
|
|
let open Location in
|
|
match c_guard with
|
|
| None -> c_rhs.exp_loc
|
|
| Some g -> {c_rhs.exp_loc with loc_start=g.exp_loc.loc_start}
|
|
in
|
|
bind_variables loc c_lhs
|
|
)
|
|
l
|
|
|
|
let record_module_binding scope mb =
|
|
Stypes.record (Stypes.An_ident
|
|
(mb.mb_name.loc,
|
|
Option.value mb.mb_name.txt ~default:"_",
|
|
Annot.Idef scope))
|
|
|
|
let rec iterator ~scope rebuild_env =
|
|
let super = default_iterator in
|
|
let class_expr sub node =
|
|
Stypes.record (Stypes.Ti_class node);
|
|
super.class_expr sub node
|
|
|
|
and module_expr _sub node =
|
|
Stypes.record (Stypes.Ti_mod node);
|
|
super.module_expr (iterator ~scope:node.mod_loc rebuild_env) node
|
|
|
|
and expr sub exp =
|
|
begin match exp.exp_desc with
|
|
| Texp_ident (path, _, _) ->
|
|
let full_name = Path.name ~paren:Oprint.parenthesized_ident path in
|
|
let env =
|
|
if rebuild_env then
|
|
Env.env_of_only_summary Envaux.env_from_summary exp.exp_env
|
|
else
|
|
exp.exp_env
|
|
in
|
|
let annot =
|
|
try
|
|
let desc = Env.find_value path env in
|
|
let dloc = desc.Types.val_loc in
|
|
if dloc.Location.loc_ghost then Annot.Iref_external
|
|
else Annot.Iref_internal dloc
|
|
with Not_found ->
|
|
Annot.Iref_external
|
|
in
|
|
Stypes.record
|
|
(Stypes.An_ident (exp.exp_loc, full_name , annot))
|
|
| Texp_let (Recursive, bindings, _) ->
|
|
bind_bindings exp.exp_loc bindings
|
|
| Texp_let (Nonrecursive, bindings, body) ->
|
|
bind_bindings body.exp_loc bindings
|
|
| Texp_match (_, f1, _) ->
|
|
bind_cases f1
|
|
| Texp_function { cases = f; }
|
|
| Texp_try (_, f) ->
|
|
bind_cases f
|
|
| Texp_letmodule (_, modname, _, _, body ) ->
|
|
Stypes.record (Stypes.An_ident
|
|
(modname.loc,Option.value ~default:"_" modname.txt,
|
|
Annot.Idef body.exp_loc))
|
|
| _ -> ()
|
|
end;
|
|
Stypes.record (Stypes.Ti_expr exp);
|
|
super.expr sub exp
|
|
|
|
and pat sub (type k) (p : k general_pattern) =
|
|
Stypes.record (Stypes.Ti_pat (classify_pattern p, p));
|
|
super.pat sub p
|
|
in
|
|
|
|
let structure_item_rem sub str rem =
|
|
let open Location in
|
|
let loc = str.str_loc in
|
|
begin match str.str_desc with
|
|
| Tstr_value (rec_flag, bindings) ->
|
|
let doit loc_start = bind_bindings {scope with loc_start} bindings in
|
|
begin match rec_flag, rem with
|
|
| Recursive, _ -> doit loc.loc_start
|
|
| Nonrecursive, [] -> doit loc.loc_end
|
|
| Nonrecursive, {str_loc = loc2} :: _ -> doit loc2.loc_start
|
|
end
|
|
| Tstr_module mb ->
|
|
record_module_binding
|
|
{ scope with Location.loc_start = loc.loc_end } mb
|
|
| Tstr_recmodule mbs ->
|
|
List.iter (record_module_binding
|
|
{ scope with Location.loc_start = loc.loc_start }) mbs
|
|
| _ ->
|
|
()
|
|
end;
|
|
Stypes.record_phrase loc;
|
|
super.structure_item sub str
|
|
in
|
|
let structure_item sub s =
|
|
(* This will be used for Partial_structure_item.
|
|
We don't have here the location of the "next" item,
|
|
this will give a slightly different scope for the non-recursive
|
|
binding case. *)
|
|
structure_item_rem sub s []
|
|
in
|
|
let structure sub l =
|
|
let rec loop = function
|
|
| str :: rem -> structure_item_rem sub str rem; loop rem
|
|
| [] -> ()
|
|
in
|
|
loop l.str_items
|
|
in
|
|
{super with class_expr; module_expr; expr; pat; structure_item; structure}
|
|
|
|
let binary_part iter x =
|
|
let open Cmt_format in
|
|
match x with
|
|
| Partial_structure x -> iter.structure iter x
|
|
| Partial_structure_item x -> iter.structure_item iter x
|
|
| Partial_expression x -> iter.expr iter x
|
|
| Partial_pattern (_, x) -> iter.pat iter x
|
|
| Partial_class_expr x -> iter.class_expr iter x
|
|
| Partial_signature x -> iter.signature iter x
|
|
| Partial_signature_item x -> iter.signature_item iter x
|
|
| Partial_module_type x -> iter.module_type iter x
|
|
|
|
let gen_annot target_filename ~sourcefile ~use_summaries annots =
|
|
let open Cmt_format in
|
|
let scope =
|
|
match sourcefile with
|
|
| None -> Location.none
|
|
| Some s -> Location.in_file s
|
|
in
|
|
let iter = iterator ~scope use_summaries in
|
|
match annots with
|
|
| Implementation typedtree ->
|
|
iter.structure iter typedtree;
|
|
Stypes.dump target_filename
|
|
| Partial_implementation parts ->
|
|
Array.iter (binary_part iter) parts;
|
|
Stypes.dump target_filename
|
|
| Interface _ | Packed _ | Partial_interface _ ->
|
|
()
|