2022-03-09 12:43:17 +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-08 02:21:55 +03:00
|
|
|
|
|
2022-03-09 12:43:17 +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-08 02:21:55 +03:00
|
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
2022-03-09 12:43:17 +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
|
2020-03-08 02:21:55 +03:00
|
|
|
|
the License. *)
|
|
|
|
|
|
2022-03-09 12:43:17 +03:00
|
|
|
|
(** This modules weaves the source code and the legislative text together into a
|
|
|
|
|
document that law professionals can understand. *)
|
2020-03-08 02:21:55 +03:00
|
|
|
|
|
2022-11-21 12:46:17 +03:00
|
|
|
|
open Catala_utils
|
2021-05-26 22:39:40 +03:00
|
|
|
|
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} *)
|
|
|
|
|
|
2022-08-26 13:00:25 +03:00
|
|
|
|
let lines_of_code = ref 0
|
|
|
|
|
|
|
|
|
|
let update_lines_of_code c =
|
|
|
|
|
lines_of_code :=
|
|
|
|
|
!lines_of_code
|
|
|
|
|
+ Pos.get_end_line (Marked.get_mark c)
|
|
|
|
|
- Pos.get_start_line (Marked.get_mark c)
|
|
|
|
|
- 1
|
|
|
|
|
|
2020-12-14 20:09:38 +03:00
|
|
|
|
(** Espaces various LaTeX-sensitive characters *)
|
2021-12-31 22:17:55 +03:00
|
|
|
|
let pre_latexify (s : string) : string =
|
2022-04-30 00:47:02 +03:00
|
|
|
|
(* Then we send to pandoc, to ensure the markdown features used in the
|
|
|
|
|
original document are correctly printed! *)
|
2022-05-26 20:05:06 +03:00
|
|
|
|
String.trim (run_pandoc s `Latex)
|
2020-03-08 02:21:55 +03:00
|
|
|
|
|
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. *)
|
2022-03-09 12:43:17 +03:00
|
|
|
|
let wrap_latex
|
|
|
|
|
(source_files : string list)
|
|
|
|
|
(language : C.backend_lang)
|
|
|
|
|
(fmt : Format.formatter)
|
2021-03-02 20:27:39 +03:00
|
|
|
|
(wrapped : Format.formatter -> unit) =
|
2022-05-05 11:37:51 +03:00
|
|
|
|
Format.fprintf fmt
|
2022-05-18 16:32:13 +03:00
|
|
|
|
{latex|\documentclass[%s, 11pt, a4paper]{article}
|
|
|
|
|
|
2022-05-26 20:05:06 +03:00
|
|
|
|
\usepackage[T1]{fontenc}
|
|
|
|
|
\usepackage[utf8]{inputenc}
|
|
|
|
|
\usepackage{amssymb}
|
|
|
|
|
\usepackage{babel}
|
|
|
|
|
\usepackage{fontspec}
|
|
|
|
|
\usepackage[hidelinks]{hyperref}
|
|
|
|
|
%s
|
2023-03-13 20:33:15 +03:00
|
|
|
|
\usepackage{fancyvrb}
|
|
|
|
|
\usepackage{color}
|
2022-05-26 20:05:06 +03:00
|
|
|
|
\usepackage{longtable}
|
2023-01-10 12:49:03 +03:00
|
|
|
|
\usepackage{booktabs,tabularx}
|
2022-05-26 20:05:06 +03:00
|
|
|
|
\usepackage{newunicodechar}
|
|
|
|
|
\usepackage{textcomp}
|
|
|
|
|
\usepackage[hidelinks]{hyperref}
|
|
|
|
|
\usepackage[dvipsnames]{xcolor}
|
|
|
|
|
\usepackage[left=2cm,right=2cm,top=3cm,bottom=3cm,headheight=2cm]{geometry}
|
|
|
|
|
\usepackage[many]{tcolorbox}
|
2022-05-18 16:32:13 +03:00
|
|
|
|
|
2022-05-26 20:05:06 +03:00
|
|
|
|
\usepackage{fancyhdr}
|
|
|
|
|
\pagestyle{fancy}
|
|
|
|
|
\fancyhf{}
|
|
|
|
|
\fancyhead[C]{\leftmark}
|
|
|
|
|
\fancyfoot[C]{\thepage}
|
|
|
|
|
\renewcommand{\headrulewidth}{0.5pt}
|
|
|
|
|
\renewcommand{\footrulewidth}{0.5pt}
|
|
|
|
|
\usepackage{titlesec}
|
|
|
|
|
\titleclass{\subsubsubsection}{straight}[\subsection]
|
|
|
|
|
\newcounter{subsubsubsection}[subsubsection]
|
|
|
|
|
\renewcommand\thesubsubsubsection{\thesubsubsection.\arabic{subsubsubsection}}
|
|
|
|
|
\titleformat{\subsubsubsection}{\normalfont\normalsize\bfseries}{\thesubsubsubsection}{1em}{}
|
|
|
|
|
\titlespacing*{\subsubsubsection}{0pt}{3.25ex plus 1ex minus .2ex}{1.5ex plus .2ex}
|
|
|
|
|
\titleclass{\subsubsubsubsection}{straight}[\subsubsection]
|
|
|
|
|
\newcounter{subsubsubsubsection}[subsubsubsection]
|
|
|
|
|
\renewcommand\thesubsubsubsubsection{\thesubsubsubsection.\arabic{subsubsubsubsection}}
|
|
|
|
|
\titleformat{\subsubsubsubsection}{\normalfont\normalsize\bfseries}{\thesubsubsubsubsection}{0.75em}{}
|
|
|
|
|
\titlespacing*{\subsubsubsubsection}{0pt}{2.75ex plus 1ex minus .2ex}{1.25ex plus .2ex}
|
|
|
|
|
\titleclass{\subsubsubsubsubsection}{straight}[\subsubsubsection]
|
|
|
|
|
\newcounter{subsubsubsubsubsection}[subsubsubsubsection]
|
|
|
|
|
\renewcommand\thesubsubsubsubsubsection{\thesubsubsubsubsection.\arabic{subsubsubsubsubsection}}
|
|
|
|
|
\titleformat{\subsubsubsubsubsection}{\normalfont\normalsize\bfseries}{\thesubsubsubsubsubsection}{0.7em}{}
|
|
|
|
|
\titlespacing*{\subsubsubsubsubsection}{0pt}{2.5ex plus 1ex minus .2ex}{1.1ex plus .2ex}
|
|
|
|
|
\titleclass{\subsubsubsubsubsubsection}{straight}[\subsubsubsubsection]
|
|
|
|
|
\newcounter{subsubsubsubsubsubsection}[subsubsubsubsubsection]
|
|
|
|
|
\renewcommand\thesubsubsubsubsubsubsection{\thesubsubsubsubsubsection.\arabic{subsubsubsubsubsubsection}}
|
|
|
|
|
\titleformat{\subsubsubsubsubsubsection}{\normalfont\normalsize\bfseries}{\thesubsubsubsubsubsubsection}{0.6em}{}
|
|
|
|
|
\titlespacing*{\subsubsubsubsubsubsection}{0pt}{2.25ex plus 1ex minus .2ex}{1ex plus .2ex}
|
|
|
|
|
\makeatletter
|
|
|
|
|
\def\toclevel@subsubsubsection{4}
|
|
|
|
|
\def\toclevel@subsubsubsubsection{5}
|
|
|
|
|
\def\toclevel@subsubsubsubsubsection{6}
|
|
|
|
|
\def\toclevel@subsubsubsubsubsubsection{7}
|
|
|
|
|
\def\toclevel@paragraph{8}
|
|
|
|
|
\def\toclevel@subparagraph{9}
|
|
|
|
|
\def\l@subsection{\@dottedtocline{1}{1em}{0.5em}}
|
|
|
|
|
\def\l@subsubsection{\@dottedtocline{2}{2em}{1em}}
|
|
|
|
|
\def\l@subsubsubsection{\@dottedtocline{3}{3em}{1.5em}}
|
|
|
|
|
\def\l@subsubsubsubsection{\@dottedtocline{5}{4em}{2em}}
|
|
|
|
|
\def\l@subsubsubsubsubsection{\@dottedtocline{6}{5em}{2.5em}}
|
|
|
|
|
\def\l@subsubsubsubsubsubsection{\@dottedtocline{7}{6em}{3em}}
|
|
|
|
|
\def\l@paragraph{\@dottedtocline{8}{7em}{3.5em}}
|
|
|
|
|
\def\l@subparagraph{\@dottedtocline{9}{8em}{4em}}
|
|
|
|
|
\makeatother
|
|
|
|
|
\setcounter{secnumdepth}{0}
|
|
|
|
|
\setcounter{tocdepth}{9}
|
|
|
|
|
\newunicodechar{÷}{$\div$}
|
|
|
|
|
\newunicodechar{×}{$\times$}
|
|
|
|
|
\newunicodechar{≤}{$\leqslant$}
|
|
|
|
|
\newunicodechar{≥}{$\geqslant$}
|
|
|
|
|
\newunicodechar{→}{$\rightarrow$}
|
|
|
|
|
\newunicodechar{≠}{$\neq$}
|
2022-05-18 16:32:13 +03:00
|
|
|
|
|
2023-03-13 20:33:15 +03:00
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
\newcommand*\FancyVerbStartString{\PY{l+s}{```catala}}
|
|
|
|
|
\newcommand*\FancyVerbStopString{\PY{l+s}{```}}
|
2022-05-18 16:32:13 +03:00
|
|
|
|
|
2022-05-26 20:05:06 +03:00
|
|
|
|
\fvset{
|
|
|
|
|
numbers=left,
|
|
|
|
|
frame=lines,
|
|
|
|
|
framesep=3mm,
|
|
|
|
|
rulecolor=\color{gray!70},
|
|
|
|
|
firstnumber=last,
|
|
|
|
|
codes={\catcode`\$=3\catcode`\^=7}
|
|
|
|
|
}
|
|
|
|
|
\newcommand{\tightlist}{\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
|
2022-05-18 16:32:13 +03:00
|
|
|
|
|
2022-05-26 20:05:06 +03:00
|
|
|
|
\title{
|
|
|
|
|
%s\\
|
|
|
|
|
%s Catala version %s
|
|
|
|
|
}
|
|
|
|
|
\begin{document}
|
|
|
|
|
\maketitle
|
2022-05-18 16:32:13 +03:00
|
|
|
|
|
2022-05-26 20:05:06 +03:00
|
|
|
|
%s
|
2022-05-18 16:32:13 +03:00
|
|
|
|
|
2022-05-26 20:05:06 +03:00
|
|
|
|
%s :
|
|
|
|
|
\begin{itemize}%s\end{itemize}
|
2022-05-18 16:32:13 +03:00
|
|
|
|
|
2022-05-26 20:05:06 +03:00
|
|
|
|
\clearpage
|
|
|
|
|
\tableofcontents
|
2022-05-18 16:32:13 +03:00
|
|
|
|
|
2022-05-26 20:05:06 +03:00
|
|
|
|
\[\star\star\star\]
|
2023-01-04 18:29:21 +03:00
|
|
|
|
\clearpage
|
|
|
|
|
|latex}
|
2022-05-05 11:37:51 +03:00
|
|
|
|
(match language with Fr -> "french" | En -> "english" | Pl -> "polish")
|
2022-05-05 15:00:24 +03:00
|
|
|
|
(match language with Fr -> "\\setmainfont{Marianne}" | _ -> "")
|
|
|
|
|
(* for France, we use the official font of the French state design system
|
|
|
|
|
https://gouvfr.atlassian.net/wiki/spaces/DB/pages/223019527/Typographie+-+Typography *)
|
2023-03-13 20:33:15 +03:00
|
|
|
|
(call_pygmentize ["-f"; "latex"; "-S"; "default"])
|
2022-05-05 11:37:51 +03:00
|
|
|
|
(literal_title language)
|
|
|
|
|
(literal_generated_by language)
|
2022-11-21 12:46:17 +03:00
|
|
|
|
Cli.version
|
2022-05-05 15:00:24 +03:00
|
|
|
|
(pre_latexify (literal_disclaimer_and_link language))
|
2022-05-05 11:37:51 +03:00
|
|
|
|
(literal_source_files language)
|
|
|
|
|
(String.concat
|
2022-05-26 20:05:06 +03:00
|
|
|
|
((match language with Fr -> " ;" | En -> ";" | Pl -> ";") ^ "\n")
|
2022-05-05 11:37:51 +03:00
|
|
|
|
(List.map
|
|
|
|
|
(fun filename ->
|
|
|
|
|
let mtime = (Unix.stat filename).Unix.st_mtime in
|
|
|
|
|
let ltime = Unix.localtime mtime in
|
|
|
|
|
let ftime =
|
|
|
|
|
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
|
|
|
|
|
in
|
|
|
|
|
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-04-17 13:29:30 +03:00
|
|
|
|
|
2020-12-14 20:09:38 +03:00
|
|
|
|
(** {1 Weaving} *)
|
|
|
|
|
|
2023-03-13 16:44:34 +03:00
|
|
|
|
let code_block ~meta lang fmt (code, pos) =
|
2023-03-13 20:33:15 +03:00
|
|
|
|
(* Pygments does'nt allow to specify multiple 'verboptions' (escaping bug ?)
|
|
|
|
|
so we call it with "nowrap" and write the FancyVrb wrapper ourselves. *)
|
|
|
|
|
let pygmentized_code =
|
|
|
|
|
let contents = String.concat "" ["```catala\n"; code; "```"] in
|
|
|
|
|
File.with_temp_file "catala_latex_pygments" "in" ~contents
|
|
|
|
|
@@ fun temp_file_in ->
|
2023-03-21 18:10:00 +03:00
|
|
|
|
call_pygmentize ~lang ["-f"; "latex"; "-O"; "nowrap=True"; temp_file_in]
|
2023-03-13 20:33:15 +03:00
|
|
|
|
in
|
2023-03-13 16:44:34 +03:00
|
|
|
|
Format.fprintf fmt
|
2023-03-13 20:33:15 +03:00
|
|
|
|
{latex|\begin{Verbatim}[commandchars=\\\{\},numbers=left,firstnumber=%d,stepnumber=1,label={\hspace*{\fill}\texttt{%s}}%s]|latex}
|
2023-03-13 16:44:34 +03:00
|
|
|
|
(Pos.get_start_line pos + 1)
|
2023-03-13 20:33:15 +03:00
|
|
|
|
(pre_latexify (Filename.basename (Pos.get_file pos)))
|
|
|
|
|
(if meta then ",numbersep=9mm" else "");
|
|
|
|
|
Format.pp_print_newline fmt ();
|
|
|
|
|
Format.pp_print_string fmt pygmentized_code;
|
|
|
|
|
Format.pp_print_string fmt "\\end{Verbatim}\n"
|
2023-03-13 16:44:34 +03:00
|
|
|
|
|
2022-03-09 12:43:17 +03:00
|
|
|
|
let rec law_structure_to_latex
|
|
|
|
|
(language : C.backend_lang)
|
2022-05-26 20:05:06 +03:00
|
|
|
|
(print_only_law : bool)
|
2022-03-09 12:43:17 +03:00
|
|
|
|
(fmt : Format.formatter)
|
|
|
|
|
(i : A.law_structure) : unit =
|
2020-10-04 02:25:37 +03:00
|
|
|
|
match i with
|
|
|
|
|
| A.LawHeading (heading, children) ->
|
2022-04-28 14:32:35 +03:00
|
|
|
|
Format.fprintf fmt "\\%s{%s}\n\n"
|
2020-10-04 02:25:37 +03:00
|
|
|
|
(match heading.law_heading_precedence with
|
2021-11-26 20:07:14 +03:00
|
|
|
|
| 0 -> "section"
|
|
|
|
|
| 1 -> "subsection"
|
|
|
|
|
| 2 -> "subsubsection"
|
2022-04-29 11:25:46 +03:00
|
|
|
|
| 3 -> "subsubsubsection"
|
2022-04-29 11:50:15 +03:00
|
|
|
|
| 4 -> "subsubsubsubsection"
|
|
|
|
|
| 5 -> "subsubsubsubsubsection"
|
|
|
|
|
| 6 -> "subsubsubsubsubsubsection"
|
|
|
|
|
| 7 -> "paragraph"
|
2021-05-15 02:16:08 +03:00
|
|
|
|
| _ -> "subparagraph")
|
2022-05-30 12:20:48 +03:00
|
|
|
|
(pre_latexify (Marked.unmark heading.law_heading_name));
|
2020-10-04 02:25:37 +03:00
|
|
|
|
Format.pp_print_list
|
|
|
|
|
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n\n")
|
2022-05-26 20:05:06 +03:00
|
|
|
|
(law_structure_to_latex language print_only_law)
|
2022-03-09 12:43:17 +03:00
|
|
|
|
fmt children
|
2020-12-11 23:17:01 +03:00
|
|
|
|
| A.LawInclude (A.PdfFile ((file, _), page)) ->
|
2022-03-09 12:43:17 +03:00
|
|
|
|
let label =
|
|
|
|
|
file
|
|
|
|
|
^ match page with None -> "" | Some p -> Format.sprintf "_page_%d," p
|
|
|
|
|
in
|
2020-12-11 23:17:01 +03:00
|
|
|
|
Format.fprintf fmt
|
2022-03-09 12:43:17 +03:00
|
|
|
|
"\\begin{center}\\textit{Annexe incluse, retranscrite page \
|
|
|
|
|
\\pageref{%s}}\\end{center} \
|
2020-12-11 23:17:01 +03:00
|
|
|
|
\\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 _) -> ()
|
2022-01-19 16:43:42 +03:00
|
|
|
|
| A.LawText t -> Format.fprintf fmt "%s" (pre_latexify t)
|
2022-05-26 20:05:06 +03:00
|
|
|
|
| A.CodeBlock (_, c, false) when not print_only_law ->
|
2022-08-26 13:00:25 +03:00
|
|
|
|
let start_line = Pos.get_start_line (Marked.get_mark c) - 1 in
|
2023-03-21 13:24:19 +03:00
|
|
|
|
let filename = Pos.get_file (Marked.get_mark c) in
|
2022-08-26 13:00:25 +03:00
|
|
|
|
let block_content = Marked.unmark c in
|
|
|
|
|
check_exceeding_lines start_line filename block_content;
|
|
|
|
|
update_lines_of_code c;
|
2023-03-13 16:44:34 +03:00
|
|
|
|
code_block ~meta:false language fmt c
|
2022-05-26 20:05:06 +03:00
|
|
|
|
| A.CodeBlock (_, c, true) when not print_only_law ->
|
2021-05-10 00:06:59 +03:00
|
|
|
|
let metadata_title =
|
2022-03-09 12:43:17 +03:00
|
|
|
|
match language with
|
|
|
|
|
| Fr -> "Métadonnées"
|
|
|
|
|
| En -> "Metadata"
|
|
|
|
|
| Pl -> "Metadane"
|
2021-05-10 00:06:59 +03:00
|
|
|
|
in
|
2022-11-24 17:17:00 +03:00
|
|
|
|
let start_line = Pos.get_start_line (Marked.get_mark c) + 1 in
|
2023-03-21 13:24:19 +03:00
|
|
|
|
let filename = Pos.get_file (Marked.get_mark c) in
|
2022-05-30 12:20:48 +03:00
|
|
|
|
let block_content = Marked.unmark c in
|
2022-05-01 17:53:04 +03:00
|
|
|
|
check_exceeding_lines start_line filename block_content;
|
2022-08-26 13:00:25 +03:00
|
|
|
|
update_lines_of_code c;
|
2020-10-04 02:25:37 +03:00
|
|
|
|
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 \
|
2022-03-09 12:43:17 +03:00
|
|
|
|
break=\\textcolor{black}{\\texttt{%s}},before skip=1em, after skip=1em]\n\
|
2023-03-13 16:44:34 +03:00
|
|
|
|
%a\n\
|
2020-04-10 13:02:05 +03:00
|
|
|
|
\\end{tcolorbox}"
|
2023-03-13 16:44:34 +03:00
|
|
|
|
metadata_title metadata_title
|
|
|
|
|
(code_block ~meta:true language)
|
|
|
|
|
c
|
2022-05-26 20:05:06 +03:00
|
|
|
|
| A.CodeBlock _ -> ()
|
2020-03-08 02:21:55 +03:00
|
|
|
|
|
2020-12-14 20:09:38 +03:00
|
|
|
|
(** {1 API} *)
|
|
|
|
|
|
2022-03-09 12:43:17 +03:00
|
|
|
|
let ast_to_latex
|
|
|
|
|
(language : C.backend_lang)
|
2022-05-26 20:05:06 +03:00
|
|
|
|
~(print_only_law : bool)
|
2022-03-09 12:43:17 +03:00
|
|
|
|
(fmt : Format.formatter)
|
|
|
|
|
(program : A.program) : unit =
|
2020-10-04 02:25:37 +03:00
|
|
|
|
Format.pp_print_list
|
|
|
|
|
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n\n")
|
2022-05-26 20:05:06 +03:00
|
|
|
|
(law_structure_to_latex language print_only_law)
|
2022-08-26 13:00:25 +03:00
|
|
|
|
fmt program.program_items;
|
|
|
|
|
Cli.debug_print "Lines of Catala inside literate source code: %d"
|
|
|
|
|
!lines_of_code
|