summaryrefslogtreecommitdiff
path: root/ocaml-binary-annot/ocamldoc/odoc_latex.ml
diff options
context:
space:
mode:
Diffstat (limited to 'ocaml-binary-annot/ocamldoc/odoc_latex.ml')
-rw-r--r--ocaml-binary-annot/ocamldoc/odoc_latex.ml1201
1 files changed, 1201 insertions, 0 deletions
diff --git a/ocaml-binary-annot/ocamldoc/odoc_latex.ml b/ocaml-binary-annot/ocamldoc/odoc_latex.ml
new file mode 100644
index 0000000000..c20c344b51
--- /dev/null
+++ b/ocaml-binary-annot/ocamldoc/odoc_latex.ml
@@ -0,0 +1,1201 @@
+(***********************************************************************)
+(* 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
+
+
+
+let separate_files = ref false
+
+let latex_titles = ref [
+ 1, "section" ;
+ 2, "subsection" ;
+ 3, "subsubsection" ;
+ 4, "paragraph" ;
+ 5, "subparagraph" ;
+]
+
+let latex_value_prefix = ref Odoc_messages.default_latex_value_prefix
+let latex_type_prefix = ref Odoc_messages.default_latex_type_prefix
+let latex_exception_prefix = ref Odoc_messages.default_latex_exception_prefix
+let latex_module_prefix = ref Odoc_messages.default_latex_module_prefix
+let latex_module_type_prefix = ref Odoc_messages.default_latex_module_type_prefix
+let latex_class_prefix = ref Odoc_messages.default_latex_class_prefix
+let latex_class_type_prefix = ref Odoc_messages.default_latex_class_type_prefix
+let latex_attribute_prefix = ref Odoc_messages.default_latex_attribute_prefix
+let latex_method_prefix = ref Odoc_messages.default_latex_method_prefix
+
+let new_buf () = Buffer.create 1024
+let new_fmt () =
+ let b = new_buf () in
+ let fmt = Format.formatter_of_buffer b in
+ (fmt,
+ fun () ->
+ Format.pp_print_flush fmt ();
+ let s = Buffer.contents b in
+ Buffer.reset b;
+ s
+ )
+
+let p = Format.fprintf
+let ps f s = Format.fprintf f "%s" s
+
+
+let bp = Printf.bprintf
+let bs = Buffer.add_string
+
+let print_concat fmt sep f =
+ let rec iter = function
+ [] -> ()
+ | [c] -> f c
+ | c :: q ->
+ f c;
+ ps fmt sep;
+ iter q
+ in
+ iter
+
+(** 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 !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 = !latex_value_prefix^(self#label ?no_ name)
+
+ (** Make a correct label from an attribute name. *)
+ method attribute_label ?no_ name = !latex_attribute_prefix^(self#label ?no_ name)
+
+ (** Make a correct label from a method name. *)
+ method method_label ?no_ name = !latex_method_prefix^(self#label ?no_ name)
+
+ (** Make a correct label from a class name. *)
+ method class_label ?no_ name = !latex_class_prefix^(self#label ?no_ name)
+
+ (** Make a correct label from a class type name. *)
+ method class_type_label ?no_ name = !latex_class_type_prefix^(self#label ?no_ name)
+
+ (** Make a correct label from a module name. *)
+ method module_label ?no_ name = !latex_module_prefix^(self#label ?no_ name)
+
+ (** Make a correct label from a module type name. *)
+ method module_type_label ?no_ name = !latex_module_type_prefix^(self#label ?no_ name)
+
+ (** Make a correct label from an exception name. *)
+ method exception_label ?no_ name = !latex_exception_prefix^(self#label ?no_ name)
+
+ (** Make a correct label from a type name. *)
+ method type_label ?no_ name = !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^"}"
+
+ (** Print the LaTeX code corresponding to the [text] parameter.*)
+ method latex_of_text fmt t =
+ List.iter (self#latex_of_text_element fmt) t
+
+ (** Print the LaTeX code for the [text_element] in parameter. *)
+ method latex_of_text_element fmt te =
+ match te with
+ | Odoc_info.Raw s -> self#latex_of_Raw fmt s
+ | Odoc_info.Code s -> self#latex_of_Code fmt s
+ | Odoc_info.CodePre s -> self#latex_of_CodePre fmt s
+ | Odoc_info.Verbatim s -> self#latex_of_Verbatim fmt s
+ | Odoc_info.Bold t -> self#latex_of_Bold fmt t
+ | Odoc_info.Italic t -> self#latex_of_Italic fmt t
+ | Odoc_info.Emphasize t -> self#latex_of_Emphasize fmt t
+ | Odoc_info.Center t -> self#latex_of_Center fmt t
+ | Odoc_info.Left t -> self#latex_of_Left fmt t
+ | Odoc_info.Right t -> self#latex_of_Right fmt t
+ | Odoc_info.List tl -> self#latex_of_List fmt tl
+ | Odoc_info.Enum tl -> self#latex_of_Enum fmt tl
+ | Odoc_info.Newline -> self#latex_of_Newline fmt
+ | Odoc_info.Block t -> self#latex_of_Block fmt t
+ | Odoc_info.Title (n, l_opt, t) -> self#latex_of_Title fmt n l_opt t
+ | Odoc_info.Latex s -> self#latex_of_Latex fmt s
+ | Odoc_info.Link (s, t) -> self#latex_of_Link fmt s t
+ | Odoc_info.Ref (name, ref_opt, text_opt) ->
+ self#latex_of_Ref fmt name ref_opt text_opt
+ | Odoc_info.Superscript t -> self#latex_of_Superscript fmt t
+ | Odoc_info.Subscript t -> self#latex_of_Subscript fmt t
+ | Odoc_info.Module_list _ -> ()
+ | Odoc_info.Index_list -> ()
+ | Odoc_info.Custom (s,t) -> self#latex_of_custom_text fmt s t
+ | Odoc_info.Target (target, code) -> self#latex_of_Target fmt ~target ~code
+
+ method latex_of_custom_text fmt s t = ()
+
+ method latex_of_Target fmt ~target ~code =
+ if String.lowercase target = "latex" then
+ self#latex_of_Latex fmt code
+ else
+ ()
+
+ method latex_of_Raw fmt s =
+ ps fmt (self#escape s)
+
+ method latex_of_Code fmt s =
+ let s2 = self#escape_code s in
+ let s3 = Str.global_replace (Str.regexp "\n") ("\\\\\n") s2 in
+ p fmt "{\\tt{%s}}" s3
+
+ method latex_of_CodePre fmt s =
+ ps fmt "\\begin{ocamldoccode}\n";
+ ps fmt (self#escape_simple s);
+ ps fmt "\n\\end{ocamldoccode}\n"
+
+ method latex_of_Verbatim fmt s =
+ ps fmt "\\begin{verbatim}";
+ ps fmt s;
+ ps fmt "\\end{verbatim}"
+
+ method latex_of_Bold fmt t =
+ ps fmt "{\\bf ";
+ self#latex_of_text fmt t;
+ ps fmt "}"
+
+ method latex_of_Italic fmt t =
+ ps fmt "{\\it ";
+ self#latex_of_text fmt t;
+ ps fmt "}"
+
+ method latex_of_Emphasize fmt t =
+ ps fmt "{\\em ";
+ self#latex_of_text fmt t;
+ ps fmt "}"
+
+ method latex_of_Center fmt t =
+ ps fmt "\\begin{center}\n";
+ self#latex_of_text fmt t;
+ ps fmt "\\end{center}\n"
+
+ method latex_of_Left fmt t =
+ ps fmt "\\begin{flushleft}\n";
+ self#latex_of_text fmt t;
+ ps fmt "\\end{flushleft}\n"
+
+ method latex_of_Right fmt t =
+ ps fmt "\\begin{flushright}\n";
+ self#latex_of_text fmt t;
+ ps fmt "\\end{flushright}\n"
+
+ method latex_of_List fmt tl =
+ ps fmt "\\begin{itemize}\n";
+ List.iter
+ (fun t ->
+ ps fmt "\\item ";
+ self#latex_of_text fmt t;
+ ps fmt "\n"
+ )
+ tl;
+ ps fmt "\\end{itemize}\n"
+
+ method latex_of_Enum fmt tl =
+ ps fmt "\\begin{enumerate}\n";
+ List.iter
+ (fun t ->
+ ps fmt "\\item ";
+ self#latex_of_text fmt t;
+ ps fmt "\n"
+ )
+ tl;
+ ps fmt "\\end{enumerate}\n"
+
+ method latex_of_Newline fmt = ps fmt "\n\n"
+
+ method latex_of_Block fmt t =
+ ps fmt "\\begin{ocamldocdescription}\n";
+ self#latex_of_text fmt t;
+ ps fmt "\n\\end{ocamldocdescription}\n"
+
+ method latex_of_Title fmt n label_opt t =
+ let (fmt2, flush) = new_fmt () in
+ self#latex_of_text fmt2 t;
+ let s_title2 = self#section_style n (flush ()) in
+ ps fmt s_title2;
+ (
+ match label_opt with
+ None -> ()
+ | Some l ->
+ ps fmt (self#make_label (self#label ~no_: false l))
+ )
+
+ method latex_of_Latex fmt s = ps fmt s
+
+ method latex_of_Link fmt s t =
+ self#latex_of_text fmt t ;
+ ps fmt "[\\url{";
+ ps fmt s ;
+ ps fmt "}]"
+
+ method latex_of_Ref fmt name ref_opt text_opt =
+ match ref_opt with
+ None ->
+ self#latex_of_text fmt
+ (match text_opt with
+ None ->
+ [Odoc_info.Code (Odoc_info.use_hidden_modules name)]
+ | Some t -> t
+ )
+ | Some (RK_section _) ->
+ self#latex_of_text_element fmt
+ (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
+ let text =
+ match text_opt with
+ None -> [Odoc_info.Code (Odoc_info.use_hidden_modules name)]
+ | Some t -> t
+ in
+ self#latex_of_text fmt
+ (text @ [Latex ("["^(self#make_ref (f_label name))^"]")])
+
+ method latex_of_Superscript fmt t =
+ ps fmt "$^{";
+ self#latex_of_text fmt t;
+ ps fmt "}$"
+
+ method latex_of_Subscript fmt t =
+ ps fmt "$_{";
+ self#latex_of_text fmt t;
+ ps fmt "}$"
+
+ 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 : Format.formatter -> Odoc_info.text -> unit
+
+ (** 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
+
+ (** Print LaTeX code for a description, except for the [i_params] field. *)
+ method latex_of_info fmt ?(block=false) info_opt =
+ self#latex_of_text fmt
+ (self#text_of_info ~block info_opt)
+ end
+
+module Generator =
+struct
+(** 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)
+
+ (** Print LaTeX code for a value. *)
+ method latex_of_value fmt v =
+ Odoc_info.reset_type_names () ;
+ let label = self#value_label v.val_name in
+ let latex = self#make_label label in
+ self#latex_of_text fmt
+ ((Latex latex) ::
+ (to_text#text_of_value v))
+
+ (** Print LaTeX code for a class attribute. *)
+ method latex_of_attribute fmt a =
+ self#latex_of_text fmt
+ ((Latex (self#make_label (self#attribute_label a.att_value.val_name))) ::
+ (to_text#text_of_attribute a))
+
+ (** Print LaTeX code for a class method. *)
+ method latex_of_method fmt m =
+ self#latex_of_text fmt
+ ((Latex (self#make_label (self#method_label m.met_value.val_name))) ::
+ (to_text#text_of_method m))
+
+ (** Print LaTeX code for the parameters of a type. *)
+ method latex_of_type_params fmt m_name t =
+ let print_one (p, co, cn) =
+ ps fmt (Odoc_info.string_of_variance t (co,cn));
+ ps fmt (self#normal_type m_name p)
+ in
+ match t.ty_parameters with
+ [] -> ()
+ | [(p,co,cn)] -> print_one (p, co, cn)
+ | l ->
+ ps fmt "(";
+ print_concat fmt ", " print_one t.ty_parameters;
+ ps fmt ")"
+
+ method latex_of_class_parameter_list fmt father c =
+ self#latex_of_text fmt
+ (self#text_of_class_params father c)
+
+ (** Print LaTeX code for a type. *)
+ method latex_of_type fmt t =
+ let s_name = Name.simple t.ty_name in
+ let text =
+ let (fmt2, flush2) = new_fmt () in
+ Odoc_info.reset_type_names () ;
+ let mod_name = Name.father t.ty_name in
+ Format.fprintf fmt2 "@[<h 2>type ";
+ self#latex_of_type_params fmt2 mod_name t;
+ (match t.ty_parameters with [] -> () | _ -> ps fmt2 " ");
+ ps fmt2 s_name;
+ let priv = t.ty_private = Asttypes.Private in
+ (
+ match t.ty_manifest with
+ None -> ()
+ | Some typ ->
+ p fmt2 " = %s%s" (if priv then "private " else "") (self#normal_type mod_name typ)
+ );
+ let s_type3 =
+ p fmt2
+ " %s"
+ (
+ match t.ty_kind with
+ Type_abstract -> ""
+ | Type_variant _ -> "="^(if priv then " private" else "")
+ | Type_record _ -> "= "^(if priv then "private " else "")^"{"
+ ) ;
+ flush2 ()
+ in
+
+ let defs =
+ match t.ty_kind with
+ Type_abstract -> []
+ | Type_variant l ->
+ (List.flatten
+ (List.map
+ (fun constr ->
+ let s_cons =
+ p fmt2 "@[<h 6> | %s" constr.vc_name;
+ (
+ match constr.vc_args with
+ [] -> ()
+ | l ->
+ p fmt2 " %s@ %s"
+ "of"
+ (self#normal_type_list ~par: false mod_name " * " l)
+ );
+ flush2 ()
+ in
+ [ CodePre s_cons ] @
+ (match constr.vc_text with
+ None -> []
+ | Some t ->
+ let s =
+ ps fmt2 "\\begin{ocamldoccomment}\n";
+ self#latex_of_text fmt2 t;
+ ps fmt2 "\n\\end{ocamldoccomment}\n";
+ flush2 ()
+ in
+ [ Latex s]
+ )
+ )
+ l
+ )
+ )
+ | Type_record l ->
+ (List.flatten
+ (List.map
+ (fun r ->
+ let s_field =
+ p fmt2
+ "@[<h 6> %s%s :@ %s ;"
+ (if r.rf_mutable then "mutable " else "")
+ r.rf_name
+ (self#normal_type mod_name r.rf_type);
+ flush2 ()
+ in
+ [ CodePre s_field ] @
+ (match r.rf_text with
+ None -> []
+ | Some t ->
+ let s =
+ ps fmt2 "\\begin{ocamldoccomment}\n";
+ self#latex_of_text fmt2 t;
+ ps fmt2 "\n\\end{ocamldoccomment}\n";
+ flush2 ()
+ in
+ [ Latex s]
+ )
+ )
+ 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#label s_name)^"@\\verb`"^(self#label ~no_:false s_name)^"`}\n")] @
+ (self#text_of_info t.ty_info)
+ in
+ self#latex_of_text fmt
+ ((Latex (self#make_label (self#type_label t.ty_name))) :: text)
+
+ (** Print LaTeX code for an exception. *)
+ method latex_of_exception fmt e =
+ Odoc_info.reset_type_names () ;
+ self#latex_of_text fmt
+ ((Latex (self#make_label (self#exception_label e.ex_name))) ::
+ (to_text#text_of_exception e))
+
+ method latex_of_module_parameter fmt m_name p =
+ self#latex_of_text fmt
+ [
+ Code "functor (";
+ Code p.mp_name ;
+ Code " : ";
+ ] ;
+ self#latex_of_module_type_kind fmt m_name p.mp_kind;
+ self#latex_of_text fmt [ Code ") -> "]
+
+
+ method latex_of_module_type_kind fmt father kind =
+ match kind with
+ Module_type_struct eles ->
+ self#latex_of_text fmt [Latex "\\begin{ocamldocsigend}\n"];
+ List.iter (self#latex_of_module_element fmt father) eles;
+ self#latex_of_text fmt [Latex "\\end{ocamldocsigend}\n"]
+ | Module_type_functor (p, k) ->
+ self#latex_of_module_parameter fmt father p;
+ self#latex_of_module_type_kind fmt father k
+ | Module_type_alias a ->
+ self#latex_of_text fmt
+ [Code (self#relative_module_idents father a.mta_name)]
+ | Module_type_with (k, s) ->
+ self#latex_of_module_type_kind fmt father k;
+ self#latex_of_text fmt
+ [ Code " ";
+ Code (self#relative_idents father s);
+ ]
+ | Module_type_typeof s ->
+ self#latex_of_text fmt
+ [ Code "module type of ";
+ Code (self#relative_idents father s);
+ ]
+
+ method latex_of_module_kind fmt father kind =
+ match kind with
+ Module_struct eles ->
+ self#latex_of_text fmt [Latex "\\begin{ocamldocsigend}\n"];
+ List.iter (self#latex_of_module_element fmt father) eles;
+ self#latex_of_text fmt [Latex "\\end{ocamldocsigend}\n"]
+ | Module_alias a ->
+ self#latex_of_text fmt
+ [Code (self#relative_module_idents father a.ma_name)]
+ | Module_functor (p, k) ->
+ self#latex_of_module_parameter fmt father p;
+ self#latex_of_module_kind fmt father k
+ | Module_apply (k1, k2) ->
+ (* TODO: l'application n'est pas correcte dans un .mli.
+ Que faire ? -> afficher le module_type du typedtree *)
+ self#latex_of_module_kind fmt father k1;
+ self#latex_of_text fmt [Code "("];
+ self#latex_of_module_kind fmt father k2;
+ self#latex_of_text fmt [Code ")"]
+ | Module_with (k, s) ->
+ (* TODO: à modifier quand Module_with sera plus détaillé *)
+ self#latex_of_module_type_kind fmt father k;
+ self#latex_of_text fmt
+ [ Code " ";
+ Code (self#relative_idents father s) ;
+ ]
+ | Module_constraint (k, tk) ->
+ (* TODO: on affiche quoi ? *)
+ self#latex_of_module_kind fmt father k
+ | Module_typeof s ->
+ self#latex_of_text fmt
+ [ Code "module type of ";
+ Code (self#relative_idents father s);
+ ]
+ | Module_unpack (s, _) ->
+ self#latex_of_text fmt
+ [
+ Code (self#relative_idents father s);
+ ]
+
+ method latex_of_class_kind fmt father kind =
+ match kind with
+ Class_structure (inh, eles) ->
+ self#latex_of_text fmt [Latex "\\begin{ocamldocobjectend}\n"];
+ self#generate_inheritance_info fmt inh;
+ List.iter (self#latex_of_class_element fmt father) eles;
+ self#latex_of_text fmt [Latex "\\end{ocamldocobjectend}\n"]
+
+ | Class_apply capp ->
+ (* TODO: afficher le type final à partir du typedtree *)
+ self#latex_of_text fmt [Raw "class application not handled yet"]
+
+ | Class_constr cco ->
+ (
+ match cco.cco_type_parameters with
+ [] -> ()
+ | l ->
+ self#latex_of_text fmt
+ (
+ Code "[" ::
+ (self#text_of_class_type_param_expr_list father l) @
+ [Code "] "]
+ )
+ );
+ self#latex_of_text fmt
+ [Code (self#relative_idents father cco.cco_name)]
+
+ | Class_constraint (ck, ctk) ->
+ self#latex_of_text fmt [Code "( "] ;
+ self#latex_of_class_kind fmt father ck;
+ self#latex_of_text fmt [Code " : "] ;
+ self#latex_of_class_type_kind fmt father ctk;
+ self#latex_of_text fmt [Code " )"]
+
+ method latex_of_class_type_kind fmt father kind =
+ match kind with
+ Class_type cta ->
+ (
+ match cta.cta_type_parameters with
+ [] -> ()
+ | l ->
+ self#latex_of_text fmt
+ (Code "[" ::
+ (self#text_of_class_type_param_expr_list father l) @
+ [Code "] "]
+ )
+ );
+ self#latex_of_text fmt
+ [Code (self#relative_idents father cta.cta_name)]
+
+ | Class_signature (inh, eles) ->
+ self#latex_of_text fmt [Latex "\\begin{ocamldocobjectend}\n"];
+ self#generate_inheritance_info fmt inh;
+ List.iter (self#latex_of_class_element fmt father) eles;
+ self#latex_of_text fmt [Latex "\\end{ocamldocobjectend}\n"]
+
+ method latex_for_module_index fmt m =
+ let s_name = Name.simple m.m_name in
+ self#latex_of_text fmt
+ [Latex ("\\index{"^(self#label s_name)^"@\\verb`"^
+ (self#label ~no_:false s_name)^"`}\n"
+ )
+ ]
+
+ method latex_for_module_type_index fmt mt =
+ let s_name = Name.simple mt.mt_name in
+ self#latex_of_text fmt
+ [Latex ("\\index{"^(self#label s_name)^"@\\verb`"^
+ (self#label ~no_:false (Name.simple s_name))^"`}\n"
+ )
+ ]
+
+ method latex_for_module_label fmt m =
+ ps fmt (self#make_label (self#module_label m.m_name))
+
+ method latex_for_module_type_label fmt mt =
+ ps fmt (self#make_label (self#module_type_label mt.mt_name))
+
+
+ method latex_for_class_index fmt c =
+ let s_name = Name.simple c.cl_name in
+ self#latex_of_text fmt
+ [Latex ("\\index{"^(self#label s_name)^"@\\verb`"^
+ (self#label ~no_:false s_name)^"`}\n"
+ )
+ ]
+
+ method latex_for_class_type_index fmt ct =
+ let s_name = Name.simple ct.clt_name in
+ self#latex_of_text fmt
+ [Latex ("\\index{"^(self#label s_name)^"@\\verb`"^
+ (self#label ~no_:false s_name)^"`}\n"
+ )
+ ]
+
+ method latex_for_class_label fmt c =
+ ps fmt (self#make_label (self#class_label c.cl_name))
+
+ method latex_for_class_type_label fmt ct =
+ ps fmt (self#make_label (self#class_type_label ct.clt_name))
+
+ (** Print the LaTeX code for the given module. *)
+ method latex_of_module fmt m =
+ let father = Name.father m.m_name in
+ let t =
+ [
+ Latex "\\begin{ocamldoccode}\n" ;
+ Code "module ";
+ Code (Name.simple m.m_name);
+ Code " : ";
+ ]
+ in
+ self#latex_of_text fmt t;
+ self#latex_of_text fmt [ Latex "\\end{ocamldoccode}\n" ];
+ self#latex_for_module_label fmt m;
+ self#latex_for_module_index fmt m;
+ p fmt "@[<h 4>";
+ self#latex_of_module_kind fmt father m.m_kind;
+ (
+ match Module.module_is_functor m with
+ false -> ()
+ | true ->
+ self#latex_of_text fmt [Newline];
+ (
+ match List.filter (fun (_,d) -> d <> None)
+ (module_parameters ~trans: false m)
+ with
+ [] -> ()
+ | l ->
+ let t =
+ [ Bold [Raw "Parameters: "];
+ List
+ (List.map
+ (fun (p,text_opt) ->
+ let t = match text_opt with None -> [] | Some t -> t in
+ ( Raw p.mp_name :: Raw ": " :: t)
+ )
+ l
+ )
+ ]
+ in
+ self#latex_of_text fmt t
+ );
+ );
+ self#latex_of_text fmt [Newline];
+ self#latex_of_info fmt ~block: true m.m_info;
+ p fmt "@]";
+
+
+ (** Print the LaTeX code for the given module type. *)
+ method latex_of_module_type fmt mt =
+ let father = Name.father mt.mt_name in
+ let t =
+ [
+ Latex "\\begin{ocamldoccode}\n" ;
+ Code "module type " ;
+ Code (Name.simple mt.mt_name);
+ ]
+ in
+ self#latex_of_text fmt t;
+ (
+ match mt.mt_type, mt.mt_kind with
+ | Some mtyp, Some kind ->
+ self#latex_of_text fmt [ Code " = " ];
+ self#latex_of_text fmt [ Latex "\\end{ocamldoccode}\n" ];
+ self#latex_for_module_type_label fmt mt;
+ self#latex_for_module_type_index fmt mt;
+ p fmt "@[<h 4>";
+ self#latex_of_module_type_kind fmt father kind
+ | _ ->
+ self#latex_of_text fmt [ Latex "\\end{ocamldoccode}\n" ];
+ self#latex_for_module_type_index fmt mt;
+ p fmt "@[<h 4>";
+ );
+ (
+ match Module.module_type_is_functor mt with
+ false -> ()
+ | true ->
+ self#latex_of_text fmt [Newline];
+ (
+ match List.filter (fun (_,d) -> d <> None)
+ (module_type_parameters ~trans: false mt)
+ with
+ [] -> ()
+ | l ->
+ let t =
+ [ Bold [Raw "Parameters: "];
+ List
+ (List.map
+ (fun (p,text_opt) ->
+ let t = match text_opt with None -> [] | Some t -> t in
+ ( Raw p.mp_name :: Raw ": " :: t)
+ )
+ l
+ )
+ ]
+ in
+ self#latex_of_text fmt t
+ );
+ );
+ self#latex_of_text fmt [Newline];
+ self#latex_of_info fmt ~block: true mt.mt_info;
+ p fmt "@]";
+
+ (** Print the LaTeX code for the given included module. *)
+ method latex_of_included_module fmt im =
+ self#latex_of_text fmt
+ ((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)
+ )
+
+ (** Print the LaTeX code for the given class. *)
+ method latex_of_class fmt c =
+ Odoc_info.reset_type_names () ;
+ let father = Name.father c.cl_name in
+ let type_params =
+ match c.cl_type_parameters with
+ [] -> ""
+ | l -> (self#normal_class_type_param_list father l)^" "
+ in
+ let t =
+ [
+ Latex "\\begin{ocamldoccode}\n" ;
+ Code (Printf.sprintf
+ "class %s%s%s : "
+ (if c.cl_virtual then "virtual " else "")
+ type_params
+ (Name.simple c.cl_name)
+ )
+ ]
+ in
+ self#latex_of_text fmt t;
+ self#latex_of_class_parameter_list fmt father c;
+ (* avoid a big gap if the kind is a consrt *)
+ (
+ match c.cl_kind with
+ Class.Class_constr _ ->
+ self#latex_of_class_kind fmt father c.cl_kind
+ | _ ->
+ ()
+ );
+ self#latex_of_text fmt [ Latex "\\end{ocamldoccode}\n" ];
+ self#latex_for_class_label fmt c;
+ self#latex_for_class_index fmt c;
+ p fmt "@[<h 4>";
+ (match c.cl_kind with
+ Class.Class_constr _ -> ()
+ | _ -> self#latex_of_class_kind fmt father c.cl_kind
+ );
+ self#latex_of_text fmt [Newline];
+ self#latex_of_info fmt ~block: true c.cl_info;
+ p fmt "@]"
+
+ (** Print the LaTeX code for the given class type. *)
+ method latex_of_class_type fmt ct =
+ Odoc_info.reset_type_names () ;
+ let father = Name.father ct.clt_name in
+ let type_params =
+ match ct.clt_type_parameters with
+ [] -> ""
+ | l -> (self#normal_class_type_param_list father l)^" "
+ in
+ let t =
+ [
+ Latex "\\begin{ocamldoccode}\n" ;
+ Code (Printf.sprintf
+ "class type %s%s%s = "
+ (if ct.clt_virtual then "virtual " else "")
+ type_params
+ (Name.simple ct.clt_name)
+ )
+ ]
+ in
+ self#latex_of_text fmt t;
+
+ self#latex_of_text fmt [ Latex "\\end{ocamldoccode}\n" ];
+ self#latex_for_class_type_label fmt ct;
+ self#latex_for_class_type_index fmt ct;
+ p fmt "@[<h 4>";
+ self#latex_of_class_type_kind fmt father ct.clt_kind;
+ self#latex_of_text fmt [Newline];
+ self#latex_of_info fmt ~block: true ct.clt_info;
+ p fmt "@]"
+
+ (** Print the LaTeX code for the given class element. *)
+ method latex_of_class_element fmt class_name class_ele =
+ self#latex_of_text fmt [Newline];
+ match class_ele with
+ Class_attribute att -> self#latex_of_attribute fmt att
+ | Class_method met -> self#latex_of_method fmt met
+ | Class_comment t ->
+ match t with
+ | [] -> ()
+ | (Title (_,_,_)) :: _ -> self#latex_of_text fmt t
+ | _ -> self#latex_of_text fmt [ Title ((Name.depth class_name) + 2, None, t) ]
+
+ (** Print the LaTeX code for the given module element. *)
+ method latex_of_module_element fmt module_name module_ele =
+ self#latex_of_text fmt [Newline];
+ match module_ele with
+ Element_module m -> self#latex_of_module fmt m
+ | Element_module_type mt -> self#latex_of_module_type fmt mt
+ | Element_included_module im -> self#latex_of_included_module fmt im
+ | Element_class c -> self#latex_of_class fmt c
+ | Element_class_type ct -> self#latex_of_class_type fmt ct
+ | Element_value v -> self#latex_of_value fmt v
+ | Element_exception e -> self#latex_of_exception fmt e
+ | Element_type t -> self#latex_of_type fmt t
+ | Element_module_comment t -> self#latex_of_text fmt t
+
+ (** Generate the LaTeX code for the given list of inherited classes.*)
+ method generate_inheritance_info fmt inher_l =
+ let f inh =
+ match inh.ic_class with
+ None -> (* we can't make the reference *)
+ Newline ::
+ Code ("inherit "^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 *)
+ Newline ::
+ Odoc_info.Code ("inherit "^inh.ic_name) ::
+ (Odoc_info.Latex (" ["^(self#make_ref label)^"]")) ::
+ (match inh.ic_text with
+ None -> []
+ | Some t -> Newline :: t
+ )
+ in
+ List.iter (self#latex_of_text fmt) (List.map f inher_l)
+
+ (** Generate the LaTeX code for the inherited classes of the given class. *)
+ method generate_class_inheritance_info fmt cl =
+ let rec iter_kind k =
+ match k with
+ Class_structure ([], _) ->
+ ()
+ | Class_structure (l, _) ->
+ self#generate_inheritance_info fmt 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 fmt clt =
+ match clt.clt_kind with
+ Class_signature ([], _) ->
+ ()
+ | Class_signature (l, _) ->
+ self#generate_inheritance_info fmt l
+ | Class_type _ ->
+ ()
+
+ (** Generate the LaTeX code for the given top module, in the given buffer. *)
+ method generate_for_top_module fmt m =
+ let (first_t, rest_t) = self#first_and_rest_of_info m.m_info in
+ let text =
+ if m.m_text_only then
+ [ Title (1, None, [Raw m.m_name] @
+ (match first_t with
+ [] -> []
+ | t -> (Raw " : ") :: t)
+ ) ;
+ ]
+ else
+ [ Title (1, None,
+ [ Raw (Odoc_messages.modul^" ") ; Code m.m_name ] @
+ (match first_t with
+ [] -> []
+ | t -> (Raw " : ") :: t)) ;
+ ]
+ in
+ self#latex_of_text fmt text;
+ self#latex_for_module_label fmt m;
+ self#latex_for_module_index fmt m;
+ self#latex_of_text fmt rest_t ;
+
+ self#latex_of_text fmt [ Newline ] ;
+ if not m.m_text_only then ps fmt "\\ocamldocvspace{0.5cm}\n\n";
+ List.iter
+ (fun ele ->
+ self#latex_of_module_element fmt m.m_name ele;
+ ps fmt "\n\n"
+ )
+ (Module.module_elements ~trans: false m)
+
+ (** Print the header of the TeX document. *)
+ method latex_header fmt module_list =
+ ps fmt "\\documentclass[11pt]{article} \n";
+ ps fmt "\\usepackage[latin1]{inputenc} \n";
+ ps fmt "\\usepackage[T1]{fontenc} \n";
+ ps fmt "\\usepackage{fullpage} \n";
+ ps fmt "\\usepackage{url} \n";
+ ps fmt "\\usepackage{ocamldoc}\n";
+ (
+ match !Global.title with
+ None -> ()
+ | Some s ->
+ ps fmt "\\title{";
+ ps fmt (self#escape s);
+ ps fmt "}\n"
+ );
+ ps fmt "\\begin{document}\n";
+ (match !Global.title with
+ None -> () |
+ Some _ -> ps fmt "\\maketitle\n"
+ );
+ if !Global.with_toc then ps fmt "\\tableofcontents\n";
+ (
+ let info = Odoc_info.apply_opt
+ (Odoc_info.info_of_comment_file module_list)
+ !Odoc_info.Global.intro_file
+ in
+ (match info with None -> () | Some _ -> ps fmt "\\vspace{0.2cm}");
+ self#latex_of_info fmt info;
+ (match info with None -> () | Some _ -> ps fmt "\n\n")
+ )
+
+
+ (** Generate the LaTeX style file, if it does not exists. *)
+ method generate_style_file =
+ try
+ let dir = Filename.dirname !Global.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.Global.out_file} file. *)
+ method generate module_list =
+ self#generate_style_file ;
+ let main_file = !Global.out_file in
+ let dir = Filename.dirname main_file in
+ if !separate_files then
+ (
+ let f m =
+ try
+ let chanout =
+ open_out ((Filename.concat dir (Name.simple m.m_name))^".tex")
+ in
+ let fmt = Format.formatter_of_out_channel chanout in
+ self#generate_for_top_module fmt m ;
+ Format.pp_print_flush fmt ();
+ 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 main_file in
+ let fmt = Format.formatter_of_out_channel chanout in
+ if !Global.with_header then self#latex_header fmt module_list;
+ List.iter
+ (fun m ->
+ if !separate_files then
+ ps fmt ("\\input{"^((Name.simple m.m_name))^".tex}\n")
+ else
+ self#generate_for_top_module fmt m
+ )
+ module_list ;
+ if !Global.with_trailer then ps fmt "\\end{document}";
+ Format.pp_print_flush fmt ();
+ close_out chanout
+ with
+ Failure s
+ | Sys_error s ->
+ prerr_endline s ;
+ incr Odoc_info.errors
+ end
+end
+
+module type Latex_generator = module type of Generator