1 (***********************************************************************)
4 (* Maxence Guesdon, projet Cristal, INRIA Rocquencourt *)
6 (* Copyright 2001 Institut National de Recherche en Informatique et *)
7 (* en Automatique. All rights reserved. This file is distributed *)
8 (* under the terms of the Q Public License version 1.0. *)
10 (***********************************************************************)
12 (* $Id: odoc_sig.ml 8927 2008-07-23 08:55:36Z guesdon $ *)
14 (** Analysis of interface files. *)
22 let print_DEBUG s = print_string s ; print_newline ();;
24 module Name = Odoc_name
33 module Signature_search =
46 type tab = (ele, Types.signature_item) Hashtbl.t
48 let add_to_hash table signat =
50 Types.Tsig_value (ident, _) ->
51 Hashtbl.add table (V (Name.from_ident ident)) signat
52 | Types.Tsig_exception (ident, _) ->
53 Hashtbl.add table (E (Name.from_ident ident)) signat
54 | Types.Tsig_type (ident, _, _) ->
55 Hashtbl.add table (T (Name.from_ident ident)) signat
56 | Types.Tsig_class (ident, _, _) ->
57 Hashtbl.add table (C (Name.from_ident ident)) signat
58 | Types.Tsig_cltype (ident, _, _) ->
59 Hashtbl.add table (CT (Name.from_ident ident)) signat
60 | Types.Tsig_module (ident, _, _) ->
61 Hashtbl.add table (M (Name.from_ident ident)) signat
62 | Types.Tsig_modtype (ident,_) ->
63 Hashtbl.add table (MT (Name.from_ident ident)) signat
66 let t = Hashtbl.create 13 in
67 List.iter (add_to_hash t) signat;
70 let search_value table name =
71 match Hashtbl.find table (V name) with
72 | (Types.Tsig_value (_, val_desc)) -> val_desc.Types.val_type
75 let search_exception table name =
76 match Hashtbl.find table (E name) with
77 | (Types.Tsig_exception (_, type_expr_list)) ->
81 let search_type table name =
82 match Hashtbl.find table (T name) with
83 | (Types.Tsig_type (_, type_decl, _)) -> type_decl
86 let search_class table name =
87 match Hashtbl.find table (C name) with
88 | (Types.Tsig_class (_, class_decl, _)) -> class_decl
91 let search_class_type table name =
92 match Hashtbl.find table (CT name) with
93 | (Types.Tsig_cltype (_, cltype_decl, _)) -> cltype_decl
96 let search_module table name =
97 match Hashtbl.find table (M name) with
98 | (Types.Tsig_module (ident, module_type, _)) -> module_type
101 let search_module_type table name =
102 match Hashtbl.find table (MT name) with
103 | (Types.Tsig_modtype (_, Types.Tmodtype_manifest module_type)) ->
105 | (Types.Tsig_modtype (_, Types.Tmodtype_abstract)) ->
109 let search_attribute_type name class_sig =
110 let (_, _, type_expr) = Types.Vars.find name class_sig.Types.cty_vars in
113 let search_method_type name class_sig =
114 let fields = Odoc_misc.get_fields class_sig.Types.cty_self in
115 List.assoc name fields
118 module type Info_retriever =
120 val all_special : string -> string -> int * (Odoc_types.info list)
121 val blank_line_outside_simple : string -> string -> bool
122 val just_after_special : string -> string -> (int * Odoc_types.info option)
123 val first_special : string -> string -> (int * Odoc_types.info option)
125 (Odoc_types.text -> 'a) -> string -> string -> (Odoc_types.info option * 'a list)
129 functor (My_ir : Info_retriever) ->
131 (** This variable is used to load a file as a string and retrieve characters from it.*)
133 (** The name of the analysed file. *)
134 let file_name = ref ""
136 (** This function takes two indexes (start and end) and return the string
137 corresponding to the indexes in the file global variable. The function
138 prepare_file must have been called to fill the file global variable.*)
139 let get_string_of_file the_start the_end =
141 let s = String.sub !file the_start (the_end-the_start) in
144 Invalid_argument _ ->
147 (** This function loads the given file in the file global variable,
148 and sets file_name.*)
149 let prepare_file f input_f =
151 let s = Odoc_misc.input_file_as_string input_f in
159 (** The function used to get the comments in a class. *)
160 let get_comments_in_class pos_start pos_end =
161 My_ir.get_comments (fun t -> Class_comment t)
163 (get_string_of_file pos_start pos_end)
165 (** The function used to get the comments in a module. *)
166 let get_comments_in_module pos_start pos_end =
167 My_ir.get_comments (fun t -> Element_module_comment t)
169 (get_string_of_file pos_start pos_end)
171 let merge_infos = Odoc_merge.merge_info_opt Odoc_types.all_merge_options
173 let name_comment_from_type_kind pos_end pos_limit tk =
175 Parsetree.Ptype_abstract ->
177 | Parsetree.Ptype_variant cons_core_type_list_list ->
178 let rec f acc cons_core_type_list_list =
179 match cons_core_type_list_list with
182 | (name, core_type_list, loc) :: [] ->
183 let s = get_string_of_file
184 loc.Location.loc_end.Lexing.pos_cnum
187 let (len, comment_opt) = My_ir.just_after_special !file_name s in
188 (len, acc @ [ (name, comment_opt) ])
189 | (name, core_type_list, loc) :: (name2, core_type_list2, loc2)
191 let pos_end_first = loc.Location.loc_end.Lexing.pos_cnum in
192 let pos_start_second = loc2.Location.loc_start.Lexing.pos_cnum in
193 let s = get_string_of_file pos_end_first pos_start_second in
194 let (_,comment_opt) = My_ir.just_after_special !file_name s in
195 f (acc @ [name, comment_opt])
196 ((name2, core_type_list2, loc2) :: q)
198 f [] cons_core_type_list_list
200 | Parsetree.Ptype_record name_mutable_type_list (* of (string * mutable_flag * core_type) list*) ->
204 | (name, _, ct, xxloc) :: [] ->
205 let pos = ct.Parsetree.ptyp_loc.Location.loc_end.Lexing.pos_cnum in
206 let s = get_string_of_file pos pos_end in
207 let (_,comment_opt) = My_ir.just_after_special !file_name s in
209 | (name,_,ct,xxloc) :: ((name2,_,ct2,xxloc2) as ele2) :: q ->
210 let pos = ct.Parsetree.ptyp_loc.Location.loc_end.Lexing.pos_cnum in
211 let pos2 = ct2.Parsetree.ptyp_loc.Location.loc_start.Lexing.pos_cnum in
212 let s = get_string_of_file pos pos2 in
213 let (_,comment_opt) = My_ir.just_after_special !file_name s in
214 (name, comment_opt) :: (f (ele2 :: q))
216 (0, f name_mutable_type_list)
218 let get_type_kind env name_comment_list type_kind =
220 Types.Type_abstract ->
221 Odoc_type.Type_abstract
223 | Types.Type_variant l ->
224 let f (constructor_name, type_expr_list) =
227 match List.assoc constructor_name name_comment_list with
229 | Some d -> d.Odoc_types.i_desc
230 with Not_found -> None
233 vc_name = constructor_name ;
234 vc_args = List.map (Odoc_env.subst_type env) type_expr_list ;
235 vc_text = comment_opt
238 Odoc_type.Type_variant (List.map f l)
240 | Types.Type_record (l, _) ->
241 let f (field_name, mutable_flag, type_expr) =
244 match List.assoc field_name name_comment_list with
246 | Some d -> d.Odoc_types.i_desc
247 with Not_found -> None
250 rf_name = field_name ;
251 rf_mutable = mutable_flag = Mutable ;
252 rf_type = Odoc_env.subst_type env type_expr ;
253 rf_text = comment_opt
256 Odoc_type.Type_record (List.map f l)
258 (** Analysis of the elements of a class, from the information in the parsetree and in the class
259 signature. @return the couple (inherited_class list, elements).*)
260 let analyse_class_elements env current_class_name last_pos pos_limit
261 class_type_field_list class_signature =
262 let get_pos_limit2 q =
267 Parsetree.Pctf_val (_, _, _, _, loc)
268 | Parsetree.Pctf_virt (_, _, _, loc)
269 | Parsetree.Pctf_meth (_, _, _, loc)
270 | Parsetree.Pctf_cstr (_, _, loc) -> loc.Location.loc_start.Lexing.pos_cnum
271 | Parsetree.Pctf_inher class_type ->
272 class_type.Parsetree.pcty_loc.Location.loc_start.Lexing.pos_cnum
274 let get_method name comment_opt private_flag loc q =
275 let complete_name = Name.concat current_class_name name in
277 try Signature_search.search_method_type name class_signature
279 raise (Failure (Odoc_messages.method_type_not_found current_class_name name))
281 let subst_typ = Odoc_env.subst_type env typ in
286 val_name = complete_name ;
287 val_info = comment_opt ;
288 val_type = subst_typ ;
289 val_recursive = false ;
290 val_parameters = Odoc_value.dummy_parameter_list subst_typ ;
292 val_loc = { loc_impl = None ; loc_inter = Some (!file_name, loc.Location.loc_start.Lexing.pos_cnum) };
294 met_private = private_flag = Asttypes.Private ;
295 met_virtual = false ;
298 let pos_limit2 = get_pos_limit2 q in
299 let pos_end = loc.Location.loc_end.Lexing.pos_cnum in
300 let (maybe_more, info_after_opt) =
301 My_ir.just_after_special
303 (get_string_of_file pos_end pos_limit2)
305 met.met_value.val_info <- merge_infos met.met_value.val_info info_after_opt ;
306 (* update the parameter description *)
307 Odoc_value.update_value_parameters_text met.met_value;
310 let rec f last_pos class_type_field_list =
311 match class_type_field_list with
313 let s = get_string_of_file last_pos pos_limit in
314 let (_, ele_coms) = My_ir.all_special !file_name s in
317 (fun acc -> fun sc ->
318 match sc.Odoc_types.i_desc with
322 acc @ [Class_comment t])
328 | Parsetree.Pctf_val (name, mutable_flag, virtual_flag, _, loc) :: q ->
329 (* of (string * mutable_flag * core_type option * Location.t)*)
330 let (comment_opt, eles_comments) = get_comments_in_class last_pos loc.Location.loc_start.Lexing.pos_cnum in
331 let complete_name = Name.concat current_class_name name in
333 try Signature_search.search_attribute_type name class_signature
335 raise (Failure (Odoc_messages.attribute_type_not_found current_class_name name))
337 let subst_typ = Odoc_env.subst_type env typ in
342 val_name = complete_name ;
343 val_info = comment_opt ;
344 val_type = subst_typ;
345 val_recursive = false ;
346 val_parameters = [] ;
348 val_loc = { loc_impl = None ; loc_inter = Some (!file_name, loc.Location.loc_start.Lexing.pos_cnum)} ;
350 att_mutable = mutable_flag = Asttypes.Mutable ;
351 att_virtual = virtual_flag = Asttypes.Virtual ;
354 let pos_limit2 = get_pos_limit2 q in
355 let pos_end = loc.Location.loc_end.Lexing.pos_cnum in
356 let (maybe_more, info_after_opt) =
357 My_ir.just_after_special
359 (get_string_of_file pos_end pos_limit2)
361 att.att_value.val_info <- merge_infos att.att_value.val_info info_after_opt ;
362 let (inher_l, eles) = f (pos_end + maybe_more) q in
363 (inher_l, eles_comments @ ((Class_attribute att) :: eles))
365 | Parsetree.Pctf_virt (name, private_flag, _, loc) :: q ->
366 (* of (string * private_flag * core_type * Location.t) *)
367 let (comment_opt, eles_comments) = get_comments_in_class last_pos loc.Location.loc_start.Lexing.pos_cnum in
368 let (met, maybe_more) = get_method name comment_opt private_flag loc q in
369 let met2 = { met with met_virtual = true } in
370 let (inher_l, eles) = f (loc.Location.loc_end.Lexing.pos_cnum + maybe_more) q in
371 (inher_l, eles_comments @ ((Class_method met2) :: eles))
373 | Parsetree.Pctf_meth (name, private_flag, _, loc) :: q ->
374 (* of (string * private_flag * core_type * Location.t) *)
375 let (comment_opt, eles_comments) = get_comments_in_class last_pos loc.Location.loc_start.Lexing.pos_cnum in
376 let (met, maybe_more) = get_method name comment_opt private_flag loc q in
377 let (inher_l, eles) = f (loc.Location.loc_end.Lexing.pos_cnum + maybe_more) q in
378 (inher_l, eles_comments @ ((Class_method met) :: eles))
380 | (Parsetree.Pctf_cstr (_, _, loc)) :: q ->
381 (* of (core_type * core_type * Location.t) *)
382 (* A VOIR : cela correspond aux contraintes, non ? on ne les garde pas pour l'instant *)
383 let (comment_opt, eles_comments) = get_comments_in_class last_pos loc.Location.loc_start.Lexing.pos_cnum in
384 let (inher_l, eles) = f loc.Location.loc_end.Lexing.pos_cnum q in
385 (inher_l, eles_comments @ eles)
387 | Parsetree.Pctf_inher class_type :: q ->
388 let loc = class_type.Parsetree.pcty_loc in
389 let (comment_opt, eles_comments) =
390 get_comments_in_class last_pos loc.Location.loc_start.Lexing.pos_cnum
392 let pos_limit2 = get_pos_limit2 q in
393 let pos_end = loc.Location.loc_end.Lexing.pos_cnum in
394 let (maybe_more, info_after_opt) =
395 My_ir.just_after_special
397 (get_string_of_file pos_end pos_limit2)
399 let comment_opt2 = merge_infos comment_opt info_after_opt in
400 let text_opt = match comment_opt2 with None -> None | Some i -> i.Odoc_types.i_desc in
402 match class_type.Parsetree.pcty_desc with
403 Parsetree.Pcty_constr (longident, _) ->
404 (*of Longident.t * core_type list*)
405 let name = Name.from_longident longident in
408 ic_name = Odoc_env.full_class_or_class_type_name env name ;
415 | Parsetree.Pcty_signature _
416 | Parsetree.Pcty_fun _ ->
417 (* we don't have a name for the class signature, so we call it "object ... end" *)
419 ic_name = Odoc_messages.object_end ;
424 let (inher_l, eles) = f (pos_end + maybe_more) q in
425 (inh :: inher_l , eles_comments @ eles)
427 f last_pos class_type_field_list
429 (** Analyse of a .mli parse tree, to get the corresponding elements.
430 last_pos is the position of the first character which may be used to look for special comments.
432 let rec analyse_parsetree env signat current_module_name last_pos pos_limit sig_item_list =
433 let table = Signature_search.table signat in
434 (* we look for the comment of each item then analyse the item *)
435 let rec f acc_eles acc_env last_pos = function
437 let s = get_string_of_file last_pos pos_limit in
438 let (_, ele_coms) = My_ir.all_special !file_name s in
441 (fun acc -> fun sc ->
442 match sc.Odoc_types.i_desc with
446 acc @ [Element_module_comment t])
450 acc_eles @ ele_comments
453 let (assoc_com, ele_comments) = get_comments_in_module
455 ele.Parsetree.psig_loc.Location.loc_start.Lexing.pos_cnum
457 let (maybe_more, new_env, elements) = analyse_signature_item_desc
462 ele.Parsetree.psig_loc.Location.loc_start.Lexing.pos_cnum
463 ele.Parsetree.psig_loc.Location.loc_end.Lexing.pos_cnum
466 | ele2 :: _ -> ele2.Parsetree.psig_loc.Location.loc_start.Lexing.pos_cnum
469 ele.Parsetree.psig_desc
471 f (acc_eles @ (ele_comments @ elements))
473 (ele.Parsetree.psig_loc.Location.loc_end.Lexing.pos_cnum + maybe_more)
474 (* for the comments of constructors in types,
475 which are after the constructor definition and can
476 go beyond ele.Parsetree.psig_loc.Location.loc_end.Lexing.pos_cnum *)
479 f [] env last_pos sig_item_list
481 (** Analyse the given signature_item_desc to create the corresponding module element
482 (with the given attached comment).*)
483 and analyse_signature_item_desc env signat table current_module_name
484 pos_start_ele pos_end_ele pos_limit comment_opt sig_item_desc =
485 match sig_item_desc with
486 Parsetree.Psig_value (name_pre, value_desc) ->
488 try Signature_search.search_value table name_pre
490 raise (Failure (Odoc_messages.value_not_found current_module_name name_pre))
492 let name = Name.parens_if_infix name_pre in
493 let subst_typ = Odoc_env.subst_type env type_expr in
496 val_name = Name.concat current_module_name name ;
497 val_info = comment_opt ;
498 val_type = subst_typ ;
499 val_recursive = false ;
500 val_parameters = Odoc_value.dummy_parameter_list subst_typ ;
502 val_loc = { loc_impl = None ; loc_inter = Some (!file_name, pos_start_ele)}
505 let (maybe_more, info_after_opt) =
506 My_ir.just_after_special
508 (get_string_of_file pos_end_ele pos_limit)
510 v.val_info <- merge_infos v.val_info info_after_opt ;
511 (* update the parameter description *)
512 Odoc_value.update_value_parameters_text v;
514 let new_env = Odoc_env.add_value env v.val_name in
515 (maybe_more, new_env, [ Element_value v ])
517 | Parsetree.Psig_exception (name, exception_decl) ->
518 let types_excep_decl =
519 try Signature_search.search_exception table name
521 raise (Failure (Odoc_messages.exception_not_found current_module_name name))
525 ex_name = Name.concat current_module_name name ;
526 ex_info = comment_opt ;
527 ex_args = List.map (Odoc_env.subst_type env) types_excep_decl ;
529 ex_loc = { loc_impl = None ; loc_inter = Some (!file_name, pos_start_ele) } ;
532 if !Odoc_args.keep_code then
533 Some (get_string_of_file pos_start_ele pos_end_ele)
539 let (maybe_more, info_after_opt) =
540 My_ir.just_after_special
542 (get_string_of_file pos_end_ele pos_limit)
544 e.ex_info <- merge_infos e.ex_info info_after_opt ;
545 let new_env = Odoc_env.add_exception env e.ex_name in
546 (maybe_more, new_env, [ Element_exception e ])
548 | Parsetree.Psig_type name_type_decl_list ->
549 (* we start by extending the environment *)
552 (fun acc_env -> fun (name, _) ->
553 let complete_name = Name.concat current_module_name name in
554 Odoc_env.add_type acc_env complete_name
559 let rec f ?(first=false) acc_maybe_more last_pos name_type_decl_list =
560 match name_type_decl_list with
563 | (name, type_decl) :: q ->
564 let (assoc_com, ele_comments) =
568 get_comments_in_module
570 type_decl.Parsetree.ptype_loc.Location.loc_start.Lexing.pos_cnum
575 | (_, td) :: _ -> td.Parsetree.ptype_loc.Location.loc_start.Lexing.pos_cnum
577 let (maybe_more, name_comment_list) =
578 name_comment_from_type_kind
579 type_decl.Parsetree.ptype_loc.Location.loc_end.Lexing.pos_cnum
581 type_decl.Parsetree.ptype_kind
583 print_DEBUG ("Type "^name^" : "^(match assoc_com with None -> "sans commentaire" | Some c -> Odoc_misc.string_of_info c));
584 let f_DEBUG (name, c_opt) = print_DEBUG ("constructor/field "^name^": "^(match c_opt with None -> "sans commentaire" | Some c -> Odoc_misc.string_of_info c)) in
585 List.iter f_DEBUG name_comment_list;
586 (* get the information for the type in the signature *)
588 try Signature_search.search_type table name
590 raise (Failure (Odoc_messages.type_not_found current_module_name name))
592 (* get the type kind with the associated comments *)
593 let type_kind = get_type_kind new_env name_comment_list sig_type_decl.Types.type_kind in
594 let loc_start = type_decl.Parsetree.ptype_loc.Location.loc_start.Lexing.pos_cnum in
595 let new_end = type_decl.Parsetree.ptype_loc.Location.loc_end.Lexing.pos_cnum + maybe_more in
596 (* associate the comments to each constructor and build the [Type.t_type] *)
599 ty_name = Name.concat current_module_name name ;
600 ty_info = assoc_com ;
602 List.map2 (fun p (co,cn,_) ->
603 (Odoc_env.subst_type new_env p,
606 sig_type_decl.Types.type_params
607 sig_type_decl.Types.type_variance;
609 ty_private = sig_type_decl.Types.type_private;
611 (match sig_type_decl.Types.type_manifest with
613 | Some t -> Some (Odoc_env.subst_type new_env t));
616 loc_inter = Some (!file_name,loc_start) ;
620 if !Odoc_args.keep_code then
621 Some (get_string_of_file loc_start new_end)
627 let (maybe_more2, info_after_opt) =
628 My_ir.just_after_special
630 (get_string_of_file new_end pos_limit2)
632 new_type.ty_info <- merge_infos new_type.ty_info info_after_opt ;
633 let (new_maybe_more, eles) = f
634 (maybe_more + maybe_more2)
635 (new_end + maybe_more2)
638 (new_maybe_more, (ele_comments @ [Element_type new_type]) @ eles)
640 let (maybe_more, types) = f ~first: true 0 pos_start_ele name_type_decl_list in
641 (maybe_more, new_env, types)
643 | Parsetree.Psig_open _ -> (* A VOIR *)
644 let ele_comments = match comment_opt with
649 | Some t -> [Element_module_comment t]
651 (0, env, ele_comments)
653 | Parsetree.Psig_module (name, module_type) ->
654 let complete_name = Name.concat current_module_name name in
655 (* get the the module type in the signature by the module name *)
656 let sig_module_type =
657 try Signature_search.search_module table name
659 raise (Failure (Odoc_messages.module_not_found current_module_name name))
661 let module_kind = analyse_module_kind env complete_name module_type sig_module_type in
663 if !Odoc_args.keep_code then
664 let loc = module_type.Parsetree.pmty_loc in
665 let st = loc.Location.loc_start.Lexing.pos_cnum in
666 let en = loc.Location.loc_end.Lexing.pos_cnum in
667 Some (get_string_of_file st en)
673 m_name = complete_name ;
674 m_type = sig_module_type;
675 m_info = comment_opt ;
676 m_is_interface = true ;
677 m_file = !file_name ;
678 m_kind = module_kind ;
679 m_loc = { loc_impl = None ; loc_inter = Some (!file_name, pos_start_ele) } ;
682 m_code_intf = code_intf ;
683 m_text_only = false ;
686 let (maybe_more, info_after_opt) =
687 My_ir.just_after_special
689 (get_string_of_file pos_end_ele pos_limit)
691 new_module.m_info <- merge_infos new_module.m_info info_after_opt ;
692 let new_env = Odoc_env.add_module env new_module.m_name in
694 match new_module.m_type with (* A VOIR : cela peut-il être Tmty_ident ? dans ce cas, on aurait pas la signature *)
695 Types.Tmty_signature s -> Odoc_env.add_signature new_env new_module.m_name ~rel: (Name.simple new_module.m_name) s
698 (maybe_more, new_env2, [ Element_module new_module ])
700 | Parsetree.Psig_recmodule decls ->
701 (* we start by extending the environment *)
704 (fun acc_env -> fun (name, _) ->
705 let complete_name = Name.concat current_module_name name in
706 let e = Odoc_env.add_module acc_env complete_name in
707 (* get the information for the module in the signature *)
708 let sig_module_type =
709 try Signature_search.search_module table name
711 raise (Failure (Odoc_messages.module_not_found current_module_name name))
713 match sig_module_type with
714 (* A VOIR : cela peut-il être Tmty_ident ? dans ce cas, on aurait pas la signature *)
715 Types.Tmty_signature s ->
716 Odoc_env.add_signature e complete_name ~rel: name s
718 print_DEBUG "not a Tmty_signature";
724 let rec f ?(first=false) acc_maybe_more last_pos name_mtype_list =
725 match name_mtype_list with
728 | (name, modtype) :: q ->
729 let complete_name = Name.concat current_module_name name in
730 let loc_start = modtype.Parsetree.pmty_loc.Location.loc_start.Lexing.pos_cnum in
731 let loc_end = modtype.Parsetree.pmty_loc.Location.loc_end.Lexing.pos_cnum in
732 let (assoc_com, ele_comments) =
736 get_comments_in_module
743 | (_, mty) :: _ -> mty.Parsetree.pmty_loc.Location.loc_start.Lexing.pos_cnum
745 (* get the information for the module in the signature *)
746 let sig_module_type =
747 try Signature_search.search_module table name
749 raise (Failure (Odoc_messages.module_not_found current_module_name name))
751 (* associate the comments to each constructor and build the [Type.t_type] *)
752 let module_kind = analyse_module_kind new_env complete_name modtype sig_module_type in
754 if !Odoc_args.keep_code then
755 let loc = modtype.Parsetree.pmty_loc in
756 let st = loc.Location.loc_start.Lexing.pos_cnum in
757 let en = loc.Location.loc_end.Lexing.pos_cnum in
758 Some (get_string_of_file st en)
764 m_name = complete_name ;
765 m_type = sig_module_type;
767 m_is_interface = true ;
768 m_file = !file_name ;
769 m_kind = module_kind ;
770 m_loc = { loc_impl = None ; loc_inter = Some (!file_name, pos_start_ele) } ;
773 m_code_intf = code_intf ;
774 m_text_only = false ;
777 let (maybe_more, info_after_opt) =
778 My_ir.just_after_special
780 (get_string_of_file loc_end pos_limit2)
782 new_module.m_info <- merge_infos new_module.m_info info_after_opt ;
784 let (maybe_more2, eles) = f
786 (loc_end + maybe_more)
789 (maybe_more2, (ele_comments @ [Element_module new_module]) @ eles)
791 let (maybe_more, mods) = f ~first: true 0 pos_start_ele decls in
792 (maybe_more, new_env, mods)
794 | Parsetree.Psig_modtype (name, Parsetree.Pmodtype_abstract) ->
796 try Signature_search.search_module_type table name
798 raise (Failure (Odoc_messages.module_type_not_found current_module_name name))
800 let complete_name = Name.concat current_module_name name in
803 mt_name = complete_name ;
804 mt_info = comment_opt ;
805 mt_type = sig_mtype ;
806 mt_is_interface = true ;
807 mt_file = !file_name ;
809 mt_loc = { loc_impl = None ; loc_inter = Some (!file_name, pos_start_ele) } ;
812 let (maybe_more, info_after_opt) =
813 My_ir.just_after_special
815 (get_string_of_file pos_end_ele pos_limit)
817 mt.mt_info <- merge_infos mt.mt_info info_after_opt ;
818 let new_env = Odoc_env.add_module_type env mt.mt_name in
819 (maybe_more, new_env, [ Element_module_type mt ])
821 | Parsetree.Psig_modtype (name, Parsetree.Pmodtype_manifest module_type) ->
822 let complete_name = Name.concat current_module_name name in
824 try Signature_search.search_module_type table name
826 raise (Failure (Odoc_messages.module_type_not_found current_module_name name))
828 let module_type_kind =
829 match sig_mtype_opt with
830 | Some sig_mtype -> Some (analyse_module_type_kind env complete_name module_type sig_mtype)
835 mt_name = complete_name ;
836 mt_info = comment_opt ;
837 mt_type = sig_mtype_opt ;
838 mt_is_interface = true ;
839 mt_file = !file_name ;
840 mt_kind = module_type_kind ;
841 mt_loc = { loc_impl = None ; loc_inter = Some (!file_name, pos_start_ele) } ;
844 let (maybe_more, info_after_opt) =
845 My_ir.just_after_special
847 (get_string_of_file pos_end_ele pos_limit)
849 mt.mt_info <- merge_infos mt.mt_info info_after_opt ;
850 let new_env = Odoc_env.add_module_type env mt.mt_name in
852 match sig_mtype_opt with (* A VOIR : cela peut-il être Tmty_ident ? dans ce cas, on aurait pas la signature *)
853 Some (Types.Tmty_signature s) -> Odoc_env.add_signature new_env mt.mt_name ~rel: (Name.simple mt.mt_name) s
856 (maybe_more, new_env2, [ Element_module_type mt ])
858 | Parsetree.Psig_include module_type ->
860 Parsetree.Pmty_ident longident ->
861 Name.from_longident longident
862 | Parsetree.Pmty_signature _ ->
864 | Parsetree.Pmty_functor _ ->
866 | Parsetree.Pmty_with (mt, _) ->
867 f mt.Parsetree.pmty_desc
869 let name = (f module_type.Parsetree.pmty_desc) in
870 let full_name = Odoc_env.full_module_or_module_type_name env name in
873 im_name = full_name ;
875 im_info = comment_opt;
878 (0, env, [ Element_included_module im ]) (* A VOIR : étendre l'environnement ? avec quoi ? *)
880 | Parsetree.Psig_class class_description_list ->
881 (* we start by extending the environment *)
884 (fun acc_env -> fun class_desc ->
885 let complete_name = Name.concat current_module_name class_desc.Parsetree.pci_name in
886 Odoc_env.add_class acc_env complete_name
889 class_description_list
891 let rec f ?(first=false) acc_maybe_more last_pos class_description_list =
892 match class_description_list with
896 let (assoc_com, ele_comments) =
900 get_comments_in_module
902 class_desc.Parsetree.pci_loc.Location.loc_start.Lexing.pos_cnum
904 let pos_end = class_desc.Parsetree.pci_loc.Location.loc_end.Lexing.pos_cnum in
908 | cd :: _ -> cd.Parsetree.pci_loc.Location.loc_start.Lexing.pos_cnum
910 let name = class_desc.Parsetree.pci_name in
911 let complete_name = Name.concat current_module_name name in
913 try Signature_search.search_class table name
915 raise (Failure (Odoc_messages.class_not_found current_module_name name))
917 let sig_class_type = sig_class_decl.Types.cty_type in
918 let (parameters, class_kind) =
922 class_desc.Parsetree.pci_loc.Location.loc_start.Lexing.pos_cnum
923 class_desc.Parsetree.pci_expr
928 cl_name = complete_name ;
929 cl_info = assoc_com ;
930 cl_type = Odoc_env.subst_class_type env sig_class_type ;
931 cl_type_parameters = sig_class_decl.Types.cty_params;
932 cl_virtual = class_desc.Parsetree.pci_virt = Asttypes.Virtual ;
933 cl_kind = class_kind ;
934 cl_parameters = parameters ;
935 cl_loc = { loc_impl = None ; loc_inter = Some (!file_name, pos_start_ele) } ;
938 let (maybe_more, info_after_opt) =
939 My_ir.just_after_special
941 (get_string_of_file pos_end pos_limit2)
943 new_class.cl_info <- merge_infos new_class.cl_info info_after_opt ;
944 Odoc_class.class_update_parameters_text new_class ;
945 let (new_maybe_more, eles) =
946 f maybe_more (pos_end + maybe_more) q
949 ele_comments @ (( Element_class new_class ) :: eles))
951 let (maybe_more, eles) =
952 f ~first: true 0 pos_start_ele class_description_list
954 (maybe_more, new_env, eles)
956 | Parsetree.Psig_class_type class_type_declaration_list ->
957 (* we start by extending the environment *)
960 (fun acc_env -> fun class_type_decl ->
961 let complete_name = Name.concat current_module_name class_type_decl.Parsetree.pci_name in
962 Odoc_env.add_class_type acc_env complete_name
965 class_type_declaration_list
967 let rec f ?(first=false) acc_maybe_more last_pos class_type_description_list =
968 match class_type_description_list with
972 let (assoc_com, ele_comments) =
976 get_comments_in_module
978 ct_decl.Parsetree.pci_loc.Location.loc_start.Lexing.pos_cnum
980 let pos_end = ct_decl.Parsetree.pci_loc.Location.loc_end.Lexing.pos_cnum in
984 | ct_decl2 :: _ -> ct_decl2.Parsetree.pci_loc.Location.loc_start.Lexing.pos_cnum
986 let name = ct_decl.Parsetree.pci_name in
987 let complete_name = Name.concat current_module_name name in
988 let sig_cltype_decl =
989 try Signature_search.search_class_type table name
991 raise (Failure (Odoc_messages.class_type_not_found current_module_name name))
993 let sig_class_type = sig_cltype_decl.Types.clty_type in
994 let kind = analyse_class_type_kind
997 ct_decl.Parsetree.pci_loc.Location.loc_start.Lexing.pos_cnum
998 ct_decl.Parsetree.pci_expr
1003 clt_name = complete_name ;
1004 clt_info = assoc_com ;
1005 clt_type = Odoc_env.subst_class_type env sig_class_type ;
1006 clt_type_parameters = sig_cltype_decl.clty_params ;
1007 clt_virtual = ct_decl.Parsetree.pci_virt = Asttypes.Virtual ;
1009 clt_loc = { loc_impl = None ; loc_inter = Some (!file_name, pos_start_ele) } ;
1012 let (maybe_more, info_after_opt) =
1013 My_ir.just_after_special
1015 (get_string_of_file pos_end pos_limit2)
1017 ct.clt_info <- merge_infos ct.clt_info info_after_opt ;
1018 let (new_maybe_more, eles) =
1019 f maybe_more (pos_end + maybe_more) q
1022 ele_comments @ (( Element_class_type ct) :: eles))
1024 let (maybe_more, eles) =
1025 f ~first: true 0 pos_start_ele class_type_declaration_list
1027 (maybe_more, new_env, eles)
1029 (** Return a module_type_kind from a Parsetree.module_type and a Types.module_type *)
1030 and analyse_module_type_kind env current_module_name module_type sig_module_type =
1031 match module_type.Parsetree.pmty_desc with
1032 Parsetree.Pmty_ident longident ->
1034 match sig_module_type with
1035 Types.Tmty_ident path -> Name.from_path path
1036 | _ -> Name.from_longident longident
1037 (* A VOIR cela arrive quand on fait module type F : functor ... -> Toto, Toto n'est pas un ident mais une structure *)
1039 Module_type_alias { mta_name = Odoc_env.full_module_type_name env name ;
1042 | Parsetree.Pmty_signature ast ->
1044 (* we must have a signature in the module type *)
1045 match sig_module_type with
1046 Types.Tmty_signature signat ->
1047 let pos_start = module_type.Parsetree.pmty_loc.Location.loc_start.Lexing.pos_cnum in
1048 let pos_end = module_type.Parsetree.pmty_loc.Location.loc_end.Lexing.pos_cnum in
1049 let elements = analyse_parsetree env signat current_module_name pos_start pos_end ast in
1050 Module_type_struct elements
1052 raise (Failure "Parsetree.Pmty_signature signature but not Types.Tmty_signature signat")
1055 | Parsetree.Pmty_functor (_,pmodule_type2, module_type2) ->
1057 let loc_start = pmodule_type2.Parsetree.pmty_loc.Location.loc_start.Lexing.pos_cnum in
1058 let loc_end = pmodule_type2.Parsetree.pmty_loc.Location.loc_end.Lexing.pos_cnum in
1059 let mp_type_code = get_string_of_file loc_start loc_end in
1060 print_DEBUG (Printf.sprintf "mp_type_code=%s" mp_type_code);
1061 match sig_module_type with
1062 Types.Tmty_functor (ident, param_module_type, body_module_type) ->
1063 let mp_kind = analyse_module_type_kind env
1064 current_module_name pmodule_type2 param_module_type
1068 mp_name = Name.from_ident ident ;
1069 mp_type = Odoc_env.subst_module_type env param_module_type ;
1070 mp_type_code = mp_type_code ;
1074 let k = analyse_module_type_kind env
1079 Module_type_functor (param, k)
1082 (* if we're here something's wrong *)
1083 raise (Failure "Parsetree.Pmty_functor _ but not Types.Tmty_functor _")
1086 | Parsetree.Pmty_with (module_type2, _) ->
1087 (* of module_type * (Longident.t * with_constraint) list *)
1089 let loc_start = module_type2.Parsetree.pmty_loc.Location.loc_end.Lexing.pos_cnum in
1090 let loc_end = module_type.Parsetree.pmty_loc.Location.loc_end.Lexing.pos_cnum in
1091 let s = get_string_of_file loc_start loc_end in
1092 let k = analyse_module_type_kind env current_module_name module_type2 sig_module_type in
1093 Module_type_with (k, s)
1096 (** Analyse of a Parsetree.module_type and a Types.module_type.*)
1097 and analyse_module_kind env current_module_name module_type sig_module_type =
1098 match module_type.Parsetree.pmty_desc with
1099 Parsetree.Pmty_ident longident ->
1100 let k = analyse_module_type_kind env current_module_name module_type sig_module_type in
1101 Module_with ( k, "" )
1103 | Parsetree.Pmty_signature signature ->
1105 match sig_module_type with
1106 Types.Tmty_signature signat ->
1112 module_type.Parsetree.pmty_loc.Location.loc_start.Lexing.pos_cnum
1113 module_type.Parsetree.pmty_loc.Location.loc_end.Lexing.pos_cnum
1117 (* if we're here something's wrong *)
1118 raise (Failure "Parsetree.Pmty_signature signature but not Types.Tmty_signature signat")
1120 | Parsetree.Pmty_functor (_,pmodule_type2,module_type2) (* of string * module_type * module_type *) ->
1122 match sig_module_type with
1123 Types.Tmty_functor (ident, param_module_type, body_module_type) ->
1124 let loc_start = pmodule_type2.Parsetree.pmty_loc.Location.loc_start.Lexing.pos_cnum in
1125 let loc_end = pmodule_type2.Parsetree.pmty_loc.Location.loc_end.Lexing.pos_cnum in
1126 let mp_type_code = get_string_of_file loc_start loc_end in
1127 print_DEBUG (Printf.sprintf "mp_type_code=%s" mp_type_code);
1128 let mp_kind = analyse_module_type_kind env
1129 current_module_name pmodule_type2 param_module_type
1133 mp_name = Name.from_ident ident ;
1134 mp_type = Odoc_env.subst_module_type env param_module_type ;
1135 mp_type_code = mp_type_code ;
1139 let k = analyse_module_kind env
1144 Module_functor (param, k)
1147 (* if we're here something's wrong *)
1148 raise (Failure "Parsetree.Pmty_functor _ but not Types.Tmty_functor _")
1150 | Parsetree.Pmty_with (module_type2, _) ->
1151 (*of module_type * (Longident.t * with_constraint) list*)
1153 let loc_start = module_type2.Parsetree.pmty_loc.Location.loc_end.Lexing.pos_cnum in
1154 let loc_end = module_type.Parsetree.pmty_loc.Location.loc_end.Lexing.pos_cnum in
1155 let s = get_string_of_file loc_start loc_end in
1156 let k = analyse_module_type_kind env current_module_name module_type2 sig_module_type in
1160 (** Analyse of a Parsetree.class_type and a Types.class_type to return a couple
1161 (class parameters, class_kind).*)
1162 and analyse_class_kind env current_class_name last_pos parse_class_type sig_class_type =
1163 match parse_class_type.Parsetree.pcty_desc, sig_class_type with
1164 (Parsetree.Pcty_constr (_, _) (*of Longident.t * core_type list *),
1165 Types.Tcty_constr (p, typ_list, _) (*of Path.t * type_expr list * class_type*)) ->
1166 print_DEBUG "Tcty_constr _";
1167 let path_name = Name.from_path p in
1168 let name = Odoc_env.full_class_or_class_type_name env path_name in
1174 cco_type_parameters = List.map (Odoc_env.subst_type env) typ_list
1179 | (Parsetree.Pcty_signature (_, class_type_field_list), Types.Tcty_signature class_signature) ->
1180 (* we get the elements of the class in class_type_field_list *)
1181 let (inher_l, ele) = analyse_class_elements env current_class_name
1183 parse_class_type.Parsetree.pcty_loc.Location.loc_end.Lexing.pos_cnum
1184 class_type_field_list
1187 ([], Class_structure (inher_l, ele))
1189 | (Parsetree.Pcty_fun (parse_label, _, pclass_type), Types.Tcty_fun (label, type_expr, class_type)) ->
1190 (* label = string. Dans les signatures, pas de nom de paramètres à l'intérieur des tuples *)
1191 (* si label = "", pas de label. ici on a l'information pour savoir si on a un label explicite. *)
1192 if parse_label = label then
1194 let new_param = Simple_name
1196 sn_name = Btype.label_name label ;
1197 sn_type = Odoc_env.subst_type env type_expr ;
1198 sn_text = None ; (* will be updated when the class will be created *)
1201 let (l, k) = analyse_class_kind env current_class_name last_pos pclass_type class_type in
1202 ( (new_param :: l), k )
1206 raise (Failure "Parsetree.Pcty_fun (parse_label, _, pclass_type), labels différents")
1210 raise (Failure "analyse_class_kind pas de correspondance dans le match")
1212 (** Analyse of a Parsetree.class_type and a Types.class_type to return a class_type_kind.*)
1213 and analyse_class_type_kind env current_class_name last_pos parse_class_type sig_class_type =
1214 match parse_class_type.Parsetree.pcty_desc, sig_class_type with
1215 (Parsetree.Pcty_constr (_, _) (*of Longident.t * core_type list *),
1216 Types.Tcty_constr (p, typ_list, _) (*of Path.t * type_expr list * class_type*)) ->
1217 print_DEBUG "Tcty_constr _";
1221 cta_name = Odoc_env.full_class_or_class_type_name env (Name.from_path p) ;
1223 cta_type_parameters = List.map (Odoc_env.subst_type env) typ_list
1228 | (Parsetree.Pcty_signature (_, class_type_field_list), Types.Tcty_signature class_signature) ->
1229 (* we get the elements of the class in class_type_field_list *)
1230 let (inher_l, ele) = analyse_class_elements env current_class_name
1232 parse_class_type.Parsetree.pcty_loc.Location.loc_end.Lexing.pos_cnum
1233 class_type_field_list
1236 Class_signature (inher_l, ele)
1238 | (Parsetree.Pcty_fun (parse_label, _, pclass_type), Types.Tcty_fun (label, type_expr, class_type)) ->
1239 raise (Failure "analyse_class_type_kind : Parsetree.Pcty_fun (...) with Types.Tcty_fun (...)")
1241 | (Parsetree.Pcty_constr (longident, _) (*of Longident.t * core_type list *),
1242 Types.Tcty_signature class_signature) ->
1243 (* A VOIR : c'est pour le cas des contraintes de classes :
1244 class type cons = object
1248 class ['a] maxou x =
1258 cta_name = Odoc_env.full_class_name env (Name.from_longident longident) ;
1260 cta_type_parameters = List.map (Odoc_env.subst_type env) typ_list (* ?? *)
1266 raise (Failure "analyse_class_type_kind pas de correspondance dans le match")
1268 let analyse_signature source_file input_file
1269 (ast : Parsetree.signature) (signat : Types.signature) =
1270 let complete_source_file =
1272 let curdir = Sys.getcwd () in
1273 let (dirname, basename) = (Filename.dirname source_file, Filename.basename source_file) in
1275 let complete = Filename.concat (Sys.getcwd ()) basename in
1281 incr Odoc_global.errors ;
1284 prepare_file complete_source_file input_file;
1285 (* We create the t_module for this file. *)
1286 let mod_name = String.capitalize
1287 (Filename.basename (try Filename.chop_extension source_file with _ -> source_file))
1289 let (len,info_opt) = My_ir.first_special !file_name !file in
1291 analyse_parsetree Odoc_env.empty signat mod_name len (String.length !file) ast
1294 if !Odoc_args.keep_code then
1301 m_type = Types.Tmty_signature signat ;
1303 m_is_interface = true ;
1304 m_file = !file_name ;
1305 m_kind = Module_struct elements ;
1306 m_loc = { loc_impl = None ; loc_inter = Some (!file_name, 0) } ;
1309 m_code_intf = code_intf ;
1310 m_text_only = false ;