catala/compiler/literate/latex.ml

181 lines
7.0 KiB
OCaml
Raw Normal View History

2020-04-16 18:47:35 +03:00
(* This file is part of the Catala compiler, a specification language for tax and social benefits
computation rules. Copyright (C) 2020 Inria, contributors: Denis Merigoux
<denis.merigoux@inria.fr>, Emile Rolley <emile.rolley@tuta.io>
2020-03-09 14:01:56 +03:00
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
in compliance with the License. You may obtain a copy of the License at
2020-03-09 14:01:56 +03:00
http://www.apache.org/licenses/LICENSE-2.0
2020-03-09 14:01:56 +03:00
Unless required by applicable law or agreed to in writing, software distributed under the License
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the License for the specific language governing permissions and limitations under
the License. *)
2020-03-09 14:01:56 +03:00
(** This modules weaves the source code and the legislative text together into a document that law
professionals can understand. *)
2021-01-21 23:33:04 +03:00
open Utils
open Literate_common
2020-11-23 11:22:47 +03:00
module A = Surface.Ast
2020-04-11 19:36:00 +03:00
module R = Re.Pcre
2020-04-20 09:13:57 +03:00
module C = Cli
2020-04-11 19:36:00 +03:00
2020-12-14 20:09:38 +03:00
(** {1 Helpers} *)
(** Espaces various LaTeX-sensitive characters *)
2020-04-11 19:36:00 +03:00
let pre_latexify (s : string) =
let percent = R.regexp "%" in
2020-04-16 10:07:21 +03:00
let s = R.substitute ~rex:percent ~subst:(fun _ -> "\\%") s in
2020-05-18 10:47:13 +03:00
let dollar = R.regexp "\\$" in
let s = R.substitute ~rex:dollar ~subst:(fun _ -> "\\$") s in
2020-04-16 10:07:21 +03:00
let premier = R.regexp "1er" in
let s = R.substitute ~rex:premier ~subst:(fun _ -> "1\\textsuperscript{er}") s in
let underscore = R.regexp "\\_" in
let s = R.substitute ~rex:underscore ~subst:(fun _ -> "\\_") s in
2020-04-16 10:07:21 +03:00
s
2020-12-14 20:09:38 +03:00
(** Usage: [wrap_latex source_files custom_pygments language fmt wrapped]
Prints an LaTeX complete documùent structure around the [wrapped] content. *)
2021-03-02 20:27:39 +03:00
let wrap_latex (source_files : string list) (language : C.backend_lang) (fmt : Format.formatter)
(wrapped : Format.formatter -> unit) =
Format.fprintf fmt
2020-04-19 20:56:27 +03:00
"\\documentclass[11pt, a4paper]{article}\n\n\
\\usepackage[T1]{fontenc}\n\
\\usepackage[utf8]{inputenc}\n\
2021-05-11 21:24:34 +03:00
\\usepackage{amssymb}\n\
2020-04-19 20:56:27 +03:00
\\usepackage[%s]{babel}\n\
\\usepackage{lmodern}\n\
\\usepackage{minted}\n\
\\usepackage{newunicodechar}\n\
\\usepackage{textcomp}\n\
\\usepackage[hidelinks]{hyperref}\n\
\\usepackage[dvipsnames]{xcolor}\n\
\\usepackage{fullpage}\n\
\\usepackage[many]{tcolorbox}\n\n\
\\newunicodechar{÷}{$\\div$}\n\
\\newunicodechar{×}{$\\times$}\n\
\\newunicodechar{}{$\\leqslant$}\n\
\\newunicodechar{}{$\\geqslant$}\n\
\\newunicodechar{}{$\\rightarrow$}\n\
\\newunicodechar{}{$\\neq$}\n\n\
2021-03-10 17:58:01 +03:00
\\newcommand*\\FancyVerbStartString{```catala}\n\
\\newcommand*\\FancyVerbStopString{```}\n\n\
\\fvset{\n\
numbers=left,\n\
2020-04-19 20:04:11 +03:00
frame=lines,\n\
2020-04-19 20:56:27 +03:00
framesep=3mm,\n\
2020-04-19 20:04:11 +03:00
rulecolor=\\color{gray!70},\n\
firstnumber=last,\n\
codes={\\catcode`\\$=3\\catcode`\\^=7}\n\
}\n\n\
\\title{\n\
2020-04-19 20:56:27 +03:00
%s\n\
}\n\
\\author{\n\
2020-04-19 20:56:27 +03:00
%s Catala version %s\n\
}\n\
\\begin{document}\n\
\\maketitle\n\n\
2020-04-19 20:56:27 +03:00
%s : \n\
\\begin{itemize}%s\\end{itemize}\n\n\
\\[\\star\\star\\star\\]\\\\\n"
(match language with Fr -> "french" | En -> "english" | Pl -> "polish")
(literal_title language) (literal_generated_by language) Utils.Cli.version
(literal_source_files language)
(String.concat ","
2020-04-17 16:28:34 +03:00
(List.map
(fun filename ->
let mtime = (Unix.stat filename).Unix.st_mtime in
let ltime = Unix.localtime mtime in
let ftime =
2020-05-17 20:20:03 +03:00
Printf.sprintf "%d-%02d-%02d, %d:%02d" (1900 + ltime.Unix.tm_year)
(ltime.Unix.tm_mon + 1) ltime.Unix.tm_mday ltime.Unix.tm_hour ltime.Unix.tm_min
2020-04-17 16:28:34 +03:00
in
2020-04-19 20:56:27 +03:00
Printf.sprintf "\\item\\texttt{%s}, %s %s"
(pre_latexify (Filename.basename filename))
(literal_last_modification language)
ftime)
source_files));
wrapped fmt;
Format.fprintf fmt "\n\n\\end{document}"
2020-12-14 20:09:38 +03:00
(** Replaces math operators by their nice unicode counterparts *)
let math_syms_replace (c : string) : string =
let date = "\\d\\d/\\d\\d/\\d\\d\\d\\d" in
2020-05-17 16:23:48 +03:00
let syms = R.regexp (date ^ "|!=|<=|>=|--|->|\\*|/") in
let syms2cmd = function
| "!=" -> ""
| "<=" -> ""
| ">=" -> ""
| "--" -> ""
| "->" -> ""
| "*" -> "×"
| "/" -> "÷"
| s -> s
in
R.substitute ~rex:syms ~subst:syms2cmd c
2020-12-14 20:09:38 +03:00
(** {1 Weaving} *)
let rec law_structure_to_latex (language : C.backend_lang) (fmt : Format.formatter)
(i : A.law_structure) : unit =
match i with
| A.LawHeading (heading, children) ->
Format.fprintf fmt "\\%s*{%s}\n\n"
2021-03-23 12:59:43 +03:00
(match heading.law_heading_precedence with
| 0 -> "chapter"
| 1 -> "section"
| 2 -> "subsection"
| 4 -> "subsubsection"
| 5 -> "paragraph"
| _ -> "subparagraph")
(pre_latexify (Pos.unmark heading.law_heading_name));
Format.pp_print_list
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n\n")
(law_structure_to_latex language) fmt children
| A.LawInclude (A.PdfFile ((file, _), page)) ->
let label = file ^ match page with None -> "" | Some p -> Format.sprintf "_page_%d," p in
Format.fprintf fmt
"\\begin{center}\\textit{Annexe incluse, retranscrite page \\pageref{%s}}\\end{center} \
\\begin{figure}[p]\\begin{center}\\includegraphics[%swidth=\\textwidth]{%s}\\label{%s}\\end{center}\\end{figure}"
label
(match page with None -> "" | Some p -> Format.sprintf "page=%d," p)
file label
| A.LawInclude (A.CatalaFile _ | A.LegislativeText _) -> ()
| A.LawText t -> Format.fprintf fmt "%s" (pre_latexify t)
| A.CodeBlock (_, c, false) ->
Format.fprintf fmt
"\\begin{minted}[label={\\hspace*{\\fill}\\texttt{%s}},firstnumber=%d]{%s}\n\
```catala%s```\n\
\\end{minted}"
(pre_latexify (Filename.basename (Pos.get_file (Pos.get_position c))))
(Pos.get_start_line (Pos.get_position c) - 1)
(get_language_extension language)
(math_syms_replace (Pos.unmark c))
| A.CodeBlock (_, c, true) ->
2021-05-10 00:06:59 +03:00
let metadata_title =
match language with Fr -> "Métadonnées" | En -> "Metadata" | Pl -> "Metadane"
2021-05-10 00:06:59 +03:00
in
Format.fprintf fmt
2020-04-10 13:02:05 +03:00
"\\begin{tcolorbox}[colframe=OliveGreen, breakable, \
2020-05-17 19:51:00 +03:00
title=\\textcolor{black}{\\texttt{%s}},title after \
break=\\textcolor{black}{\\texttt{%s}},before skip=1em, after skip=1em]\n\
\\begin{minted}[numbersep=9mm, firstnumber=%d, label={\\hspace*{\\fill}\\texttt{%s}}]{%s}\n\
2021-03-10 17:58:01 +03:00
```catala%s```\n\
\\end{minted}\n\
2020-04-10 13:02:05 +03:00
\\end{tcolorbox}"
2020-05-17 19:51:00 +03:00
metadata_title metadata_title
2020-12-17 22:09:33 +03:00
(Pos.get_start_line (Pos.get_position c) - 1)
(pre_latexify (Filename.basename (Pos.get_file (Pos.get_position c))))
(get_language_extension language)
(math_syms_replace (Pos.unmark c))
2020-12-14 20:09:38 +03:00
(** {1 API} *)
let ast_to_latex (language : C.backend_lang) (fmt : Format.formatter) (program : A.program) : unit =
Format.pp_print_list
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n\n")
(law_structure_to_latex language) fmt program.program_items