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 (***********************************************************************)
14 (** Analysis of comments. *)
18 let print_DEBUG s
= print_string s
; print_newline
();;
20 (** This variable contains the regular expression representing a blank but not a '\n'.*)
21 let simple_blank = "[ \013\009\012]"
25 (** Return a text structure from a string. *)
26 val text_of_string
: string -> text
29 module Info_retriever
=
30 functor (MyTexter
: Texter
) ->
34 let lexbuf = Lexing.from_string s
in
35 let (see_ref
, s
) = Odoc_parser.see_info
Odoc_see_lexer.main
lexbuf in
36 (see_ref
, MyTexter.text_of_string s
)
38 | Odoc_text.Text_syntax
(l
, c
, s
) ->
39 raise
(Failure
(Odoc_messages.text_parse_error l c s
))
41 raise
(Failure
("Erreur inconnue lors du parse de see : "^s
))
43 let retrieve_info fun_lex file
(s
: string) =
45 let _ = Odoc_comments_global.init
() in
46 Odoc_lexer.comments_level
:= 0;
47 let lexbuf = Lexing.from_string s
in
48 match Odoc_parser.main fun_lex
lexbuf with
51 | Some
(desc
, remain_opt
) ->
52 let mem_nb_chars = !Odoc_comments_global.nb_chars
in
58 (*DEBUG*)print_string
("remain: "^s
); print_newline
();
59 let lexbuf2 = Lexing.from_string s
in
60 Odoc_parser.info_part2
Odoc_lexer.elements
lexbuf2
65 i_desc
= (match desc
with "" -> None
| _ -> Some
(MyTexter.text_of_string desc
));
66 i_authors
= !Odoc_comments_global.authors
;
67 i_version
= !Odoc_comments_global.version
;
68 i_sees
= (List.map
create_see !Odoc_comments_global.sees
) ;
69 i_since
= !Odoc_comments_global.since
;
71 (match !Odoc_comments_global.deprecated
with
72 None
-> None
| Some s
-> Some
(MyTexter.text_of_string s
));
74 (List.map
(fun (n
, s
) ->
75 (n
, MyTexter.text_of_string s
)) !Odoc_comments_global.params
);
77 (List.map
(fun (n
, s
) ->
78 (n
, MyTexter.text_of_string s
)) !Odoc_comments_global.raised_exceptions
);
80 (match !Odoc_comments_global.return_value
with
81 None
-> None
| Some s
-> Some
(MyTexter.text_of_string s
)) ;
83 (fun (tag
, s
) -> (tag
, MyTexter.text_of_string s
))
84 !Odoc_comments_global.customs
)
89 incr
Odoc_global.errors
;
90 prerr_endline
(file^
" : "^s^
"\n");
92 | Odoc_text.Text_syntax
(l
, c
, s
) ->
93 incr
Odoc_global.errors
;
94 prerr_endline
(file^
" : "^
(Odoc_messages.text_parse_error l c s
));
97 incr
Odoc_global.errors
;
98 prerr_endline
(file^
" : "^
Odoc_messages.parse_error^
"\n");
101 (** This function takes a string where a simple comment may has been found. It returns
102 false if there is a blank line or the first comment is a special one, or if there is
103 no comment if the string.*)
104 let nothing_before_simple_comment s
=
105 (* get the position of the first "(*" *)
107 print_DEBUG ("comment_is_attached: "^s
);
108 let pos = Str.search_forward
(Str.regexp
"(\\*") s
0 in
109 let next_char = if (String.length s
) >= (pos + 1) then s
.[pos + 2] else '
_'
in
110 (next_char <> '
*'
) &&
112 (* there is no special comment between the constructor and the coment we got *)
113 let s2 = String.sub s
0 pos in
114 print_DEBUG ("s2="^
s2);
116 let _ = Str.search_forward
(Str.regexp
("['\n']"^
simple_blank^
"*['\n']")) s2 0 in
117 (* a blank line was before the comment *)
127 (** Return true if the given string contains a blank line. *)
130 let _ = Str.search_forward
(Str.regexp
("['\n']"^
simple_blank^
"*['\n']")) s
0 in
131 (* a blank line was before the comment *)
137 let retrieve_info_special file
(s
: string) =
138 retrieve_info Odoc_lexer.main file s
140 let retrieve_info_simple file
(s
: string) =
141 let _ = Odoc_comments_global.init
() in
142 Odoc_lexer.comments_level
:= 0;
143 let lexbuf = Lexing.from_string s
in
144 match Odoc_parser.main
Odoc_lexer.simple
lexbuf with
147 | Some
(desc
, remain_opt
) ->
148 (!Odoc_comments_global.nb_chars
, Some
Odoc_types.dummy_info
)
150 (** Return true if the given string contains a blank line outside a simple comment. *)
151 let blank_line_outside_simple file s
=
153 match retrieve_info_simple file
s2 with
158 let pos = Str.search_forward
(Str.regexp_string
"(*") s2 0 in
159 let s_before = String.sub
s2 0 pos in
160 let s_after = String.sub
s2 len
((String.length
s2) - len
) in
161 (blank_line s_before) || (iter s_after)
164 (* we shouldn't get here *)
169 (** This function returns the first simple comment in
170 the given string. If strict is [true] then no
171 comment is returned if a blank line or a special
172 comment is found before the simple comment. *)
173 let retrieve_first_info_simple ?
(strict
=true) file
(s
: string) =
174 match retrieve_info_simple file s
with
178 (* we check if the comment we got was really attached to the constructor,
179 i.e. that there was no blank line or any special comment "(**" before *)
180 if (not strict
) or (nothing_before_simple_comment s
) then
181 (* ok, we attach the comment to the constructor *)
184 (* a blank line or special comment was before the comment,
185 so we must not attach this comment to the constructor. *)
188 let retrieve_last_info_simple file
(s
: string) =
189 print_DEBUG ("retrieve_last_info_simple:"^s
);
190 let rec f cur_len cur_d
=
192 let s2 = String.sub s cur_len
((String.length s
) - cur_len
) in
193 print_DEBUG ("retrieve_last_info_simple.f:"^
s2);
194 match retrieve_info_simple file
s2 with
196 print_DEBUG "retrieve_last_info_simple: None";
197 (cur_len
+ len
, cur_d
)
199 print_DEBUG "retrieve_last_info_simple: Some";
200 f (len
+ cur_len
) (Some d
)
203 print_DEBUG "retrieve_last_info_simple : Erreur String.sub";
208 let retrieve_last_special_no_blank_after file
(s
: string) =
209 print_DEBUG ("retrieve_last_special_no_blank_after:"^s
);
210 let rec f cur_len cur_d
=
212 let s2 = String.sub s cur_len
((String.length s
) - cur_len
) in
213 print_DEBUG ("retrieve_last_special_no_blank_after.f:"^
s2);
214 match retrieve_info_special file
s2 with
216 print_DEBUG "retrieve_last_special_no_blank_after: None";
217 (cur_len
+ len
, cur_d
)
219 print_DEBUG "retrieve_last_special_no_blank_after: Some";
220 f (len
+ cur_len
) (Some d
)
223 print_DEBUG "retrieve_last_special_no_blank_after : Erreur String.sub";
228 let all_special file s
=
229 print_DEBUG ("all_special: "^s
);
230 let rec iter acc n
s2 =
231 match retrieve_info_special file
s2 with
235 print_DEBUG ("all_special: avant String.sub new_s="^
s2);
236 print_DEBUG ("n2="^
(string_of_int n2
)) ;
237 print_DEBUG ("len(s2)="^
(string_of_int
(String.length
s2))) ;
238 let new_s = String.sub
s2 n2
((String.length
s2) - n2
) in
239 print_DEBUG ("all_special: apres String.sub new_s="^
new_s);
240 iter (acc
@ [i
]) (n
+ n2
) new_s
242 let res = iter [] 0 s
in
243 print_DEBUG ("all_special: end");
246 let just_after_special file s
=
247 print_DEBUG ("just_after_special: "^s
);
248 let res = match retrieve_info_special file s
with
252 (* we must not have a simple comment or a blank line before. *)
253 match retrieve_info_simple file
(String.sub s
0 len
) with
257 (* if the special comment is the stop comment (**/**),
258 then we must not associate it
. *)
259 let pos = Str.search_forward
(Str.regexp_string
"(**") s
0 in
260 if blank_line (String.sub s
0 pos) or
261 d
.Odoc_types.i_desc
= Some
[Odoc_types.Raw
"/*"]
268 (* should not occur *)
274 print_DEBUG ("just_after_special:end");
277 let first_special file s
=
278 retrieve_info_special file s
280 let get_comments f_create_ele file s
=
281 let (assoc_com
, ele_coms
) =
282 (* get the comments *)
283 let (len
, special_coms
) = all_special file s
in
284 (* if there is no blank line after the special comments, and
285 if the last special comment is not the stop special comment, then the
286 last special comments must be associated to the element. *)
287 match List.rev special_coms
with
291 if (blank_line_outside_simple file
292 (String.sub s len
((String.length s
) - len
)) )
293 or h
.Odoc_types.i_desc
= Some
[Odoc_types.Raw
"/*"]
301 (fun acc
-> fun sc
->
302 match sc
.Odoc_types.i_desc
with
306 acc
@ [f_create_ele t
])
310 (assoc_com
, ele_comments)
313 module Basic_info_retriever
= Info_retriever
(Odoc_text.Texter
)
315 let info_of_string s
=
323 i_deprecated
= None
;
325 i_raised_exceptions
= [] ;
326 i_return_value
= None
;
330 let s2 = Printf.sprintf
"(** %s *)" s
in
331 let (_, i_opt
) = Basic_info_retriever.first_special "-" s2 in
336 let info_of_comment_file modlist
f =
338 let s = Odoc_misc.input_file_as_string
f in
339 let i = info_of_string s in
340 Odoc_cross.assoc_comments_info
"" modlist
i