(************************************************************************) (* * The Coq Proof Assistant / The Coq Development Team *) (* v * INRIA, CNRS and contributors - Copyright 1999-2018 *) (* <O___,, * (see CREDITS file for the list of authors) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************)
open Cdglobals open Index
(*s Low level output *)
let output_char c = Pervasives.output_char !out_channel c
let output_string s = Pervasives.output_string !out_channel s
let printf s = Printf.fprintf !out_channel s
let sprintf = Printf.sprintf
(*s Coq keywords *)
let build_table l = let h = Hashtbl.create 101 in List.iter (fun key ->Hashtbl.add h key ()) l;
function s -> try Hashtbl.find h s; truewith Not_found -> false
let current_module : (string * stringoption) ref = ref ("",None)
let get_module withsub = let (m,sub) = !current_module in if withsub then matchsubwith
| None -> m
| Some sub -> m ^ ": " ^ sub else
m
let set_module m sub = current_module := (m,sub);
page_title := get_module true
(*s Common to both LaTeX and HTML *)
let item_level = ref 0 let in_doc = reffalse
(*s Customized and predefined pretty-print *)
let initialize_texmacs () = let ensuremath x = sprintf ">" x in List.fold_right (fun (s,t) tt -> Tokens.ttree_add tt s t)
[ "*", ensuremath "times"; "->", ensuremath "rightarrow"; "<-", ensuremath "leftarrow"; "<->", ensuremath "leftrightarrow"; "=>", ensuremath "Rightarrow"; "<=", ensuremath "le"; ">=", ensuremath "ge"; "<>", ensuremath "noteq"; "~", ensuremath "lnot"; "/\\", ensuremath "land"; "\\/", ensuremath "lor"; "|-", ensuremath "vdash"
] Tokens.empty_ttree
let token_tree_texmacs = ref (initialize_texmacs ())
let token_tree_latex = ref Tokens.empty_ttree let token_tree_html = ref Tokens.empty_ttree
let initialize_tex_html () = let if_utf8 = if !Cdglobals.utf8 thenfun x -> Some x elsefun _ -> None in let (tree_latex, tree_html) = List.fold_right (fun (s,l,l') (tt,tt') ->
(Tokens.ttree_add tt s l, match l' with None -> tt' | Some l' -> Tokens.ttree_add tt' s l'))
[ "*" , "\\ensuremath{\\times}", if_utf8 "×"; "|", "\\ensuremath{|}", None; "->", "\\ensuremath{\\rightarrow}", if_utf8 "→"; "->~", "\\ensuremath{\\rightarrow\\lnot}", None; "->~~", "\\ensuremath{\\rightarrow\\lnot\\lnot}", None; "<-", "\\ensuremath{\\leftarrow}", None; "<->", "\\ensuremath{\\leftrightarrow}", if_utf8 "↔"; "=>", "\\ensuremath{\\Rightarrow}", if_utf8 "⇒"; "<=", "\\ensuremath{\\le}", if_utf8 "≤"; ">=", "\\ensuremath{\\ge}", if_utf8 "≥"; "<>", "\\ensuremath{\\not=}", if_utf8 "≠"; "~", "\\ensuremath{\\lnot}", if_utf8 "¬"; "/\\", "\\ensuremath{\\land}", if_utf8 "∧"; "\\/", "\\ensuremath{\\lor}", if_utf8 "∨"; "|-", "\\ensuremath{\\vdash}", None; "forall", "\\ensuremath{\\forall}", if_utf8 "∀"; "exists", "\\ensuremath{\\exists}", if_utf8 "∃"; "Π", "\\ensuremath{\\Pi}", if_utf8 "Π"; "λ", "\\ensuremath{\\lambda}", if_utf8 "λ"; (* "fun", "\\ensuremath{\\lambda}" ? *)
] (Tokens.empty_ttree,Tokens.empty_ttree) in
token_tree_latex := tree_latex;
token_tree_html := tree_html
let add_printing_token s (t1,t2) =
(match t1 with None -> () | Some t1 ->
token_tree_latex := Tokens.ttree_add !token_tree_latex s t1);
(match t2 with None -> () | Some t2 ->
token_tree_html := Tokens.ttree_add !token_tree_html s t2)
let remove_printing_token s =
token_tree_latex := Tokens.ttree_remove !token_tree_latex s;
token_tree_html := Tokens.ttree_remove !token_tree_html s
(*s Table of contents *)
type toc_entry =
| Toc_library ofstring * stringoption
| Toc_section of int * (unit -> unit) * string
let (toc_q : toc_entry Queue.t) = Queue.create ()
let add_toc_entry e = Queue.add e toc_q
let new_label = let r = ref 0 infun () -> incr r; "lab" ^ string_of_int !r
(*s LaTeX output *)
module Latex = struct
let in_title = reffalse
(*s Latex preamble *)
let (preamble : string Queue.t) = Queue.create ()
let push_in_preamble s = Queue.add s preamble
let utf8x_extra_support () =
printf "\n";
printf "%%Warning: tipa declares many non-standard macros used by utf8x to\n";
printf "%%interpret utf8 characters but extra packages might have to be added\n";
printf "%%such as \"textgreek\" for Greek letters not already in tipa\n";
printf "%%or \"stmaryrd\" for mathematical symbols.\n";
printf "%%Utf8 codes missing a LaTeX interpretation can be defined by using\n";
printf "%%\\DeclareUnicodeCharacter{code}{interpretation}.\n";
printf "%%Use coqdoc's option -p to add new packages or declarations.\n";
printf "\\usepackage{tipa}\n";
printf "\n"
let header () = if !header_trailer thenbegin
printf "\\documentclass[12pt]{report}\n"; if !inputenc != ""then printf "\\usepackage[%s]{inputenc}\n" !inputenc; if !inputenc = "utf8x"then utf8x_extra_support ();
printf "\\usepackage[T1]{fontenc}\n";
printf "\\usepackage{fullpage}\n";
printf "\\usepackage{coqdoc}\n";
printf "\\usepackage{amsmath,amssymb}\n";
printf "\\usepackage{url}\n";
(match !toc_depth with
| None -> ()
| Some n -> printf "\\setcounter{tocdepth}{%i}\n" n);
Queue.iter (fun s -> printf "%s\n" s) preamble;
printf "\\begin{document}\n" end;
output_string "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
output_string "%% This file has been automatically generated with the command\n";
output_string "%% ";
Array.iter (fun s -> printf "%s " s) Sys.argv;
printf "\n";
output_string "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
let trailer () = if !header_trailer thenbegin
printf "\\end{document}\n" end
(*s Latex low-level translation *)
let nbsp () = output_char '~'
let char c = match c with
| '\\' ->
printf "\\symbol{92}"
| '$' | '#' | '%' | '&' | '{' | '}' | '_' ->
output_char '\\'; output_char c
| '^' | '~' ->
output_char '\\'; output_char c; printf "{}"
| _ ->
output_char c
let label_char c = match c with
| '_' -> output_char ' '
| '\\' | '$' | '#' | '%' | '&' | '{' | '}'
| '^' | '~' -> printf "x%X" (Char.code c)
| _ -> if c >= '\x80'then printf "x%X" (Char.code c) else output_char c
let label_ident s =
for i = 0 to String.length s - 1 do label_char s.[i] done
let latex_char = output_char let latex_string = output_string
let html_char _ = () let html_string _ = ()
(*s Latex char escaping *)
let escaped = let buff = Buffer.create 5 in fun s ->
Buffer.clear buff;
for i = 0 to String.length s - 1 do match s.[i] with
| '\\' ->
Buffer.add_string buff "\\symbol{92}"
| '$' | '#' | '%' | '&' | '{' | '}' | '_' as c ->
Buffer.add_char buff '\\'; Buffer.add_char buff c
| '^' | '~' as c ->
Buffer.add_char buff '\\'; Buffer.add_char buff c;
Buffer.add_string buff "{}"
| '\'' -> if i < String.length s - 1 && s.[i+1] = '\'' then begin
Buffer.add_char buff '\''; Buffer.add_char buff '{';
Buffer.add_char buff '}' endelse
Buffer.add_char buff '\''
| c ->
Buffer.add_char buff c
done;
Buffer.contents buff
(*s Latex reference and symbol translation *)
let start_module () = let ln = !lib_name in ifnot !short thenbegin
printf "\\coqlibrary{";
label_ident (get_module false);
printf "}{"; if ln <> ""then printf "%s " ln;
printf "}{%s}\n\n" (escaped (get_module true)) end
let start_latex_math () = output_char '$'
let stop_latex_math () = output_char '$'
let start_quote () = output_char '`'; output_char '`' let stop_quote () = output_char '\''; output_char '\''
let start_verbatim inline = if inline then printf "\\texttt{" else printf "\\begin{verbatim}"
let stop_verbatim inline = if inline then printf "}" else printf "\\end{verbatim}\n"
let url addr name =
printf "%s\\footnote{\\url{%s}}"
(match name with
| None -> ""
| Some n -> n)
addr
let indentation n = if n == 0 then
printf "\\coqdocnoindent\n" else let space = 0.5 *. (float n) in
printf "\\coqdocindent{%2.2fem}\n" space
let ident_ref m fid typ s = let id = if fid <> ""then (m ^ "." ^ fid) else m in match find_module m with
| Local -> if typ = Variable then
printf "\\coqdoc%s{%s}" (type_name typ) s else
(printf "\\coqref{"; label_ident id;
printf "}{\\coqdoc%s{%s}}" (type_name typ) s)
| External m when !externals ->
printf "\\coqexternalref{"; label_ident fid;
printf "}{%s}{\\coqdoc%s{%s}}" (escaped m) (type_name typ) s
| External _ | Unknown ->
printf "\\coqdoc%s{%s}" (type_name typ) s
let defref m id ty s = if ty <> Notation then
(printf "\\coqdef{"; label_ident (m ^ "." ^ id);
printf "}{%s}{\\coqdoc%s{%s}}" s (type_name ty) s) else (* Glob file still not able to say the exact extent of the definition *) (* so we currently renounce to highlight the notation location *)
(printf "\\coqdef{"; label_ident (m ^ "." ^ id);
printf "}{%s}{%s}" s s)
let reference s = function
| Def (fullid,typ) ->
defref (get_module false) fullid typ s
| Ref (m,fullid,typ) ->
ident_ref m fullid typ s
(*s The sublexer buffers symbol characters and attached uninterpreted ident and try to apply special translation such as, predefined, translation "->" to "\ensuremath{\rightarrow}" or,
virtually, a user-level translation from "=_h" to "\ensuremath{=_{h}}" *)
let output_sublexer_string doescape issymbchar tag s = let s = if doescape then escaped s else s in match tag with
| Some ref -> reference s ref
| None -> if issymbchar then output_string s else printf "\\coqdocvar{%s}" s
let last_was_in = reffalse
let sublexer c loc = if c = '*' && !last_was_in thenbegin
Tokens.flush_sublexer ();
output_char '*' endelsebegin let tag = try Some (Index.find (get_module false) loc) with Not_found -> None in
Tokens.output_tagged_symbol_char tag c end;
last_was_in := false
let sublexer_in_doc c = if c = '*' && !last_was_in thenbegin
Tokens.flush_sublexer ();
output_char '*' endelse
Tokens.output_tagged_symbol_char None c;
last_was_in := false
(*s Interpreting ident with fallback on sublexer if unknown ident *)
let translate s = match Tokens.translate s with Some s -> s | None -> escaped s
let keyword s loc =
printf "\\coqdockw{%s}" (translate s)
let ident s loc =
last_was_in := s = "in"; try match loc with
| None -> raise Not_found
| Some loc -> let tag = Index.find (get_module false) loc in
reference (translate s) tag with Not_found -> if is_tactic s then
printf "\\coqdoctac{%s}" (translate s) elseif is_keyword s then
printf "\\coqdockw{%s}" (translate s) elseif !Cdglobals.interpolate && !in_doc (* always a var otherwise *) then try let tag = Index.find_string s in
reference (translate s) tag with _ -> Tokens.output_tagged_ident_string s else Tokens.output_tagged_ident_string s
let ident s l = if !in_title then (
printf "\\texorpdfstring{\\protect";
ident s l;
printf "}{%s}" (translate s)) else
ident s l
(*s Translating structure *)
let proofbox () = printf "\\ensuremath{\\Box}"
let rec reach_item_level n = if !item_level < n thenbegin
printf "\n\\begin{itemize}\n\\item "; incr item_level;
reach_item_level n endelseif !item_level > n thenbegin
printf "\n\\end{itemize}\n"; decr item_level;
reach_item_level n end
let item n = let old_level = !item_level in
reach_item_level n; if n <= old_level then printf "\n\\item "
let stop_item () = reach_item_level 0
let start_doc () = in_doc := true
let end_doc () = in_doc := false; stop_item ()
(* This is broken if we are in math mode, but coqdoc currently isn't
tracking that *) let start_emph () = printf "\\textit{"
let stop_emph () = printf "}"
let start_comment () = printf "\\begin{coqdoccomment}\n"
let end_comment () = printf "\\end{coqdoccomment}\n"
let section lev f =
stop_item ();
output_string (section_kind lev);
in_title := true; f (); in_title := false;
printf "}\n\n"
let rule () =
printf "\\par\n\\noindent\\hrulefill\\par\n\\noindent{}"
let paragraph () = printf "\n\n"
let line_break () = printf "\\coqdoceol\n"
let empty_line_of_code () = printf "\\coqdocemptyline\n"
let start_inline_coq_block () = line_break (); empty_line_of_code ()
let end_inline_coq_block () = empty_line_of_code ()
let start_inline_coq () = ()
let end_inline_coq () = ()
let make_multi_index () = ()
let make_index () = ()
let make_toc () = printf "\\tableofcontents\n"
end
(*s HTML output *)
module Html = struct
let header () = if !header_trailer then if !header_file_spec then let cin = Pervasives.open_in !header_file in try whiletruedo let s = Pervasives.input_line cin in
printf "%s\n" s
done with End_of_file -> Pervasives.close_in cin else begin
printf "-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
printf "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
printf "http://www.w3.org/1999/xhtml\">\n<head>\n";
printf "Content-Type\" content=\"text/html; charset=%s\" />\n" !charset;
printf "coqdoc.css\" rel=\"stylesheet\" type=\"text/css\" />\n";
printf "%s\n\n\n" !page_title;
printf "\n\n
page\">\n\n
header\">\n
\n\n";
printf "
main\">\n\n" end
let trailer () = if !header_trailer && !footer_file_spec then let cin = Pervasives.open_in !footer_file in try whiletruedo let s = Pervasives.input_line cin in
printf "%s\n" s
done with End_of_file -> Pervasives.close_in cin else begin if !index && (get_module false) <> "Index"then
printf "
\n\n
footer\">\n%s.html\">Index" !index_name;
printf "This page has been generated by ";
printf "%s\">coqdoc\n" Coq_config.wwwcoq;
printf "