987 lines
35 KiB
OCaml
987 lines
35 KiB
OCaml
(***********************************************************************)
|
|
(* OCamldoc *)
|
|
(* *)
|
|
(* Maxence Guesdon, projet Cristal, INRIA Rocquencourt *)
|
|
(* *)
|
|
(* Copyright 2001 Institut National de Recherche en Informatique et *)
|
|
(* en Automatique. All rights reserved. This file is distributed *)
|
|
(* under the terms of the Q Public License version 1.0. *)
|
|
(* *)
|
|
(***********************************************************************)
|
|
|
|
(* $Id$ *)
|
|
|
|
(** Generation of LaTeX documentation. *)
|
|
|
|
let print_DEBUG s = print_string s ; print_newline ()
|
|
|
|
open Odoc_info
|
|
open Parameter
|
|
open Value
|
|
open Type
|
|
open Exception
|
|
open Class
|
|
open Module
|
|
|
|
|
|
(** Generation of LaTeX code from text structures. *)
|
|
class text =
|
|
object (self)
|
|
(** Return latex code to make a sectionning according to the given level,
|
|
and with the given latex code. *)
|
|
method section_style level s =
|
|
try
|
|
let sec = List.assoc level !Args.latex_titles in
|
|
"\\"^sec^"{"^s^"}\n"
|
|
with Not_found -> s
|
|
|
|
(** Associations of strings to subsitute in latex code. *)
|
|
val mutable subst_strings = [
|
|
("MAXENCE"^"ZZZ", "\\$");
|
|
("MAXENCE"^"YYY", "\\&");
|
|
("MAXENCE"^"XXX", "{\\textbackslash}") ;
|
|
("à", "\\`a") ;
|
|
("â", "\\^a") ;
|
|
("é", "\\'e") ;
|
|
("è", "\\`e") ;
|
|
("ê", "\\^e") ;
|
|
("ë", "\\\"e") ;
|
|
("ç", "\\c{c}") ;
|
|
("ô", "\\^o") ;
|
|
("ö", "\\\"o") ;
|
|
("î", "\\^i") ;
|
|
("ï", "\\\"i") ;
|
|
("ù", "\\`u") ;
|
|
("û", "\\^u") ;
|
|
("%", "\\%") ;
|
|
("_", "\\_");
|
|
("\\.\\.\\.", "$\\ldots$");
|
|
("~", "\\~{}");
|
|
("#", "\\verb`#`");
|
|
("}", "\\}");
|
|
("{", "\\{");
|
|
("&", "\\&");
|
|
(">", "$>$");
|
|
("<", "$<$");
|
|
("=", "$=$");
|
|
(">=", "$\\geq$");
|
|
("<=", "$\\leq$");
|
|
("->", "$\\rightarrow$") ;
|
|
("<-", "$\\leftarrow$");
|
|
("|", "\\textbar ");
|
|
("\\^", "\\textasciicircum ") ;
|
|
("\\.\\.\\.", "$\\ldots$");
|
|
("\\\\", "MAXENCE"^"XXX") ;
|
|
("&", "MAXENCE"^"YYY") ;
|
|
("\\$", "MAXENCE"^"ZZZ")
|
|
]
|
|
|
|
val mutable subst_strings_simple =
|
|
[
|
|
("MAXENCE"^"XXX", "{\\textbackslash}") ;
|
|
"}", "\\}" ;
|
|
"{", "\\{" ;
|
|
("\\\\", "MAXENCE"^"XXX") ;
|
|
]
|
|
|
|
val mutable subst_strings_code = [
|
|
("MAXENCE"^"ZZZ", "\\$");
|
|
("MAXENCE"^"YYY", "\\&");
|
|
("MAXENCE"^"XXX", "{\\textbackslash}") ;
|
|
("%", "\\%") ;
|
|
("_", "\\_");
|
|
("~", "\\~{}");
|
|
("#", "\\verb`#`");
|
|
("}", "\\}");
|
|
("{", "\\{");
|
|
("&", "\\&");
|
|
("\\^", "\\textasciicircum ") ;
|
|
("&", "MAXENCE"^"YYY") ;
|
|
("\\$", "MAXENCE"^"ZZZ") ;
|
|
("\\\\", "MAXENCE"^"XXX") ;
|
|
]
|
|
|
|
method subst l s =
|
|
List.fold_right
|
|
(fun (s, s2) -> fun acc -> Str.global_replace (Str.regexp s) s2 acc)
|
|
l
|
|
s
|
|
|
|
(** Escape the strings which would clash with LaTeX syntax. *)
|
|
method escape s = self#subst subst_strings s
|
|
|
|
(** Escape the ['\'], ['{'] and ['}'] characters. *)
|
|
method escape_simple s = self#subst subst_strings_simple s
|
|
|
|
(** Escape some characters for the code style. *)
|
|
method escape_code s = self#subst subst_strings_code s
|
|
|
|
(** Make a correct latex label from a name. *)
|
|
(* The following characters are forbidden in LaTeX \index:
|
|
\ { } $ & # ^ _ % ~ ! " @ | (" to close the double quote)
|
|
The following characters are forbidden in LaTeX \label:
|
|
\ { } $ & # ^ _ % ~
|
|
So we will use characters not forbidden in \index if no_ = true.
|
|
*)
|
|
method label ?(no_=true) name =
|
|
let len = String.length name in
|
|
let buf = Buffer.create len in
|
|
for i = 0 to len - 1 do
|
|
let (s_no_, s) =
|
|
match name.[i] with
|
|
'_' -> ("-underscore", "_")
|
|
| '~' -> ("-tilde", "~")
|
|
| '%' -> ("-percent", "%")
|
|
| '@' -> ("-at", "\"@")
|
|
| '!' -> ("-bang", "\"!")
|
|
| '|' -> ("-pipe", "\"|")
|
|
| '<' -> ("-lt", "<")
|
|
| '>' -> ("-gt", ">")
|
|
| '^' -> ("-exp", "^")
|
|
| '&' -> ("-ampersand", "&")
|
|
| '+' -> ("-plus", "+")
|
|
| '-' -> ("-minus", "-")
|
|
| '*' -> ("-star", "*")
|
|
| '/' -> ("-slash", "/")
|
|
| '$' -> ("-dollar", "$")
|
|
| '=' -> ("-equal", "=")
|
|
| ':' -> ("-colon", ":")
|
|
| c -> (String.make 1 c, String.make 1 c)
|
|
in
|
|
Buffer.add_string buf (if no_ then s_no_ else s)
|
|
done;
|
|
Buffer.contents buf
|
|
|
|
(** Make a correct label from a value name. *)
|
|
method value_label ?no_ name = !Args.latex_value_prefix^(self#label ?no_ name)
|
|
|
|
(** Make a correct label from an attribute name. *)
|
|
method attribute_label ?no_ name = !Args.latex_attribute_prefix^(self#label ?no_ name)
|
|
|
|
(** Make a correct label from a method name. *)
|
|
method method_label ?no_ name = !Args.latex_method_prefix^(self#label ?no_ name)
|
|
|
|
(** Make a correct label from a class name. *)
|
|
method class_label ?no_ name = !Args.latex_class_prefix^(self#label ?no_ name)
|
|
|
|
(** Make a correct label from a class type name. *)
|
|
method class_type_label ?no_ name = !Args.latex_class_type_prefix^(self#label ?no_ name)
|
|
|
|
(** Make a correct label from a module name. *)
|
|
method module_label ?no_ name = !Args.latex_module_prefix^(self#label ?no_ name)
|
|
|
|
(** Make a correct label from a module type name. *)
|
|
method module_type_label ?no_ name = !Args.latex_module_type_prefix^(self#label ?no_ name)
|
|
|
|
(** Make a correct label from an exception name. *)
|
|
method exception_label ?no_ name = !Args.latex_exception_prefix^(self#label ?no_ name)
|
|
|
|
(** Make a correct label from a type name. *)
|
|
method type_label ?no_ name = !Args.latex_type_prefix^(self#label ?no_ name)
|
|
|
|
(** Return latex code for the label of a given label. *)
|
|
method make_label label = "\\label{"^label^"}"
|
|
|
|
(** Return latex code for the ref to a given label. *)
|
|
method make_ref label = "\\ref{"^label^"}"
|
|
|
|
(** Return the LaTeX code corresponding to the [text] parameter.*)
|
|
method latex_of_text t = String.concat "" (List.map self#latex_of_text_element t)
|
|
|
|
(** Return the LaTeX code for the [text_element] in parameter. *)
|
|
method latex_of_text_element te =
|
|
match te with
|
|
| Odoc_info.Raw s -> self#latex_of_Raw s
|
|
| Odoc_info.Code s -> self#latex_of_Code s
|
|
| Odoc_info.CodePre s -> self#latex_of_CodePre s
|
|
| Odoc_info.Verbatim s -> self#latex_of_Verbatim s
|
|
| Odoc_info.Bold t -> self#latex_of_Bold t
|
|
| Odoc_info.Italic t -> self#latex_of_Italic t
|
|
| Odoc_info.Emphasize t -> self#latex_of_Emphasize t
|
|
| Odoc_info.Center t -> self#latex_of_Center t
|
|
| Odoc_info.Left t -> self#latex_of_Left t
|
|
| Odoc_info.Right t -> self#latex_of_Right t
|
|
| Odoc_info.List tl -> self#latex_of_List tl
|
|
| Odoc_info.Enum tl -> self#latex_of_Enum tl
|
|
| Odoc_info.Newline -> self#latex_of_Newline
|
|
| Odoc_info.Block t -> self#latex_of_Block t
|
|
| Odoc_info.Title (n, l_opt, t) -> self#latex_of_Title n l_opt t
|
|
| Odoc_info.Latex s -> self#latex_of_Latex s
|
|
| Odoc_info.Link (s, t) -> self#latex_of_Link s t
|
|
| Odoc_info.Ref (name, ref_opt) -> self#latex_of_Ref name ref_opt
|
|
| Odoc_info.Superscript t -> self#latex_of_Superscript t
|
|
| Odoc_info.Subscript t -> self#latex_of_Subscript t
|
|
|
|
method latex_of_Raw s = self#escape s
|
|
|
|
method latex_of_Code s =
|
|
let s2 = self#escape_code s in
|
|
let s3 = Str.global_replace (Str.regexp "\n") ("\\\\\n") s2 in
|
|
"{\\tt{"^s3^"}}"
|
|
|
|
method latex_of_CodePre s =
|
|
"\\begin{ocamldoccode}\n"^(self#escape_simple s)^"\n\\end{ocamldoccode}\n"
|
|
|
|
method latex_of_Verbatim s = "\\begin{verbatim}"^s^"\\end{verbatim}"
|
|
|
|
method latex_of_Bold t =
|
|
let s = self#latex_of_text t in
|
|
"{\\bf "^s^"}"
|
|
|
|
method latex_of_Italic t =
|
|
let s = self#latex_of_text t in
|
|
"{\\it "^s^"}"
|
|
|
|
method latex_of_Emphasize t =
|
|
let s = self#latex_of_text t in
|
|
"{\\em "^s^"}"
|
|
|
|
method latex_of_Center t =
|
|
let s = self#latex_of_text t in
|
|
"\\begin{center}\n"^s^"\\end{center}\n"
|
|
|
|
method latex_of_Left t =
|
|
let s = self#latex_of_text t in
|
|
"\\begin{flushleft}\n"^s^"\\end{flushleft}\n"
|
|
|
|
method latex_of_Right t =
|
|
let s = self#latex_of_text t in
|
|
"\\begin{flushright}\n"^s^"\\end{flushright}\n"
|
|
|
|
method latex_of_List tl =
|
|
"\\begin{itemize}"^
|
|
(String.concat ""
|
|
(List.map (fun t -> "\\item "^(self#latex_of_text t)^"\n") tl))^
|
|
"\\end{itemize}\n"
|
|
|
|
method latex_of_Enum tl =
|
|
"\\begin{enumerate}"^
|
|
(String.concat ""
|
|
(List.map (fun t -> "\\item "^(self#latex_of_text t)^"\n") tl))^
|
|
"\\end{enumerate}\n"
|
|
|
|
method latex_of_Newline = "\n\n"
|
|
|
|
method latex_of_Block t =
|
|
let s = self#latex_of_text t in
|
|
"\\begin{ocamldocdescription}\n"^s^"\n\\end{ocamldocdescription}\n"
|
|
|
|
method latex_of_Title n label_opt t =
|
|
let s_title = self#latex_of_text t in
|
|
let s_title2 = self#section_style n s_title in
|
|
s_title2^
|
|
(match label_opt with
|
|
None -> ""
|
|
| Some l -> self#make_label (self#label ~no_: false l))
|
|
|
|
method latex_of_Latex s = s
|
|
|
|
method latex_of_Link s t =
|
|
let s1 = self#latex_of_text t in
|
|
let s2 = "[\\url{"^s^"}]" in
|
|
s1^s2
|
|
|
|
method latex_of_Ref name ref_opt =
|
|
match ref_opt with
|
|
None ->
|
|
self#latex_of_text_element
|
|
(Odoc_info.Code (Odoc_info.use_hidden_modules name))
|
|
| Some (RK_section _) ->
|
|
self#latex_of_text_element
|
|
(Latex ("["^(self#make_ref (self#label ~no_:false (Name.simple name)))^"]"))
|
|
| Some kind ->
|
|
let f_label =
|
|
match kind with
|
|
Odoc_info.RK_module -> self#module_label
|
|
| Odoc_info.RK_module_type -> self#module_type_label
|
|
| Odoc_info.RK_class -> self#class_label
|
|
| Odoc_info.RK_class_type -> self#class_type_label
|
|
| Odoc_info.RK_value -> self#value_label
|
|
| Odoc_info.RK_type -> self#type_label
|
|
| Odoc_info.RK_exception -> self#exception_label
|
|
| Odoc_info.RK_attribute -> self#attribute_label
|
|
| Odoc_info.RK_method -> self#method_label
|
|
| Odoc_info.RK_section _ -> assert false
|
|
in
|
|
(self#latex_of_text
|
|
[
|
|
Odoc_info.Code (Odoc_info.use_hidden_modules name) ;
|
|
Latex ("["^(self#make_ref (f_label name))^"]")
|
|
]
|
|
)
|
|
|
|
method latex_of_Superscript t = "$^{"^(self#latex_of_text t)^"}$"
|
|
|
|
method latex_of_Subscript t = "$_{"^(self#latex_of_text t)^"}$"
|
|
|
|
end
|
|
|
|
(** A class used to generate LaTeX code for info structures. *)
|
|
class virtual info =
|
|
object (self)
|
|
(** The method used to get LaTeX code from a [text]. *)
|
|
method virtual latex_of_text : Odoc_info.text -> string
|
|
|
|
(** The method used to get a [text] from an optionel info structure. *)
|
|
method virtual text_of_info : ?block: bool -> Odoc_info.info option -> Odoc_info.text
|
|
|
|
(** Return LaTeX code for a description, except for the [i_params] field. *)
|
|
method latex_of_info info_opt =
|
|
self#latex_of_text
|
|
(self#text_of_info ~block: false info_opt)
|
|
end
|
|
|
|
(** This class is used to create objects which can generate a simple LaTeX documentation. *)
|
|
class latex =
|
|
object (self)
|
|
inherit text
|
|
inherit Odoc_to_text.to_text as to_text
|
|
inherit info
|
|
|
|
(** Get the first sentence and the rest of a description,
|
|
from an optional [info] structure. The first sentence
|
|
can be empty if it would not appear right in a title.
|
|
In the first sentence, the titles and lists has been removed,
|
|
since it is used in LaTeX titles and would make LaTeX complain
|
|
if we has two nested \section commands.
|
|
*)
|
|
method first_and_rest_of_info i_opt =
|
|
match i_opt with
|
|
None -> ([], [])
|
|
| Some i ->
|
|
match i.Odoc_info.i_desc with
|
|
None -> ([], self#text_of_info ~block: true i_opt)
|
|
| Some t ->
|
|
let (first,_) = Odoc_info.first_sentence_and_rest_of_text t in
|
|
let (_, rest) = Odoc_info.first_sentence_and_rest_of_text (self#text_of_info ~block: false i_opt) in
|
|
(Odoc_info.text_no_title_no_list first, rest)
|
|
|
|
(** Return LaTeX code for a value. *)
|
|
method latex_of_value v =
|
|
Odoc_info.reset_type_names () ;
|
|
self#latex_of_text
|
|
((Latex (self#make_label (self#value_label v.val_name))) ::
|
|
(to_text#text_of_value v))
|
|
|
|
(** Return LaTeX code for a class attribute. *)
|
|
method latex_of_attribute a =
|
|
self#latex_of_text
|
|
((Latex (self#make_label (self#attribute_label a.att_value.val_name))) ::
|
|
(to_text#text_of_attribute a))
|
|
|
|
(** Return LaTeX code for a class method. *)
|
|
method latex_of_method m =
|
|
self#latex_of_text
|
|
((Latex (self#make_label (self#method_label m.met_value.val_name))) ::
|
|
(to_text#text_of_method m))
|
|
|
|
(** Return LaTeX code for the parameters of a type. *)
|
|
method latex_of_type_params m_name t =
|
|
let f (p, co, cn) =
|
|
Printf.sprintf "%s%s"
|
|
(Odoc_info.string_of_variance t (co,cn))
|
|
(self#normal_type m_name p)
|
|
in
|
|
match t.ty_parameters with
|
|
[] -> ""
|
|
| [(p,co,cn)] -> f (p, co, cn)
|
|
| l ->
|
|
Printf.sprintf "(%s)"
|
|
(String.concat ", " (List.map f t.ty_parameters))
|
|
|
|
(** Return LaTeX code for a type. *)
|
|
method latex_of_type t =
|
|
let s_name = Name.simple t.ty_name in
|
|
let text =
|
|
Odoc_info.reset_type_names () ;
|
|
let mod_name = Name.father t.ty_name in
|
|
let s_type1 =
|
|
Format.fprintf Format.str_formatter "@[<hov 2>type ";
|
|
Format.fprintf Format.str_formatter "%s%s"
|
|
(self#latex_of_type_params mod_name t)
|
|
(match t.ty_parameters with [] -> "" | _ -> " ");
|
|
Format.flush_str_formatter ()
|
|
in
|
|
Format.fprintf Format.str_formatter
|
|
("@[<hov 2>%s %s")
|
|
s_type1
|
|
s_name;
|
|
let s_type2 =
|
|
(
|
|
match t.ty_manifest with
|
|
None -> ()
|
|
| Some typ ->
|
|
Format.fprintf Format.str_formatter
|
|
" = %s"
|
|
(self#normal_type mod_name typ)
|
|
);
|
|
Format.flush_str_formatter ()
|
|
in
|
|
let s_type3 =
|
|
Format.fprintf Format.str_formatter
|
|
("%s %s")
|
|
s_type2
|
|
(
|
|
match t.ty_kind with
|
|
Type_abstract -> ""
|
|
| Type_variant (_, priv) -> "="^(if priv then " private" else "")
|
|
| Type_record (_, priv) -> "= "^(if priv then "private " else "")^"{"
|
|
) ;
|
|
Format.flush_str_formatter ()
|
|
in
|
|
|
|
let defs =
|
|
match t.ty_kind with
|
|
Type_abstract -> []
|
|
| Type_variant (l, _) ->
|
|
(List.flatten
|
|
(List.map
|
|
(fun constr ->
|
|
let s_cons =
|
|
Format.fprintf Format.str_formatter
|
|
"@[<hov 6> | %s"
|
|
constr.vc_name;
|
|
(
|
|
match constr.vc_args with
|
|
[] -> ()
|
|
| l ->
|
|
Format.fprintf Format.str_formatter " %s@ %s"
|
|
"of"
|
|
(self#normal_type_list ~par: false mod_name " * " l)
|
|
);
|
|
Format.flush_str_formatter ()
|
|
in
|
|
[ CodePre s_cons ] @
|
|
(match constr.vc_text with
|
|
None -> []
|
|
| Some t ->
|
|
[ Latex
|
|
("\\begin{ocamldoccomment}\n"^
|
|
(self#latex_of_text t)^
|
|
"\n\\end{ocamldoccomment}\n")
|
|
]
|
|
)
|
|
)
|
|
l
|
|
)
|
|
)
|
|
| Type_record (l, _) ->
|
|
(List.flatten
|
|
(List.map
|
|
(fun r ->
|
|
let s_field =
|
|
Format.fprintf Format.str_formatter
|
|
"@[<hov 6> %s%s :@ %s ;"
|
|
(if r.rf_mutable then "mutable " else "")
|
|
r.rf_name
|
|
(self#normal_type mod_name r.rf_type);
|
|
Format.flush_str_formatter ()
|
|
in
|
|
[ CodePre s_field ] @
|
|
(match r.rf_text with
|
|
None -> []
|
|
| Some t ->
|
|
[ Latex
|
|
("\\begin{ocamldoccomment}\n"^
|
|
(self#latex_of_text t)^
|
|
"\n\\end{ocamldoccomment}\n")
|
|
]
|
|
)
|
|
)
|
|
l
|
|
)
|
|
) @
|
|
[ CodePre "}" ]
|
|
in
|
|
let defs2 = (CodePre s_type3) :: defs in
|
|
let rec iter = function
|
|
[] -> []
|
|
| [e] -> [e]
|
|
| (CodePre s1) :: (CodePre s2) :: q ->
|
|
iter ((CodePre (s1^"\n"^s2)) :: q)
|
|
| e :: q ->
|
|
e :: (iter q)
|
|
in
|
|
(iter defs2) @
|
|
[Latex ("\\index{"^(self#type_label s_name)^"@\\verb`"^(self#label ~no_:false s_name)^"`}\n")] @
|
|
(self#text_of_info t.ty_info)
|
|
in
|
|
self#latex_of_text
|
|
((Latex (self#make_label (self#type_label t.ty_name))) :: text)
|
|
|
|
(** Return LaTeX code for an exception. *)
|
|
method latex_of_exception e =
|
|
Odoc_info.reset_type_names () ;
|
|
self#latex_of_text
|
|
((Latex (self#make_label (self#exception_label e.ex_name))) ::
|
|
(to_text#text_of_exception e))
|
|
|
|
(** Return the LaTeX code for the given module.
|
|
@param for_detail indicate if we must print the type ([false]) or just ["sig"] ([true]).*)
|
|
method latex_of_module ?(for_detail=false) ?(with_link=true) m =
|
|
let buf = Buffer.create 32 in
|
|
let f = Format.formatter_of_buffer buf in
|
|
let father = Name.father m.m_name in
|
|
let t =
|
|
Format.fprintf f "module %s" (Name.simple m.m_name);
|
|
Format.fprintf f " : %s"
|
|
(
|
|
if for_detail
|
|
then "sig"
|
|
else (self#normal_module_type father m.m_type)
|
|
);
|
|
|
|
Format.pp_print_flush f ();
|
|
|
|
(CodePre (Buffer.contents buf)) ::
|
|
(
|
|
if with_link
|
|
then [Odoc_info.Latex ("\\\n["^(self#make_ref (self#module_label m.m_name))^"]")]
|
|
else []
|
|
)
|
|
in
|
|
self#latex_of_text t
|
|
|
|
(** Return the LaTeX code for the given module type.
|
|
@param for_detail indicate if we must print the type ([false]) or just ["sig"] ([true]).*)
|
|
method latex_of_module_type ?(for_detail=false) ?(with_link=true) mt =
|
|
let buf = Buffer.create 32 in
|
|
let f = Format.formatter_of_buffer buf in
|
|
let father = Name.father mt.mt_name in
|
|
let t =
|
|
Format.fprintf f "module type %s" (Name.simple mt.mt_name);
|
|
(match mt.mt_type with
|
|
None -> ()
|
|
| Some mtyp ->
|
|
Format.fprintf f " = %s"
|
|
(
|
|
if for_detail
|
|
then "sig"
|
|
else (self#normal_module_type father mtyp)
|
|
)
|
|
);
|
|
|
|
Format.pp_print_flush f ();
|
|
|
|
(CodePre (Buffer.contents buf)) ::
|
|
(
|
|
if with_link
|
|
then [Odoc_info.Latex ("\\\n["^(self#make_ref (self#module_type_label mt.mt_name))^"]")]
|
|
else []
|
|
)
|
|
in
|
|
self#latex_of_text t
|
|
|
|
(** Return the LaTeX code for the given included module. *)
|
|
method latex_of_included_module im =
|
|
(self#latex_of_text ((Code "include ") ::
|
|
(Code
|
|
(match im.im_module with
|
|
None -> im.im_name
|
|
| Some (Mod m) -> m.m_name
|
|
| Some (Modtype mt) -> mt.mt_name)
|
|
) ::
|
|
(self#text_of_info im.im_info)
|
|
)
|
|
)
|
|
|
|
(** Return the LaTeX code for the given class.
|
|
@param for_detail indicate if we must print the type ([false]) or just ["object"] ([true]).*)
|
|
method latex_of_class ?(for_detail=false) ?(with_link=true) c =
|
|
Odoc_info.reset_type_names () ;
|
|
let buf = Buffer.create 32 in
|
|
let f = Format.formatter_of_buffer buf in
|
|
let father = Name.father c.cl_name in
|
|
let t =
|
|
Format.fprintf f "class %s"
|
|
(if c.cl_virtual then "virtual " else "");
|
|
(
|
|
match c.cl_type_parameters with
|
|
[] -> ()
|
|
| l ->
|
|
let s1 = self#normal_class_type_param_list father l in
|
|
Format.fprintf f "%s " s1
|
|
);
|
|
Format.fprintf f "%s : %s"
|
|
(Name.simple c.cl_name)
|
|
(
|
|
if for_detail then
|
|
"object"
|
|
else
|
|
self#normal_class_type father c.cl_type
|
|
);
|
|
|
|
Format.pp_print_flush f ();
|
|
|
|
(CodePre (Buffer.contents buf)) ::
|
|
(
|
|
if with_link
|
|
then [Odoc_info.Latex (" ["^(self#make_ref (self#class_label c.cl_name))^"]")]
|
|
else []
|
|
)
|
|
in
|
|
self#latex_of_text t
|
|
|
|
(** Return the LaTeX code for the given class type.
|
|
@param for_detail indicate if we must print the type ([false]) or just ["object"] ([true]).*)
|
|
method latex_of_class_type ?(for_detail=false) ?(with_link=true) ct =
|
|
Odoc_info.reset_type_names () ;
|
|
let buf = Buffer.create 32 in
|
|
let f = Format.formatter_of_buffer buf in
|
|
let father = Name.father ct.clt_name in
|
|
let t =
|
|
Format.fprintf f "class type %s"
|
|
(if ct.clt_virtual then "virtual " else "");
|
|
(
|
|
match ct.clt_type_parameters with
|
|
[] -> ()
|
|
| l ->
|
|
let s1 = self#normal_class_type_param_list father l in
|
|
Format.fprintf f "%s " s1
|
|
);
|
|
Format.fprintf f "%s = %s"
|
|
(Name.simple ct.clt_name)
|
|
(if for_detail then
|
|
"object"
|
|
else
|
|
self#normal_class_type father ct.clt_type
|
|
);
|
|
|
|
Format.pp_print_flush f ();
|
|
(CodePre (Buffer.contents buf)) ::
|
|
(
|
|
if with_link
|
|
then [Odoc_info.Latex (" ["^(self#make_ref (self#class_type_label ct.clt_name))^"]")]
|
|
else []
|
|
)
|
|
in
|
|
self#latex_of_text t
|
|
|
|
(** Return the LaTeX code for the given class element. *)
|
|
method latex_of_class_element class_name class_ele =
|
|
(self#latex_of_text [Newline])^
|
|
(
|
|
match class_ele with
|
|
Class_attribute att -> self#latex_of_attribute att
|
|
| Class_method met -> self#latex_of_method met
|
|
| Class_comment t ->
|
|
match t with
|
|
| [] -> ""
|
|
| (Title (_,_,_)) :: _ -> self#latex_of_text t
|
|
| _ -> self#latex_of_text [ Title ((Name.depth class_name) + 2, None, t) ]
|
|
)
|
|
|
|
(** Return the LaTeX code for the given module element. *)
|
|
method latex_of_module_element module_name module_ele =
|
|
(self#latex_of_text [Newline])^
|
|
(
|
|
match module_ele with
|
|
Element_module m -> self#latex_of_module m
|
|
| Element_module_type mt -> self#latex_of_module_type mt
|
|
| Element_included_module im -> self#latex_of_included_module im
|
|
| Element_class c -> self#latex_of_class c
|
|
| Element_class_type ct -> self#latex_of_class_type ct
|
|
| Element_value v -> self#latex_of_value v
|
|
| Element_exception e -> self#latex_of_exception e
|
|
| Element_type t -> self#latex_of_type t
|
|
| Element_module_comment t -> self#latex_of_text t
|
|
)
|
|
|
|
(** Generate the LaTeX code for the given list of inherited classes.*)
|
|
method generate_inheritance_info chanout inher_l =
|
|
let f inh =
|
|
match inh.ic_class with
|
|
None -> (* we can't make the reference *)
|
|
(Odoc_info.Code inh.ic_name) ::
|
|
(match inh.ic_text with
|
|
None -> []
|
|
| Some t -> Newline :: t
|
|
)
|
|
| Some cct ->
|
|
let label =
|
|
match cct with
|
|
Cl _ -> self#class_label inh.ic_name
|
|
| Cltype _ -> self#class_type_label inh.ic_name
|
|
in
|
|
(* we can create the reference *)
|
|
(Odoc_info.Code inh.ic_name) ::
|
|
(Odoc_info.Latex (" ["^(self#make_ref label)^"]")) ::
|
|
(match inh.ic_text with
|
|
None -> []
|
|
| Some t -> Newline :: t
|
|
)
|
|
in
|
|
let text = [
|
|
Odoc_info.Bold [Odoc_info.Raw Odoc_messages.inherits ];
|
|
Odoc_info.List (List.map f inher_l)
|
|
]
|
|
in
|
|
let s = self#latex_of_text text in
|
|
output_string chanout s
|
|
|
|
(** Generate the LaTeX code for the inherited classes of the given class. *)
|
|
method generate_class_inheritance_info chanout cl =
|
|
let rec iter_kind k =
|
|
match k with
|
|
Class_structure ([], _) ->
|
|
()
|
|
| Class_structure (l, _) ->
|
|
self#generate_inheritance_info chanout l
|
|
| Class_constraint (k, _) ->
|
|
iter_kind k
|
|
| Class_apply _
|
|
| Class_constr _ ->
|
|
()
|
|
in
|
|
iter_kind cl.cl_kind
|
|
|
|
(** Generate the LaTeX code for the inherited classes of the given class type. *)
|
|
method generate_class_type_inheritance_info chanout clt =
|
|
match clt.clt_kind with
|
|
Class_signature ([], _) ->
|
|
()
|
|
| Class_signature (l, _) ->
|
|
self#generate_inheritance_info chanout l
|
|
| Class_type _ ->
|
|
()
|
|
|
|
(** Generate the LaTeX code for the given class, in the given out channel. *)
|
|
method generate_for_class chanout c =
|
|
Odoc_info.reset_type_names () ;
|
|
let depth = Name.depth c.cl_name in
|
|
let (first_t, rest_t) = self#first_and_rest_of_info c.cl_info in
|
|
let text = [ Title (depth, None, [ Raw (Odoc_messages.clas^" ") ; Code c.cl_name ] @
|
|
(match first_t with
|
|
[] -> []
|
|
| t -> (Raw " : ") :: t)) ;
|
|
Latex (self#make_label (self#class_label c.cl_name)) ;
|
|
]
|
|
in
|
|
output_string chanout (self#latex_of_text text);
|
|
output_string chanout ((self#latex_of_class ~for_detail: true ~with_link: false c)^"\n\n") ;
|
|
let s_name = Name.simple c.cl_name in
|
|
output_string chanout
|
|
(self#latex_of_text [Latex ("\\index{"^(self#class_label s_name)^"@\\verb`"^(self#label ~no_:false s_name)^"`}\n")]);
|
|
output_string chanout (self#latex_of_text rest_t) ;
|
|
(* parameters *)
|
|
output_string chanout
|
|
(self#latex_of_text (self#text_of_parameter_list (Name.father c.cl_name) c.cl_parameters));
|
|
|
|
output_string chanout (self#latex_of_text [ Newline ] );
|
|
output_string chanout ("\\ocamldocvspace{0.5cm}\n\n");
|
|
self#generate_class_inheritance_info chanout c;
|
|
|
|
List.iter
|
|
(fun ele -> output_string chanout ((self#latex_of_class_element c.cl_name ele)^"\n\n"))
|
|
(Class.class_elements ~trans: false c);
|
|
|
|
output_string chanout (self#latex_of_text [ CodePre "end"])
|
|
|
|
(** Generate the LaTeX code for the given class type, in the given out channel. *)
|
|
method generate_for_class_type chanout ct =
|
|
Odoc_info.reset_type_names () ;
|
|
let depth = Name.depth ct.clt_name in
|
|
let (first_t, rest_t) = self#first_and_rest_of_info ct.clt_info in
|
|
let text = [ Title (depth, None, [ Raw (Odoc_messages.class_type^" ") ; Code ct.clt_name ] @
|
|
(match first_t with
|
|
[] -> []
|
|
| t -> (Raw " : ") :: t)) ;
|
|
Latex (self#make_label (self#class_type_label ct.clt_name)) ;
|
|
]
|
|
in
|
|
|
|
output_string chanout (self#latex_of_text text);
|
|
output_string chanout ((self#latex_of_class_type ~for_detail: true ~with_link: false ct)^"\n\n") ;
|
|
let s_name = Name.simple ct.clt_name in
|
|
output_string chanout
|
|
(self#latex_of_text [Latex ("\\index{"^(self#class_type_label s_name)^"@\\verb`"^(self#label ~no_:false s_name)^"`}\n")]);
|
|
output_string chanout ((self#latex_of_text rest_t)) ;
|
|
output_string chanout (self#latex_of_text [ Newline]) ;
|
|
output_string chanout ("\\ocamldocvspace{0.5cm}\n\n");
|
|
self#generate_class_type_inheritance_info chanout ct;
|
|
|
|
List.iter
|
|
(fun ele -> output_string chanout ((self#latex_of_class_element ct.clt_name ele)^"\n\n"))
|
|
(Class.class_type_elements ~trans: false ct);
|
|
|
|
output_string chanout (self#latex_of_text [ CodePre "end"])
|
|
|
|
(** Generate the LaTeX code for the given module type, in the given out channel. *)
|
|
method generate_for_module_type chanout mt =
|
|
let depth = Name.depth mt.mt_name in
|
|
let (first_t, rest_t) = self#first_and_rest_of_info mt.mt_info in
|
|
let text = [ Title (depth, None,
|
|
[ Raw (Odoc_messages.module_type^" ") ; Code mt.mt_name ] @
|
|
(match first_t with
|
|
[] -> []
|
|
| t -> (Raw " : ") :: t)) ;
|
|
Latex (self#make_label (self#module_type_label mt.mt_name)) ;
|
|
]
|
|
in
|
|
output_string chanout (self#latex_of_text text);
|
|
if depth > 1 then
|
|
output_string chanout ((self#latex_of_module_type ~for_detail: true ~with_link: false mt)^"\n\n");
|
|
let s_name = Name.simple mt.mt_name in
|
|
output_string chanout
|
|
(self#latex_of_text [Latex ("\\index{"^(self#module_type_label s_name)^"@\\verb`"^(self#label ~no_:false s_name)^"`}\n")]);
|
|
output_string chanout (self#latex_of_text rest_t) ;
|
|
(* parameters *)
|
|
output_string chanout
|
|
(self#latex_of_text
|
|
(self#text_of_module_parameter_list
|
|
(Module.module_type_parameters mt)));
|
|
|
|
output_string chanout (self#latex_of_text [ Newline ] );
|
|
output_string chanout ("\\ocamldocvspace{0.5cm}\n\n");
|
|
List.iter
|
|
(fun ele -> output_string chanout ((self#latex_of_module_element mt.mt_name ele)^"\n\n"))
|
|
(Module.module_type_elements ~trans: false mt);
|
|
|
|
if depth > 1 then
|
|
output_string chanout (self#latex_of_text [ CodePre "end"]);
|
|
|
|
(* create sub parts for modules, module types, classes and class types *)
|
|
let rec iter ele =
|
|
match ele with
|
|
Element_module m -> self#generate_for_module chanout m
|
|
| Element_module_type mt -> self#generate_for_module_type chanout mt
|
|
| Element_class c -> self#generate_for_class chanout c
|
|
| Element_class_type ct -> self#generate_for_class_type chanout ct
|
|
| _ -> ()
|
|
in
|
|
List.iter iter (Module.module_type_elements ~trans: false mt)
|
|
|
|
(** Generate the LaTeX code for the given module, in the given out channel. *)
|
|
method generate_for_module chanout m =
|
|
let depth = Name.depth m.m_name in
|
|
let (first_t, rest_t) = self#first_and_rest_of_info m.m_info in
|
|
let text = [ Title (depth, None,
|
|
[ Raw (Odoc_messages.modul^" ") ; Code m.m_name ] @
|
|
(match first_t with
|
|
[] -> []
|
|
| t -> (Raw " : ") :: t)) ;
|
|
Latex (self#make_label (self#module_label m.m_name)) ;
|
|
]
|
|
in
|
|
output_string chanout (self#latex_of_text text);
|
|
if depth > 1 then
|
|
output_string chanout ((self#latex_of_module ~for_detail:true ~with_link: false m)^"\n\n");
|
|
let s_name = Name.simple m.m_name in
|
|
output_string chanout
|
|
(self#latex_of_text [Latex ("\\index{"^(self#module_label s_name)^"@\\verb`"^(self#label ~no_:false s_name)^"`}\n")]);
|
|
output_string chanout (self#latex_of_text rest_t) ;
|
|
(* parameters *)
|
|
output_string chanout
|
|
(self#latex_of_text
|
|
(self#text_of_module_parameter_list
|
|
(Module.module_parameters m)));
|
|
|
|
output_string chanout (self#latex_of_text [ Newline ]) ;
|
|
output_string chanout ("\\ocamldocvspace{0.5cm}\n\n");
|
|
List.iter
|
|
(fun ele -> output_string chanout ((self#latex_of_module_element m.m_name ele)^"\n\n"))
|
|
(Module.module_elements ~trans: false m);
|
|
|
|
if depth > 1 then
|
|
output_string chanout (self#latex_of_text [ CodePre "end"]);
|
|
|
|
(* create sub parts for modules, module types, classes and class types *)
|
|
let rec iter ele =
|
|
match ele with
|
|
Element_module m -> self#generate_for_module chanout m
|
|
| Element_module_type mt -> self#generate_for_module_type chanout mt
|
|
| Element_class c -> self#generate_for_class chanout c
|
|
| Element_class_type ct -> self#generate_for_class_type chanout ct
|
|
| _ -> ()
|
|
in
|
|
List.iter iter (Module.module_elements ~trans: false m)
|
|
|
|
(** Return the header of the TeX document. *)
|
|
method latex_header =
|
|
"\\documentclass[11pt]{article} \n"^
|
|
"\\usepackage[latin1]{inputenc} \n"^
|
|
"\\usepackage[T1]{fontenc} \n"^
|
|
"\\usepackage{fullpage} \n"^
|
|
"\\usepackage{url} \n"^
|
|
"\\usepackage{ocamldoc}\n"^
|
|
(
|
|
match !Args.title with
|
|
None -> ""
|
|
| Some s -> "\\title{"^(self#escape s)^"}\n"
|
|
)^
|
|
"\\begin{document}\n"^
|
|
(match !Args.title with None -> "" | Some _ -> "\\maketitle\n")^
|
|
(if !Args.with_toc then "\\tableofcontents\n" else "")^
|
|
(
|
|
let info = Odoc_info.apply_opt
|
|
Odoc_info.info_of_comment_file !Odoc_info.Args.intro_file
|
|
in
|
|
Printf.sprintf "%s%s%s"
|
|
(match info with None -> "" | Some _ -> "\\vspace{0.2cm}")
|
|
(self#latex_of_info info)
|
|
(match info with None -> "" | Some _ -> "\n\n")
|
|
)
|
|
|
|
|
|
(** Generate the LaTeX style file, if it does not exists. *)
|
|
method generate_style_file =
|
|
try
|
|
let dir = Filename.dirname !Args.out_file in
|
|
let file = Filename.concat dir "ocamldoc.sty" in
|
|
if Sys.file_exists file then
|
|
Odoc_info.verbose (Odoc_messages.file_exists_dont_generate file)
|
|
else
|
|
(
|
|
let chanout = open_out file in
|
|
output_string chanout Odoc_latex_style.content ;
|
|
flush chanout ;
|
|
close_out chanout;
|
|
Odoc_info.verbose (Odoc_messages.file_generated file)
|
|
)
|
|
with
|
|
Sys_error s ->
|
|
prerr_endline s ;
|
|
incr Odoc_info.errors ;
|
|
|
|
(** Generate the LaTeX file from a module list, in the {!Odoc_info.Args.out_file} file. *)
|
|
method generate module_list =
|
|
self#generate_style_file ;
|
|
if !Args.separate_files then
|
|
(
|
|
let f m =
|
|
try
|
|
let chanout =
|
|
open_out ((Filename.concat !Args.target_dir (Name.simple m.m_name))^".tex")
|
|
in
|
|
self#generate_for_module chanout m ;
|
|
close_out chanout
|
|
with
|
|
Failure s
|
|
| Sys_error s ->
|
|
prerr_endline s ;
|
|
incr Odoc_info.errors
|
|
in
|
|
List.iter f module_list
|
|
);
|
|
|
|
try
|
|
let chanout = open_out !Args.out_file in
|
|
let _ = if !Args.with_header then output_string chanout self#latex_header else () in
|
|
List.iter
|
|
(fun m -> if !Args.separate_files then
|
|
output_string chanout ("\\input{"^((Name.simple m.m_name))^".tex}\n")
|
|
else
|
|
self#generate_for_module chanout m
|
|
)
|
|
module_list ;
|
|
let _ = if !Args.with_trailer then output_string chanout "\\end{document}" else () in
|
|
close_out chanout
|
|
with
|
|
Failure s
|
|
| Sys_error s ->
|
|
prerr_endline s ;
|
|
incr Odoc_info.errors
|
|
end
|
|
|
|
(* eof $Id$ *)
|