File: docgen.ml

package info (click to toggle)
frama-c 20161101%2Bsilicon%2Bdfsg-5
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 42,324 kB
  • ctags: 35,695
  • sloc: ml: 200,142; ansic: 31,465; makefile: 2,334; sh: 1,643; lisp: 259; python: 85; asm: 26
file content (421 lines) | stat: -rw-r--r-- 14,778 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
(**************************************************************************)
(*                                                                        *)
(*  This file is part of Frama-C.                                         *)
(*                                                                        *)
(*  Copyright (C) 2007-2016                                               *)
(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
(*         alternatives)                                                  *)
(*                                                                        *)
(*  you can redistribute it and/or modify it under the terms of the GNU   *)
(*  Lesser General Public License as published by the Free Software       *)
(*  Foundation, version 2.1.                                              *)
(*                                                                        *)
(*  It is distributed in the hope that it will be useful,                 *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
(*  GNU Lesser General Public License for more details.                   *)
(*                                                                        *)
(*  See the GNU Lesser General Public License version 2.1                 *)
(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
(*                                                                        *)
(**************************************************************************)

open Odoc_module
open Odoc_info
open Odoc_html

let doc_path = ref "."
let lib_files = ref []

let add_libfiles analyse s =
  let f = Odoc_global.Intf_file s in
  lib_files :=
    (String.capitalize (Filename.chop_extension (Filename.basename s))) ::
      !lib_files;
  if analyse then Odoc_global.files := f :: !Odoc_global.files

let rec root_name s =
  let simple = Odoc_info.Name.simple s in
  let father = Odoc_info.Name.father s in
  if father = "" then simple else root_name father

let equal_module_name m s =
  let n = m.m_name in
  n = s && n = root_name n

let equal_module m1 m2 = equal_module_name m1 m2.m_name

type chapter = Chapter of int * string * string | Directory of string
let compare_chapter c1 c2 = match c1 , c2 with
    | Chapter(a,_,_) , Chapter(b,_,_) -> a-b
    | Directory a , Directory b -> compare a b
    | Chapter _ , Directory _ -> (-1)
    | Directory _ , Chapter _ -> 1

let merge3
    (s1 : 'a -> 'a -> int)
    (s2 : 'b -> 'b -> int)
    (s3 : 'c -> 'c -> int)
    (triplets : ('a * 'b * 'c) list)
    : ('a * ('b * 'c list) list) list =
  let sort3_rev s1 s2 s3 (x,y,z) (x',y',z') =
    let c = s1 x' x in
    if c <> 0 then c else
      let c = s2 y' y in
      if c <> 0 then c else
	s3 z' z
  in
  let rec merge3_rev acc triplets =
    match triplets , acc with
      | [] , _ -> acc
      | (a,b,c)::tail , (dir_a,all_a)::a_merged when a = dir_a ->
	  begin
	    match all_a with
	      | (dir_b,all_b)::b_merged when b = dir_b ->
		  merge3_rev ((dir_a,(dir_b,c::all_b)::b_merged)::a_merged) tail
	      | _ ->
		  merge3_rev ((dir_a,(b,[c])::all_a)::a_merged) tail
	  end
      | (a,b,c)::tail , merged ->
	  merge3_rev (( a , [b,[c]] )::merged) tail
  in
  merge3_rev [] (List.sort (sort3_rev s1 s2 s3) triplets)

module Generator (G:Odoc_html.Html_generator) =
struct
  class html = object (self)
      
    inherit G.html as super

    val mutable memo = []
      
    method private loaded_modules =
      match memo with
      | [] ->
	let l = List.flatten
	  (List.map
	     (fun f ->
	       Odoc_info.verbose (Odoc_messages.loading f);
	       try
		 let l = Odoc_analyse.load_modules f in
		 Odoc_info.verbose Odoc_messages.ok;
		 l
	       with Failure s ->
		 prerr_endline s ;
		 incr Odoc_global.errors ;
		 []
	     )
	     !Odoc_global.load
	  )
	in
	memo <- l;
	l
      | (_ :: _) as l -> l
        
    method private path s =
      let name = root_name s in
      if List.exists (fun m -> m = name) !lib_files then
        "http://caml.inria.fr/pub/docs/manual-ocaml/libref/"
      else
        if List.exists (fun m -> m.m_name = name) self#loaded_modules
        then !doc_path ^ "/"
        else "./"

    method create_fully_qualified_idents_links m_name s =
      let f str_t =
        let match_s = Str.matched_string str_t in
        let rel = Odoc_info.Name.get_relative m_name match_s in
        let s_final = Odoc_info.apply_if_equal
	  Odoc_info.use_hidden_modules
	  match_s
	  rel
        in
        if StringSet.mem match_s known_types_names then
	  "<a href=\"" ^ self#path match_s ^ Naming.complete_target Naming.mark_type
	    match_s ^"\">" ^ s_final ^ "</a>"
        else
	  if StringSet.mem match_s known_classes_names then
            let (html_file, _) = Naming.html_files match_s in
            "<a href=\""^ self#path html_file ^ html_file^"\">"^s_final^"</a>"
	  else
            s_final
      in
      let s2 = Str.global_substitute
        (Str.regexp "\\([A-Z]\\([a-zA-Z_'0-9]\\)*\\.\\)+\\([a-z][a-zA-Z_'0-9]*\\)")
        f
        s
      in
      s2

    (** Take a string and return the string where fully qualified module idents
        have been replaced by links to the module referenced by the ident.*)
    method create_fully_qualified_module_idents_links m_name s =
      let f str_t =
        let match_s = Str.matched_string str_t in
        let rel = Odoc_info.Name.get_relative m_name match_s in
        let s_final = Odoc_info.apply_if_equal
	  Odoc_info.use_hidden_modules
	  match_s
	  rel
        in
        if StringSet.mem match_s known_modules_names then
	  let (html_file, _) = Naming.html_files match_s in
	  "<a href=\"" ^ self#path match_s ^ html_file^"\">"^s_final^"</a>"
        else
	  s_final
      in
      let s2 = Str.global_substitute
        (Str.regexp "\\([A-Z]\\([a-zA-Z_'0-9]\\)*\\.\\)+\\([A-Z][a-zA-Z_'0-9]*\\)")
        f
        s
      in
      s2

    (** redefine from file odoc_html.ml *)
    method html_of_Module_list b l =
      let dir f = (* <dir> , <name> *)
        let chop dir f =
	  let n = Str.search_forward (Str.regexp dir) f 0 in
	  let f = String.sub f n (String.length f - n) in
	  let d = Filename.dirname f in
	  String.capitalize (Filename.basename d)
        in
        try
          Chapter(1,"Kernel Services","src/kernel_services"),
          chop "kernel_services/" f
        with Not_found ->
          try Chapter(2,"Libraries","src/libraries"), chop "libraries/" f
          with Not_found ->
            try
              Chapter(3,"Kernel Internals","src/kernel_internals"),
              chop "kernel_internals/" f
            with Not_found ->
              let d = Filename.dirname f in
              Directory (Filename.basename (Filename.dirname d)) ,
              String.capitalize (Filename.basename d)
      in
      let structured_modules (* chapter, section, module *) =
        (List.map
           (fun name ->
             let m = List.find (fun m -> m.m_name = name) self#list_modules in
             let dir,name = dir m.m_file in
             dir,name,m)
           l)
      in
      let toc_modules (* chapter/section/modules *) =
        merge3 compare_chapter compare compare structured_modules
      in
      List.iter
        (fun (chapter, subdirs) ->
	  let dir =
	    ( match chapter with
	    | Chapter (n,a,d) ->
	      bp b "<h1 class=\"chapter\">Chapter %d. %s</h1>" n a ; d
	    | Directory d ->
	      bp b "<h1>Directory %s</h1>" d ; d)
	  in
	  List.iter
	    (fun (subdir,modules) ->
	      bp b "<h2 class=\"section\">Section %s <span class=\"directory\">(in %s/%s)</span></h2>\n"
		subdir dir (String.lowercase subdir) ;
	      bs b "<br>\n<table class=\"indextable\">\n";
	      List.iter
		(fun m ->
		  bs b "<tr><td>";
		  (try
		     let (html, _) = Naming.html_files m.m_name in
		     bp b "<a href=\"%s\">%s</a></td>" html m.m_name;
		     bs b "<td>";
		     self#html_of_info_first_sentence b m.m_info;
		   with Not_found ->
		     Odoc_global.pwarning
		       (Odoc_messages.cross_module_not_found m.m_name);
		     bp b "%s</td><td>" m.m_name);
		  bs b "</td></tr>\n")
		modules;
	      bs b "</table>\n")
	    subdirs)
        toc_modules

    (** Print html code for an included module. *)
    method html_of_included_module b im =
      bs b "<pre>";
      bs b ((self#keyword "include")^" ");
      (
        match im.im_module with
          None ->
            bs b im.im_name
        | Some mmt ->
          let (file, name) =
            match mmt with
              Mod m ->
                let (html_file, _) = Naming.html_files m.m_name in
                (html_file, m.m_name)
            | Modtype mt ->
              let (html_file, _) =
		Naming.html_files mt.mt_name
	      in
              (html_file, mt.mt_name)
          in
          bp b "<a href=\"%s%s\">%s</a>" (self#path name) file name
      );
      bs b "</pre>\n";
      self#html_of_info b im.im_info

    (** Generate all the html files from a module list. The main
        file is [<index_prefix>.html]. *)
    method generate module_list =

      (* init the style *)
      self#init_style ;

      (* init the lists of elements *)
      list_values <- Odoc_info.Search.values module_list ;
      list_exceptions <- Odoc_info.Search.exceptions module_list ;
      list_types <- Odoc_info.Search.types module_list ;
      list_attributes <- Odoc_info.Search.attributes module_list ;
      list_methods <- Odoc_info.Search.methods module_list ;
      list_classes <- Odoc_info.Search.classes module_list ;
      list_class_types <- Odoc_info.Search.class_types module_list ;
      list_modules <- Odoc_info.Search.modules module_list ;
      list_module_types <- Odoc_info.Search.module_types module_list ;

      (* prepare the page header *)
      self#prepare_header module_list ;

      (* Get the names of all known types. *)
      let types = Odoc_info.Search.types module_list in
      known_types_names <-
        List.fold_left
        (fun acc t -> StringSet.add t.Odoc_type.ty_name acc)
        known_types_names
        types ;

      (* Get the names of all class and class types. *)
      let classes = Odoc_info.Search.classes module_list in
      let class_types = Odoc_info.Search.class_types module_list in
      known_classes_names <-
        List.fold_left
        (fun acc c -> StringSet.add c.Odoc_class.cl_name acc)
        known_classes_names
        classes ;
      known_classes_names <-
        List.fold_left
        (fun acc ct -> StringSet.add ct.Odoc_class.clt_name acc)
        known_classes_names
        class_types ;

      (* Get the names of all known modules and module types. *)
      let module_types = Odoc_info.Search.module_types module_list in
      let modules = Odoc_info.Search.modules module_list in
      known_modules_names <-
        List.fold_left
        (fun acc m -> StringSet.add m.m_name acc)
        known_modules_names
        modules ;
      known_modules_names <-
        List.fold_left
        (fun acc mt -> StringSet.add mt.mt_name acc)
        known_modules_names
        module_types ;

      (* generate html for each module *)
      let keep_list =
        let keep m =
	  not (List.exists (equal_module m) self#loaded_modules) &&
	    not (List.exists (equal_module_name m) !lib_files)
        in
        List.filter keep module_list
      in

      if not !Odoc_html.index_only then
        self#generate_elements self#generate_for_module keep_list ;

      (* reinit the lists of elements *)
      list_values <- Odoc_info.Search.values keep_list ;
      list_exceptions <- Odoc_info.Search.exceptions keep_list ;
      list_types <- Odoc_info.Search.types keep_list ;
      list_attributes <- Odoc_info.Search.attributes keep_list ;
      list_methods <- Odoc_info.Search.methods keep_list ;
      list_classes <- Odoc_info.Search.classes keep_list ;
      list_class_types <- Odoc_info.Search.class_types keep_list ;
      list_modules <- Odoc_info.Search.modules keep_list ;
      list_module_types <- Odoc_info.Search.module_types keep_list ;

      try
        self#generate_index keep_list;
        self#generate_values_index keep_list ;
        self#generate_exceptions_index keep_list ;
        self#generate_types_index keep_list ;
        self#generate_attributes_index keep_list ;
        self#generate_methods_index keep_list ;
        self#generate_classes_index keep_list ;
        self#generate_class_types_index keep_list ;
        self#generate_modules_index keep_list ;
        self#generate_module_types_index keep_list ;
      with Failure s ->
        prerr_endline s ;
        incr Odoc_info.errors

    method private html_of_plugin_developer_guide _t =
      "<b>Consult the <a href=\"http://www.frama-c.com/download/frama-c-plugin-development-guide.pdf\">Plugin Development Guide</a></b> for additional details.<br>\n"

    method private html_of_ignore _t = ""

    method private html_of_modify t = match t with
    | [] -> 
      Odoc_info.warning "Found an empty @modify tag"; 
      ""
    | Raw s :: l ->
      let time, explanation =
	try
	  let idx = String.index s ' ' in
	  String.sub s 0 idx,
	  ":" ^ String.sub s idx (String.length s - idx)
	with Not_found ->
	  s, ""
      in
      let text =
	Bold [ Raw "Change in "; Raw time ] :: Raw explanation :: l
      in
      let buf = Buffer.create 7 in
      self#html_of_text buf text;
      Buffer.add_string buf "<br>\n";
      Buffer.contents buf
    | _ :: _ ->
      assert false

    method private html_of_call t = match t with
    | [] -> 
      Odoc_info.warning "Found an empty @call tag"; 
      ""
    | l ->
      let buf = Buffer.create 97 in
      Buffer.add_string buf "<b>Access it by</b> <code class=\"code\">";
      self#html_of_text buf l;
      Buffer.add_string buf "</code>\n";
      Buffer.contents buf

    (* Write the subtitle (eg. "Frama-C Kernel" after the main title
       instead of before, for users that use many tabs in their browser *)
    method inner_title s =
      match self#title with "" -> "" | t -> self#escape s ^ " - " ^ t

    initializer
      tag_functions <-
        ("modify", self#html_of_modify) ::
        ("ignore", self#html_of_ignore) ::
	("call", self#html_of_call) ::
        ("plugin", self#html_of_plugin_developer_guide) :: tag_functions

  end
end

let () =
  Odoc_args.extend_html_generator (module Generator: Odoc_gen.Html_functor);
  Odoc_args.add_option
    ("-docpath", Arg.Set_string doc_path, "Frama-C documentation directory");
  Odoc_args.add_option
    ("-stdlib", Arg.String (add_libfiles true), "Standard library files");
  Odoc_args.add_option
    ("-stdlib-path", Arg.String (add_libfiles false), "Standard library files")