% \iffalse -*- coding: utf-8 ; -*- \fi % \iffalse meta-comment % % Copyright (C) 2022-2024 by F. Pantigny % ----------------------------------- % % This file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in: % % http://www.latex-project.org/lppl.txt % % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % \fi % \iffalse % %<*batchfile> \begingroup \input l3docstrip.tex \endgroup % % %<@@=piton> %<*driver> \documentclass{l3doc} \usepackage{geometry} \geometry{left=2.8cm,right=2.8cm,top=2.5cm,bottom=2.5cm,papersize={21cm,29.7cm}} \usepackage{fontspec} \usepackage[dvipsnames,svgnames]{xcolor} \usepackage{caption,tabularx,tcolorbox,luacolor,lua-ul,upquote} \def\emphase{\bgroup\color{RoyalPurple}\let\next=} \fvset{commandchars=\~\#\@,formatcom=\color{gray}} \captionsetup{labelfont = bf} \usepackage{ragged2e} \usepackage[footnotehyper]{piton} \PitonOptions { splittable = 4 , math-comments, begin-escape = ! , end-escape = ! , begin-escape-math = \( , end-escape-math = \) , detected-commands = highLight } \parindent 0pt \skip\footins = 2\bigskipamount \def\CC{{C\nolinebreak[4]\hspace{-.05em}\raisebox{.4ex}{\tiny\bfseries ++}}} \usepackage{makeidx} \makeindex \NewDocumentCommand{\indexcommand}{m}{\index{#1@\texttt{\textbackslash #1}}} \NewDocumentCommand{\indexenv}{m}{\index{#1@\texttt{\{#1\}}}} \PitonOptions{gobble=2} \EnableCrossrefs \begin{document} \DocInput{piton.dtx} \end{document} % % \fi % \iffalse %<*STY> % \fi \def\PitonFileVersion{2.6} \def\PitonFileDate{2024/02/27} % \iffalse % %<*LUA> -- Version 2.6 of 2024/02/27 % %\fi % % \catcode`\" = 11 % % \title{The package \pkg{piton}\thanks{This document corresponds to the % version~\PitonFileVersion\space of \pkg{piton}, at the date of~\PitonFileDate.}} % \author{F. Pantigny \\ \texttt{fpantigny@wanadoo.fr}} % % \maketitle % % \begin{abstract} % The package \pkg{piton} provides tools to typeset computer listings in Python, % OCaml, C and SQL with syntactic highlighting by using the Lua library LPEG. It % requires LuaLaTeX. % \end{abstract} % % % % \section{Presentation} % % % The package \pkg{piton} uses the Lua library LPEG\footnote{LPEG is a % pattern-matching library for Lua, written in C, based on \emph{parsing % expression grammars}: % \url{http://www.inf.puc-rio.br/~roberto/lpeg/}} for parsing Python, OCaml, C % or SQL listings and typesets them with syntactic highlighting. Since it uses % the Lua of LuaLaTeX, it works with |lualatex| only (and won't work with the % other engines: |latex|, |pdflatex| and |xelatex|). It does not use external % program and the compilation does not require |--shell-escape|. The compilation % is very fast since all the parsing is done by the library LPEG, written in C. % % \bigskip % Here is an example of code typeset by \pkg{piton}, with the environment |{Piton}|. % % \bigskip % % \begin{Piton} % from math import pi % % def arctan(x,n=10): % """Compute the mathematical value of arctan(x) % % n is the number of terms in the sum % """ % if x < 0: % return -arctan(-x) # recursive call % elif x > 1: % return pi/2 - arctan(1/x) % #> (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ for $x>0$)\footnote{This LaTeX escape has been done by beginning the comment by \ttfamily\#>.} % else: % s = 0 % for k in range(n): % s += (-1)**k/(2*k+1)*x**(2*k+1) % return s % \end{Piton} % % % \section{Installation} % % The package \pkg{piton} is contained in two files: |piton.sty| and |piton.lua| % (the LaTeX file |piton.sty| loaded by |\usepackage| will load the Lua file % |piton.lua|). Both files must be in a repertory where LaTeX will be able to % find them, for instance in a |texmf| tree. However, the best is to install % \pkg{piton} with a TeX distribution such as MiKTeX, TeX Live or MacTeX. % % \section{Use of the package} % % \subsection{Loading the package} % % The package \pkg{piton} should be loaded with the classical command % |\usepackage|: |\usepackage{piton}|. % % \smallskip % Nevertheless, we have two remarks: % \begin{itemize} % \item the package \pkg{piton} uses the package \pkg{xcolor} (but \pkg{piton} % does \emph{not} load \pkg{xcolor}: if \pkg{xcolor} is not loaded before the % |\begin{document}|, a fatal error will be raised). % \item the package \pkg{piton} must be used with LuaLaTeX exclusively: if % another LaTeX engine (|latex|, |pdflatex|, |xelatex|,\dots ) is used, a % fatal error will be raised. % \end{itemize} % % \subsection{Choice of the computer language} % % In current version, the package \pkg{piton} supports four computer languages: % Python, OCaml, SQL and C (in fact \CC). It supports also a special language % called ``|minimal|'': cf. p.~\pageref{minimal}. % % \smallskip % By default, the language used is Python. % % \smallskip % \index{language (key)} % It's possible to change the current language with the command |\PitonOptions| % and its key |language|: |\PitonOptions{language = C}|. % % \smallskip % For the developpers, let's say that the name of the current language is stored % (in lower case) in the L3 public variable |\l_piton_language_str|. % % \smallskip % In what follows, we will speak of Python, but the features described also % apply to the other languages. % % \subsection{The tools provided to the user} % % \indexenv{Piton} % % The package \pkg{piton} provides several tools to typeset Python code: the % command |\piton|, the environment |{Piton}| and the command |\PitonInputFile|. % % \begin{itemize}\setlength{\fboxsep}{1pt} % \item The command \colorbox{gray!20}{\texttt\textbackslash piton} should be % used to typeset small pieces of code inside a paragraph. For example: % % {\color{gray}\verb|\piton{def square(x): return x*x}|}\qquad % \piton{def square(x): return x*x} % % The syntax and particularities of the command |\piton| are detailed below. % % \item The environment \colorbox{gray!20}{\ttfamily\{Piton\}} should be used to % typeset multi-lines code. Since it takes its argument in a verbatim mode, it % can't be used within the argument of a LaTeX command. For sake of % customization, it's possible to define new environments similar to the % environment |{Piton}| with the command |\NewPitonEnvironment|: % cf.~\ref{NewPitonEnvironment} p.~\pageref{NewPitonEnvironment}. % % \item The command \colorbox{gray!20}{\ttfamily\textbackslash PitonInputFile} % is used to insert and typeset a external file. % % It's possible to insert only a part of the file: cf. % part~\ref{part-of-a-file}, p.~\pageref{part-of-a-file}. % % The key |path| of the command |\PitonOptions| specifies a path where the files % included by |\PitonInputFile| will be searched. % \end{itemize} % % \subsection{The syntax of the command \textbackslash piton} % % \indexcommand{piton} % % In fact, the command |\piton| is provided with a double syntax. It may be used % as a standard command of LaTeX taking its argument between curly braces % (|\piton{...}|) but it may also be used with a syntax similar to the syntax of % the command % |\verb|, that is to say with the argument delimited by two identical characters (e.g.: \verb!\piton|...|!). % % \begin{itemize} % \item {\color{blue} \textsf{Syntax} \verb|\piton{...}|}\par\nobreak % When its argument is given between curly braces, the command |\piton| does not % take its argument in verbatim mode. In particular: % \begin{itemize} % \item several consecutive spaces will be replaced by only one space (and the % also the character of end on line), % % {\color{cyan} but the command |\|␣ is provided to force the insertion of a space}; % % \item it's not possible to use |%| inside the argument, % % {\color{cyan} but the command |\%| is provided to insert a |%|}; % % \item the braces must be appear by pairs correctly nested % % {\color{cyan} but the commands |\{| and |\}| are also provided for individual braces}; % % \item the LaTeX commands\footnote{That concerns the commands beginning with a % backslash but also the active characters (with catcode equal to 13).} are % fully expanded and not executed, % % {\color{cyan} so it's possible to use |\\| to insert a backslash}. % \end{itemize} % % % The other characters (including |#|, |^|, |_|, |&|, |$| and |@|) % must be inserted without backslash. % % \bigskip %\begin{tabular}{>{\color{gray}}w{l}{75mm}@{\hspace*{1cm}}l} % \omit Examples : \hfil \\ % \noalign{\vskip1mm} % \verb|\piton{MyString = '\\n'}| & % \piton{MyString = '\\n'} \\ % \verb|\piton{def even(n): return n\%2==0}| & % \piton{def even(n): return n\%2==0} \\ % \verb|\piton{c="#" # an affectation }| & % \piton{c="#" # an affectation } \\ % \verb|\piton{c="#" \ \ \ # an affectation }| & % \piton{c="#" \ \ \ # an affectation } \\ % \verb|\piton{MyDict = {'a': 3, 'b': 4 }}| & % \piton{MyDict = {'a': 3, 'b': 4 }} % \end{tabular} % % \bigskip % It's possible to use the command |\piton| in the arguments of a % LaTeX command.\footnote{For example, it's possible to use the command % \texttt{\textbackslash piton} in a footnote. Example : % \piton{s = 'A string'}.} % % \bigskip % \item {\color{blue} \textsf{Syntaxe} \verb!\piton|...|!}\par\nobreak % % When the argument of the command |\piton| is provided between two identical % characters, that argument is taken in a \emph{verbatim mode}. Therefore, with % that syntax, the command |\piton| can't be used within the argument of another % command. % % \medskip % % \begin{tabular}{>{\color{gray}}w{l}{75mm}@{\hspace*{1cm}}l} % \omit Examples : \hfil \\ % \noalign{\vskip1mm} % \verb!\piton|MyString = '\n'|! & % \piton|MyString = '\n'| \\ % \verb|\piton!def even(n): return n%2==0!| & % \piton!def even(n): return n%2==0! \\ % \verb|\piton+c="#" # an affectation +| & % \piton+c="#" # an affectation + \\ % \verb|\piton?MyDict = {'a': 3, 'b': 4}?| & % \piton!MyDict = {'a': 3, 'b': 4}! % \end{tabular} % % \end{itemize} % % \section{Customization} % % With regard to the font used by \pkg{piton} in its listings, it's only the % current monospaced font. The package \pkg{piton} merely uses internally the % standard LaTeX command |\texttt|. % % \subsection{The keys of the command \textbackslash PitonOptions} % % % \NewDocumentCommand{\Definition}{m} % {{\setlength{\fboxsep}{1pt}\colorbox{gray!20}{\ttfamily \vphantom{gl}#1}}} % % \indexcommand{PitonOptions} % % The command |\PitonOptions| takes in as argument a comma-separated list of % \textsl{key=value} pairs. The scope of the settings done by that command is % the current TeX group.\footnote{We remind that a LaTeX environment is, in % particular, a TeX group.} % % These keys may also be applied to an individual environment |{Piton}| (between % square brackets). % % \begin{itemize} % \item The key \Definition{language} speficies which computer language is % considered (that key is case-insensitive). Five values are allowed : % |Python|, |OCaml|, |C|, |SQL| and |minimal|. The initial value is |Python|. % % \item \index{path} The key \Definition{path} specifies a path where the files % included by |\PitonInputFile| will be searched. % % \item \index{gobble}\label{gobble} The key \Definition{gobble} takes in as % value a positive integer~$n$: the first $n$ characters are discarded (before % the process of highlightning of the code) for each line of the environment % |{Piton}|. These characters are not necessarily spaces. % % \item \index{auto-gobble}\index{gobble!auto-gobble} When the key % \Definition{auto-gobble} is in force, the extension \pkg{piton} computes the % minimal value $n$ of the number of consecutive spaces beginning each (non % empty) line of the environment |{Piton}| and applies |gobble| with that value % of~$n$. % % \item \index{env-gobble}\index{gobble!env-gobble} % When the key \Definition{env-gobble} is in force, \pkg{piton} analyzes the last % line of the environment |{Piton}|, that is to say the line which contains % |\end{Piton}| and determines whether that line contains only spaces followed % by the |\end{Piton}|. If we are in that situation, \pkg{piton} computes the % number~$n$ of spaces on that line and applies |gobble| with that value of~$n$. % The name of that key comes from \emph{environment gobble}: the effect of % gobble is set by the position of the commands |\begin{Piton}| and % |\end{Piton}| which delimit the current environment. % % \item \index{write} The key \Definition{write} takes in as argument a name of % file (with its extension) and write the content\footnote{In fact, it's not % exactly the body of the environment but the value of |piton.get_last_code()| % which is the body without the overwritten LaTeX formatting instructions (cf. % the part~\ref{API}, p.~\pageref{API}).} of the current environment in % that file. At the first use of a file by \pkg{piton}, it is erased. % % \item \index{path-write}\colorbox{yellow!50}{\bfseries New 2.5}\enskip The key % \Definition{path-write} specifies a path where the files written by the key % |write| will be written. % % \item \index{line-numbers} The key \Definition{line-numbers} activates the % line numbering in the environments |{Piton}| and in the listings resulting % from the use of |\PitonInputFile|. % % In fact, the key |line-numbers| has several subkeys. % \begin{itemize} % \item With the key \Definition{line-numbers/skip-empty-lines}, the empty lines % are considered as non existent for the line numbering (if the key |/absolute| % is in force, the key |/skip-empty-lines| is no-op in |\PitonInputFile|). The % initial value of that key is |true| (and not |false|).\footnote{For the % language Python, the empty lines in the docstrings are taken into account (by % design).} % \item With the key \Definition{line-numbers/label-empty-lines}, the labels % (that is to say the numbers) of the empty lines are displayed. If the key % |/skip-empty-line| is in force, the clé |/label-empty-lines| is no-op. The % initial value of that key is~|true|. % \item With the key \Definition{line-numbers/absolute}, in the listings % generated in |\PitonInputFile|, the numbers of the lines displayed are % \emph{absolute} (that is to say: they are the numbers of the lines in the % file). That key may be useful when |\PitonInputFile| is used to insert only a % part of the file (cf. part~\ref{part-of-a-file}, p.~\pageref{part-of-a-file}). % The key |/absolute| is no-op in the environments |{Piton}| and those created % by |\NewPitonEnvironment|. % \item The key \Definition{line-numbers/start} requires that the line numbering % begins to the value of the key. % \item With the key \Definition{line-numbers/resume}, the counter of lines is % not set to zero at the beginning of each environment |{Piton}| or use of % |\PitonInputFile| as it is otherwise. That allows a numbering of the lines % across several environments. % \item The key \Definition{line-numbers/sep} is the horizontal distance between % the numbers of lines (inserted by |line-numbers|) and the beginning of the % lines of code. The initial value is 0.7~em. % \end{itemize} % % For convenience, a mechanism of factorisation of the prefix |line-numbers| is % provided. That means that it is possible, for instance, to write: % \begin{Verbatim} % \PitonOptions % { % line-numbers = % { % skip-empty-lines = false , % label-empty-lines = false , % sep = 1 em % } % } % \end{Verbatim} % % % \item \index{left-margin} The key \Definition{left-margin} corresponds to a % margin on the left. That key may be useful in conjonction with the key % |line-numbers| if one does not want the numbers in an overlapping position on % the left. % % It's possible to use the key |left-margin| with the value |auto|. With that % value, if the key |line-numbers| is in force, a margin will be automatically % inserted to fit the numbers of lines. See an example part % \ref{example-numbering} on page~\pageref{example-numbering}. % % \item \index{background-color} The key \Definition{background-color} sets the % background color of the environments |{Piton}| and the listings produced by % |\PitonInputFile| (it's possible to fix the width of that background with the % key |width| described below). % % \smallskip % The key |background-color| supports also as value a \emph{list} of colors. In % this case, the successive rows are colored by using the colors of the list in % a cyclic way. % % \emph{Example} : |\PitonOptions{background-color = {gray!5,white}}| % % The key |background-color| accepts a color defined «on the fly». For example, % it's possible to write |background-color = [cmyk]{0.1,0.05,0,0}|. % % \item \index{prompt-background-color} With the key % \Definition{prompt-background-color}, \pkg{piton} adds a % color background to the lines beginning with the prompt ``|>>>|'' (and its % continuation ``|...|'') characteristic of the Python consoles with % \textsc{repl} (\emph{read-eval-print loop}). % % \item \index{width} The key \Definition{width} will fix the width of the % listing. That width applies to the colored backgrounds specified by % |background-color| and |prompt-background-color| but also for the automatic % breaking of the lines (when required by |break-lines|: cf.~\ref{line-breaks}, % p.~\pageref{line-breaks}). % % That key may take in as value a numeric value but also the special % value~|min|. With that value, the width will be computed from the maximal % width of the lines of code. Caution: the special value~|min| requires two % compilations with LuaLaTeX\footnote{The maximal width is computed during the % first compilation, written on the |aux| file and re-used during the second % compilation. Several tools such as |latexmk| (used by Overleaf) do % automatically a sufficient number of compilations.}. % % For an example of use of |width=min|, see the section~\ref{example-comments}, % p.~\pageref{example-comments}. % % % \item \index{show-spaces-in-strings} When the key % \Definition{show-spaces-in-strings} is activated, the spaces in the % strings of characters\footnote{With the language Python that feature applies % only to the short strings (delimited by~\verb|'| or~\verb|"|). In OCaml, that % feature does not apply to the \emph{quoted strings}.} are replaced by the % character~␣ (U+2423 : \textsc{open box}). Of course, that character~U+2423 % must be present in the monospaced font which is used.\footnote{The package % \pkg{piton} simply uses the current monospaced font. The best way to change % that font is to use the command \texttt{\textbackslash setmonofont} of the % package \pkg{fontspec}.}\par\nobreak \begingroup % \PitonOptions{show-spaces-in-strings} Example : % \piton|my_string = 'Very good answer'| \endgroup % % With the key \index{show-spaces} \Definition{show-spaces}, all the spaces are % replaced by U+2423 (and no line break can occur on those ``visible spaces'', % even when the key |break-lines|\footnote{cf. \ref{line-breaks} % p.~\pageref{line-breaks}} is in force). % \end{itemize} % % \bigskip % \begingroup % \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} % \begin{Verbatim} % ~emphase&\begin{Piton}[language=C,line-numbers,auto-gobble,background-color = gray!15]@ % void bubbleSort(int arr[], int n) { % int temp; % int swapped; % for (int i = 0; i < n-1; i++) { % swapped = 0; % for (int j = 0; j < n - i - 1; j++) { % if (arr[j] > arr[j + 1]) { % temp = arr[j]; % arr[j] = arr[j + 1]; % arr[j + 1] = temp; % swapped = 1; % } % } % if (!swapped) break; % } % } % \end{Piton} % \end{Verbatim} % \endgroup % % \begingroup % \PitonOptions{language=C,line-numbers,gobble=6,background-color = gray!15} % \begin{Piton} % void bubbleSort(int arr[], int n) { % int temp; % int swapped; % for (int i = 0; i < n-1; i++) { % swapped = 0; % for (int j = 0; j < n - i - 1; j++) { % if (arr[j] > arr[j + 1]) { % temp = arr[j]; % arr[j] = arr[j + 1]; % arr[j + 1] = temp; % swapped = 1; % } % } % if (!swapped) break; % } % } % \end{Piton} % \endgroup % % % \bigskip % The command |\PitonOptions| provides in fact several other keys which will be % described further (see in particular the ``Pages breaks and line breaks'' % p.~\pageref{breakable}). % % \subsection{The styles} % % \label{styles} % % \subsubsection{Notion of style} % % The package \pkg{piton} provides the command |\SetPitonStyle| to customize the % different styles used to format the syntactic elements of the Python listings. % The customizations done by that command are limited to the current TeX % group.\footnote{We remind that a LaTeX environment is, in particular, a TeX group.} % % \bigskip % \indexcommand{SetPitonStyle} % The command |\SetPitonStyle| takes in as argument a comma-separated list of % \textsl{key=value} pairs. The keys are names of styles and the value are LaTeX % formatting instructions. % % \bigskip % These LaTeX instructions must be formatting instructions such as % |\color{...}|, |\bfseries|, |\slshape|, etc. (the commands of this kind are % sometimes called \emph{semi-global} commands). It's also possible to put, % \emph{at the end of the list of instructions}, a LaTeX command taking exactly % one argument. % % \bigskip % Here an example which changes the style used to highlight, in the definition % of a Python function, the name of the function which is defined. That code % uses the command |\highLight| of \pkg{lua-ul} (that package requires also the % package \pkg{luacolor}). % % \begin{verbatim} % \SetPitonStyle{ Name.Function = \bfseries \highLight[red!50] } % \end{verbatim} % % In that example, |\highLight[red!50]| must be considered as the name of a % LaTeX command which takes in exactly one argument, since, usually, it is used % with |\highLight[red!50]{...}|. % % \medskip % \begingroup % \SetPitonStyle % { Name.Function = \bfseries \highLight[red!50] } % With that setting, we will have : \piton{def cube(x) : return x * x * x } % \endgroup % % \bigskip % The different styles, and their use by \pkg{piton} in the different languages % which it supports (Python, OCaml, C, SQL and ``|minimal|''), are described in % the part \ref{Semantic}, starting at the page \pageref{Semantic}. % % % \bigskip % \indexcommand{PitonStyle} % The command |\PitonStyle| takes in as argument the name of a style and allows % to retrieve the value (as a list of LaTeX instructions) of that style. % % \smallskip % For example, it's possible to write |{\PitonStyle{Keyword}{function}}| and we % will have the word {\PitonStyle{Keyword}{function}} formatted as a keyword. % % \smallskip % The syntax |{\PitonStyle{|\textsl{\texttt{style}}|}{...}}| is mandatory in % order to be able to deal both with the semi-global commands and the commands % with arguments which may be present in the definition of the style % \texttt{\textsl{style}}. % % \bigskip % \subsubsection{Global styles and local styles} % % A style may be defined globally with the command |\SetPitonStyle|. That means % that it will apply to all the informatic languages that use that style. % % \bigskip % For example, with the command % \begin{Verbatim} % \SetPitonStyle{Comment = \color{gray}} % \end{Verbatim} % all the comments will be composed in gray in all the listings, whatever % informatic language they use (Python, C, OCaml, etc.). % % \bigskip % But it's also possible to define a style locally for a given informatic % langage by providing the name of that language as optional argument (between % square brackets) to the command |\SetPitonStyle|.\footnote{We recall, that, in % the package \pkg{piton}, the names of the informatic languages are % case-insensitive.} % % \bigskip % For example, with the command % \begin{Verbatim} % \SetPitonStyle~emphase#[SQL]@{Keywords = \color[HTML]{006699} \bfseries \MakeUppercase} % \end{Verbatim} % the keywords in the SQL listings will be composed in capital letters, even if % they appear in lower case in the LaTeX source (we recall that, in SQL, the % keywords are case-insensitive). % % \bigskip % As expected, if an informatic language uses a given style and if that style has % no local definition for that language, the global version is used. That notion % of ``global style'' has no link with the notion of global definition in TeX % (the notion of \emph{group} in TeX).\footnote{As regards the TeX groups, the % definitions done by \texttt{\textbackslash SetPitonStyle} are always local.} % % \bigskip % The package \pkg{piton} itself (that is to say the file |piton.sty|) defines % all the styles globally. % % \bigskip % % \subsubsection{The style UserFunction} % % \index{UserFunction (style)} % % The extension \pkg{piton} provides a special style called~|UserFunction|. That % style applies to the names of the functions previously defined by the user % (for example, in Python, these names are those following the keyword % \piton{def} in a previous Python listing). The initial value of that style is % empty, and, therefore, the names of the functions are formatted as standard % text (in black). However, it's possible to change the value of that style, as % any other style, with the command |\SetPitonStyle|. % % \medskip % In the following example, we fix as value for that style |UserFunction| the % initial value of the style |Name.Function| (which applies to the name of % the functions, \emph{at the moment of their definition}). % % \begingroup % % \begin{Verbatim} % \SetPitonStyle{~emphase#UserFunction@ = \color[HTML]{CC00FF}} % \end{Verbatim} % % \SetPitonStyle{UserFunction = \color[HTML]{CC00FF}} % % \begin{Piton} % def transpose(v,i,j): % x = v[i] % v[i] = v[j] % v[j] = x % % def passe(v): % for in in range(0,len(v)-1): % if v[i] > v[i+1]: % transpose(v,i,i+1) % \end{Piton} % % \endgroup % % As one see, the name |transpose| has been highlighted because it's the name of % a Python function previously defined by the user (hence the name % |UserFunction| for that style). % % \PitonClearUserFunctions[Python] % % \bigskip % \begin{small} % Of course, the list of the names of Python functions previously défined is % kept in the memory of LuaLaTeX (in a global way, that is to say independently % of the TeX groups). The extension \pkg{piton} provides a command to clear that % list : it's the command |\PitonClearUserFunctions|. When it is used without % argument, that command is applied to all the informatic languages used by the % user but it's also possible to use it with an optional argument (between % square brackets) which is a list of informatic languages to which the command % will be applied.\footnote{We remind that, in \pkg{piton}, the name of the % informatic languages are case-insensitive.} % \end{small} % % \subsection{Creation of new environments} % % \label{NewPitonEnvironment} % \indexcommand{NewPitonEnvironment} % % Since the environment |{Piton}| has to catch its body in a special way (more % or less as verbatim text), it's not possible to construct new environments % directly over the environment |{Piton}| with the classical commands % |\newenvironment| (of standard LaTeX) or |\NewDocumentEnvironment| (of % LaTeX3). % % That's why \pkg{piton} provides a command |\NewPitonEnvironment|. That % command takes in three mandatory arguments. % That command has the same syntax as the classical environment % |\NewDocumentEnvironment|.\footnote{However, the specifier of argument |b| % (used to catch the body of the environment as a LaTeX argument) is % not allowed.} % % % \bigskip % With the following instruction, a new environment |{Python}| will be % constructed with the same behaviour as |{Piton}|: % % {\color{gray}\verb|\NewPitonEnvironment{Python}{O{}}{\PitonOptions{#1}}{}|} % % \bigskip % If one wishes to format Python code in a box of \pkg{tcolorbox}, it's possible % to define an environment |{Python}| with the following code (of course, the % package \pkg{tcolorbox} must be loaded). % %\begin{verbatim} % \NewPitonEnvironment{Python}{} % {\begin{tcolorbox}} % {\end{tcolorbox}} % \end{verbatim} % % \bigskip % With this new environment |{Python}|, it's possible to write: % % \begin{Verbatim} % ~emphase#\begin{Python}@ % def square(x): % """Compute the square of a number""" % return x*x % ~emphase#\end{Python}@ % \end{Verbatim} % % \NewPitonEnvironment{Python}{} % {\begin{tcolorbox}} % {\end{tcolorbox}} % % \begin{Python} % def square(x): % """Compute the square of a number""" % return x*x % \end{Python} % % % \section{Advanced features} % % \subsection{Page breaks and line breaks} % % \label{breakable} % % \subsubsection{Page breaks} % \index{splittable} % % By default, the listings produced by the environment |{Piton}| and the command % |\PitonInputFile| are not breakable. % % However, the command |\PitonOptions| provides the key \Definition{splittable} % to allow such breaks. % % \begin{itemize} % \item If the key |splittable| is used without any value, the % listings are breakable everywhere. % \item If the key |splittable| is used with a numeric value~$n$ (which must be % a non-negative integer number), the listings are breakable but no break will % occur within the first $n$ lines and within the last $n$ lines. Therefore, % |splittable=1| is equivalent to |splittable|. % \end{itemize} % % \medskip % Even with a background color (set by the key |background-color|), the pages % breaks are allowed, as soon as the key |splittable| is in force.\footnote{With % the key |splittable|, the environments \texttt{\{Piton\}} are breakable, even % within a (breakable) environment of \pkg{tcolorbox}. Remind that an % environment of \pkg{tcolorbox} included in another environment of % \pkg{tcolorbox} is \emph{not} breakable, even when both environments use the % key |breakable| of \pkg{tcolorbox}.} % % \subsubsection{Line breaks} % % \label{line-breaks} % % By default, the elements produced by \pkg{piton} can't be broken by an end on % line. However, there are keys to allow such breaks (the possible breaking % points are the spaces, even the spaces in the Python strings). % \begin{itemize} % \item \index{break-lines!break-lines-in-piton} With the key % \Definition{break-lines-in-piton}, the line breaks are allowed in the command % |\piton{...}| (but not in the command \verb+\piton|...|+, that is to say the % command |\piton| in verbatim mode). % \item \index{break-lines!break-lines-in-Piton} With the key % \Definition{break-lines-in-Piton}, the line breaks are allowed in the % environment |{Piton}| (hence the capital letter |P| in the name) and in the % listings produced by |\PitonInputFile|. % \item \index{break-lines} The key \Definition{break-lines} is a conjonction of % the two previous keys. % \end{itemize} % % \bigskip % The package \pkg{piton} provides also several keys to control the appearance % on the line breaks allowed by |break-lines-in-Piton|. % % \begin{itemize} % \item \index{indent-broken-lines} With the key % \Definition{indent-broken-lines}, the indentation of a % broken line is respected at carriage return. % % \item The key \Definition{end-of-broken-line} corresponds to the symbol placed % at the end of a broken line. The initial value is: % |\hspace*{0.5em}\textbackslash|. % % \item \index{continuation-symbol} The key \Definition{continuation-symbol} % corresponds to the symbol placed at each carriage return. The initial value % is: |+\;| (the command |\;| inserts a small horizontal space). % % \item \index{continuation-symbol-on-indentation} % The key \Definition{continuation-symbol-on-indentation} corresponds to % the symbol placed at each carriage return, on the position of the indentation % (only when the key |indent-broken-line| is in force). The initial value is: % |$\hookrightarrow\;$|. % \end{itemize} % % % \bigskip % The following code has been composed with the following tuning: % % \begin{Verbatim} % \PitonOptions{width=12cm,break-lines,indent-broken-lines,background-color=gray!15} % \end{Verbatim} % % \begin{center} % \PitonOptions{width=12cm,break-lines,indent-broken-lines,background-color=gray!15} % \begin{Piton} % def dict_of_list(l): % """Converts a list of subrs and descriptions of glyphs in a dictionary""" % our_dict = {} % for list_letter in l: % if (list_letter[0][0:3] == 'dup'): # if it's a subr % name = list_letter[0][4:-3] % print("We treat the subr of number " + name) % else: % name = list_letter[0][1:-3] # if it's a glyph % print("We treat the glyph of number " + name) % our_dict[name] = [treat_Postscript_line(k) for k in list_letter[1:-1]] % return dict % \end{Piton} % \end{center} % % % \bigskip % \subsection{Insertion of a part of a file} % % \label{part-of-a-file} % \indexcommand{PitonInputFile} % % The command |\PitonInputFile| inserts (with formating) the content of a file. % In fact, it's possible to insert only \emph{a part} of that file. Two % mechanisms are provided in this aim. % \begin{itemize} % \item It's possible to specify the part that we want to insert by the numbers % of the lines (in the original file). % \item It's also possible to specify the part to insert with textual markers. % \end{itemize} % In both cases, if we want to number the lines with the numbers of the % lines in the file, we have to use the key |line-numbers/absolute|. % % \subsubsection{With line numbers} % % The command |\PitonInputFile| supports the keys \Definition{first-line} and % \Definition{last-line} in order to insert only the part of file between the % corresponding lines. Not to be confused with the key |line-numbers/start| % which fixes the first line number for the line numbering. In a sens, % |line-numbers/start| deals with the output whereas |first-line| and % |last-line| deal with the input. % % \subsubsection{With textual markers} % % \index{marker/beginning} % \index{marker/end} % % In order to use that feature, we first have to specify the format of the % markers (for the beginning and the end of the part to include) with the keys % \Definition{marker-beginning} and \Definition{marker-end} (usually with the % command |\PitonOptions|). % % % \medskip % Let us take a practical example. % % \medskip % We assume that the file to include contains solutions to exercises of % programmation on the following model. % % \begin{Verbatim}[formatcom=\small\color{gray}] % ~#[Exercise 1] Iterative version % def fibo(n): % if n==0: return 0 % else: % u=0 % v=1 % for i in range(n-1): % w = u+v % u = v % v = w % return v % ~# % \end{Verbatim} % % The markers of the beginning and the end are the strings |#[Exercise 1]| and % |#|. The string ``|Exercise 1|'' will be called the \emph{label} % of the exercise (or of the part of the file to be included). % % In order to specify such markers in \pkg{piton}, we will use the keys % |marker/beginning| and |marker/end| with the following instruction (the % character |#| of the comments of Python must be inserted with the protected % form |\#|). % % \begin{Verbatim} % \PitonOptions{ ~emphase#marker/beginning@ = \~#[~#1] , ~emphase#marker/end@ = \~#<~#1> } % \end{Verbatim} % % As one can see, |marker/beginning| is an expression corresponding to the % mathematical function which transforms the label (here |Exercise 1|) into the % the beginning marker (in the example |#[Exercise 1]|). The string |#1| % corresponds to the occurrences of the argument of that function, which the % classical syntax in TeX. Idem for |marker/end|. % % \bigskip % Now, you only have to use the key \Definition{range} of |\PitonInputFile| to % insert a marked content of the file. % % \smallskip % \begin{Verbatim} % \PitonInputFile[~emphase#range = Exercise 1@]{~textsl#file_name@} % \end{Verbatim} % % \medskip % \begin{Piton} % def fibo(n): % if n==0: return 0 % else: % u=0 % v=1 % for i in range(n-1): % w = u+v % u = v % v = w % return v % \end{Piton} % % \vspace{1cm} % \index{marker/include-line} % The key \Definition{marker/include-line} requires the insertion of the lines % containing the markers. % % \begin{Verbatim} % \PitonInputFile[~emphase#marker/include-lines@,range = Exercise 1]{~textsl#file_name@} % \end{Verbatim} % % \begin{Piton} % #[Exercise 1] Iterative version % def fibo(n): % if n==0: return 0 % else: % u=0 % v=1 % for i in range(n-1): % w = u+v % u = v % v = w % return v % # % \end{Piton} % % % \bigskip % \index{begin-range} % \index{end-range} % In fact, there exist also the keys \Definition{begin-range} and % \Definition{end-range} to insert several marked contents at the same time. % % For example, in order to insert the solutions of the exercises~3 to~5, we will % write (if the file has the correct structure!): % % % \begin{Verbatim} % \PitonInputFile[~emphase#begin-range = Exercise 3, end-range = Exercise 5@]{~textsl#file_name@} % \end{Verbatim} % % % % \subsection{Highlighting some identifiers} % % \label{SetPitonIdentifier} % % \colorbox{yellow!50}{\bfseries Modification 2.4}\par\nobreak % % \smallskip % The command |\SetPitonIdentifier| allows to change the formatting of some % identifiers. % % \smallskip % That command takes in three arguments: % % \begin{itemize} % \item The optionnal argument (within square brackets) specifies the informatic % langage. If this argument is not present, the tunings done by % |\SetPitonIdentifier| will apply to all the informatic langages of % \pkg{piton}.\footnote{We recall, that, in the package \pkg{piton}, the % names of the informatic languages are case-insensitive.} % % \item The first mandatory argument is a comma-separated list of names of % identifiers. % % \item The second mandatory argument is a list of LaTeX instructions of the % same type as \pkg{piton} ``styles'' previously presented (cf~\ref{styles} % p.~\pageref{styles}). % \end{itemize} % % \emph{Caution}: Only the identifiers may be concerned by that key. The % keywords and the built-in functions won't be affected, even if their name % appear in the first argument of the command |\SetPitonIdentifier|. % % \begin{Verbatim} % ~emphase#\SetPitonIdentifier{l1,l2}{\color{red}}@ % \begin{Piton} % def tri(l): % """Segmentation sort""" % if len(l) <= 1: % return l % else: % a = l[0] % l1 = [ x for x in l[1:] if x < a ] % l2 = [ x for x in l[1:] if x >= a ] % return tri(l1) + [a] + tri(l2) % \end{Piton} % \end{Verbatim} % % % \bigskip % % \begingroup % % \SetPitonIdentifier{l1,l2}{\color{red}} % % \begin{Piton} % def tri(l): % """Segmentation sort""" % if len(l) <= 1: % return l % else: % a = l[0] % l1 = [ x for x in l[1:] if x < a ] % l2 = [ x for x in l[1:] if x >= a ] % return tri(l1) + [a] + tri(l2) % \end{Piton} % % \endgroup % % \bigskip % By using the command |\SetPitonIdentifier|, it's possible to add other % built-in functions (or other new keywords, etc.) that will be detected by % \pkg{piton}. % % % \begin{Verbatim} % ~emphase#\SetPitonIdentifier[Python]@ % {cos, sin, tan, floor, ceil, trunc, pow, exp, ln, factorial} % {\PitonStyle{Name.Builtin}} % % \begin{Piton} % from math import * % cos(pi/2) % factorial(5) % ceil(-2.3) % floor(5.4) % \end{Piton} % \end{Verbatim} % % \begingroup % % \SetPitonIdentifier[Python] % {cos, sin, tan, floor, ceil, trunc, pow, exp, ln, factorial} % {\PitonStyle{Name.Builtin}} % % \begin{Piton} % from math import * % cos(pi/2) % factorial(5) % ceil(-2.3) % floor(5.4) % \end{Piton} % % % \endgroup % % % \subsection{Mechanisms to escape to LaTeX} % % \index{escapes to LaTeX} % % The package \pkg{piton} provides several mechanisms for escaping to LaTeX: % \begin{itemize} % \item It's possible to compose comments entirely in LaTeX. % \item It's possible to have the elements between \texttt{\$} in the comments % composed in LateX mathematical mode. % \item It's possible to ask \pkg{piton} to detect automatically some LaTeX % commands, thanks to the key |detected-commands|. % \item It's also possible to insert LaTeX code almost everywhere in a Python listing. % \end{itemize} % % One should aslo remark that, when the extension \pkg{piton} is used with the % class \cls{beamer}, \pkg{piton} detects in |{Piton}| many commands and % environments of Beamer: cf. \ref{beamer} p.~\pageref{beamer}. % % \subsubsection{The ``LaTeX comments''} % % \index{comment-latex} % % In this document, we call ``LaTeX comments'' the comments which begins by % |#>|. The code following those characters, until the end of the line, will be % composed as standard LaTeX code. There is two tools to customize those % comments. % % \begin{itemize} % \item It's possible to change the syntatic mark (which, by default, is |#>|). % For this purpose, there is a key |comment-latex| available only in the % preamble of the document, allows to choice the characters which, % preceded by |#|, will be the syntatic marker. % % For example, if the preamble contains the following instruction: % % \quad \verb|\PitonOptions{comment-latex = LaTeX}| % % the LaTeX comments will begin by |#LaTeX|. % % If the key |comment-latex| is used with the empty value, all the Python % comments (which begins by |#|) will, in fact, be ``LaTeX comments''. % % \smallskip % \item It's possible to change the formatting of the LaTeX comment itself by % changing the \pkg{piton} style |Comment.LaTeX|. % % For example, with |\SetPitonStyle{Comment.LaTeX = \normalfont\color{blue}}|, % the LaTeX comments will be composed in blue. % % If you want to have a character |#| at the beginning of the LaTeX comment in % the \textsc{pdf}, you can use set |Comment.LaTeX| as follows: % % \begin{Verbatim} % \SetPitonStyle{Comment.LaTeX = \color{gray}\~#\normalfont\space } % \end{Verbatim} % % For other examples of customization of the LaTeX comments, see the part % \ref{example-comments} p.~\pageref{example-comments} % \end{itemize} % % \bigskip % If the user has required line numbers (with the key |line-numbers|), it's % possible to refer to a number of line with the command |\label| used in a % LaTeX comment.\footnote{That feature is implemented by using a redefinition of % the standard command \texttt{\textbackslash label} in the environments % \texttt{\{Piton\}}. Therefore, incompatibilities may occur with extensions % which redefine (globally) that command \texttt{\textbackslash label} (for % example: \pkg{varioref}, \pkg{refcheck}, \pkg{showlabels}, etc.)} % % \subsubsection{The key ``math-comments''} % % \index{math-comments} % % It's possible to request that, in the standard Python comments (that is to say % those beginning by |#| and not |#>|), the elements between \texttt{\$} be % composed in LaTeX mathematical mode (the other elements of the comment being % composed verbatim). % % That feature is activated by the key \Definition{math-comments}, \emph{which is % available only in the preamble of the document}. % % \medskip % Here is a example, where we have assumed that the preamble of the document % contains the instruction |\PitonOptions{math-comment}|: % % \begin{Verbatim} % \begin{Piton} % def square(x): % return x*x ~# compute $x^2$ % \end{Piton} % \end{Verbatim} % % \begin{Piton} % def square(x): % return x*x # compute $x^2$ % \end{Piton} % % \subsubsection{The key ``detected-commands''} % % \index{detected-commands (key)} % \label{detected-commands} % % The key |detected-commands| of |\PitonOptions| allow to specify a % (comma-separated) list of names of LaTeX commands that will be detected % directly by \pkg{piton}. % % \begin{itemize} % \item The key |detected-commands| must be used in the preamble of the LaTeX document. % % \item The names of the LaTeX commands must appear without the leading % backslash (eg. |detected-commands = { emph, textbf }|). % % \item These commands must be LaTeX commands with only one (mandatory) argument % between braces (and these braces must be explicit). % \end{itemize} % % \medskip % We assume that the preamble of the LaTeX document contains the following line. % \begin{Verbatim} % \PitonOptions{~emphase#detected-commands@ = highLight} % \end{Verbatim} % % Then, it's possible to write directly: % \begin{Verbatim} % \begin{Piton} % def fact(n): % if n==0: % return 1 % else: % ~emphase#\highLight@{return n*fact(n-1)} % \end{Piton} % \end{Verbatim} % % \begin{Piton} % def fact(n): % if n==0: % return 1 % else: % \highLight{return n*fact(n-1)} % \end{Piton} % % % \subsubsection{The mechanism ``escape''} % % \label{escape} % % It's also possible to overwrite the Python listings to insert LaTeX code % almost everywhere (but between lexical units, of course). By default, % \pkg{piton} does not fix any delimiters for that kind of escape. % % In order to use this mechanism, it's necessary to specify the delimiters which % will delimit the escape (one for the beginning and one for the end) by using % the keys \Definition{begin-escape} and \Definition{end-escape}, \emph{available only % in the preamble of the document}. % % \medskip % We consider once again the previous example of a recursive programmation of % the factorial. We want to highlight in pink the instruction containing the % recursive call. With the package \pkg{lua-ul}, we can use the syntax % |\highLight[LightPink]{...}|. Because of the optional argument between square % brackets, it's not possible to use the key |detected-commands| but it's % possible to acheive our goal with the more general mechanism ``escape''. % % \medskip % We assume that the preamble of the document contains % the following instruction: % % \begin{Verbatim} % \PitonOptions{~emphase#begin-escape=!,end-escape=!@} % \end{Verbatim} % % \medskip % Then, it's possible to write: % \begin{Verbatim} % \begin{Piton} % def fact(n): % if n==0: % return 1 % else: % ~emphase#!\highLight[LightPink]{!@return n*fact(n-1)~emphase#!}!@ % \end{Piton} % \end{Verbatim} % % \begin{Piton} % def fact(n): % if n==0: % return 1 % else: % !\highLight[LightPink]{!return n*fact(n-1)!}! % \end{Piton} % % % % \bigskip % \emph{Caution} : The escape to LaTeX allowed by the |begin-escape| and % |end-escape| is not active in the strings nor in the Python comments (however, % it's possible to have a whole Python comment composed in LaTeX by beginning it % with |#>|; such comments are merely called ``LaTeX comments'' in this % document). % % % \subsubsection{The mechanism ``escape-math''} % % The mechanism ``|escape-math|'' is very similar to the mechanism ``|escape|'' % since the only difference is that the elements sent to LaTeX are composed in % the math mode of LaTeX. % % This mechanism is activated with the keys \Definition{begin-escape-math} and % \Definition{end-escape-math} (\emph{which are available only in the preamble of the % document}). % % Despite the technical similarity, the use of the the mechanism % ``|escape-math|'' is in fact rather different from that of the mechanism % ``|escape|''. Indeed, since the elements are composed in a mathématical mode % of LaTeX, they are, in particular, composed within a TeX group and therefore, % they can't be used to change the formatting of other lexical units. % % In the langages where the character \verb|$| does not play a important role, % it's possible to activate that mechanism ``|escape-math|'' with the character % \verb|$|: % \begin{Verbatim} % \PitonOptions{~emphase#begin-escape-math=$,end-escape-math=$@} % \end{Verbatim} % Remark that the character \verb|$| must \emph{not} be protected by a backslash. % % \bigskip % However, it's probably more prudent to use |\(| et |\)|. % \begin{Verbatim} % \PitonOptions{~emphase#begin-escape-math=\(,end-escape-math=\)@} % \end{Verbatim} % % \bigskip % Here is an example of utilisation. % % \medskip % \begin{Verbatim} % \begin{Piton}[line-numbers] % def arctan(x,n=10): % if ~emphase#\(x < 0\)@ : % return ~emphase#\(-\arctan(-x)\)@ % elif ~emphase#\(x > 1\)@ : % return ~emphase#\(\pi/2 - \arctan(1/x)\)@ % else: % s = ~emphase#\(0\)@ % for ~emphase#\(k\)@ in range(~emphase#\(n\)@): s += ~emphase#\(\smash{\frac{(-1)^k}{2k+1} x^{2k+1}}\)@ % return s % \end{Piton} % \end{Verbatim} % % % \bigskip % % \begin{Piton}[line-numbers] % def arctan(x,n=10): % if \(x < 0\) : % return \(-\arctan(-x)\) % elif \(x > 1\) : % return \(\pi/2 - \arctan(1/x)\) % else: % s = \(0\) % for \(k\) in range(\(n\)): s += \(\smash{\frac{(-1)^k}{2k+1} x^{2k+1}}\) % return s % \end{Piton} % % % \subsection{Behaviour in the class Beamer} % % \label{beamer} % \index{Beamer@\cls{Beamer} (class)} % % \emph{First remark}\par\nobreak % Since the environment |{Piton}| catches its body with a verbatim mode, it's % necessary to use the environments |{Piton}| within environments |{frame}| of % Beamer protected by the key |fragile|, i.e. beginning with % |\begin{frame}[fragile]|.\footnote{Remind that for an environment % \texttt{\{frame\}} of Beamer using the key |fragile|, the instruction % \texttt{\textbackslash end\{frame\}} must be alone on a single line (except % for any leading whitespace).} % % % \bigskip % When the package \pkg{piton} is used within the class % \cls{beamer}\footnote{The extension \pkg{piton} detects the class \cls{beamer} % and the package \pkg{beamerarticle} if it is loaded previously % but, if needed, it's also possible to activate that mechanism with the key % |beamer| provided by \pkg{piton} at load-time: |\textbackslash % usepackage[beamer]\{piton\}|}, the behaviour of \pkg{piton} is slightly % modified, as described now. % % \subsubsection{\{Piton\} et \textbackslash PitonInputFile are % ``overlay-aware''} % % When \pkg{piton} is used in the class \cls{beamer}, the environment |{Piton}| % and the command |\PitonInputFile| accept the optional argument |<...>| of % Beamer for the overlays which are involved. % % For example, it's possible to write: % % \begin{Verbatim} % \begin{Piton}~emphase#<2-5>@ % ... % \end{Piton} % \end{Verbatim} % % and % % \begin{Verbatim} % \PitonInputFile~emphase#<2-5>@{my_file.py} % \end{Verbatim} % % \subsubsection{Commands of Beamer allowed in \{Piton\} and \textbackslash PitonInputFile} % % When \pkg{piton} is used in the class \cls{beamer} , the following commands of % \cls{beamer} (classified upon their number of arguments) are automatically % detected in the environments |{Piton}| (and in the listings processed by % |\PitonInputFile|): % \begin{itemize} % \item no mandatory argument : |\pause|\footnote{One should remark that it's % also possible to use the command \texttt{\textbackslash pause} in a ``LaTeX % comment'', that is to say by writing \texttt{\#> \textbackslash pause}. By % this way, if the Python code is copied, it's still executable by Python}. ; % \item one mandatory argument : |\action|, |\alert|, |\invisible|, |\only|, |\uncover| and |\visible| ; % \item two mandatory arguments : |\alt| ; % \item three mandatory arguments : |\temporal|. % \end{itemize} % \medskip % In the mandatory arguments of these commands, the braces must be balanced. % However, the braces included in short strings\footnote{The short strings of % Python are the strings delimited by characters \texttt{'} or the characters % \texttt{"} and not \texttt{'''} nor \texttt{"""}. In Python, the short strings % can't extend on several lines.} of Python are not considered. % % \medskip % Regarding the fonctions |\alt| and |\temporal| there should be no carriage % returns in the mandatory arguments of these functions. % % \medskip % Here is a complete example of file: % % \begin{Verbatim}[formatcom = \small\color{gray}] % \documentclass{beamer} % \usepackage{piton} % \begin{document} % \begin{frame}[fragile] % \begin{Piton} % def string_of_list(l): % """Convert a list of numbers in string""" % ~emphase# \only<2->{s = "{" + str(l[0])}@ % ~emphase# \only<3->{for x in l[1:]: s = s + "," + str(x)}@ % ~emphase# \only<4->{s = s + "}"}@ % return s % \end{Piton} % \end{frame} % \end{document} % \end{Verbatim} % % In the previous example, the braces in the Python strings |"{"| and |"}"| are % correctly interpreted (without any escape character). % % % % % \bigskip % \subsubsection{Environments of Beamer allowed in \{Piton\} and \textbackslash PitonInputFile} % % When \pkg{piton} is used in the class \pkg{beamer}, the following environments % of Beamer are directly detected in the environments |{Piton}| (and in the % listings processed by |\PitonInputFile|): |{actionenv}|, |{alertenv}|, % |{invisibleenv}|, |{onlyenv}|, |{uncoverenv}| and |{visibleenv}|. % % However, there is a restriction: these environments must contain only \emph{whole % lines of Python code} in their body. % %\medskip % Here is an example: % % \begin{Verbatim}[formatcom = \small\color{gray}] % \documentclass{beamer} % \usepackage{piton} % \begin{document} % \begin{frame}[fragile] % \begin{Piton} % def square(x): % """Compure the square of its argument""" % ~emphase#\begin{uncoverenv}<2>@ % return x*x % ~emphase#\end{uncoverenv}@ % \end{Piton} % \end{frame} % \end{document} % \end{Verbatim} % % % \vspace{1cm} % \textbf{Remark concerning the command \textbackslash alert and the environment % \{alertenv\} of Beamer}\par\nobreak % % \smallskip % Beamer provides an easy way to change the color used by the environment % |{alertenv}| (and by the command |\alert| which relies upon it) to highlight % its argument. Here is an example: % % \begin{Verbatim} % \setbeamercolor{~emphase#alerted text@}{fg=blue} % \end{Verbatim} % % However, when used inside an environment |{Piton}|, such tuning will probably % not be the best choice because \pkg{piton} will, by design, change (most of % the time) the color the different elements of text. One may prefer an environment % |{alertenv}| that will change the background color for the elements to be % hightlighted. % % \smallskip % Here is a code that will do that job and add a yellow background. That code % uses the command |\@highLight| of \pkg{lua-ul} (that extension requires also % the package \pkg{luacolor}). % % \begingroup % \fvset{commandchars=\~\#\+,formatcom=\color{gray}} % \begin{Verbatim} % \setbeamercolor{alerted text}{bg=yellow!50} % \makeatletter % \AddToHook{env/Piton/begin} % {\renewenvironment<>{alertenv}{\only~#1{~emphase#\@highLight+[alerted text.bg]}}{}} % \makeatother % \end{Verbatim} % \endgroup % % That code redefines locally the environment |{alertenv}| within the % environments |{Piton}| (we recall that the command |\alert| relies upon that % environment |{alertenv}|). % % % \subsection{Footnotes in the environments of piton} % % \index{footnote@\pkg{footnote} (extension)} % \index{footnote (key)} % \index{footnotehyper@\pkg{footnotehyper} (extension)} % \index{footnotehyper (key)} % % \label{footnote} % If you want to put footnotes in an environment |{Piton}| or % (or, more unlikely, in a listing produced by |\PitonInputFile|), you can use a % pair |\footnotemark|--|\footnotetext|. % % \smallskip % However, it's also possible to extract the footnotes with the help of the % package \pkg{footnote} or the package \pkg{footnotehyper}. % % \smallskip % If \pkg{piton} is loaded with the option |footnote| (with % |\usepackage[footnote]{piton}| or with |\PassOptionsToPackage|), the % package \pkg{footnote} is loaded (if it is not yet loaded) and it is used to % extract the footnotes. % % \smallskip % If \pkg{piton} is loaded with the option |footnotehyper|, the package % \pkg{footnotehyper} is loaded (if it is not yet loaded) ant it is used to % extract footnotes. % % \smallskip % Caution: The packages \pkg{footnote} and \pkg{footnotehyper} are incompatible. % The package \pkg{footnotehyper} is the successor of the package \pkg{footnote} % and should be used preferently. The package \pkg{footnote} has some drawbacks, % in particular: it must be loaded after the package \pkg{xcolor} and it is not % perfectly compatible with \pkg{hyperref}. % % \medskip % In this document, the package \pkg{piton} has been loaded with the % option |footnotehyper|. For examples of notes, cf. \ref{notes-examples}, % p.~\pageref{notes-examples}. % % \subsection{Tabulations} % % \index{tabulations} % \index{tab-size} % % \smallskip % Even though it's recommended to indent the Python listings with spaces (see % PEP~8), \pkg{piton} accepts the characters of tabulation (that is to say the % characters U+0009) at the beginning of the lines. Each character U+0009 is % replaced by $n$~spaces. The initial value of $n$ is $4$ but it's possible to % change it with the key |tab-size| of |\PitonOptions|. % % \smallskip % There exists also a key |tabs-auto-gobble| which computes the minimal value % $n$ of the number of consecutive characters U+0009 beginning each (non empty) % line of the environment |{Piton}| and applies |gobble| with that value of~$n$ % (before replacement of the tabulations by spaces, of course). Hence, that key % is similar to the key |auto-gobble| but acts on U+0009 instead of U+0020 % (spaces). % % % \bigskip % \section{API for the developpers} % % \label{API} % % The L3 variable |\l_piton_language_str| contains the name of the current % language of \pkg{piton} (in lower case). % % \bigskip % \colorbox{yellow!50}{\textbf{New 2.6}}\par\nobreak % % The extension \pkg{piton} provides a Lua function |piton.get_last_code| % without argument which returns the code in the latest environment of % \pkg{piton}. % \begin{itemize} % \item The carriage returns (which are present in the initial environment) % appears as characters |\r| (i.e. U+000D). % % \item The code returned by |piton.get_last_code()| takes into account the % potential application of a key |gobble|, |auto-gobble| or |env-gobble| % (cf.~p.~\pageref{gobble}). % % \item The extra formatting elements added in the code are deleted in the code % returned by |piton.get_last_code()|. That concerns the LaTeX commands declared % by the key |detected-commands| (cf. part~\ref{detected-commands}) and the % elements inserted by the mechanism ``|escape|'' (cf. part~\ref{escape}). % % \item |piton.get_last_code| is a Lua function and not a Lua string: the % treatments outlined above are executed when the function is called. Therefore, % it might be judicious to store the value returned by |piton.get_last_code()| % in a variable of Lua if it will be used serveral times. % \end{itemize} % % \medskip % For an example of use, see the part concerning |pyluatex|, part~\ref{pyluatex}, % p.~\pageref{pyluatex}. % % % \section{Examples} % % \subsection{Line numbering} % % \label{example-numbering} % \index{numbers of the lines de code|emph} % % We remind that it's possible to have an automatic numbering of the lines in % the Python listings by using the key |line-numbers|. % % By default, the numbers of the lines are composed by \pkg{piton} in an % overlapping position on the left (by using internally the command |\llap| of LaTeX). % % In order to avoid that overlapping, it's possible to use the option |left-margin=auto| % which will insert automatically a margin adapted to the numbers of lines that % will be written (that margin is larger when the numbers are greater than~10). % % % \begingroup % \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} % \begin{Verbatim} % ~emphase&\PitonOptions{background-color=gray!10, left-margin = auto, line-numbers}@ % \begin{Piton} % def arctan(x,n=10): % if x < 0: % return -arctan(-x) #> (recursive call) % elif x > 1: % return pi/2 - arctan(1/x) #> (other recursive call) % else: % return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) % \end{Piton} % \end{Verbatim} % \endgroup % % % % \begingroup % \PitonOptions{background-color=gray!10,left-margin = auto, line-numbers} % \begin{Piton} % def arctan(x,n=10): % if x < 0: % return -arctan(-x) #> (recursive call) % elif x > 1: % return pi/2 - arctan(1/x) #> (other recursive call) % else: % return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) % \end{Piton} % \endgroup % % % % \bigskip % \subsection{Formatting of the LaTeX comments} % % \label{example-comments} % % It's possible to modify the style |Comment.LaTeX| (with |\SetPitonStyle|) in % order to display the LaTeX comments (which begin with |#>|) aligned on the % right margin. % % % \begingroup % \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} % \begin{Verbatim} % \PitonOptions{background-color=gray!10} % ~emphase&\SetPitonStyle{Comment.LaTeX = \hfill \normalfont\color{gray}}@ % \begin{Piton} % def arctan(x,n=10): % if x < 0: % return -arctan(-x) #> recursive call % elif x > 1: % return pi/2 - arctan(1/x) #> other recursive call % else: % return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) % \end{Piton} % \end{Verbatim} % \endgroup % % \begingroup % \PitonOptions{background-color=gray!10} % \SetPitonStyle{Comment.LaTeX = \hfill \normalfont\color{gray}} % \begin{Piton} % def arctan(x,n=10): % if x < 0: % return -arctan(-x) #> recursive call % elif x > 1: % return pi/2 - arctan(1/x) #> another recursive call % else: % return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) % \end{Piton} % \endgroup % % % \vspace{1cm} % It's also possible to display these LaTeX comments in a kind of second column % by limiting the width of the Python code with the key |width|. In the % following example, we use the key |width| with the special value~|min|. % % % \begingroup % \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} % \begin{Verbatim} % \PitonOptions{background-color=gray!10, width=min} % ~emphase&\NewDocumentCommand{\MyLaTeXCommand}{m}{\hfill \normalfont\itshape\rlap{\quad #1}}@ % ~emphase&\SetPitonStyle{Comment.LaTeX = \MyLaTeXCommand}@ % \begin{Piton} % def arctan(x,n=10): % if x < 0: % return -arctan(-x) #> recursive call % elif x > 1: % return pi/2 - arctan(1/x) #> another recursive call % else: % s = 0 % for k in range(n): % s += (-1)**k/(2*k+1)*x**(2*k+1) % return s % \end{Piton} % \end{Verbatim} % \endgroup % % % % \begingroup % \PitonOptions{background-color=gray!10, width=min} % \NewDocumentCommand{\MyLaTeXCommand}{m}{\hfill \normalfont\itshape\rlap{\quad #1}} % \SetPitonStyle{Comment.LaTeX = \MyLaTeXCommand} % \begin{Piton} % def arctan(x,n=10): % if x < 0: % return -arctan(-x) #> recursive call % elif x > 1: % return pi/2 - arctan(1/x) #> another recursive call % else: % s = 0 % for k in range(n): % s += (-1)**k/(2*k+1)*x**(2*k+1) % return s % \end{Piton} % \endgroup % % % \bigskip % \subsection{Notes in the listings} % % \label{notes-examples} % \index{notes in the listings} % % In order to be able to extract the notes (which are typeset with the command % |\footnote|), the extension \pkg{piton} must be loaded with the key |footnote| % or the key |footenotehyper| as explained in the section \ref{footnote} % p.~\pageref{footnote}. In this document, the extension \pkg{piton} has been % loaded with the key |footnotehyper|. % % Of course, in an environment |{Piton}|, a command |\footnote| may appear only % within a LaTeX comment (which begins with |#>|). It's possible to have comments % which contain only that command |\footnote|. That's the case in the following example. % % % % \begingroup % \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} % \begin{Verbatim} % \PitonOptions{background-color=gray!10} % \begin{Piton} % def arctan(x,n=10): % if x < 0: % return -arctan(-x)~emphase&#>\footnote{First recursive call.}]@ % elif x > 1: % return pi/2 - arctan(1/x)~emphase&#>\footnote{Second recursive call.}@ % else: % return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) % \end{Piton} % \end{Verbatim} % \endgroup % % \begingroup % \PitonOptions{background-color=gray!10} % \begin{Piton} % def arctan(x,n=10): % if x < 0: % return -arctan(-x)#>\footnote{First recursive call.} % elif x > 1: % return pi/2 - arctan(1/x)#>\footnote{Second recursive call.} % else: % return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) % \end{Piton} % \endgroup % % % \vspace{1cm} % % If an environment |{Piton}| is used in an environment |{minipage}| of LaTeX, % the notes are composed, of course, at the foot of the environment % |{minipage}|. Recall that such |{minipage}| can't be broken by a page break. % % % \begingroup % \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} % \begin{Verbatim} % \PitonOptions{background-color=gray!10} % \emphase\begin{minipage}{\linewidth} % \begin{Piton} % def arctan(x,n=10): % if x < 0: % return -arctan(-x)~emphase&#>\footnote{First recursive call.}@ % elif x > 1: % return pi/2 - arctan(1/x)~emphase&#>\footnote{Second recursive call.}@ % else: % return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) % \end{Piton} % \end{minipage} % \end{Verbatim} % \endgroup % % \begingroup % \PitonOptions{background-color=gray!10} % \begin{minipage}{\linewidth} % \begin{Piton} % def arctan(x,n=10): % if x < 0: % return -arctan(-x)#>\footnote{First recursive call.} % elif x > 1: % return pi/2 - arctan(1/x)#>\footnote{Second recursive call.} % else: % return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) % \end{Piton} % \end{minipage} % \endgroup % % % % \bigskip % % \subsection{An example of tuning of the styles} % % The graphical styles have been presented in the section \ref{styles}, % p.~\pageref{styles}. % % \smallskip % We present now an example of tuning of these styles adapted to the documents % in black and white. We use the font \emph{DejaVu Sans Mono}\footnote{See: % \url{https://dejavu-fonts.github.io}} specified by the command |\setmonofont| of % \pkg{fontspec}. % % That tuning uses the command |\highLight| of \pkg{lua-ul} (that package % requires itself the package \pkg{luacolor}). % % \begin{Verbatim} % \setmonofont[Scale=0.85]{DejaVu Sans Mono} % % \SetPitonStyle % { % Number = , % String = \itshape , % String.Doc = \color{gray} \slshape , % Operator = , % Operator.Word = \bfseries , % Name.Builtin = , % Name.Function = \bfseries \highLight[gray!20] , % Comment = \color{gray} , % Comment.LaTeX = \normalfont \color{gray}, % Keyword = \bfseries , % Name.Namespace = , % Name.Class = , % Name.Type = , % InitialValues = \color{gray} % } % \end{Verbatim} % % In that tuning, many values given to the keys are empty: that means that the % corresponding style won't insert any formating instruction (the element will % be composed in the standard color, usually in black, etc.). Nevertheless, % those entries are mandatory because the initial value of those keys in % \pkg{piton} is \emph{not} empty. % % \begingroup % % \setmonofont[Scale=0.85]{DejaVu Sans Mono} % % \PitonOptions{splittable} % % \SetPitonStyle % { % Number = , % String = \itshape , % String.Doc = \color{gray} \slshape , % Operator.Word = \bfseries , % Operator = , % Name.Builtin = , % Name.Function = \bfseries \highLight[gray!20] , % Comment = \color{gray} , % Comment.LaTeX = \normalfont \color{gray} , % Keyword = \bfseries , % Name.Namespace = , % Name.Class = , % Name.Type = , % InitialValues = \color{gray} % } % % % \bigskip % % \begin{Piton} % from math import pi % % def arctan(x,n=10): % """Compute the mathematical value of arctan(x) % % n is the number of terms in the sum % """ % if x < 0: % return -arctan(-x) # recursive call % elif x > 1: % return pi/2 - arctan(1/x) % #> (we have used that $\arctan(x)+\arctan(1/x)=\pi/2$ for $x>0$) % else: % s = 0 % for k in range(n): % s += (-1)**k/(2*k+1)*x**(2*k+1) % return s % \end{Piton} % % \endgroup % % \subsection{Use with pyluatex} % % \index{pyluatex@{\pkg{pyluatex}} (extension)} % \label{pyluatex} % % The package \pkg{pyluatex} is an extension which allows the execution of some % Python code from |lualatex| (provided that Python is installed on the machine % and that the compilation is done with |lualatex| and |--shell-escape|). % % Here is, for example, an environment |{PitonExecute}| which formats a Python % listing (with \pkg{piton}) but also displays the output of the execution of the % code with Python. % % \medskip % \begin{Verbatim} % \NewPitonEnvironment{~emphase#PitonExecute@}{!O{}} % {\PitonOptions{~#1}} % {\begin{center} % \directlua{pyluatex.execute(piton.get_last_code(), false, true, false, true)}% % \end{center} % \ignorespacesafterend} % \end{Verbatim} % % \medskip % We have used the Lua function |piton.get_last_code| provided in the API of % \pkg{piton} : cf.~part~\ref{API}, p.~\pageref{API}. % % \medskip % This environment |{PitonExecute}| takes in as optional argument (between % square brackets) the options of the command |\PitonOptions|. % % % % \clearpage % \section{The styles for the different computer languages} % % \label{Semantic} % % % \subsection{The language Python} % % In \pkg{piton}, the default language is Python. If necessary, it's possible to % come back to the language Python with |\PitonOptions{language=Python}|. % % \bigskip % % The initial settings % done by \pkg{piton} in |piton.sty| are inspired by the style \pkg{manni} de % Pygments, as applied by Pygments to the language Python.\footnote{See: % \url{https://pygments.org/styles/}. Remark that, by default, Pygments provides % for its style \pkg{manni} a colored background whose color is the HTML color % \texttt{\#F0F3F3}. It's possible to have the same color in \texttt{\{Piton\}} % with the instruction \texttt{\textbackslash PitonOptions\{background-color = % [HTML]\{F0F3F3\}\}}.} % % \vspace{1cm} % % \begin{center} % \begin{tabularx}{0.9\textwidth}{@{}>{\ttfamily}l>{\raggedright\arraybackslash}X@{}} % \toprule % \normalfont Style & Use \\ % \midrule % Number & the numbers \\ % String.Short & the short strings (entre \texttt{'} ou \texttt{"}) \\ % String.Long & the long strings (entre \texttt{'''} ou \texttt{"""}) excepted % the doc-strings (governed by |String.Doc|)\\ % String & that key fixes both |String.Short| et |String.Long| \\ % String.Doc & the doc-strings (only with |"""| following PEP~257) \\ % String.Interpol & the syntactic elements of the fields of the f-strings % (that is to say the characters \texttt{\{} et \texttt{\}}); that style % inherits for the styles |String.Short| and |String.Long| (according the kind % of string where the interpolation appears) \\ % Interpol.Inside & the content of the interpolations in the f-strings (that % is to say the elements between \texttt{\{} and~\texttt{\}}); if the final % user has not set that key, those elements will be formatted by \pkg{piton} % as done for any Python code. \\ % Operator & the following operators: \texttt{!= == << >> - \~{} + / * \% = < > \& .} \verb+|+ \verb|@| \\ % Operator.Word & the following operators: |in|, |is|, |and|, |or| et |not| \\ % Name.Builtin & almost all the functions predefined by Python \\ % Name.Decorator & the decorators (instructions beginning by \verb|@|) \\ % Name.Namespace & the name of the modules \\ % Name.Class & the name of the Python classes defined by the user \emph{at their point of definition} (with the keyword |class|) \\ % Name.Function & the name of the Python functions defined by the user \emph{at their % point of definition} (with the keyword |def|) \\ % UserFunction & the name of the Python functions previously defined by the user % (the initial value of that parameter is empty and, hence, these % elements are drawn, by default, in the current color, usually black) \\ % Exception & les exceptions prédéfinies (ex.: \texttt{SyntaxError}) \\ % InitialValues & the initial values (and the preceding symbol |=|) of the % optional arguments in the definitions of functions; if the final % user has not set that key, those elements will be formatted by \pkg{piton} % as done for any Python code. \\ % Comment & the comments beginning with \texttt{\#} \\ % Comment.LaTeX & the comments beginning with \texttt{\#>}, which are composed by % \pkg{piton} as LaTeX code (merely named ``LaTeX comments'' in this document) \\ % Keyword.Constant & |True|, |False| et |None| \\ % Keyword & the following keywords: % \ttfamily assert, break, case, continue, del, % elif, else, except, exec, finally, for, from, % global, if, import, lambda, non local, % pass, raise, return, try, while, % with, yield et yield from.\\ % \bottomrule % \end{tabularx} % \end{center} % % % \newpage % % \subsection{The language OCaml} % % It's possible to switch to the language |OCaml| with |\PitonOptions{language = OCaml}|. % % \bigskip % It's also possible to set the language OCaml for an individual environment |{Piton}|. % % % \begin{Verbatim} % \begin{Piton}~emphase#[language=OCaml]@ % ... % \end{Piton} % \end{Verbatim} % % \bigskip % The option exists also for |\PitonInputFile| : |\PitonInputFile[language=OCaml]{...}| % % \vspace{1cm} % % % \begin{center} % \begin{tabularx}{0.9\textwidth}{@{}>{\ttfamily}l>{\raggedright\arraybackslash}X@{}} % \toprule % \normalfont Style & Use \\ % \midrule % Number & the numbers \\ % String.Short & the characters (between \texttt{'}) \\ % String.Long & the strings, between |"| but also the \emph{quoted-strings} \\ % String & that key fixes both |String.Short| and |String.Long| \\ % Operator & les opérateurs, en particulier |+|, |-|, |/|, |*|, |@|, |!=|, |==|, |&&| \\ % Operator.Word & les opérateurs suivants : |and|, |asr|, |land|, |lor|, |lsl|, |lxor|, |mod| et |or| \\ % Name.Builtin & les fonctions |not|, |incr|, |decr|, |fst| et |snd| \\ % Name.Type & the name of a type of OCaml \\ % Name.Field & the name of a field of a module \\ % Name.Constructor & the name of the constructors of types (which begins by a capital) \\ % Name.Module & the name of the modules \\ % Name.Function & the name of the Python functions defined by the user \emph{at their % point of definition} (with the keyword |let|) \\ % UserFunction & the name of the OCaml functions previously defined by the user % (the initial value of that parameter is empty and these % elements are drawn in the current color, usually black) \\ % Exception & the predefined exceptions (eg : |End_of_File|) \\ % TypeParameter & the parameters of the types \\ % Comment & the comments, between |(*| et |*)|; these comments may be nested \\ % Keyword.Constant & |true| et |false| \\ % Keyword & the following keywords: % |assert|, |as|, |begin|, |class|, |constraint|, |done|, % |downto|, |do|, |else|, |end|, |exception|, |external|, % |for|, |function|, |functor|, |fun| , |if| % |include|, |inherit|, |initializer|, |in| , |lazy|, |let|, % |match|, |method|, |module|, |mutable|, |new|, |object|, % |of|, |open|, |private|, |raise|, |rec|, |sig|, % |struct|, |then|, |to|, |try|, |type|, % |value|, |val|, |virtual|, |when|, |while| and |with| \\ % \bottomrule % \end{tabularx} % \end{center} % % \newpage % % \subsection[The language C (and C++)]{The language C (and \CC)} % % % It's possible to switch to the language |C| with |\PitonOptions{language = C}|. % % \bigskip % It's also possible to set the language C for an individual environment |{Piton}|. % % % \begin{Verbatim} % \begin{Piton}~emphase#[language=C]@ % ... % \end{Piton} % \end{Verbatim} % % \bigskip % The option exists also for |\PitonInputFile| : |\PitonInputFile[language=C]{...}| % % \vspace{1cm} % % \begin{center} % \begin{tabularx}{0.9\textwidth}{@{}>{\ttfamily}l>{\raggedright\arraybackslash}X@{}} % \toprule % \normalfont Style & Use \\ % \midrule % Number & the numbers \\ % String.Long & the strings (between \texttt{"}) \\ % String.Interpol & the elements \texttt{\%d}, \texttt{\%i}, \texttt{\%f}, % \texttt{\%c}, etc. in the strings; that style inherits from the style |String.Long| \\ % Operator & the following operators : \texttt{!= == << >> - \~{} + / * \% = < > \& .} \verb+|+ \verb|@| \\ % Name.Type & the following predefined types: % |bool|, |char|, |char16_t|, |char32_t|, |double|, |float|, |int|, |int8_t|, |int16_t|, |int32_t|, % |int64_t|, |long|, |short|, |signed|, |unsigned|, |void| et |wchar_t| \\ % Name.Builtin & the following predefined functions: |printf|, |scanf|, |malloc|, |sizeof| and |alignof| \\ % Name.Class & le nom des classes au moment de leur définition, c'est-à-dire % après le mot-clé \verb|class| \\ % Name.Function & the name of the Python functions defined by the user \emph{at their % point of definition} (with the keyword |let|) \\ % UserFunction & the name of the Python functions previously defined by the user % (the initial value of that parameter is empty and these % elements are drawn in the current color, usually black) \\ % Preproc & the instructions of the preprocessor (beginning par |#|) \\ % Comment & the comments (beginning by \texttt{//} or between |/*| and |*/|) \\ % Comment.LaTeX & the comments beginning by \texttt{//>} which are composed by % \pkg{piton} as LaTeX code (merely named ``LaTeX comments'' in this document) \\ % Keyword.Constant & |default|, |false|, |NULL|, |nullptr| and |true| \\ % Keyword & the following keywords: % |alignas|, |asm|, |auto|, |break|, |case|, |catch|, |class|, % |constexpr|, |const|, |continue|, |decltype|, |do|, |else|, |enum|, % |extern|, |for|, |goto|, |if|, |nexcept|, |private|, |public|, |register|, |restricted|, |try|, % |return|, |static|, |static_assert|, |struct|, |switch|, |thread_local|, |throw|, % |typedef|, |union|, |using|, |virtual|, |volatile| and |while| % \\ % \bottomrule % \end{tabularx} % \end{center} % % \newpage % % \subsection{The language SQL} % % % It's possible to switch to the language |SQL| with |\PitonOptions{language = SQL}|. % % \bigskip % It's also possible to set the language SQL for an individual environment |{Piton}|. % % % \begin{Verbatim} % \begin{Piton}~emphase#[language=SQL]@ % ... % \end{Piton} % \end{Verbatim} % % \bigskip % The option exists also for |\PitonInputFile| : |\PitonInputFile[language=SQL]{...}| % % % \vspace{1cm} % % \begin{center} % \begin{tabularx}{0.9\textwidth}{@{}>{\ttfamily}l>{\raggedright\arraybackslash}X@{}} % \toprule % \normalfont Style & Use \\ % \midrule % Number & the numbers \\ % String.Long & the strings (between \texttt{'} and not \texttt{"} because the % elements between \texttt{"} are names of fields and formatted with |Name.Field|) \\ % Operator & the following operators : \texttt{= != <> >= > < <= * + / } \\ % Name.Table & the names of the tables \\ % Name.Field & the names of the fields of the tables \\ % Name.Builtin & the following built-in functions (their names are \emph{not} case-sensitive): % |avg|, |count|, |char_lenght|, |concat|, |curdate|, |current_date|, % |date_format|, |day|, |lower|, |ltrim|, |max|, |min|, |month|, |now|, % |rank|, |round|, |rtrim|, |substring|, |sum|, |upper| and |year|. \\ % Comment & the comments (beginning by \texttt{--} or between |/*| and |*/|) \\ % Comment.LaTeX & the comments beginning by \texttt{-->} which are composed by % \pkg{piton} as LaTeX code (merely named ``LaTeX comments'' in this document) \\ % Keyword & the following keywords (their names are \emph{not} case-sensitive): % |add|, |after|, |all|, |alter|, |and|, |as|, |asc|, |between|, |by|, % |change|, |column|, |create|, |cross join|, |delete|, |desc|, |distinct|, % |drop|, |from|, |group|, |having|, |in|, |inner|, |insert|, |into|, |is|, % |join|, |left|, |like|, |limit|, |merge|, |not|, |null|, |on|, |or|, % |order|, |over|, |right|, |select|, |set|, |table|, |then|, |truncate|, % |union|, |update|, |values|, |when|, |where| and |with|. \\ % \bottomrule % \end{tabularx} % \end{center} % % % \bigskip % It's possible to automatically capitalize the keywords by modifiying locally % for the language SQL the style |Keywords|. % \begin{Verbatim} % \SetPitonStyle~emphase#[SQL]@{Keywords = \bfseries \MakeUppercase} % \end{Verbatim} % % \newpage % % \subsection{The language ``minimal''} % % It's possible to switch to the language ``|minimal|'' with |\PitonOptions{language = minimal}|. % % \bigskip % It's also possible to set the language ``|minimal|'' for an individual environment |{Piton}|. % % % \begin{Verbatim} % \begin{Piton}~emphase#[language=minimal]@ % ... % \end{Piton} % \end{Verbatim} % % \bigskip % The option exists also for |\PitonInputFile| : |\PitonInputFile[language=minimal]{...}| % % % \label{minimal} % % \vspace{1cm} % % \begin{center} % \begin{tabularx}{0.9\textwidth}{@{}>{\ttfamily}l>{\raggedright\arraybackslash}X@{}} % \toprule % \normalfont Style & Usage \\ % \midrule % Number & the numbers \\ % String & the strings (between \texttt{"}) \\ % Comment & les comments (which begins with |#|) \\ % Comment.LaTeX & the comments beginning with \texttt{\#>}, which are composed by % \pkg{piton} as LaTeX code (merely named ``LaTeX comments'' in this document) \\ % \bottomrule % \end{tabularx} % \end{center} % % \bigskip % That language is provided for the final user who might wish to add keywords in % that language (with the command |\SetPitonIdentifier|: cf. \ref{SetPitonIdentifier}, % p.~\pageref{SetPitonIdentifier}) in order to create, for example, a language % for pseudo-code. % % \newpage % % \section{Implementation} % % \medskip % The development of the extension \pkg{piton} is done on the following GitHub % depot: % % \verb|https://github.com/fpantigny/piton| % % \subsection{Introduction} % % The main job of the package \pkg{piton} is to take in as input a Python % listing and to send back to LaTeX as output that code \emph{with interlaced LaTeX % instructions of formatting}. % % In fact, all that job is done by a \textsc{lpeg} called |python|. That % \textsc{lpeg}, when matched against the string of a Python listing, % returns as capture a Lua table containing data to send to LaTeX. % The only thing to do after will be to apply |tex.tprint| to each element of % that table.\footnote{Recall that |tex.tprint| takes in as argument a Lua table whose % first component is a ``catcode table'' and the second element a string. The % string will be sent to LaTeX with the regime of catcodes specified by the % catcode table. If no catcode table is provided, the standard catcodes of LaTeX % will be used.} % % \bigskip % Consider, for example, the following Python code: % % \begin{Piton} % def parity(x): % return x%2 % \end{Piton} % % The capture returned by the \pkg{lpeg} |python| against that code is the % Lua table containing the following elements : % % \bigskip % \begin{minipage}{\linewidth} % \color{gray} % % |{ "\\__piton_begin_line:" }|\footnote{Each line of the Python listings will % be encapsulated in a pair: \texttt{\textbackslash_@@_begin_line:} -- % \texttt{\textbackslash@@_end_line:}. The token % \texttt{\textbackslash@@_end_line:} must be explicit because it will be used as % marker in order to delimit the argument of the command \texttt{\textbackslash % @@\_begin\_line:}. Both tokens \texttt{\textbackslash_@@_begin_line:} and % \texttt{\textbackslash@@_end_line:} will be nullified in the command % \texttt{\textbackslash piton} (since there can't be lines breaks in the % argument of a command \texttt{\textbackslash piton}).} % % \texttt{\{ "\{\textbackslash PitonStyle\{Keyword\}\{" \}}\footnote{The % lexical elements of Python for which we have a \pkg{piton} style will be % formatted via the use of the command \texttt{\textbackslash PitonStyle}. % Such an element is typeset in LaTeX via the syntax \texttt{\{\textbackslash % PitonStyle\{\textsl{style}\}\{...\}\}} because the instructions inside an \texttt{\textbackslash % PitonStyle} may be both semi-global declarations like % \texttt{\textbackslash bfseries} and commands with one argument like % \texttt{\textbackslash fbox}.} % % \texttt{\{ % luatexbase.catcodetables.CatcodeTableOther\footnote{\texttt{luatexbase.catcodetables.CatcodeTableOther} is a mere number which corresponds to the ``catcode table'' whose all characters have the catcode ``other'' (which means that they will be typeset by LaTeX verbatim).}, "def" \} } % % |{ "}}" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, " " }| % % |{ "{\PitonStyle{Name.Function}{" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, "parity" }| % % |{ "}}" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, "(" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, "x" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, ")" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, ":" }| % % |{ "\\__piton_end_line: \\__piton_newline: \\__piton_begin_line:" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, " " }| % % |{ "{\PitonStyle{Keyword}{" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, "return" }| % % |{ "}}" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, " " }| % % |{ luatexbase.catcodetables.CatcodeTableOther, "x" }| % % |{ "{\PitonStyle{Operator}{" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, "&" }| % % |{ "}}" }| % % |{ "{\PitonStyle{Number}{" }| % % |{ luatexbase.catcodetables.CatcodeTableOther, "2" }| % % |{ "}}" }| % % |{ "\\__piton_end_line:" }| % % \end{minipage} % % \bigskip % We give now the LaTeX code which is sent back by Lua to TeX (we have written % on several lines for legibility but no character |\r| will be sent to LaTeX). The % characters which are greyed-out are sent to LaTeX with the catcode ``other'' % (=12). All the others characters are sent with the regime of catcodes of L3 % (as set by |\ExplSyntaxOn|) % % % \begingroup % \def\gbox#1{\colorbox{gray!20}{\strut #1}} % \setlength{\fboxsep}{1pt} % % \begin{Verbatim*}[formatcom = \color{black}] % \__piton_begin_line:{\PitonStyle{Keyword}{~gbox#def@}} % ~gbox# @{\PitonStyle{Name.Function}{~gbox#parity@}}~gbox#(x):@\__piton_end_line:\__piton_newline: % \__piton_begin_line:~gbox# @{\PitonStyle{Keyword}{~gbox#return@}} % ~gbox# x@{\PitonStyle{Operator}{~gbox#%@}}{\PitonStyle{Number}{~gbox#2@}}\__piton_end_line: % \end{Verbatim*} % \endgroup % % % % % \subsection{The L3 part of the implementation} % % \subsubsection{Declaration of the package} % \begin{macrocode} %<*STY> \NeedsTeXFormat{LaTeX2e} \RequirePackage{l3keys2e} \ProvidesExplPackage {piton} {\PitonFileDate} {\PitonFileVersion} {Highlight informatic listings with LPEG on LuaLaTeX} % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_error:n { \msg_error:nn { piton } } \cs_new_protected:Npn \@@_warning:n { \msg_warning:nn { piton } } \cs_new_protected:Npn \@@_error:nn { \msg_error:nnn { piton } } \cs_new_protected:Npn \@@_error:nnn { \msg_error:nnnn { piton } } \cs_new_protected:Npn \@@_fatal:n { \msg_fatal:nn { piton } } \cs_new_protected:Npn \@@_fatal:nn { \msg_fatal:nnn { piton } } \cs_new_protected:Npn \@@_msg_new:nn { \msg_new:nnn { piton } } \cs_new_protected:Npn \@@_msg_new:nnn { \msg_new:nnnn { piton } } \cs_new_protected:Npn \@@_gredirect_none:n #1 { \group_begin: \globaldefs = 1 \msg_redirect_name:nnn { piton } { #1 } { none } \group_end: } % \end{macrocode} % % \bigskip % \begin{macrocode} \@@_msg_new:nn { LuaLaTeX~mandatory } { LuaLaTeX~is~mandatory.\\ The~package~'piton'~requires~the~engine~LuaLaTeX.\\ \str_if_eq:onT \c_sys_jobname_str { output } { If~you~use~Overleaf,~you~can~switch~to~LuaLaTeX~in~the~"Menu". \\} If~you~go~on,~the~package~'piton'~won't~be~loaded. } \sys_if_engine_luatex:F { \msg_critical:nn { piton } { LuaLaTeX~mandatory } } % \end{macrocode} % % \bigskip % \begin{macrocode} \RequirePackage { luatexbase } \RequirePackage { luacode } % \end{macrocode} % % \bigskip % \begin{macrocode} \@@_msg_new:nnn { piton.lua~not~found } { The~file~'piton.lua'~can't~be~found.\\ The~package~'piton'~won't~be~loaded.\\ If~you~want~to~know~how~to~retrieve~the~file~'piton.lua',~type~H~. } { On~the~site~CTAN,~go~to~the~page~of~'piton':~https://ctan.org/pkg/piton.~ The~file~'README.md'~explains~how~to~retrieve~the~files~'piton.sty'~and~ 'piton.lua'. } % \end{macrocode} % % \bigskip % \begin{macrocode} \file_if_exist:nF { piton.lua } { \msg_critical:nn { piton } { piton.lua~not~found } } % \end{macrocode} % % % \bigskip % The boolean |\g_@@_footnotehyper_bool| will indicate if the option % |footnotehyper| is used. % \begin{macrocode} \bool_new:N \g_@@_footnotehyper_bool % \end{macrocode} % % \medskip % The boolean |\g_@@_footnote_bool| will indicate if the option |footnote| is % used, but quicky, it will also be set to |true| if the option |footnotehyper| % is used. % \begin{macrocode} \bool_new:N \g_@@_footnote_bool % \end{macrocode} % % \medskip % The following boolean corresponds to the key |math-comments| (available only at load-time). % \begin{macrocode} \bool_new:N \g_@@_math_comments_bool % \end{macrocode} % % \medskip % \begin{macrocode} \bool_new:N \g_@@_beamer_bool \tl_new:N \g_@@_escape_inside_tl % \end{macrocode} % % \bigskip % We define a set of keys for the options at load-time. % \begin{macrocode} \keys_define:nn { piton / package } { footnote .bool_gset:N = \g_@@_footnote_bool , footnotehyper .bool_gset:N = \g_@@_footnotehyper_bool , beamer .bool_gset:N = \g_@@_beamer_bool , beamer .default:n = true , math-comments .code:n = \@@_error:n { moved~to~preamble } , comment-latex .code:n = \@@_error:n { moved~to~preamble } , unknown .code:n = \@@_error:n { Unknown~key~for~package } } % \end{macrocode} % % % \bigskip % \begin{macrocode} \@@_msg_new:nn { moved~to~preamble } { The~key~'\l_keys_key_str'~*must*~now~be~used~with~ \token_to_str:N \PitonOptions`in~the~preamble~of~your~ document.\\ That~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Unknown~key~for~package } { Unknown~key.\\ You~have~used~the~key~'\l_keys_key_str'~but~the~only~keys~available~here~ are~'beamer',~'footnote',~'footnotehyper'.~Other~keys~are~available~in~ \token_to_str:N \PitonOptions.\\ That~key~will~be~ignored. } % \end{macrocode} % % % \bigskip % We process the options provided by the user at load-time. % \begin{macrocode} \ProcessKeysOptions { piton / package } % \end{macrocode} % % % \bigskip % \begin{macrocode} \@ifclassloaded { beamer } { \bool_gset_true:N \g_@@_beamer_bool } { } \@ifpackageloaded { beamerarticle } { \bool_gset_true:N \g_@@_beamer_bool } { } \bool_if:NT \g_@@_beamer_bool { \lua_now:n { piton_beamer = true } } % \end{macrocode} % % \bigskip % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \@ifpackageloaded { xcolor } { } { \msg_fatal:nn { piton } { xcolor~not~loaded } } } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { xcolor~not~loaded } { xcolor~not~loaded \\ The~package~'xcolor'~is~required~by~'piton'.\\ This~error~is~fatal. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { footnote~with~footnotehyper~package } { Footnote~forbidden.\\ You~can't~use~the~option~'footnote'~because~the~package~ footnotehyper~has~already~been~loaded.~ If~you~want,~you~can~use~the~option~'footnotehyper'~and~the~footnotes~ within~the~environments~of~piton~will~be~extracted~with~the~tools~ of~the~package~footnotehyper.\\ If~you~go~on,~the~package~footnote~won't~be~loaded. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { footnotehyper~with~footnote~package } { You~can't~use~the~option~'footnotehyper'~because~the~package~ footnote~has~already~been~loaded.~ If~you~want,~you~can~use~the~option~'footnote'~and~the~footnotes~ within~the~environments~of~piton~will~be~extracted~with~the~tools~ of~the~package~footnote.\\ If~you~go~on,~the~package~footnotehyper~won't~be~loaded. } % \end{macrocode} % % \medskip % \begin{macrocode} \bool_if:NT \g_@@_footnote_bool { % \end{macrocode} % The class \cls{beamer} has its own system to extract footnotes and that's why % we have nothing to do if \cls{beamer} is used. % \begin{macrocode} \@ifclassloaded { beamer } { \bool_gset_false:N \g_@@_footnote_bool } { \@ifpackageloaded { footnotehyper } { \@@_error:n { footnote~with~footnotehyper~package } } { \usepackage { footnote } } } } % \end{macrocode} % % \begin{macrocode} \bool_if:NT \g_@@_footnotehyper_bool { % \end{macrocode} % The class \cls{beamer} has its own system to extract footnotes and that's why % we have nothing to do if \cls{beamer} is used. % \begin{macrocode} \@ifclassloaded { beamer } { \bool_gset_false:N \g_@@_footnote_bool } { \@ifpackageloaded { footnote } { \@@_error:n { footnotehyper~with~footnote~package } } { \usepackage { footnotehyper } } \bool_gset_true:N \g_@@_footnote_bool } } % \end{macrocode} % The flag |\g_@@_footnote_bool| is raised and so, we will only have to test % |\g_@@_footnote_bool| in order to know if we have to insert an environment % |{savenotes}|. % % \bigskip % \begin{macrocode} \lua_now:n { piton = piton~or { } piton.ListCommands = lpeg.P ( false ) piton.last_code = '' piton.last_language = '' } % \end{macrocode} % % \bigskip % \subsubsection{Parameters and technical definitions} % % The following string will contain the name of the informatic language % considered (the initial value is |python|). % % \begin{macrocode} \str_new:N \l_piton_language_str \str_set:Nn \l_piton_language_str { python } % \end{macrocode} % % \medskip % Each time the command |\PitonInputFile| or an environment of \pkg{piton} is % used, the code of that environment will be stored in the following global string. % \begin{macrocode} \tl_new:N \g_piton_last_code_tl % \end{macrocode} % % \medskip % The following parameter corresponds to the key |path| (which is the path used % to include files by |\PitonInputFile|). % \begin{macrocode} \str_new:N \l_@@_path_str % \end{macrocode} % % \medskip % The following parameter corresponds to the key |path-write| (which is the path % used when writing files from listings inserted in the environments of % \pkg{piton} by use of the key |write|). % \begin{macrocode} \str_new:N \l_@@_path_write_str % \end{macrocode} % % \medskip % In order to have a better control over the keys. % \begin{macrocode} \bool_new:N \l_@@_in_PitonOptions_bool \bool_new:N \l_@@_in_PitonInputFile_bool % \end{macrocode} % % % \medskip % We will compute (with Lua) the numbers of lines of the Python code and store % it in the following counter. % \begin{macrocode} \int_new:N \l_@@_nb_lines_int % \end{macrocode} % % The same for the number of non-empty lines of the Python codes. % \begin{macrocode} \int_new:N \l_@@_nb_non_empty_lines_int % \end{macrocode} % % The following counter will be used to count the lines during the composition. % It will count all the lines, empty or not empty. It won't be used to print the % numbers of the lines. % \begin{macrocode} \int_new:N \g_@@_line_int % \end{macrocode} % % \medskip % The following token list will contain the (potential) informations to write % on the |aux| (to be used in the next compilation). % \begin{macrocode} \tl_new:N \g_@@_aux_tl % \end{macrocode} % % \medskip % The following counter corresponds to the key |splittable| of |\PitonOptions|. % If the value of |\l_@@_splittable_int| is equal to $n$, then no line break can % occur within the first $n$~lines or the last $n$~lines of the listings. % \begin{macrocode} \int_new:N \l_@@_splittable_int % \end{macrocode} % % \medskip % An initial value of |splittable| equal to 100 is equivalent to say that the % environments |{Piton}| are unbreakable. % \begin{macrocode} \int_set:Nn \l_@@_splittable_int { 100 } % \end{macrocode} % % \medskip % The following string corresponds to the key |background-color| of |\PitonOptions|. % \begin{macrocode} \clist_new:N \l_@@_bg_color_clist % \end{macrocode} % % \medskip % The package \pkg{piton} will also detect the lines of code which correspond to % the user input in a Python console, that is to say the lines of code beginning % with |>>>| and |...|. It's possible, with the key |prompt-background-color|, % to require a background for these lines of code (and the other lines of code % will have the standard background color specified by |background-color|). % \begin{macrocode} \tl_new:N \l_@@_prompt_bg_color_tl % \end{macrocode} % % \medskip % The following parameters correspond to the keys |begin-range| and |end-range| of % the command |\PitonInputFile|. % \begin{macrocode} \str_new:N \l_@@_begin_range_str \str_new:N \l_@@_end_range_str % \end{macrocode} % % \medskip % The argument of |\PitonInputFile|. % \begin{macrocode} \str_new:N \l_@@_file_name_str % \end{macrocode} % % \medskip % We will count the environments |{Piton}| (and, in fact, also the commands % |\PitonInputFile|, despite the name |\g_@@_env_int|). % \begin{macrocode} \int_new:N \g_@@_env_int % \end{macrocode} % % \medskip % The parameter |\l_@@_writer_str| corresponds to the key |write|. We will store % the list of the files already used in |\g_@@_write_seq| (we must not erase a % file which has been still been used). % \begin{macrocode} \str_new:N \l_@@_write_str \seq_new:N \g_@@_write_seq % \end{macrocode} % % \medskip % The following boolean corresponds to the key |show-spaces|. % \begin{macrocode} \bool_new:N \l_@@_show_spaces_bool % \end{macrocode} % % \medskip % The following booleans correspond to the keys |break-lines| and % |indent-broken-lines|. % \begin{macrocode} \bool_new:N \l_@@_break_lines_in_Piton_bool \bool_new:N \l_@@_indent_broken_lines_bool % \end{macrocode} % % \medskip % The following token list corresponds to the key |continuation-symbol|. % \begin{macrocode} \tl_new:N \l_@@_continuation_symbol_tl \tl_set:Nn \l_@@_continuation_symbol_tl { + } % \end{macrocode} % % \medskip % The following token list corresponds to the key % |continuation-symbol-on-indentation|. The name has been shorten to |csoi|. % \begin{macrocode} \tl_new:N \l_@@_csoi_tl \tl_set:Nn \l_@@_csoi_tl { $ \hookrightarrow \; $ } % \end{macrocode} % % \medskip % The following token list corresponds to the key |end-of-broken-line|. % \begin{macrocode} \tl_new:N \l_@@_end_of_broken_line_tl \tl_set:Nn \l_@@_end_of_broken_line_tl { \hspace*{0.5em} \textbackslash } % \end{macrocode} % % \medskip % The following boolean corresponds to the key |break-lines-in-piton|. % \begin{macrocode} \bool_new:N \l_@@_break_lines_in_piton_bool % \end{macrocode} % % \bigskip % The following dimension will be the width of the listing constructed by % |{Piton}| or |\PitonInputFile|. % \begin{itemize} % \item If the user uses the key |width| of |\PitonOptions| with a numerical % value, that value will be stored in |\l_@@_width_dim|. % \item If the user uses the key |width| with the special value~|min|, the % dimension |\l_@@_width_dim| will, \emph{in the second run}, be computed from % the value of |\l_@@_line_width_dim| stored in the |aux| file % (computed during the first run the maximal width of the lines of the listing). % During the first run, |\l_@@_width_line_dim| will be set equal to |\linewidth|. % \item Elsewhere, |\l_@@_width_dim| will be set at the beginning of the listing % (in |\@@_pre_env:|) equal to the current value of |\linewidth|. % \end{itemize} % % \begin{macrocode} \dim_new:N \l_@@_width_dim % \end{macrocode} % % \medskip % We will also use another dimension called |\l_@@_line_width_dim|. That % will the width of the actual lines of code. That dimension may be lower than % the whole |\l_@@_width_dim| because we have to take into account the value of % |\l_@@_left_margin_dim| (for the numbers of lines when |line-numbers| is in % force) and another small margin when a background color is used (with the key % |background-color|). % \begin{macrocode} \dim_new:N \l_@@_line_width_dim % \end{macrocode} % % \medskip % The following flag will be raised with the key |width| is used with the % special value |min|. % \begin{macrocode} \bool_new:N \l_@@_width_min_bool % \end{macrocode} % % \medskip % If the key |width| is used with the special value~|min|, we will compute the % maximal width of the lines of an environment |{Piton}| in |\g_@@_tmp_width_dim| % because we need it for the case of the key |width| is used with the spacial % value |min|. We need a global variable because, when the key |footnote| is in % force, each line when be composed in an environment |{savenotes}| and we need % to exit our |\g_@@_tmp_width_dim| from that environment. % \begin{macrocode} \dim_new:N \g_@@_tmp_width_dim % \end{macrocode} % % \medskip % The following dimension corresponds to the key |left-margin| of |\PitonOptions|. % \begin{macrocode} \dim_new:N \l_@@_left_margin_dim % \end{macrocode} % % \medskip % The following boolean will be set when the key |left-margin=auto| % is used. % \begin{macrocode} \bool_new:N \l_@@_left_margin_auto_bool % \end{macrocode} % % \medskip % The following dimension corresponds to the key |numbers-sep| of % |\PitonOptions|. % \begin{macrocode} \dim_new:N \l_@@_numbers_sep_dim \dim_set:Nn \l_@@_numbers_sep_dim { 0.7 em } % \end{macrocode} % % \medskip % The tabulators will be replaced by the content of the following token list. % \begin{macrocode} \tl_new:N \l_@@_tab_tl % \end{macrocode} % % \medskip % Be careful. The following sequence |\g_@@_languages_seq| is not the list of % the languages supported by \pkg{piton}. It's the list of the languages for % which at least a user function has been defined. We need that sequence only % for the command |\PitonClearUserFunctions| when it is used without its % optional argument: it must clear all the list of languages for which at least % a user function has been defined. % \begin{macrocode} \seq_new:N \g_@@_languages_seq % \end{macrocode} % % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_set_tab_tl:n #1 { \tl_clear:N \l_@@_tab_tl \prg_replicate:nn { #1 } { \tl_put_right:Nn \l_@@_tab_tl { ~ } } } \@@_set_tab_tl:n { 4 } % \end{macrocode} % % \medskip % The following integer corresponds to the key |gobble|. % \begin{macrocode} \int_new:N \l_@@_gobble_int % \end{macrocode} % % \medskip % \begin{macrocode} \tl_new:N \l_@@_space_tl \tl_set:Nn \l_@@_space_tl { ~ } % \end{macrocode} % % % \medskip % At each line, the following counter will count the spaces at the beginning. % \begin{macrocode} \int_new:N \g_@@_indentation_int % \end{macrocode} % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_an_indentation_space: { \int_gincr:N \g_@@_indentation_int } % \end{macrocode} % % \medskip % The following command |\@@_beamer_command:n| executes the argument % corresponding to its argument but also stores it in |\l_@@_beamer_command_str|. % That string is used only in the error message ``|cr~not~allowed|'' raised when % there is a carriage return in the mandatory argument of that command. % \begin{macrocode} \cs_new_protected:Npn \@@_beamer_command:n #1 { \str_set:Nn \l_@@_beamer_command_str { #1 } \use:c { #1 } } % \end{macrocode} % % \bigskip % In the environment |{Piton}|, the command |\label| will be linked to the % following command. % \begin{macrocode} \cs_new_protected:Npn \@@_label:n #1 { \bool_if:NTF \l_@@_line_numbers_bool { \@bsphack \protected@write \@auxout { } { \string \newlabel { #1 } { % \end{macrocode} % Remember that the content of a line is typeset in a box \emph{before} the % composition of the potential number of line. % \begin{macrocode} { \int_eval:n { \g_@@_visual_line_int + 1 } } { \thepage } } } \@esphack } { \@@_error:n { label~with~lines~numbers } } } % \end{macrocode} % % \bigskip % The following commands corresponds to the keys |marker/beginning| and % |marker/end|. The values of that keys are functions that will be applied to % the ``\emph{range}'' specified by the final user in an individual % |\PitonInputFile|. They will construct the markers used to find textually in % the external file loaded by \pkg{piton} the part which must be included (and % formatted). % \begin{macrocode} \cs_new_protected:Npn \@@_marker_beginning:n #1 { } \cs_new_protected:Npn \@@_marker_end:n #1 { } % \end{macrocode} % % % \bigskip % The following commands are a easy way to insert safely braces (|{| and |}|) in % the TeX flow. % \begin{macrocode} \cs_new_protected:Npn \@@_open_brace: { \lua_now:n { piton.open_brace() } } \cs_new_protected:Npn \@@_close_brace: { \lua_now:n { piton.close_brace() } } % \end{macrocode} % % \bigskip % The following token list will be evaluated at the beginning of % |\@@_begin_line:|... |\@@_end_line:| and cleared at the end. It will be used % by LPEG acting between the lines of the Python code in order to add % instructions to be executed at the beginning of the line. % \begin{macrocode} \tl_new:N \g_@@_begin_line_hook_tl % \end{macrocode} % % \smallskip % For example, the LPEG |Prompt| will trigger the following command which will % insert an instruction in the hook |\g_@@_begin_line_hook| to specify that a % background must be inserted to the current line of code. % \begin{macrocode} \cs_new_protected:Npn \@@_prompt: { \tl_gset:Nn \g_@@_begin_line_hook_tl { \tl_if_empty:NF \l_@@_prompt_bg_color_tl { \clist_set:NV \l_@@_bg_color_clist \l_@@_prompt_bg_color_tl } } } % \end{macrocode} % % % \bigskip % \subsubsection{Treatment of a line of code} % % \begin{macrocode} \cs_new_protected:Npn \@@_replace_spaces:n #1 { \tl_set:Nn \l_tmpa_tl { #1 } \bool_if:NTF \l_@@_show_spaces_bool { \tl_set:Nn \l_@@_space_tl { ␣ } \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl % U+2423 } { % \end{macrocode} % If the key |break-lines-in-Piton| is in force, we replace all the characters % U+0020 (that is to say the spaces) by |\@@_breakable_space:|. Remark that, % except the spaces inserted in the LaTeX comments (and maybe in the math % comments), all these spaces are of catcode ``other'' (=12) and are % unbreakable. % \begin{macrocode} \bool_if:NT \l_@@_break_lines_in_Piton_bool { \regex_replace_all:nnN { \x20 } { \c { @@_breakable_space: } } \l_tmpa_tl } } \l_tmpa_tl } % \end{macrocode} % % \bigskip % In the contents provided by Lua, each line of the Python code will be % surrounded by |\@@_begin_line:| and |\@@_end_line:|. |\@@_begin_line:| is a % LaTeX command that we will define now but |\@@_end_line:| is only a syntactic % marker that has no definition. % % \begin{macrocode} \cs_set_protected:Npn \@@_begin_line: #1 \@@_end_line: { \group_begin: \g_@@_begin_line_hook_tl \int_gzero:N \g_@@_indentation_int % \end{macrocode} % % \medskip % First, we will put in the coffin |\l_tmpa_coffin| the actual content of a line % of the code (without the potential number of line). % % Be careful: There is curryfication in the following code. % \begin{macrocode} \bool_if:NTF \l_@@_width_min_bool \@@_put_in_coffin_ii:n \@@_put_in_coffin_i:n { \language = -1 \raggedright \strut \@@_replace_spaces:n { #1 } \strut \hfil } % \end{macrocode} % Now, we add the potential number of line, the potential left margin and the % potential background. % \begin{macrocode} \hbox_set:Nn \l_tmpa_box { \skip_horizontal:N \l_@@_left_margin_dim \bool_if:NT \l_@@_line_numbers_bool { \bool_if:nF { \str_if_eq_p:nn { #1 } { \PitonStyle {Prompt}{} } && \l_@@_skip_empty_lines_bool } { \int_gincr:N \g_@@_visual_line_int} \bool_if:nT { ! \str_if_eq_p:nn { #1 } { \PitonStyle {Prompt}{} } || ( ! \l_@@_skip_empty_lines_bool && \l_@@_label_empty_lines_bool ) } \@@_print_number: } % \end{macrocode} % If there is a background, we must remind that there is a left margin of 0.5~em % for the background... % \begin{macrocode} \clist_if_empty:NF \l_@@_bg_color_clist { % \end{macrocode} % ... but if only if the key |left-margin| is not used ! % \begin{macrocode} \dim_compare:nNnT \l_@@_left_margin_dim = \c_zero_dim { \skip_horizontal:n { 0.5 em } } } \coffin_typeset:Nnnnn \l_tmpa_coffin T l \c_zero_dim \c_zero_dim } \box_set_dp:Nn \l_tmpa_box { \box_dp:N \l_tmpa_box + 1.25 pt } \box_set_ht:Nn \l_tmpa_box { \box_ht:N \l_tmpa_box + 1.25 pt } \clist_if_empty:NTF \l_@@_bg_color_clist { \box_use_drop:N \l_tmpa_box } { \vtop { \hbox:n { \@@_color:N \l_@@_bg_color_clist \vrule height \box_ht:N \l_tmpa_box depth \box_dp:N \l_tmpa_box width \l_@@_width_dim } \skip_vertical:n { - \box_ht_plus_dp:N \l_tmpa_box } \box_use_drop:N \l_tmpa_box } } \vspace { - 2.5 pt } \group_end: \tl_gclear:N \g_@@_begin_line_hook_tl } % \end{macrocode} % % \bigskip % In the general case (which is also the simpler), the key |width| is not used, % or (if used) it is not used with the special value~|min|. % In that case, the content of a line of code is composed in a vertical coffin % with a width equal to |\l_@@_line_width_dim|. That coffin may, % eventually, contains several lines when the key |broken-lines-in-Piton| (or % |broken-lines|) is used. % % That commands takes in its argument by curryfication. % \begin{macrocode} \cs_set_protected:Npn \@@_put_in_coffin_i:n { \vcoffin_set:Nnn \l_tmpa_coffin \l_@@_line_width_dim } % \end{macrocode} % % \bigskip % The second case is the case when the key |width| is used with the special % value~|min|. % \begin{macrocode} \cs_set_protected:Npn \@@_put_in_coffin_ii:n #1 { % \end{macrocode} % First, we compute the natural width of the line of code because we have to % compute the natural width of the whole listing (and it will be written on the % |aux| file in the variable |\l_@@_width_dim|). % \begin{macrocode} \hbox_set:Nn \l_tmpa_box { #1 } % \end{macrocode} % Now, you can actualize the value of |\g_@@_tmp_width_dim| (it will be used to % write on the |aux| file the natural width of the environment). % \begin{macrocode} \dim_compare:nNnT { \box_wd:N \l_tmpa_box } > \g_@@_tmp_width_dim { \dim_gset:Nn \g_@@_tmp_width_dim { \box_wd:N \l_tmpa_box } } % \end{macrocode} % % \begin{macrocode} \hcoffin_set:Nn \l_tmpa_coffin { \hbox_to_wd:nn \l_@@_line_width_dim % \end{macrocode} % We unpack the block in order to free the potential |\hfill| springs present in % the LaTeX comments (cf. section~\ref{example-comments}, p.~\pageref{example-comments}). % \begin{macrocode} { \hbox_unpack:N \l_tmpa_box \hfil } } } % \end{macrocode} % % % \bigskip % The command |\@@_color:N| will take in as argument a reference to a % comma-separated list of colors. A color will be picked by using the value of % |\g_@@_line_int| (modulo the number of colors in the list). % \begin{macrocode} \cs_set_protected:Npn \@@_color:N #1 { \int_set:Nn \l_tmpa_int { \clist_count:N #1 } \int_set:Nn \l_tmpb_int { \int_mod:nn \g_@@_line_int \l_tmpa_int + 1 } \tl_set:Nx \l_tmpa_tl { \clist_item:Nn #1 \l_tmpb_int } \tl_if_eq:NnTF \l_tmpa_tl { none } % \end{macrocode} % By setting |\l_@@_width_dim| to zero, the colored rectangle will be % drawn with zero width and, thus, it will be a mere strut (and we need that strut). % \begin{macrocode} { \dim_zero:N \l_@@_width_dim } { \exp_args:NV \@@_color_i:n \l_tmpa_tl } } % \end{macrocode} % % The following command |\@@_color:n| will accept both the instruction % |\@@_color:n { red!15 }| and the instruction |\@@_color:n { [rgb]{0.9,0.9,0} }|. % \begin{macrocode} \cs_set_protected:Npn \@@_color_i:n #1 { \tl_if_head_eq_meaning:nNTF { #1 } [ { \tl_set:Nn \l_tmpa_tl { #1 } \tl_set_rescan:Nno \l_tmpa_tl { } \l_tmpa_tl \exp_last_unbraced:No \color \l_tmpa_tl } { \color { #1 } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_newline: { \int_gincr:N \g_@@_line_int \int_compare:nNnT \g_@@_line_int > { \l_@@_splittable_int - 1 } { \int_compare:nNnT { \l_@@_nb_lines_int - \g_@@_line_int } > \l_@@_splittable_int { \egroup \bool_if:NT \g_@@_footnote_bool { \end { savenotes } } \par \mode_leave_vertical: \bool_if:NT \g_@@_footnote_bool { \begin { savenotes } } \vtop \bgroup } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_set_protected:Npn \@@_breakable_space: { \discretionary { \hbox:n { \color { gray } \l_@@_end_of_broken_line_tl } } { \hbox_overlap_left:n { { \normalfont \footnotesize \color { gray } \l_@@_continuation_symbol_tl } \skip_horizontal:n { 0.3 em } \clist_if_empty:NF \l_@@_bg_color_clist { \skip_horizontal:n { 0.5 em } } } \bool_if:NT \l_@@_indent_broken_lines_bool { \hbox:n { \prg_replicate:nn { \g_@@_indentation_int } { ~ } { \color { gray } \l_@@_csoi_tl } } } } { \hbox { ~ } } } % \end{macrocode} % % \bigskip % \subsubsection{PitonOptions} % % \medskip % \begin{macrocode} \bool_new:N \l_@@_line_numbers_bool \bool_new:N \l_@@_skip_empty_lines_bool \bool_set_true:N \l_@@_skip_empty_lines_bool \bool_new:N \l_@@_line_numbers_absolute_bool \bool_new:N \l_@@_label_empty_lines_bool \bool_set_true:N \l_@@_label_empty_lines_bool \int_new:N \l_@@_number_lines_start_int \bool_new:N \l_@@_resume_bool % \end{macrocode} % % % \bigskip % \begin{macrocode} \keys_define:nn { PitonOptions / marker } { beginning .code:n = \cs_set:Nn \@@_marker_beginning:n { #1 } , beginning .value_required:n = true , end .code:n = \cs_set:Nn \@@_marker_end:n { #1 } , end .value_required:n = true , include-lines .bool_set:N = \l_@@_marker_include_lines_bool , include-lines .default:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~marker } } % \end{macrocode} % % \bigskip % \begin{macrocode} \keys_define:nn { PitonOptions / line-numbers } { true .code:n = \bool_set_true:N \l_@@_line_numbers_bool , false .code:n = \bool_set_false:N \l_@@_line_numbers_bool , start .code:n = \bool_if:NTF \l_@@_in_PitonOptions_bool { Invalid~key } { \bool_set_true:N \l_@@_line_numbers_bool \int_set:Nn \l_@@_number_lines_start_int { #1 } } , start .value_required:n = true , skip-empty-lines .code:n = \bool_if:NF \l_@@_in_PitonOptions_bool { \bool_set_true:N \l_@@_line_numbers_bool } \str_if_eq:nnTF { #1 } { false } { \bool_set_false:N \l_@@_skip_empty_lines_bool } { \bool_set_true:N \l_@@_skip_empty_lines_bool } , skip-empty-lines .default:n = true , label-empty-lines .code:n = \bool_if:NF \l_@@_in_PitonOptions_bool { \bool_set_true:N \l_@@_line_numbers_bool } \str_if_eq:nnTF { #1 } { false } { \bool_set_false:N \l_@@_label_empty_lines_bool } { \bool_set_true:N \l_@@_label_empty_lines_bool } , label-empty-lines .default:n = true , absolute .code:n = \bool_if:NTF \l_@@_in_PitonOptions_bool { \bool_set_true:N \l_@@_line_numbers_absolute_bool } { \bool_set_true:N \l_@@_line_numbers_bool } \bool_if:NT \l_@@_in_PitonInputFile_bool { \bool_set_true:N \l_@@_line_numbers_absolute_bool \bool_set_false:N \l_@@_skip_empty_lines_bool } \bool_lazy_or:nnF \l_@@_in_PitonInputFile_bool \l_@@_in_PitonOptions_bool { \@@_error:n { Invalid~key } } , absolute .value_forbidden:n = true , resume .code:n = \bool_set_true:N \l_@@_resume_bool \bool_if:NF \l_@@_in_PitonOptions_bool { \bool_set_true:N \l_@@_line_numbers_bool } , resume .value_forbidden:n = true , sep .dim_set:N = \l_@@_numbers_sep_dim , sep .value_required:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~line-numbers } } % \end{macrocode} % % \bigskip % Be careful! The name of the following set of keys must be considered as % public! Hence, it should \emph{not} be changed. % % \begin{macrocode} \keys_define:nn { PitonOptions } { detected-commands .code:n = \lua_now:n { piton.addListCommands('#1') } , detected-commands .value_required:n = true , detected-commands .usage:n = preamble , % \end{macrocode} % First, we put keys that should be avalaible only in the preamble. % % Remark that the command |\lua_escape:n| is fully expandable. That's why we use % |\lua_now:e|. % \begin{macrocode} begin-escape .code:n = \lua_now:e { piton.begin_escape = "\lua_escape:n{#1}" } , begin-escape .value_required:n = true , begin-escape .usage:n = preamble , end-escape .code:n = \lua_now:e { piton.end_escape = "\lua_escape:n{#1}" } , end-escape .value_required:n = true , end-escape .usage:n = preamble , begin-escape-math .code:n = \lua_now:e { piton.begin_escape_math = "\lua_escape:n{#1}" } , begin-escape-math .value_required:n = true , begin-escape-math .usage:n = preamble , end-escape-math .code:n = \lua_now:e { piton.end_escape_math = "\lua_escape:n{#1}" } , end-escape-math .value_required:n = true , end-escape-math .usage:n = preamble , comment-latex .code:n = \lua_now:n { comment_latex = "#1" } , comment-latex .value_required:n = true , comment-latex .usage:n = preamble , math-comments .bool_gset:N = \g_@@_math_comments_bool , math-comments .default:n = true , math-comments .usage:n = preamble , % \end{macrocode} % % \bigskip % Now, general keys. % \begin{macrocode} language .code:n = \str_set:Nx \l_piton_language_str { \str_lowercase:n { #1 } } , language .value_required:n = true , path .str_set:N = \l_@@_path_str , path .value_required:n = true , path-write .str_set:N = \l_@@_path_write_str , path-write .value_required:n = true , gobble .int_set:N = \l_@@_gobble_int , gobble .value_required:n = true , auto-gobble .code:n = \int_set:Nn \l_@@_gobble_int { -1 } , auto-gobble .value_forbidden:n = true , env-gobble .code:n = \int_set:Nn \l_@@_gobble_int { -2 } , env-gobble .value_forbidden:n = true , tabs-auto-gobble .code:n = \int_set:Nn \l_@@_gobble_int { -3 } , tabs-auto-gobble .value_forbidden:n = true , marker .code:n = \bool_lazy_or:nnTF \l_@@_in_PitonInputFile_bool \l_@@_in_PitonOptions_bool { \keys_set:nn { PitonOptions / marker } { #1 } } { \@@_error:n { Invalid~key } } , marker .value_required:n = true , line-numbers .code:n = \keys_set:nn { PitonOptions / line-numbers } { #1 } , line-numbers .default:n = true , splittable .int_set:N = \l_@@_splittable_int , splittable .default:n = 1 , background-color .clist_set:N = \l_@@_bg_color_clist , background-color .value_required:n = true , prompt-background-color .tl_set:N = \l_@@_prompt_bg_color_tl , prompt-background-color .value_required:n = true , width .code:n = \str_if_eq:nnTF { #1 } { min } { \bool_set_true:N \l_@@_width_min_bool \dim_zero:N \l_@@_width_dim } { \bool_set_false:N \l_@@_width_min_bool \dim_set:Nn \l_@@_width_dim { #1 } } , width .value_required:n = true , write .str_set:N = \l_@@_write_str , write .value_required:n = true , left-margin .code:n = \str_if_eq:nnTF { #1 } { auto } { \dim_zero:N \l_@@_left_margin_dim \bool_set_true:N \l_@@_left_margin_auto_bool } { \dim_set:Nn \l_@@_left_margin_dim { #1 } \bool_set_false:N \l_@@_left_margin_auto_bool } , left-margin .value_required:n = true , tab-size .code:n = \@@_set_tab_tl:n { #1 } , tab-size .value_required:n = true , show-spaces .bool_set:N = \l_@@_show_spaces_bool , show-spaces .default:n = true , show-spaces-in-strings .code:n = \tl_set:Nn \l_@@_space_tl { ␣ } , % U+2423 show-spaces-in-strings .value_forbidden:n = true , break-lines-in-Piton .bool_set:N = \l_@@_break_lines_in_Piton_bool , break-lines-in-Piton .default:n = true , break-lines-in-piton .bool_set:N = \l_@@_break_lines_in_piton_bool , break-lines-in-piton .default:n = true , break-lines .meta:n = { break-lines-in-piton , break-lines-in-Piton } , break-lines .value_forbidden:n = true , indent-broken-lines .bool_set:N = \l_@@_indent_broken_lines_bool , indent-broken-lines .default:n = true , end-of-broken-line .tl_set:N = \l_@@_end_of_broken_line_tl , end-of-broken-line .value_required:n = true , continuation-symbol .tl_set:N = \l_@@_continuation_symbol_tl , continuation-symbol .value_required:n = true , continuation-symbol-on-indentation .tl_set:N = \l_@@_csoi_tl , continuation-symbol-on-indentation .value_required:n = true , first-line .code:n = \@@_in_PitonInputFile:n { \int_set:Nn \l_@@_first_line_int { #1 } } , first-line .value_required:n = true , last-line .code:n = \@@_in_PitonInputFile:n { \int_set:Nn \l_@@_last_line_int { #1 } } , last-line .value_required:n = true , begin-range .code:n = \@@_in_PitonInputFile:n { \str_set:Nn \l_@@_begin_range_str { #1 } } , begin-range .value_required:n = true , end-range .code:n = \@@_in_PitonInputFile:n { \str_set:Nn \l_@@_end_range_str { #1 } } , end-range .value_required:n = true , range .code:n = \@@_in_PitonInputFile:n { \str_set:Nn \l_@@_begin_range_str { #1 } \str_set:Nn \l_@@_end_range_str { #1 } } , range .value_required:n = true , resume .meta:n = line-numbers/resume , unknown .code:n = \@@_error:n { Unknown~key~for~PitonOptions } , % deprecated all-line-numbers .code:n = \bool_set_true:N \l_@@_line_numbers_bool \bool_set_false:N \l_@@_skip_empty_lines_bool , all-line-numbers .value_forbidden:n = true , % deprecated numbers-sep .dim_set:N = \l_@@_numbers_sep_dim , numbers-sep .value_required:n = true } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_in_PitonInputFile:n #1 { \bool_if:NTF \l_@@_in_PitonInputFile_bool { #1 } { \@@_error:n { Invalid~key } } } % \end{macrocode} % % % \bigskip % \begin{macrocode} \NewDocumentCommand \PitonOptions { m } { \bool_set_true:N \l_@@_in_PitonOptions_bool \keys_set:nn { PitonOptions } { #1 } \bool_set_false:N \l_@@_in_PitonOptions_bool } % \end{macrocode} % % \bigskip % When using |\NewPitonEnvironment| a user may use |\PitonOptions| inside. % However, the set of keys available should be different that in standard % |\PitonOptions|. That's why we define a version of |\PitonOptions| with no % restrection on the set of available keys and we will link that version to % |\PitonOptions| in such environment. % \begin{macrocode} \NewDocumentCommand \@@_fake_PitonOptions { } { \keys_set:nn { PitonOptions } } % \end{macrocode} % % % % % \bigskip % \subsubsection{The numbers of the lines} % % \medskip % The following counter will be used to count the lines in the code when the % user requires the numbers of the lines to be printed (with |line-numbers|). % % \begin{macrocode} \int_new:N \g_@@_visual_line_int % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_print_number: { \hbox_overlap_left:n { { \color { gray } \footnotesize \int_to_arabic:n \g_@@_visual_line_int } \skip_horizontal:N \l_@@_numbers_sep_dim } } % \end{macrocode} % % % \bigskip % \subsubsection{The command to write on the aux file} % % % \begin{macrocode} \cs_new_protected:Npn \@@_write_aux: { \tl_if_empty:NF \g_@@_aux_tl { \iow_now:Nn \@mainaux { \ExplSyntaxOn } \iow_now:Nx \@mainaux { \tl_gset:cn { c_@@_ \int_use:N \g_@@_env_int _ tl } { \exp_not:o \g_@@_aux_tl } } \iow_now:Nn \@mainaux { \ExplSyntaxOff } } \tl_gclear:N \g_@@_aux_tl } % \end{macrocode} % % \bigskip % The following macro with be used only when the key |width| is used with the % special value~|min|. % \begin{macrocode} \cs_new_protected:Npn \@@_width_to_aux: { \tl_gput_right:Nx \g_@@_aux_tl { \dim_set:Nn \l_@@_line_width_dim { \dim_eval:n { \g_@@_tmp_width_dim } } } } % \end{macrocode} % % \bigskip % \subsubsection{The main commands and environments for the final user} % % \bigskip % \begin{macrocode} \NewDocumentCommand { \piton } { } { \peek_meaning:NTF \bgroup \@@_piton_standard \@@_piton_verbatim } % \end{macrocode} % % \begin{macrocode} \NewDocumentCommand { \@@_piton_standard } { m } { \group_begin: \ttfamily % \end{macrocode} % The following tuning of LuaTeX in order to avoid all break of lines on the % hyphens. % \begin{macrocode} \automatichyphenmode = 1 \cs_set_eq:NN \\ \c_backslash_str \cs_set_eq:NN \% \c_percent_str \cs_set_eq:NN \{ \c_left_brace_str \cs_set_eq:NN \} \c_right_brace_str \cs_set_eq:NN \$ \c_dollar_str \cs_set_eq:cN { ~ } \space \cs_set_protected:Npn \@@_begin_line: { } \cs_set_protected:Npn \@@_end_line: { } \tl_set:Nx \l_tmpa_tl { \lua_now:e { piton.ParseBis('\l_piton_language_str',token.scan_string()) } { #1 } } \bool_if:NTF \l_@@_show_spaces_bool { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 % \end{macrocode} % The following code replaces the characters U+0020 (spaces) by characters % U+0020 of catcode~10: thus, they become breakable by an end of line. % \begin{macrocode} { \bool_if:NT \l_@@_break_lines_in_piton_bool { \regex_replace_all:nnN { \x20 } { \x20 } \l_tmpa_tl } } \l_tmpa_tl \group_end: } % \end{macrocode} % % % \begin{macrocode} \NewDocumentCommand { \@@_piton_verbatim } { v } { \group_begin: \ttfamily \automatichyphenmode = 1 \cs_set_protected:Npn \@@_begin_line: { } \cs_set_protected:Npn \@@_end_line: { } \tl_set:Nx \l_tmpa_tl { \lua_now:e { piton.Parse('\l_piton_language_str',token.scan_string()) } { #1 } } \bool_if:NT \l_@@_show_spaces_bool { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 \l_tmpa_tl \group_end: } % \end{macrocode} % % \bigskip % % % \bigskip % The following command is not a user command. It will be used when we will % have to ``rescan'' some chunks of Python code. For example, it will be the % initial value of the Piton style |InitialValues| (the default values of the % arguments of a Python function). % \begin{macrocode} \cs_new_protected:Npn \@@_piton:n #1 { \group_begin: \cs_set_protected:Npn \@@_begin_line: { } \cs_set_protected:Npn \@@_end_line: { } \bool_lazy_or:nnTF \l_@@_break_lines_in_piton_bool \l_@@_break_lines_in_Piton_bool { \tl_set:Nx \l_tmpa_tl { \lua_now:e { piton.ParseTer('\l_piton_language_str',token.scan_string()) } { #1 } } } { \tl_set:Nx \l_tmpa_tl { \lua_now:e { piton.Parse('\l_piton_language_str',token.scan_string()) } { #1 } } } \bool_if:NT \l_@@_show_spaces_bool { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 \l_tmpa_tl \group_end: } % \end{macrocode} % % \bigskip % The following command is similar to the previous one but raise a fatal error if % its argument contains a carriage return. % \begin{macrocode} \cs_new_protected:Npn \@@_piton_no_cr:n #1 { \group_begin: \cs_set_protected:Npn \@@_begin_line: { } \cs_set_protected:Npn \@@_end_line: { } \cs_set_protected:Npn \@@_newline: { \msg_fatal:nn { piton } { cr~not~allowed } } \bool_lazy_or:nnTF \l_@@_break_lines_in_piton_bool \l_@@_break_lines_in_Piton_bool { \tl_set:Nx \l_tmpa_tl { \lua_now:e { piton.ParseTer('\l_piton_language_str',token.scan_string()) } { #1 } } } { \tl_set:Nx \l_tmpa_tl { \lua_now:e { piton.Parse('\l_piton_language_str',token.scan_string()) } { #1 } } } \bool_if:NT \l_@@_show_spaces_bool { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 \l_tmpa_tl \group_end: } % \end{macrocode} % % \bigskip % Despite its name, |\@@_pre_env:| will be used both in |\PitonInputFile| and % in the environments such as |{Piton}|. % \begin{macrocode} \cs_new:Npn \@@_pre_env: { \automatichyphenmode = 1 \int_gincr:N \g_@@_env_int \tl_gclear:N \g_@@_aux_tl \dim_compare:nNnT \l_@@_width_dim = \c_zero_dim { \dim_set_eq:NN \l_@@_width_dim \linewidth } % \end{macrocode} % We read the information written on the |aux| file by a previous run (when the % key |width| is used with the special value~|min|). At this time, the only % potential information written on the |aux| file is the value of % |\l_@@_line_width_dim| when the key |width| has been used with the special % value~|min|). % \begin{macrocode} \cs_if_exist_use:c { c_@@ _ \int_use:N \g_@@_env_int _ tl } \bool_if:NF \l_@@_resume_bool { \int_gzero:N \g_@@_visual_line_int } \dim_gzero:N \g_@@_tmp_width_dim \int_gzero:N \g_@@_line_int \dim_zero:N \parindent \dim_zero:N \lineskip \cs_set_eq:NN \label \@@_label:n } % \end{macrocode} % % % \bigskip % If the final user has used both |left-margin=auto| and |line-numbers|, we have % to compute the width of the maximal number of lines at the end of the % environment to fix the correct value to |left-margin|. The first argument of % the following function is the name of the Lua function that will be applied to % the second argument in order to count the number of lines. % \begin{macrocode} \cs_new_protected:Npn \@@_compute_left_margin:nn #1 #2 { \bool_lazy_and:nnT \l_@@_left_margin_auto_bool \l_@@_line_numbers_bool { \hbox_set:Nn \l_tmpa_box { \footnotesize \bool_if:NTF \l_@@_skip_empty_lines_bool { \lua_now:n { piton.#1(token.scan_argument()) } { #2 } \int_to_arabic:n { \g_@@_visual_line_int + \l_@@_nb_non_empty_lines_int } } { \int_to_arabic:n { \g_@@_visual_line_int + \l_@@_nb_lines_int } } } \dim_set:Nn \l_@@_left_margin_dim { \box_wd:N \l_tmpa_box + \l_@@_numbers_sep_dim + 0.1 em } } } \cs_generate_variant:Nn \@@_compute_left_margin:nn { n o } % \end{macrocode} % % % % \bigskip % Whereas |\l_@@_with_dim| is the width of the environment, % |\l_@@_line_width_dim| is the width of the lines of code without the % potential margins for the numbers of lines and the background. Depending on % the case, you have to compute |\l_@@_line_width_dim| from |\l_@@_width_dim| or % we have to do the opposite. % \begin{macrocode} \cs_new_protected:Npn \@@_compute_width: { \dim_compare:nNnTF \l_@@_line_width_dim = \c_zero_dim { \dim_set_eq:NN \l_@@_line_width_dim \l_@@_width_dim \clist_if_empty:NTF \l_@@_bg_color_clist % \end{macrocode} % If there is no background, we only subtract the left margin. % \begin{macrocode} { \dim_sub:Nn \l_@@_line_width_dim \l_@@_left_margin_dim } % \end{macrocode} % If there is a background, we subtract 0.5~em for the margin on the right. % \begin{macrocode} { \dim_sub:Nn \l_@@_line_width_dim { 0.5 em } % \end{macrocode} % And we subtract also for the left margin. If the key |left-margin| has been % used (with a numerical value or with the special value~|min|), % |\l_@@_left_margin_dim| has a non-zero value\footnote{If the key % \texttt{left-margin} has been used with the special value \texttt{min}, the % actual value of \texttt{\textbackslash l_\@\@_left_margin_dim} has yet been % computed when we use the current command.} and we use that value. Elsewhere, % we use a value of 0.5~em. % \begin{macrocode} \dim_compare:nNnTF \l_@@_left_margin_dim = \c_zero_dim { \dim_sub:Nn \l_@@_line_width_dim { 0.5 em } } { \dim_sub:Nn \l_@@_line_width_dim \l_@@_left_margin_dim } } } % \end{macrocode} % If |\l_@@_line_width_dim| has yet a non-zero value, that means that it has % been read in the |aux| file: it has been written by a previous run because the % key |width| is used with the special value~|min|). We compute now the width of % the environment by computations opposite to the preceding ones. % \begin{macrocode} { \dim_set_eq:NN \l_@@_width_dim \l_@@_line_width_dim \clist_if_empty:NTF \l_@@_bg_color_clist { \dim_add:Nn \l_@@_width_dim \l_@@_left_margin_dim } { \dim_add:Nn \l_@@_width_dim { 0.5 em } \dim_compare:nNnTF \l_@@_left_margin_dim = \c_zero_dim { \dim_add:Nn \l_@@_width_dim { 0.5 em } } { \dim_add:Nn \l_@@_width_dim \l_@@_left_margin_dim } } } } % \end{macrocode} % % % % \bigskip % \begin{macrocode} \NewDocumentCommand { \NewPitonEnvironment } { m m m m } { % \end{macrocode} % We construct a TeX macro which will catch as argument all the tokens until % |\end{|\texttt{\textsl{name_env}}|}| with, in that % |\end{|\texttt{\textsl{name_env}}|}|, the catcodes of |\|, |{| and |}| equal to % 12 (``\texttt{other}''). The latter explains why the definition of that % function is a bit complicated. % \begin{macrocode} \use:x { \cs_set_protected:Npn \use:c { _@@_collect_ #1 :w } ####1 \c_backslash_str end \c_left_brace_str #1 \c_right_brace_str } { \group_end: \mode_if_vertical:TF \mode_leave_vertical: \newline % \end{macrocode} % We count with Lua the number of lines of the argument. The result will be % stored by Lua in |\l_@@_nb_lines_int|. That information will be used to allow % or disallow page breaks. % \begin{macrocode} \lua_now:n { piton.CountLines(token.scan_argument()) } { ##1 } % \end{macrocode} % The first argument of the following function is the name of the Lua function % that will be applied to the second argument in order to count the number of lines. % \begin{macrocode} \@@_compute_left_margin:nn { CountNonEmptyLines } { ##1 } \@@_compute_width: \ttfamily \dim_zero:N \parskip % \end{macrocode} % |\g_@@_footnote_bool| is raised when the package \pkg{piton} has been loaded % with the key |footnote| \emph{or} the key |footnotehyper|. % \begin{macrocode} \bool_if:NT \g_@@_footnote_bool { \begin { savenotes } } % \end{macrocode} % % Now, the key |write|. % \begin{macrocode} \str_if_empty:NTF \l_@@_path_write_str { \lua_now:e { piton.write = "\l_@@_write_str" } } { \lua_now:e { piton.write = "\l_@@_path_write_str / \l_@@_write_str" } } \str_if_empty:NF \l_@@_write_str { \seq_if_in:NVTF \g_@@_write_seq \l_@@_write_str { \lua_now:n { piton.write_mode = "a" } } { \lua_now:n { piton.write_mode = "w" } \seq_gput_left:NV \g_@@_write_seq \l_@@_write_str } } \vbox \bgroup \lua_now:e { piton.GobbleParse ( '\l_piton_language_str' , \int_use:N \l_@@_gobble_int , token.scan_argument() ) } { ##1 } \vspace { 2.5 pt } \egroup \bool_if:NT \g_@@_footnote_bool { \end { savenotes } } % \end{macrocode} % If the user has used the key |width| with the special value~|min|, we write on % the |aux| file the value of |\l_@@_line_width_dim| (largest width of the lines % of code of the environment). % \begin{macrocode} \bool_if:NT \l_@@_width_min_bool \@@_width_to_aux: % \end{macrocode} % The following |\end{#1}| is only for the stack of environments of LaTeX. % \begin{macrocode} \end { #1 } \@@_write_aux: } % \end{macrocode} % % % \bigskip % We can now define the new environment. % % We are still in the definition of the command |\NewPitonEnvironment|... % \begin{macrocode} \NewDocumentEnvironment { #1 } { #2 } { \cs_set_eq:NN \PitonOptions \@@_fake_PitonOptions #3 \@@_pre_env: \int_compare:nNnT \l_@@_number_lines_start_int > \c_zero_int { \int_gset:Nn \g_@@_visual_line_int { \l_@@_number_lines_start_int - 1 } } \group_begin: \tl_map_function:nN { \ \\ \{ \} \$ \& \# \^ \_ \% \~ \^^I } \char_set_catcode_other:N \use:c { _@@_collect_ #1 :w } } { #4 } % \end{macrocode} % % \medskip % The following code is for technical reasons. We want to change the catcode of % |^^M| before catching the arguments of the new environment we are defining. % Indeed, if not, we will have problems if there is a final optional argument in % our environment (if that final argument is not used by the user in an % instance of the environment, a spurious space is inserted, probably because % the |^^M| is converted to space). % \begin{macrocode} \AddToHook { env / #1 / begin } { \char_set_catcode_other:N \^^M } } % \end{macrocode} % This is the end of the definition of the command |\NewPitonEnvironment|. % % \bigskip % Now, we define the environment |{Piton}|, which is the main environment % provided by the package \pkg{piton}. Of course, you use % |\NewPitonEnvironment|. % \begin{macrocode} \bool_if:NTF \g_@@_beamer_bool { \NewPitonEnvironment { Piton } { d < > O { } } { \keys_set:nn { PitonOptions } { #2 } \IfValueTF { #1 } { \begin { uncoverenv } < #1 > } { \begin { uncoverenv } } } { \end { uncoverenv } } } { \NewPitonEnvironment { Piton } { O { } } { \keys_set:nn { PitonOptions } { #1 } } { } } % \end{macrocode} % % % \bigskip % The code of the command |\PitonInputFile| is somewhat similar to the code of % the environment |{Piton}|. In fact, it's simpler because there isn't the % problem of catching the content of the environment in a verbatim mode. % \begin{macrocode} \NewDocumentCommand { \PitonInputFile } { d < > O { } m } { \group_begin: \tl_if_empty:NTF \l_@@_path_str { \str_set:Nn \l_@@_file_name_str { #3 } } { \str_set_eq:NN \l_@@_file_name_str \l_@@_path_str \str_put_right:Nn \l_@@_file_name_str { / #3 } } \file_if_exist:nTF { \l_@@_file_name_str } { \@@_input_file:nn { #1 } { #2 } } { \msg_error:nnn { piton } { Unknown~file } { #3 } } \group_end: } % \end{macrocode} % % The following command uses as implicit argument the name of the file in |\l_@@_file_name_str|. % \begin{macrocode} \cs_new_protected:Npn \@@_input_file:nn #1 #2 { % \end{macrocode} % We recall that, if we are in Beamer, the command |\PitonInputFile| is % ``overlay-aware'' and that's why there is an optional argument between angular % brackets (|<| and |>|). % \begin{macrocode} \tl_if_novalue:nF { #1 } { \bool_if:NTF \g_@@_beamer_bool { \begin { uncoverenv } < #1 > } { \@@_error:n { overlay~without~beamer } } } \group_begin: \int_zero_new:N \l_@@_first_line_int \int_zero_new:N \l_@@_last_line_int \int_set_eq:NN \l_@@_last_line_int \c_max_int \bool_set_true:N \l_@@_in_PitonInputFile_bool \keys_set:nn { PitonOptions } { #2 } \bool_if:NT \l_@@_line_numbers_absolute_bool { \bool_set_false:N \l_@@_skip_empty_lines_bool } \bool_if:nTF { ( \int_compare_p:nNn \l_@@_first_line_int > \c_zero_int || \int_compare_p:nNn \l_@@_last_line_int < \c_max_int ) && ! \str_if_empty_p:N \l_@@_begin_range_str } { \@@_error:n { bad~range~specification } \int_zero:N \l_@@_first_line_int \int_set_eq:NN \l_@@_last_line_int \c_max_int } { \str_if_empty:NF \l_@@_begin_range_str { \@@_compute_range: \bool_lazy_or:nnT \l_@@_marker_include_lines_bool { ! \str_if_eq_p:NN \l_@@_begin_range_str \l_@@_end_range_str } { \int_decr:N \l_@@_first_line_int \int_incr:N \l_@@_last_line_int } } } \@@_pre_env: \bool_if:NT \l_@@_line_numbers_absolute_bool { \int_gset:Nn \g_@@_visual_line_int { \l_@@_first_line_int - 1 } } \int_compare:nNnT \l_@@_number_lines_start_int > \c_zero_int { \int_gset:Nn \g_@@_visual_line_int { \l_@@_number_lines_start_int - 1 } } % \end{macrocode} % The following case arise when the code |line-numbers/absolute| is in force % without the use of a marked range. % \begin{macrocode} \int_compare:nNnT \g_@@_visual_line_int < \c_zero_int { \int_gzero:N \g_@@_visual_line_int } \mode_if_vertical:TF \mode_leave_vertical: \newline % \end{macrocode} % We count with Lua the number of lines of the argument. The result will be % stored by Lua in |\l_@@_nb_lines_int|. That information will be used to allow % or disallow page breaks. % \begin{macrocode} \lua_now:e { piton.CountLinesFile('\l_@@_file_name_str') } % \end{macrocode} % The first argument of the following function is the name of the Lua function % that will be applied to the second argument in order to count the number of lines. % \begin{macrocode} \@@_compute_left_margin:no { CountNonEmptyLinesFile } \l_@@_file_name_str \@@_compute_width: \ttfamily \bool_if:NT \g_@@_footnote_bool { \begin { savenotes } } \vtop \bgroup \lua_now:e { piton.ParseFile( '\l_piton_language_str' , '\l_@@_file_name_str' , \int_use:N \l_@@_first_line_int , \int_use:N \l_@@_last_line_int ) } \egroup \bool_if:NT \g_@@_footnote_bool { \end { savenotes } } \bool_if:NT \l_@@_width_min_bool \@@_width_to_aux: \group_end: % \end{macrocode} % We recall that, if we are in Beamer, the command |\PitonInputFile| is % ``overlay-aware'' and that's why we close now an environment |{uncoverenv}| % that we have opened at the beginning of the command. % \begin{macrocode} \tl_if_novalue:nF { #1 } { \bool_if:NT \g_@@_beamer_bool { \end { uncoverenv } } } \@@_write_aux: } % \end{macrocode} % % % \bigskip % The following command computes the values of |\l_@@_first_line_int| and % |\l_@@_last_line_int| when |\PitonInputFile| is used with textual markers. % \begin{macrocode} \cs_new_protected:Npn \@@_compute_range: { % \end{macrocode} % We store the markers in L3 strings (|str|) in order to do safely the following % replacement of |\#|. % \begin{macrocode} \str_set:Nx \l_tmpa_str { \@@_marker_beginning:n \l_@@_begin_range_str } \str_set:Nx \l_tmpb_str { \@@_marker_end:n \l_@@_end_range_str } % \end{macrocode} % We replace the sequences |\#| which may be present in the prefixes (and, more % unlikely, suffixes) added to the markers by the functions % |\@@_marker_beginning:n| and |\@@_marker_end:n| % \begin{macrocode} \exp_args:NnV \regex_replace_all:nnN { \\\# } \c_hash_str \l_tmpa_str \exp_args:NnV \regex_replace_all:nnN { \\\# } \c_hash_str \l_tmpb_str \lua_now:e { piton.ComputeRange ( '\l_tmpa_str' , '\l_tmpb_str' , '\l_@@_file_name_str' ) } } % \end{macrocode} % % \bigskip % \subsubsection{The styles} % % \medskip % The following command is fundamental: it will be used by the Lua code. % \begin{macrocode} \NewDocumentCommand { \PitonStyle } { m } { \cs_if_exist_use:cF { pitonStyle _ \l_piton_language_str _ #1 } { \use:c { pitonStyle _ #1 } } } % \end{macrocode} % % \medskip % \begin{macrocode} \NewDocumentCommand { \SetPitonStyle } { O { } m } { \str_clear_new:N \l_@@_SetPitonStyle_option_str \str_set:Nx \l_@@_SetPitonStyle_option_str { \str_lowercase:n { #1 } } \str_if_eq:onT \l_@@_SetPitonStyle_option_str { current-language } { \str_set_eq:NN \l_@@_SetPitonStyle_option_str \l_piton_language_str } \keys_set:nn { piton / Styles } { #2 } } % \end{macrocode} % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_math_scantokens:n #1 { \normalfont \scantextokens { \begin{math} #1 \end{math} } } % \end{macrocode} % % \medskip % \begin{macrocode} \clist_new:N \g_@@_styles_clist \clist_gset:Nn \g_@@_styles_clist { Comment , Comment.LaTeX , Exception , FormattingType , Identifier , InitialValues , Interpol.Inside , Keyword , Keyword.Constant , Name.Builtin , Name.Class , Name.Constructor , Name.Decorator , Name.Field , Name.Function , Name.Module , Name.Namespace , Name.Table , Name.Type , Number , Operator , Operator.Word , Preproc , Prompt , String.Doc , String.Interpol , String.Long , String.Short , TypeParameter , UserFunction } \clist_map_inline:Nn \g_@@_styles_clist { \keys_define:nn { piton / Styles } { #1 .value_required:n = true , #1 .code:n = \tl_set:cn { pitonStyle _ \str_if_empty:NF \l_@@_SetPitonStyle_option_str { \l_@@_SetPitonStyle_option_str _ } #1 } { ##1 } } } \keys_define:nn { piton / Styles } { String .meta:n = { String.Long = #1 , String.Short = #1 } , Comment.Math .tl_set:c = pitonStyle _ Comment.Math , ParseAgain .tl_set:c = pitonStyle _ ParseAgain , ParseAgain .value_required:n = true , ParseAgain.noCR .tl_set:c = pitonStyle _ ParseAgain.noCR , ParseAgain.noCR .value_required:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~SetPitonStyle } } % \end{macrocode} % % \bigskip % We add the word |String| to the list of the styles because we will use that % list in the error message for an unknown key in |\SetPitonStyle|. % % \begin{macrocode} \clist_gput_left:Nn \g_@@_styles_clist { String } % \end{macrocode} % % \bigskip % Of course, we sort that clist. % \begin{macrocode} \clist_gsort:Nn \g_@@_styles_clist { \str_compare:nNnTF { #1 } < { #2 } \sort_return_same: \sort_return_swapped: } % \end{macrocode} % % % \bigskip % \subsubsection{The initial styles} % % The initial styles are inspired by the style ``manni'' of Pygments. % % \medskip % \begin{macrocode} \SetPitonStyle { Comment = \color[HTML]{0099FF} \itshape , Exception = \color[HTML]{CC0000} , Keyword = \color[HTML]{006699} \bfseries , Keyword.Constant = \color[HTML]{006699} \bfseries , Name.Builtin = \color[HTML]{336666} , Name.Decorator = \color[HTML]{9999FF}, Name.Class = \color[HTML]{00AA88} \bfseries , Name.Function = \color[HTML]{CC00FF} , Name.Namespace = \color[HTML]{00CCFF} , Name.Constructor = \color[HTML]{006000} \bfseries , Name.Field = \color[HTML]{AA6600} , Name.Module = \color[HTML]{0060A0} \bfseries , Name.Table = \color[HTML]{309030} , Number = \color[HTML]{FF6600} , Operator = \color[HTML]{555555} , Operator.Word = \bfseries , String = \color[HTML]{CC3300} , String.Doc = \color[HTML]{CC3300} \itshape , String.Interpol = \color[HTML]{AA0000} , Comment.LaTeX = \normalfont \color[rgb]{.468,.532,.6} , Name.Type = \color[HTML]{336666} , InitialValues = \@@_piton:n , Interpol.Inside = \color{black}\@@_piton:n , TypeParameter = \color[HTML]{336666} \itshape , Preproc = \color[HTML]{AA6600} \slshape , Identifier = \@@_identifier:n , UserFunction = , Prompt = , ParseAgain.noCR = \@@_piton_no_cr:n , ParseAgain = \@@_piton:n , } % \end{macrocode} % The last styles |ParseAgain.noCR| and |ParseAgain| should be considered as % ``internal style'' (not available for the final user). However, maybe we will % change that and document these styles for the final user (why not?). % % \medskip % If the key |math-comments| has been used at load-time, we change the style % |Comment.Math| which should be considered only at an ``internal style''. % However, maybe we will document in a future version the possibility to write % change the style \emph{locally} in a document)]. % \begin{macrocode} \AtBeginDocument { \bool_if:NT \g_@@_math_comments_bool { \SetPitonStyle { Comment.Math = \@@_math_scantokens:n } } } % \end{macrocode} % % \bigskip % % \bigskip % \subsubsection{Highlighting some identifiers} % % % \medskip % \begin{macrocode} \NewDocumentCommand { \SetPitonIdentifier } { o m m } { \clist_set:Nn \l_tmpa_clist { #2 } \IfNoValueTF { #1 } { \clist_map_inline:Nn \l_tmpa_clist { \cs_set:cpn { pitonIdentifier _ ##1 } { #3 } } } { \str_set:Nx \l_tmpa_str { \str_lowercase:n { #1 } } \str_if_eq:onT \l_tmpa_str { current-language } { \str_set_eq:NN \l_tmpa_str \l_piton_language_str } \clist_map_inline:Nn \l_tmpa_clist { \cs_set:cpn { pitonIdentifier _ \l_tmpa_str _ ##1 } { #3 } } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_identifier:n #1 { \cs_if_exist_use:cF { pitonIdentifier _ \l_piton_language_str _ #1 } { \cs_if_exist_use:c { pitonIdentifier_ #1 } } { #1 } } % \end{macrocode} % % \bigskip % \begin{macrocode} \keys_define:nn { PitonOptions } { identifiers .code:n = \@@_set_identifiers:n { #1 } } % \end{macrocode} % % \bigskip % \begin{macrocode} \keys_define:nn { Piton / identifiers } { names .clist_set:N = \l_@@_identifiers_names_tl , style .tl_set:N = \l_@@_style_tl , } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_set_identifiers:n #1 { \@@_error:n { key~identifiers~deprecated } \@@_gredirect_none:n { key~identifiers~deprecated } \clist_clear_new:N \l_@@_identifiers_names_tl \tl_clear_new:N \l_@@_style_tl \keys_set:nn { Piton / identifiers } { #1 } \clist_map_inline:Nn \l_@@_identifiers_names_tl { \tl_set_eq:cN { PitonIdentifier _ \l_piton_language_str _ ##1 } \l_@@_style_tl } } % \end{macrocode} % % % \bigskip % In particular, we have an highlighting of the indentifiers which are the % names of Python functions previously defined by the user. Indeed, when a % Python function is defined, the style |Name.Function.Internal| is applied to % that name. We define now that style (you define it directly and you short-cut % the function |\SetPitonStyle|). % \begin{macrocode} \cs_new_protected:cpn { pitonStyle _ Name.Function.Internal } #1 { % \end{macrocode} % First, the element is composed in the TeX flow with the style |Name.Function| % which is provided to the final user. % \begin{macrocode} { \PitonStyle { Name.Function } { #1 } } % \end{macrocode} % Now, we specify that the name of the new Python function is a known identifier % that will be formated with the Piton style |UserFunction|. Of course, % here the affectation is global because we have to exit many groups and even % the environments |{Piton}|). % \begin{macrocode} \cs_gset_protected:cpn { PitonIdentifier _ \l_piton_language_str _ #1 } { \PitonStyle { UserFunction } } % \end{macrocode} % Now, we put the name of that new user function in the dedicated sequence % (specific of the current language). {\bfseries That sequence will be used only % by |\PitonClearUserFunctions|}. % \begin{macrocode} \seq_if_exist:cF { g_@@_functions _ \l_piton_language_str _ seq } { \seq_new:c { g_@@_functions _ \l_piton_language_str _ seq } } \seq_gput_right:cn { g_@@_functions _ \l_piton_language_str _ seq } { #1 } % \end{macrocode} % We update |\g_@@_languages_seq| which is used only by the command % |\PitonClearUserFunctions| when it's used without its optional argument. % \begin{macrocode} \seq_if_in:NVF \g_@@_languages_seq \l_piton_language_str { \seq_gput_left:NV \g_@@_languages_seq \l_piton_language_str } } % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentCommand \PitonClearUserFunctions { ! o } { \tl_if_novalue:nTF { #1 } % \end{macrocode} % If the command is used without its optional argument, we will deleted the % user language for all the informatic languages. % \begin{macrocode} { \@@_clear_all_functions: } { \@@_clear_list_functions:n { #1 } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_clear_list_functions:n #1 { \clist_set:Nn \l_tmpa_clist { #1 } \clist_map_function:NN \l_tmpa_clist \@@_clear_functions_i:n \clist_map_inline:nn { #1 } { \seq_gremove_all:Nn \g_@@_languages_seq { ##1 } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_clear_functions_i:n #1 { \exp_args:Ne \@@_clear_functions_ii:n { \str_lowercase:n { #1 } } } % \end{macrocode} % % The following command clears the list of the user-defined functions for the % language provided in argument (mandatory in lower case). % \begin{macrocode} \cs_new_protected:Npn \@@_clear_functions_ii:n #1 { \seq_if_exist:cT { g_@@_functions _ #1 _ seq } { \seq_map_inline:cn { g_@@_functions _ #1 _ seq } { \cs_undefine:c { PitonIdentifier _ #1 _ ##1} } \seq_gclear:c { g_@@_functions _ #1 _ seq } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_clear_functions:n #1 { \@@_clear_functions_i:n { #1 } \seq_gremove_all:Nn \g_@@_languages_seq { #1 } } % \end{macrocode} % % \bigskip % The following command clears all the user-defined functions for all the % informatic languages. % \begin{macrocode} \cs_new_protected:Npn \@@_clear_all_functions: { \seq_map_function:NN \g_@@_languages_seq \@@_clear_functions_i:n \seq_gclear:N \g_@@_languages_seq } % \end{macrocode} % % \bigskip % \subsubsection{Security} % % \begin{macrocode} \AddToHook { env / piton / begin } { \msg_fatal:nn { piton } { No~environment~piton } } \msg_new:nnn { piton } { No~environment~piton } { There~is~no~environment~piton!\\ There~is~an~environment~{Piton}~and~a~command~ \token_to_str:N \piton\ but~there~is~no~environment~ {piton}.~This~error~is~fatal. } % \end{macrocode} % % \bigskip % \subsubsection{The error messages of the package} % % \begin{macrocode} \@@_msg_new:nn { key~identifiers~deprecated } { The~key~'identifiers'~in~the~command~\token_to_str:N PitonOptions\ is~now~deprecated:~you~should~use~the~command~ \token_to_str:N \SetPitonIdentifier\ instead.\\ However,~you~can~go~on. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Unknown~key~for~SetPitonStyle } { The~style~'\l_keys_key_str'~is~unknown.\\ This~key~will~be~ignored.\\ The~available~styles~are~(in~alphabetic~order):~ \clist_use:Nnnn \g_@@_styles_clist { ~and~ } { ,~ } { ~and~ }. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Invalid~key } { Wrong~use~of~key.\\ You~can't~use~the~key~'\l_keys_key_str'~here.\\ That~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Unknown~key~for~line-numbers } { Unknown~key. \\ The~key~'line-numbers / \l_keys_key_str'~is~unknown.\\ The~available~keys~of~the~family~'line-numbers'~are~(in~ alphabetic~order):~ absolute,~false,~label-empty-lines,~resume,~skip-empty-lines,~ sep,~start~and~true.\\ That~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Unknown~key~for~marker } { Unknown~key. \\ The~key~'marker / \l_keys_key_str'~is~unknown.\\ The~available~keys~of~the~family~'marker'~are~(in~ alphabetic~order):~ beginning,~end~and~include-lines.\\ That~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { bad~range~specification } { Incompatible~keys.\\ You~can't~specify~the~range~of~lines~to~include~by~using~both~ markers~and~explicit~number~of~lines.\\ Your~whole~file~'\l_@@_file_name_str'~will~be~included. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { syntax~error } { Your~code~of~the~language~"\l_piton_language_str"~is~not~syntactically~correct.\\ It~won't~be~printed~in~the~PDF~file. } % \end{macrocode} % % \begin{macrocode} \NewDocumentCommand \PitonSyntaxError { } { \@@_error:n { syntax~error } } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { begin~marker~not~found } { Marker~not~found.\\ The~range~'\l_@@_begin_range_str'~provided~to~the~ command~\token_to_str:N \PitonInputFile\ has~not~been~found.~ The~whole~file~'\l_@@_file_name_str'~will~be~inserted. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { end~marker~not~found } { Marker~not~found.\\ The~marker~of~end~of~the~range~'\l_@@_end_range_str'~ provided~to~the~command~\token_to_str:N \PitonInputFile\ has~not~been~found.~The~file~'\l_@@_file_name_str'~will~ be~inserted~till~the~end. } % \end{macrocode} % % % \begin{macrocode} \NewDocumentCommand \PitonBeginMarkerNotFound { } { \@@_error:n { begin~marker~not~found } } \NewDocumentCommand \PitonEndMarkerNotFound { } { \@@_error:n { end~marker~not~found } } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Unknown~file } { Unknown~file. \\ The~file~'#1'~is~unknown.\\ Your~command~\token_to_str:N \PitonInputFile\ will~be~discarded. } % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { piton } { Unknown~key~for~PitonOptions } { Unknown~key. \\ The~key~'\l_keys_key_str'~is~unknown~for~\token_to_str:N \PitonOptions.~ It~will~be~ignored.\\ For~a~list~of~the~available~keys,~type~H~. } { The~available~keys~are~(in~alphabetic~order):~ auto-gobble,~ background-color,~ break-lines,~ break-lines-in-piton,~ break-lines-in-Piton,~ continuation-symbol,~ continuation-symbol-on-indentation,~ detected-commands,~ end-of-broken-line,~ end-range,~ env-gobble,~ gobble,~ indent-broken-lines,~ language,~ left-margin,~ line-numbers/,~ marker/,~ math-comments,~ path,~ path-write,~ prompt-background-color,~ resume,~ show-spaces,~ show-spaces-in-strings,~ splittable,~ tabs-auto-gobble,~ tab-size,~ width~and~write. } % \end{macrocode} % % \bigskip % \begin{macrocode} \@@_msg_new:nn { label~with~lines~numbers } { You~can't~use~the~command~\token_to_str:N \label\ because~the~key~'line-numbers'~is~not~active.\\ If~you~go~on,~that~command~will~ignored. } % \end{macrocode} % % \bigskip % \begin{macrocode} \@@_msg_new:nn { cr~not~allowed } { You~can't~put~any~carriage~return~in~the~argument~ of~a~command~\c_backslash_str \l_@@_beamer_command_str\ within~an~ environment~of~'piton'.~You~should~consider~using~the~ corresponding~environment.\\ That~error~is~fatal. } % \end{macrocode} % % \bigskip % \begin{macrocode} \@@_msg_new:nn { overlay~without~beamer } { You~can't~use~an~argument~<...>~for~your~command~ \token_to_str:N \PitonInputFile\ because~you~are~not~ in~Beamer.\\ If~you~go~on,~that~argument~will~be~ignored. } % \end{macrocode} % % % \bigskip % \subsubsection{We load piton.lua} % % \bigskip % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \lua_now:e { require("piton.lua") } } % \end{macrocode} % % \bigskip % \subsubsection{Detected commands} % % % \begin{macrocode} \ExplSyntaxOff \begin{luacode*} lpeg.locale(lpeg) local P , alpha , C , space , S , V = lpeg.P , lpeg.alpha , lpeg.C , lpeg.space , lpeg.S , lpeg.V local function add(...) local s = P ( false ) for _ , x in ipairs({...}) do s = s + x end return s end local my_lpeg = P { "E" , E = ( V "F" * ( P "," * V "F" ) ^ 0 ) / add , F = space ^ 0 * ( alpha ^ 1 ) / "\\%0" * space ^ 0 } function piton.addListCommands( key_value ) piton.ListCommands = piton.ListCommands + my_lpeg : match ( key_value ) end \end{luacode*} % % \end{macrocode} % % % \bigskip % \subsection{The Lua part of the implementation} % % \bigskip % The Lua code will be loaded via a |{luacode*}| environment. The environment % is by itself a Lua block and the local declarations will be local to that % block. All the global functions (used by the L3 parts of the implementation) % will be put in a Lua table |piton|. % % % \begin{macrocode} %<*LUA> if piton.comment_latex == nil then piton.comment_latex = ">" end piton.comment_latex = "#" .. piton.comment_latex % \end{macrocode} % % % \bigskip % The following functions are an easy way to safely insert braces (|{| and |}|) % in the TeX flow. % \begin{macrocode} function piton.open_brace () tex.sprint("{") end function piton.close_brace () tex.sprint("}") end % \end{macrocode} % % \bigskip % \subsubsection{Special functions dealing with LPEG} % % \medskip % We will use the Lua library \pkg{lpeg} which is built in LuaTeX. That's why we % define first aliases for several functions of that library. % \begin{macrocode} local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc local Cs , Cg , Cmt , Cb = lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb local R = lpeg.R % \end{macrocode} % % % % \bigskip % The function |Q| takes in as argument a pattern and returns a \textsc{lpeg} % \emph{which does a capture} of the pattern. That capture will be sent to LaTeX % with the catcode ``other'' for all the characters: it's suitable for elements % of the Python listings that \pkg{piton} will typeset verbatim (thanks to the % catcode ``other''). % \begin{macrocode} local function Q(pattern) return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther ) * C ( pattern ) ) end % \end{macrocode} % % % \bigskip % The function |L| takes in as argument a pattern and returns a \textsc{lpeg} % \emph{which does a capture} of the pattern. That capture will be sent to LaTeX % with standard LaTeX catcodes for all the characters: the elements captured % will be formatted as normal LaTeX codes. It's suitable for the ``LaTeX % comments'' in the environments |{Piton}| and the elements beetween % |begin-escape| and |end-escape|. That function won't be much used. % \begin{macrocode} local function L(pattern) return Ct ( C ( pattern ) ) end % \end{macrocode} % % \bigskip % The function |Lc| (the c is for \emph{constant}) takes in as argument a string % and returns a \textsc{lpeg} \emph{with does a constant capture} which returns % that string. The elements captured will be formatted as L3 code. It will be % used to send to LaTeX all the formatting LaTeX instructions we have to insert % in order to do the syntactic highlighting (that's the main job of % \pkg{piton}). That function will be widely used. % \begin{macrocode} local function Lc(string) return Cc ( { luatexbase.catcodetables.expl , string } ) end % \end{macrocode} % % \bigskip % The function |K| creates a \textsc{lpeg} which will return as capture the % whole LaTeX code corresponding to a Python chunk (that is to say with the % LaTeX formatting instructions corresponding to the syntactic nature of that % Python chunk). The first argument is a Lua string corresponding to the name of % a \pkg{piton} style and the second element is a pattern (that is to say a % \textsc{lpeg} without capture) % \begin{macrocode} local function K(style, pattern) return Lc ( "{\\PitonStyle{" .. style .. "}{" ) * Q ( pattern ) * Lc ( "}}" ) end % \end{macrocode} % The formatting commands in a given \pkg{piton} style (eg. the style |Keyword|) % may be semi-global declarations (such as |\bfseries| or |\slshape|) or LaTeX % macros with an argument (such as |\fbox| or |\colorbox{yellow}|). In order to % deal with both syntaxes, we have used two pairs of braces: % |{\PitonStyle{Keyword}{|\texttt{\slshape text to format}|}}|. % % % \bigskip % The following function |WithStyle| is similar to the function |K| but should % be used for multi-lines elements. % \begin{macrocode} local function WithStyle(style,pattern) return Ct ( Cc "Open" * Cc ( "{\\PitonStyle{" .. style .. "}{" ) * Cc "}}" ) * pattern * Ct ( Cc "Close" ) end % \end{macrocode} % % \bigskip % The following \textsc{lpeg} catches the Python chunks which are in LaTeX % escapes (and that chunks will be considered as normal LaTeX constructions). % \begin{macrocode} Escape = P ( false ) EscapeClean = P ( false ) if piton.begin_escape ~= nil then Escape = P(piton.begin_escape) * L ( ( 1 - P(piton.end_escape) ) ^ 1 ) * P(piton.end_escape) % \end{macrocode} % The LPEG |EscapeClean| will be used in the LPEG Clean (and that LPEG is used % to ``clean'' the code by removing the formatting elements). % \begin{macrocode} EscapeClean = P(piton.begin_escape) * ( 1 - P(piton.end_escape) ) ^ 1 * P(piton.end_escape) end % \end{macrocode} % % \begin{macrocode} EscapeMath = P ( false ) if piton.begin_escape_math ~= nil then EscapeMath = P(piton.begin_escape_math) * Lc ( "\\ensuremath{" ) * L ( ( 1 - P(piton.end_escape_math) ) ^ 1 ) * Lc ( "}" ) * P(piton.end_escape_math) end % \end{macrocode} % % \vspace{1cm} % The following line is mandatory. % \begin{macrocode} lpeg.locale(lpeg) % \end{macrocode} % % \bigskip % \paragraph{The basic syntactic LPEG} % % \begin{macrocode} local alpha, digit = lpeg.alpha, lpeg.digit local space = P " " % \end{macrocode} % % Remember that, for \textsc{lpeg}, the Unicode characters such as |à|, |â|, % |ç|, etc. are in fact strings of length 2 (2 bytes) because \pkg{lpeg} is not % Unicode-aware. % \begin{macrocode} local letter = alpha + P "_" + P "â" + P "à" + P "ç" + P "é" + P "è" + P "ê" + P "ë" + P "ï" + P "î" + P "ô" + P "û" + P "ü" + P "Â" + P "À" + P "Ç" + P "É" + P "È" + P "Ê" + P "Ë" + P "Ï" + P "Î" + P "Ô" + P "Û" + P "Ü" local alphanum = letter + digit % \end{macrocode} % % \bigskip % The following \textsc{lpeg} |identifier| is a mere pattern (that is to say % more or less a regular expression) which matches the Python identifiers (hence % the name). % \begin{macrocode} local identifier = letter * alphanum ^ 0 % \end{macrocode} % % \medskip % On the other hand, the \textsc{lpeg} |Identifier| (with a capital) also returns % a \emph{capture}. % \begin{macrocode} local Identifier = K ( 'Identifier' , identifier ) % \end{macrocode} % % \bigskip % By convention, we will use names with an initial capital for \textsc{lpeg} % which return captures. % % % \bigskip % Here is the first use of our function~|K|. That function will be used to % construct \textsc{lpeg} which capture Python chunks for which we have a % dedicated \pkg{piton} style. For example, for the numbers, \pkg{piton} % provides a style which is called |Number|. The name of the style is provided % as a Lua string in the second argument of the function~|K|. By convention, we % use single quotes for delimiting the Lua strings which are names of % \pkg{piton} styles (but this is only a convention). % \begin{macrocode} local Number = K ( 'Number' , ( digit^1 * P "." * digit^0 + digit^0 * P "." * digit^1 + digit^1 ) * ( S "eE" * S "+-" ^ -1 * digit^1 ) ^ -1 + digit^1 ) % \end{macrocode} % % \bigskip % We recall that |piton.begin_espace| and |piton_end_escape| are Lua strings % corresponding to the keys |begin-escape| and |end-escape|. % \begin{macrocode} local Word if piton.begin_escape ~= nil then Word = Q ( ( ( 1 - space - P(piton.begin_escape) - P(piton.end_escape) ) - S "'\"\r[({})]" - digit ) ^ 1 ) else Word = Q ( ( ( 1 - space ) - S "'\"\r[({})]" - digit ) ^ 1 ) end % \end{macrocode} % % \bigskip % \begin{macrocode} local Space = ( Q " " ) ^ 1 local SkipSpace = ( Q " " ) ^ 0 local Punct = Q ( S ".,:;!" ) local Tab = P "\t" * Lc ( '\\l_@@_tab_tl' ) % \end{macrocode} % % \bigskip % \begin{macrocode} local SpaceIndentation = Lc ( '\\@@_an_indentation_space:' ) * ( Q " " ) % \end{macrocode} % % % \bigskip % \begin{macrocode} local Delim = Q ( S "[({})]" ) % \end{macrocode} % % \bigskip % The following \textsc{lpeg} catches a space (U+0020) and replace it by % |\l_@@_space_tl|. It will be used in the strings. Usually, % |\l_@@_space_tl| will contain a space and therefore there won't be difference. % However, when the key |show-spaces-in-strings| is in force, |\\l_@@_space_tl| will % contain ␣ (U+2423) in order to visualize the spaces. % \begin{macrocode} local VisualSpace = space * Lc "\\l_@@_space_tl" % \end{macrocode} % % \bigskip % If the classe Beamer is used, some environemnts and commands of Beamer are % automatically detected in the listings of \pkg{piton}. % \begin{macrocode} local Beamer = P ( false ) local BeamerBeginEnvironments = P ( true ) local BeamerEndEnvironments = P ( true ) if piton_beamer then % \bigskip % The following function will return a \textsc{lpeg} which will catch an % environment of Beamer (supported by \pkg{piton}), that is to say |{uncover}|, % |{only}|, etc. % \begin{macrocode} local BeamerNamesEnvironments = P "uncoverenv" + P "onlyenv" + P "visibleenv" + P "invisibleenv" + P "alertenv" + P "actionenv" BeamerBeginEnvironments = ( space ^ 0 * L ( P "\\begin{" * BeamerNamesEnvironments * "}" * ( P "<" * ( 1 - P ">" ) ^ 0 * P ">" ) ^ -1 ) * P "\r" ) ^ 0 BeamerEndEnvironments = ( space ^ 0 * L ( P "\\end{" * BeamerNamesEnvironments * P "}" ) * P "\r" ) ^ 0 % \end{macrocode} % % % \bigskip % The following function will return a \textsc{lpeg} which will catch an % environment of Beamer (supported by \pkg{piton}), that is to say % |{uncoverenv}|, etc. The argument |lpeg| should be |MainLoopPython|, % |MainLoopC|, etc. % \begin{macrocode} function OneBeamerEnvironment(name,lpeg) return Ct ( Cc "Open" * C ( P ( "\\begin{" .. name .. "}" ) * ( P "<" * ( 1 - P ">") ^ 0 * P ">" ) ^ -1 ) * Cc ( "\\end{" .. name .. "}" ) ) * ( ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 ) / ( function (s) return lpeg : match(s) end ) ) * P ( "\\end{" .. name .. "}" ) * Ct ( Cc "Close" ) end end % \end{macrocode} % % % % \bigskip % \begin{macrocode} local languages = { } local CleanLPEGs = { } % \end{macrocode} % % \bigskip % \subsubsection{The LPEG python} % % \bigskip % Some strings of length 2 are explicit because we want the corresponding % ligatures available in some fonts such as \emph{Fira Code} to be active. % \begin{macrocode} local Operator = K ( 'Operator' , P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":=" + P "//" + P "**" + S "-~+/*%=<>&.@|" ) local OperatorWord = K ( 'Operator.Word' , P "in" + P "is" + P "and" + P "or" + P "not" ) local Keyword = K ( 'Keyword' , P "as" + P "assert" + P "break" + P "case" + P "class" + P "continue" + P "def" + P "del" + P "elif" + P "else" + P "except" + P "exec" + P "finally" + P "for" + P "from" + P "global" + P "if" + P "import" + P "lambda" + P "non local" + P "pass" + P "return" + P "try" + P "while" + P "with" + P "yield" + P "yield from" ) + K ( 'Keyword.Constant' ,P "True" + P "False" + P "None" ) local Builtin = K ( 'Name.Builtin' , P "__import__" + P "abs" + P "all" + P "any" + P "bin" + P "bool" + P "bytearray" + P "bytes" + P "chr" + P "classmethod" + P "compile" + P "complex" + P "delattr" + P "dict" + P "dir" + P "divmod" + P "enumerate" + P "eval" + P "filter" + P "float" + P "format" + P "frozenset" + P "getattr" + P "globals" + P "hasattr" + P "hash" + P "hex" + P "id" + P "input" + P "int" + P "isinstance" + P "issubclass" + P "iter" + P "len" + P "list" + P "locals" + P "map" + P "max" + P "memoryview" + P "min" + P "next" + P "object" + P "oct" + P "open" + P "ord" + P "pow" + P "print" + P "property" + P "range" + P "repr" + P "reversed" + P "round" + P "set" + P "setattr" + P "slice" + P "sorted" + P "staticmethod" + P "str" + P "sum" + P "super" + P "tuple" + P "type" + P "vars" + P "zip" ) local Exception = K ( 'Exception' , P "ArithmeticError" + P "AssertionError" + P "AttributeError" + P "BaseException" + P "BufferError" + P "BytesWarning" + P "DeprecationWarning" + P "EOFError" + P "EnvironmentError" + P "Exception" + P "FloatingPointError" + P "FutureWarning" + P "GeneratorExit" + P "IOError" + P "ImportError" + P "ImportWarning" + P "IndentationError" + P "IndexError" + P "KeyError" + P "KeyboardInterrupt" + P "LookupError" + P "MemoryError" + P "NameError" + P "NotImplementedError" + P "OSError" + P "OverflowError" + P "PendingDeprecationWarning" + P "ReferenceError" + P "ResourceWarning" + P "RuntimeError" + P "RuntimeWarning" + P "StopIteration" + P "SyntaxError" + P "SyntaxWarning" + P "SystemError" + P "SystemExit" + P "TabError" + P "TypeError" + P "UnboundLocalError" + P "UnicodeDecodeError" + P "UnicodeEncodeError" + P "UnicodeError" + P "UnicodeTranslateError" + P "UnicodeWarning" + P "UserWarning" + P "ValueError" + P "VMSError" + P "Warning" + P "WindowsError" + P "ZeroDivisionError" + P "BlockingIOError" + P "ChildProcessError" + P "ConnectionError" + P "BrokenPipeError" + P "ConnectionAbortedError" + P "ConnectionRefusedError" + P "ConnectionResetError" + P "FileExistsError" + P "FileNotFoundError" + P "InterruptedError" + P "IsADirectoryError" + P "NotADirectoryError" + P "PermissionError" + P "ProcessLookupError" + P "TimeoutError" + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" ) local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q ( P "(" ) % \end{macrocode} % % \bigskip % In Python, a ``decorator'' is a statement whose begins by |@| which patches % the function defined in the following statement. % \begin{macrocode} local Decorator = K ( 'Name.Decorator' , P "@" * letter^1 ) % \end{macrocode} % % \bigskip % The following \textsc{lpeg} |DefClass| will be used to detect the definition of a % new class (the name of that new class will be formatted with the \pkg{piton} % style |Name.Class|). % % \smallskip % Example:\enskip \piton{class myclass:} % \begin{macrocode} local DefClass = K ( 'Keyword' , P "class" ) * Space * K ( 'Name.Class' , identifier ) % \end{macrocode} % % If the word |class| is not followed by a identifier, it will be catched as % keyword by the \textsc{lpeg} |Keyword| (useful if we want to type a % list of keywords). % % % \bigskip % The following \textsc{lpeg} |ImportAs| is used for the lines beginning by |import|. % % We have to detect the potential keyword |as| because both the name of the % module and its alias must be formatted with the \pkg{piton} style |Name.Namespace|. % % \smallskip % Example:\enskip \piton{import numpy as np} % % \smallskip % Moreover, after the keyword |import|, it's possible to have a comma-separated % list of modules (if the keyword |as| is not used). % % \smallskip % Example:\enskip \piton{import math, numpy} % \begin{macrocode} local ImportAs = K ( 'Keyword' , P "import" ) * Space * K ( 'Name.Namespace' , identifier * ( P "." * identifier ) ^ 0 ) * ( ( Space * K ( 'Keyword' , P "as" ) * Space * K ( 'Name.Namespace' , identifier ) ) + ( SkipSpace * Q ( P "," ) * SkipSpace * K ( 'Name.Namespace' , identifier ) ) ^ 0 ) % \end{macrocode} % Be careful: there is no commutativity of |+| in the previous expression. % % \bigskip % The \textsc{lpeg} |FromImport| is used for the lines beginning by |from|. We % need a special treatment because the identifier following the keyword |from| % must be formatted with the \pkg{piton} style |Name.Namespace| and the % following keyword |import| must be formatted with the \pkg{piton} style % |Keyword| and must \emph{not} be catched by the \textsc{lpeg} |ImportAs|. % % \smallskip % Example:\enskip \piton{from math import pi} % % \smallskip % \begin{macrocode} local FromImport = K ( 'Keyword' , P "from" ) * Space * K ( 'Name.Namespace' , identifier ) * Space * K ( 'Keyword' , P "import" ) % \end{macrocode} % % \bigskip % \paragraph{The strings of Python} % % For the strings in Python, there are four categories of delimiters (without % counting the prefixes for f-strings and raw strings). We will use, in the % names of our \textsc{lpeg}, prefixes to distinguish the \textsc{lpeg} dealing % with that categories of strings, as presented in the following tabular. % \begin{center} % \begin{tabular}{@{}lcc@{}} % \toprule % & |Single| & |Double| \\ % \midrule % |Short| & |'text'| & |"text"| \\ % |Long| & |'''test'''| & |"""text"""| \\ % \bottomrule % \end{tabular} % \end{center} % % % \bigskip % We have also to deal with the interpolations in the f-strings. Here % is an example of a f-string with an interpolation and a format % instruction\footnote{There is no special \pkg{piton} style for the formatting % instruction (after the colon): the style which will be applied will be the % style of the encompassing string, that is to say |String.Short| or % |String.Long|.} in that interpolation: % % \piton{f'Total price: {total+1:.2f} €'} % % % \bigskip % The interpolations beginning by |%| (even though there is more modern % technics now in Python). % \begin{macrocode} local PercentInterpol = K ( 'String.Interpol' , P "%" * ( P "(" * alphanum ^ 1 * P ")" ) ^ -1 * ( S "-#0 +" ) ^ 0 * ( digit ^ 1 + P "*" ) ^ -1 * ( P "." * ( digit ^ 1 + P "*" ) ) ^ -1 * ( S "HlL" ) ^ -1 * S "sdfFeExXorgiGauc%" ) % \end{macrocode} % % \bigskip % We can now define the \textsc{lpeg} for the four kinds of strings. It's not % possible to use our function~|K| because of the interpolations which must be % formatted with another \pkg{piton} style that the rest of the % string.\footnote{The interpolations are formatted with the \pkg{piton} style % |Interpol.Inside|. The initial value of that style is \texttt{\textbackslash % @@\_piton:n} wich means that the interpolations are parsed once again by \pkg{piton}.} % \begin{macrocode} local SingleShortString = WithStyle ( 'String.Short' , % \end{macrocode} % First, we deal with the f-strings of Python, which are prefixed by |f| or |F|. % \begin{macrocode} Q ( P "f'" + P "F'" ) * ( K ( 'String.Interpol' , P "{" ) * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0 ) * Q ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1 * K ( 'String.Interpol' , P "}" ) + VisualSpace + Q ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 ) ) ^ 0 * Q ( P "'" ) + % \end{macrocode} % Now, we deal with the standard strings of Python, but also the ``raw strings''. % \begin{macrocode} Q ( P "'" + P "r'" + P "R'" ) * ( Q ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 ) + VisualSpace + PercentInterpol + Q ( P "%" ) ) ^ 0 * Q ( P "'" ) ) local DoubleShortString = WithStyle ( 'String.Short' , Q ( P "f\"" + P "F\"" ) * ( K ( 'String.Interpol' , P "{" ) * K ( 'Interpol.Inside' , ( 1 - S "}\":" ) ^ 0 ) * ( K ( 'String.Interpol' , P ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1 * K ( 'String.Interpol' , P "}" ) + VisualSpace + Q ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 ) ) ^ 0 * Q ( P "\"" ) + Q ( P "\"" + P "r\"" + P "R\"" ) * ( Q ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 ) + VisualSpace + PercentInterpol + Q ( P "%" ) ) ^ 0 * Q ( P "\"" ) ) local ShortString = SingleShortString + DoubleShortString % \end{macrocode} % % \bigskip % \paragraph{Beamer} % % The following pattern |balanced_braces| will be used for the (mandatory) % argument of the commands |\only| and \emph{al.} of Beamer. It's necessary to % use a \emph{grammar} because that pattern mainly checks the correct nesting of % the delimiters (and it's known in the theory of formal languages that this % can't be done with regular expressions \emph{stricto sensu} only). % \begin{macrocode} local balanced_braces = P { "E" , E = ( P "{" * V "E" * P "}" + ShortString + ( 1 - S "{}" ) ) ^ 0 } % \end{macrocode} % % \bigskip % \begin{macrocode} if piton_beamer then Beamer = L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 ) + Ct ( Cc "Open" * C ( ( P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible" + P "\\invisible" + P "\\action" ) * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" ) * Cc "}" ) * ( balanced_braces / (function (s) return MainLoopPython:match(s) end ) ) * P "}" * Ct ( Cc "Close" ) + OneBeamerEnvironment ( "uncoverenv" , MainLoopPython ) + OneBeamerEnvironment ( "onlyenv" , MainLoopPython ) + OneBeamerEnvironment ( "visibleenv" , MainLoopPython ) + OneBeamerEnvironment ( "invisibleenv" , MainLoopPython ) + OneBeamerEnvironment ( "alertenv" , MainLoopPython ) + OneBeamerEnvironment ( "actionenv" , MainLoopPython ) + L ( % \end{macrocode} % For |\\alt|, the specification of the overlays (between angular brackets) is mandatory. % \begin{macrocode} ( P "\\alt" ) * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}" ) + L ( % \end{macrocode} % For |\\temporal|, the specification of the overlays (between angular brackets) is mandatory. % \begin{macrocode} ( P "\\temporal" ) * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}" ) end % \end{macrocode} % % \bigskip % \paragraph{Detected commands} % % \begin{macrocode} DetectedCommands = Ct ( Cc "Open" * C ( piton.ListCommands * P "{" ) * Cc "}" ) * ( balanced_braces / (function (s) return MainLoopPython:match(s) end ) ) * P "}" * Ct ( Cc "Close" ) % \end{macrocode} % % \bigskip % % \paragraph{The LPEG Clean} % % \begin{macrocode} CleanLPEGs['python'] = Ct ( ( piton.ListCommands * P "{" * ( balanced_braces / ( function (s) return CleanLPEGs['python']:match(s) end ) ) * P "}" + EscapeClean + C ( P ( 1 ) ) ) ^ 0 ) / table.concat % \end{macrocode} % % % \bigskip % \paragraph{EOL} % % \bigskip % The following LPEG will detect the Python prompts when the user is typesetting % an interactive session of Python (directly or through |{pyconsole}| of % \pkg{pyluatex}). We have to detect that prompt twice. The first detection % (called \emph{hasty detection}) will be before the |\@@_begin_line:| because % you want to trigger a special background color for that row (and, after the % |\@@_begin_line:|, it's too late to change de background). % \begin{macrocode} local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\@@_prompt:' ) ) ^ -1 % \end{macrocode} % We remind that the marker |#| of \textsc{lpeg} specifies that the pattern will be % detected but won't consume any character. % % \medskip % With the following \textsc{lpeg}, a style will actually be applied to the % prompt (for instance, it's possible to decide to discard these prompts). % \begin{macrocode} local Prompt = K ( 'Prompt' , ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1 ) % \end{macrocode} % % % % \bigskip % The following \textsc{lpeg} |EOL| is for the end of lines. % \begin{macrocode} local EOL = P "\r" * ( ( space^0 * -1 ) + % \end{macrocode} % We recall that each line in the Python code we have to parse will be sent % back to LaTeX between a pair |\@@_begin_line:| -- % |\@@_end_line:|\footnote{Remember that the \texttt{\textbackslash % @@\_end\_line:} must be explicit because it will be used as marker in order to % delimit the argument of the command \texttt{\textbackslash @@\_begin\_line:}}. % \begin{macrocode} Ct ( Cc "EOL" * Ct ( Lc "\\@@_end_line:" * BeamerEndEnvironments * BeamerBeginEnvironments * PromptHastyDetection * Lc "\\@@_newline: \\@@_begin_line:" * Prompt ) ) ) * SpaceIndentation ^ 0 % \end{macrocode} % % % \bigskip % \paragraph{The long strings} % % % \begin{macrocode} local SingleLongString = WithStyle ( 'String.Long' , ( Q ( S "fF" * P "'''" ) * ( K ( 'String.Interpol' , P "{" ) * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "'''" ) ^ 0 ) * Q ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1 * K ( 'String.Interpol' , P "}" ) + Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 ) + EOL ) ^ 0 + Q ( ( S "rR" ) ^ -1 * P "'''" ) * ( Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 ) + PercentInterpol + P "%" + EOL ) ^ 0 ) * Q ( P "'''" ) ) local DoubleLongString = WithStyle ( 'String.Long' , ( Q ( S "fF" * P "\"\"\"" ) * ( K ( 'String.Interpol', P "{" ) * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) * Q ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1 * K ( 'String.Interpol' , P "}" ) + Q ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 ) + EOL ) ^ 0 + Q ( ( S "rR" ) ^ -1 * P "\"\"\"" ) * ( Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 ) + PercentInterpol + P "%" + EOL ) ^ 0 ) * Q ( P "\"\"\"" ) ) % \end{macrocode} % % \begin{macrocode} local LongString = SingleLongString + DoubleLongString % \end{macrocode} % % \bigskip % We have a \textsc{lpeg} for the Python docstrings. That \textsc{lpeg} will % be used in the \textsc{lpeg} |DefFunction| which deals with the whole preamble % of a function definition (which begins with |def|). % \begin{macrocode} local StringDoc = K ( 'String.Doc' , P "r" ^ -1 * P "\"\"\"" ) * ( K ( 'String.Doc' , (1 - P "\"\"\"" - P "\r" ) ^ 0 ) * EOL * Tab ^ 0 ) ^ 0 * K ( 'String.Doc' , ( 1 - P "\"\"\"" - P "\r" ) ^ 0 * P "\"\"\"" ) % \end{macrocode} % % \bigskip % \paragraph{The comments in the Python listings} % % We define different \textsc{lpeg} dealing with comments in the Python % listings. % \begin{macrocode} local CommentMath = P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" local Comment = WithStyle ( 'Comment' , Q ( P "#" ) * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) * ( EOL + -1 ) % \end{macrocode} % % % % \bigskip % The following \textsc{lpeg} |CommentLaTeX| is for what is called in that % document the ``LaTeX comments''. Since the elements that will be catched must % be sent to LaTeX with standard LaTeX catcodes, we put the capture (done by % the function~|C|) in a table (by using~|Ct|, which is an alias for |lpeg.Ct|). % \begin{macrocode} local CommentLaTeX = P(piton.comment_latex) * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces" * L ( ( 1 - P "\r" ) ^ 0 ) * Lc "}}" * ( EOL + -1 ) % \end{macrocode} % % \bigskip % \paragraph{DefFunction} % % The following \textsc{lpeg} |expression| will be used for the parameters in % the \emph{argspec} of a Python function. It's necessary to use a \emph{grammar} % because that pattern mainly checks the correct nesting of the delimiters % (and it's known in the theory of formal languages that this can't be done with % regular expressions \emph{stricto sensu} only). % \begin{macrocode} local expression = P { "E" , E = ( P "'" * ( P "\\'" + 1 - S "'\r" ) ^ 0 * P "'" + P "\"" * (P "\\\"" + 1 - S "\"\r" ) ^ 0 * P "\"" + P "{" * V "F" * P "}" + P "(" * V "F" * P ")" + P "[" * V "F" * P "]" + ( 1 - S "{}()[]\r," ) ) ^ 0 , F = ( P "{" * V "F" * P "}" + P "(" * V "F" * P ")" + P "[" * V "F" * P "]" + ( 1 - S "{}()[]\r\"'" ) ) ^ 0 } % \end{macrocode} % % \bigskip % We will now define a \textsc{lpeg} |Params| that will catch the list of % parameters (that is to say the \emph{argspec}) in the definition of a Python % function. For example, in the line of code % \begin{center} % \piton{def MyFunction(a,b,x=10,n:int): return n} % \end{center} % the \textsc{lpeg} |Params| will be used to catch the chunk\enskip |a,b,x=10,n:int|. % % Or course, a |Params| is simply a comma-separated list of |Param|, and that's % why we define first the \textsc{lpeg} |Param|. % % \medskip % \begin{macrocode} local Param = SkipSpace * ( Identifier + Q "*args" + Q "**kwargs" ) * SkipSpace * ( K ( 'InitialValues' , P "=" * expression ) + Q ( P ":" ) * SkipSpace * K ( 'Name.Type' , letter ^ 1 ) ) ^ -1 % \end{macrocode} % % \medskip % \begin{macrocode} local Params = ( Param * ( Q "," * Param ) ^ 0 ) ^ -1 % \end{macrocode} % % \bigskip % The following \textsc{lpeg} |DefFunction| catches a keyword |def| and the % following name of function \emph{but also everything else until a potential % docstring}. That's why this definition of \textsc{lpeg} must occur (in the file % |piton.sty|) after the definition of several other \textsc{lpeg} such as % |Comment|, |CommentLaTeX|, |Params|, |StringDoc|... % \begin{macrocode} local DefFunction = K ( 'Keyword' , P "def" ) * Space * K ( 'Name.Function.Internal' , identifier ) * SkipSpace * Q ( P "(" ) * Params * Q ( P ")" ) * SkipSpace * ( Q ( P "->" ) * SkipSpace * K ( 'Name.Type' , identifier ) ) ^ -1 % \end{macrocode} % Here, we need a \pkg{piton} style |ParseAgain| which will be linked to % |\@@_piton:n| (that means that the capture will be parsed once again by % \pkg{piton}). We could avoid that kind of trick by using a non-terminal of a % grammar but we have probably here a better legibility. % \begin{macrocode} * K ( 'ParseAgain' , ( 1 - S ":\r" )^0 ) * Q ( P ":" ) * ( SkipSpace * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL * Tab ^ 0 * SkipSpace * StringDoc ^ 0 -- there may be additionnal docstrings ) ^ -1 % \end{macrocode} % Remark that, in the previous code, |CommentLaTeX| \emph{must} appear % before |Comment|: there is no commutativity of the addition for the % \emph{parsing expression grammars} (\textsc{peg}). % % \smallskip % If the word |def| is not followed by an identifier and parenthesis, it will be % catched as keyword by the \textsc{lpeg} |Keyword| (useful if, for example, the % final user wants to speak of the keyword \piton{def}). % % % \paragraph{Miscellaneous} % % \begin{macrocode} local ExceptionInConsole = Exception * Q ( ( 1 - P "\r" ) ^ 0 ) * EOL % \end{macrocode} % % % \bigskip % \paragraph{The main LPEG for the language Python} % % First, the main loop : % \begin{macrocode} local MainPython = EOL + Space + Tab + Escape + EscapeMath + CommentLaTeX + Beamer + DetectedCommands + LongString + Comment + ExceptionInConsole + Delim + Operator + OperatorWord * ( Space + Punct + Delim + EOL + -1 ) + ShortString + Punct + FromImport + RaiseException + DefFunction + DefClass + Keyword * ( Space + Punct + Delim + EOL + -1 ) + Decorator + Builtin * ( Space + Punct + Delim + EOL + -1 ) + Identifier + Number + Word % \end{macrocode} % % Here, we must not put |local|! % \begin{macrocode} MainLoopPython = ( ( space^1 * -1 ) + MainPython ) ^ 0 % \end{macrocode} % % \bigskip % We recall that each line in the Python code to parse will be sent back to % LaTeX between a pair |\@@_begin_line:| -- |\@@_end_line:|\footnote{Remember % that the \texttt{\textbackslash @@\_end\_line:} must be explicit because it % will be used as marker in order to delimit the argument of the command % \texttt{\textbackslash @@\_begin\_line:}}. % \begin{macrocode} local python = P ( true ) python = Ct ( ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1 * BeamerBeginEnvironments * PromptHastyDetection * Lc '\\@@_begin_line:' * Prompt * SpaceIndentation ^ 0 * MainLoopPython * -1 * Lc '\\@@_end_line:' ) % \end{macrocode} % % \begin{macrocode} languages['python'] = python % \end{macrocode} % % \bigskip % \subsubsection{The LPEG ocaml} % % \begin{macrocode} local Delim = Q ( P "[|" + P "|]" + S "[()]" ) % \end{macrocode} % % \begin{macrocode} local Punct = Q ( S ",:;!" ) % \end{macrocode} % % The identifiers catched by |cap_identifier| begin with a cap. In OCaml, it's % used for the constructors of types and for the modules. % \begin{macrocode} local cap_identifier = R "AZ" * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0 % \end{macrocode} % % \begin{macrocode} local Constructor = K ( 'Name.Constructor' , cap_identifier ) local ModuleType = K ( 'Name.Type' , cap_identifier ) % \end{macrocode} % % The identifiers which begin with a lower case letter or an underscore are used % elsewhere in OCaml. % \begin{macrocode} local identifier = ( R "az" + P "_") * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0 local Identifier = K ( 'Identifier' , identifier ) % \end{macrocode} % % % Now, we deal with the records because we want to catch the names of the fields % of those records in all circunstancies. % \begin{macrocode} local expression_for_fields = P { "E" , E = ( P "{" * V "F" * P "}" + P "(" * V "F" * P ")" + P "[" * V "F" * P "]" + P "\"" * (P "\\\"" + 1 - S "\"\r" ) ^ 0 * P "\"" + P "'" * ( P "\\'" + 1 - S "'\r" ) ^ 0 * P "'" + ( 1 - S "{}()[]\r;" ) ) ^ 0 , F = ( P "{" * V "F" * P "}" + P "(" * V "F" * P ")" + P "[" * V "F" * P "]" + ( 1 - S "{}()[]\r\"'" ) ) ^ 0 } % \end{macrocode} % % \begin{macrocode} local OneFieldDefinition = ( K ( 'KeyWord' , P "mutable" ) * SkipSpace ) ^ -1 * K ( 'Name.Field' , identifier ) * SkipSpace * Q ":" * SkipSpace * K ( 'Name.Type' , expression_for_fields ) * SkipSpace local OneField = K ( 'Name.Field' , identifier ) * SkipSpace * Q "=" * SkipSpace * ( expression_for_fields / ( function (s) return LoopOCaml:match(s) end ) ) * SkipSpace local Record = Q "{" * SkipSpace * ( OneFieldDefinition * ( Q ";" * SkipSpace * OneFieldDefinition ) ^ 0 + OneField * ( Q ";" * SkipSpace * OneField ) ^ 0 ) * Q "}" % \end{macrocode} % % \bigskip % Now, we deal with the notations with points (eg: |List.length|). In OCaml, % such notation is used for the fields of the records and for the modules. % \begin{macrocode} local DotNotation = ( K ( 'Name.Module' , cap_identifier ) * Q "." * ( Identifier + Constructor + Q "(" + Q "[" + Q "{" ) + Identifier * Q "." * K ( 'Name.Field' , identifier ) ) * ( Q "." * K ( 'Name.Field' , identifier ) ) ^ 0 % \end{macrocode} % % \begin{macrocode} local Operator = K ( 'Operator' , P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":=" + P "||" + P "&&" + P "//" + P "**" + P ";;" + P "::" + P "->" + P "+." + P "-." + P "*." + P "/." + S "-~+/*%=<>&@|" ) local OperatorWord = K ( 'Operator.Word' , P "and" + P "asr" + P "land" + P "lor" + P "lsl" + P "lxor" + P "mod" + P "or" ) local Keyword = K ( 'Keyword' , P "assert" + P "and" + P "as" + P "begin" + P "class" + P "constraint" + P "done" + P "downto" + P "do" + P "else" + P "end" + P "exception" + P "external" + P "for" + P "function" + P "functor" + P "fun" + P "if" + P "include" + P "inherit" + P "initializer" + P "in" + P "lazy" + P "let" + P "match" + P "method" + P "module" + P "mutable" + P "new" + P "object" + P "of" + P "open" + P "private" + P "raise" + P "rec" + P "sig" + P "struct" + P "then" + P "to" + P "try" + P "type" + P "value" + P "val" + P "virtual" + P "when" + P "while" + P "with" ) + K ( 'Keyword.Constant' , P "true" + P "false" ) local Builtin = K ( 'Name.Builtin' , P "not" + P "incr" + P "decr" + P "fst" + P "snd" ) % \end{macrocode} % % \bigskip % The following exceptions are exceptions in the standard library of OCaml (Stdlib). % \begin{macrocode} local Exception = K ( 'Exception' , P "Division_by_zero" + P "End_of_File" + P "Failure" + P "Invalid_argument" + P "Match_failure" + P "Not_found" + P "Out_of_memory" + P "Stack_overflow" + P "Sys_blocked_io" + P "Sys_error" + P "Undefined_recursive_module" ) % \end{macrocode} % % \bigskip % \paragraph{The characters in OCaml} % % \begin{macrocode} local Char = K ( 'String.Short' , P "'" * ( ( 1 - P "'" ) ^ 0 + P "\\'" ) * P "'" ) % \end{macrocode} % % % \bigskip % \paragraph{Beamer} % % \begin{macrocode} local balanced_braces = P { "E" , E = ( P "{" * V "E" * P "}" + P "\"" * ( 1 - S "\"" ) ^ 0 * P "\"" -- OCaml strings + ( 1 - S "{}" ) ) ^ 0 } % \end{macrocode} % % % \bigskip % \begin{macrocode} if piton_beamer then Beamer = L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 ) + Ct ( Cc "Open" * C ( ( P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible" + P "\\invisible" + P "\\action" ) * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" ) * Cc "}" ) * ( balanced_braces / (function (s) return MainLoopOCaml:match(s) end ) ) * P "}" * Ct ( Cc "Close" ) + OneBeamerEnvironment ( "uncoverenv" , MainLoopOCaml ) + OneBeamerEnvironment ( "onlyenv" , MainLoopOCaml ) + OneBeamerEnvironment ( "visibleenv" , MainLoopOCaml ) + OneBeamerEnvironment ( "invisibleenv" , MainLoopOCaml ) + OneBeamerEnvironment ( "alertenv" , MainLoopOCaml ) + OneBeamerEnvironment ( "actionenv" , MainLoopOCaml ) + L ( % \end{macrocode} % For |\\alt|, the specification of the overlays (between angular brackets) is mandatory. % \begin{macrocode} ( P "\\alt" ) * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}" ) + L ( % \end{macrocode} % For |\\temporal|, the specification of the overlays (between angular brackets) is mandatory. % \begin{macrocode} ( P "\\temporal" ) * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}" ) end % \end{macrocode} % % \begin{macrocode} DetectedCommands = Ct ( Cc "Open" * C ( piton.ListCommands * P "{" ) * Cc "}" ) * ( balanced_braces / (function (s) return MainLoopOCaml:match(s) end ) ) * P "}" * Ct ( Cc "Close" ) % \end{macrocode} % % \bigskip % \begin{macrocode} CleanLPEGs['ocaml'] = Ct ( ( piton.ListCommands * P "{" * ( balanced_braces / ( function (s) return CleanLPEGs['ocaml']:match(s) end ) ) * P "}" + EscapeClean + C ( P ( 1 ) ) ) ^ 0 ) / table.concat % \end{macrocode} % % % % \bigskip % \paragraph{EOL} % \begin{macrocode} local EOL = P "\r" * ( ( space^0 * -1 ) + Ct ( Cc "EOL" * Ct ( Lc "\\@@_end_line:" * BeamerEndEnvironments * BeamerBeginEnvironments * PromptHastyDetection * Lc "\\@@_newline: \\@@_begin_line:" * Prompt ) ) ) * SpaceIndentation ^ 0 % \end{macrocode} % % % \paragraph{The strings en OCaml} % % We need a pattern |ocaml_string| without captures because it will be used % within the comments of OCaml. % \begin{macrocode} local ocaml_string = Q ( P "\"" ) * ( VisualSpace + Q ( ( 1 - S " \"\r" ) ^ 1 ) + EOL ) ^ 0 * Q ( P "\"" ) % \end{macrocode} % % \begin{macrocode} local String = WithStyle ( 'String.Long' , ocaml_string ) % \end{macrocode} % % % \bigskip % Now, the ``quoted strings'' of OCaml (for example \verb+{ext|Essai|ext}+). % % For those strings, we will do two consecutive analysis. First an analysis to % determine the whole string and, then, an analysis for the potential visual % spaces and the EOL in the string. % % The first analysis require a match-time capture. For explanations about that % programmation, see the paragraphe \emph{Lua's long % strings} in % |www.inf.puc-rio.br/~roberto/lpeg|. % \begin{macrocode} local ext = ( R "az" + P "_" ) ^ 0 local open = "{" * Cg(ext, 'init') * "|" local close = "|" * C(ext) * "}" local closeeq = Cmt ( close * Cb('init'), function (s, i, a, b) return a == b end ) % \end{macrocode} % % \medskip % The \textsc{lpeg} |QuotedStringBis| will do the second analysis. % \begin{macrocode} local QuotedStringBis = WithStyle ( 'String.Long' , ( Space + Q ( ( 1 - S " \r" ) ^ 1 ) + EOL ) ^ 0 ) % \end{macrocode} % % \medskip % We use a ``function capture'' (as called in the official documentation of the % \textsc{lpeg}) in order to do the second analysis on the result of the first one. % \begin{macrocode} local QuotedString = C ( open * ( 1 - closeeq ) ^ 0 * close ) / ( function (s) return QuotedStringBis : match(s) end ) % \end{macrocode} % % % \bigskip % \paragraph{The comments in the OCaml listings} % % In OCaml, the delimiters for the comments are |(*| and |*)|. There are % unsymmetrical and OCaml allow those comments to be nested. That's why we need a % grammar. % % In these comments, we embed the math comments (between |$| and |$|) and we % embed also a treatment for the end of lines (since the comments may be multi-lines). % % \begin{macrocode} local Comment = WithStyle ( 'Comment' , P { "A" , A = Q "(*" * ( V "A" + Q ( ( 1 - P "(*" - P "*)" - S "\r$\"" ) ^ 1 ) -- $ + ocaml_string + P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" -- $ + EOL ) ^ 0 * Q "*)" } ) % \end{macrocode} % % \bigskip % \paragraph{The DefFunction} % % \begin{macrocode} local balanced_parens = P { "E" , E = ( P "(" * V "E" * P ")" + ( 1 - S "()" ) ) ^ 0 } % \end{macrocode} % % \begin{macrocode} local Argument = K ( 'Identifier' , identifier ) + Q "(" * SkipSpace * K ( 'Identifier' , identifier ) * SkipSpace * Q ":" * SkipSpace * K ( 'Name.Type' , balanced_parens ) * SkipSpace * Q ")" % \end{macrocode} % % Despite its name, then \textsc{lpeg} |DefFunction| deals also with |let open| % which opens locally a module. % \begin{macrocode} local DefFunction = K ( 'Keyword' , P "let open" ) * Space * K ( 'Name.Module' , cap_identifier ) + K ( 'Keyword' , P "let rec" + P "let" + P "and" ) * Space * K ( 'Name.Function.Internal' , identifier ) * Space * ( Q "=" * SkipSpace * K ( 'Keyword' , P "function" ) + Argument * ( SkipSpace * Argument ) ^ 0 * ( SkipSpace * Q ":" * K ( 'Name.Type' , ( 1 - P "=" ) ^ 0 ) ) ^ -1 ) % \end{macrocode} % % % \bigskip % \paragraph{The DefModule}\par % % The following LPEG will be used in the definitions of modules but also in the % definitions of \emph{types} of modules. % \begin{macrocode} local DefModule = K ( 'Keyword' , P "module" ) * Space * ( K ( 'Keyword' , P "type" ) * Space * K ( 'Name.Type' , cap_identifier ) + K ( 'Name.Module' , cap_identifier ) * SkipSpace * ( Q "(" * SkipSpace * K ( 'Name.Module' , cap_identifier ) * SkipSpace * Q ":" * SkipSpace * K ( 'Name.Type' , cap_identifier ) * SkipSpace * ( Q "," * SkipSpace * K ( 'Name.Module' , cap_identifier ) * SkipSpace * Q ":" * SkipSpace * K ( 'Name.Type' , cap_identifier ) * SkipSpace ) ^ 0 * Q ")" ) ^ -1 * ( Q "=" * SkipSpace * K ( 'Name.Module' , cap_identifier ) * SkipSpace * Q "(" * K ( 'Name.Module' , cap_identifier ) * SkipSpace * ( Q "," * K ( 'Name.Module' , cap_identifier ) * SkipSpace ) ^ 0 * Q ")" ) ^ -1 ) + K ( 'Keyword' , P "include" + P "open" ) * Space * K ( 'Name.Module' , cap_identifier ) % \end{macrocode} % % \bigskip % \paragraph{The parameters of the types} % % \begin{macrocode} local TypeParameter = K ( 'TypeParameter' , P "'" * alpha * # ( 1 - P "'" ) ) % \end{macrocode} % % \bigskip % \paragraph{The main LPEG for the language OCaml} % % First, the main loop : % \begin{macrocode} MainOCaml = EOL + Space + Tab + Escape + EscapeMath + Beamer + DetectedCommands + TypeParameter + String + QuotedString + Char + Comment + Delim + Operator + Punct + FromImport + Exception + DefFunction + DefModule + Record + Keyword * ( Space + Punct + Delim + EOL + -1 ) + OperatorWord * ( Space + Punct + Delim + EOL + -1 ) + Builtin * ( Space + Punct + Delim + EOL + -1 ) + DotNotation + Constructor + Identifier + Number + Word LoopOCaml = MainOCaml ^ 0 MainLoopOCaml = ( ( space^1 * -1 ) + MainOCaml ) ^ 0 % \end{macrocode} % % \bigskip % We recall that each line in the Python code to parse will be sent back to % LaTeX between a pair |\@@_begin_line:| -- |\@@_end_line:|\footnote{Remember % that the \texttt{\textbackslash @@\_end\_line:} must be explicit because it % will be used as marker in order to delimit the argument of the command % \texttt{\textbackslash @@\_begin\_line:}}. % \begin{macrocode} local ocaml = P ( true ) ocaml = Ct ( ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1 * BeamerBeginEnvironments * Lc ( '\\@@_begin_line:' ) * SpaceIndentation ^ 0 * MainLoopOCaml * -1 * Lc ( '\\@@_end_line:' ) ) % \end{macrocode} % % \begin{macrocode} languages['ocaml'] = ocaml % \end{macrocode} % % \bigskip % \subsubsection{The LPEG for the language C} % % \begin{macrocode} local Delim = Q ( S "{[()]}" ) % \end{macrocode} % % \begin{macrocode} local Punct = Q ( S ",:;!" ) % \end{macrocode} % % \bigskip % Some strings of length 2 are explicit because we want the corresponding % ligatures available in some fonts such as \emph{Fira Code} to be active. % \begin{macrocode} local identifier = letter * alphanum ^ 0 local Operator = K ( 'Operator' , P "!=" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P "||" + P "&&" + S "-~+/*%=<>&.@|!" ) local Keyword = K ( 'Keyword' , P "alignas" + P "asm" + P "auto" + P "break" + P "case" + P "catch" + P "class" + P "const" + P "constexpr" + P "continue" + P "decltype" + P "do" + P "else" + P "enum" + P "extern" + P "for" + P "goto" + P "if" + P "nexcept" + P "private" + P "public" + P "register" + P "restricted" + P "return" + P "static" + P "static_assert" + P "struct" + P "switch" + P "thread_local" + P "throw" + P "try" + P "typedef" + P "union" + P "using" + P "virtual" + P "volatile" + P "while" ) + K ( 'Keyword.Constant' , P "default" + P "false" + P "NULL" + P "nullptr" + P "true" ) local Builtin = K ( 'Name.Builtin' , P "alignof" + P "malloc" + P "printf" + P "scanf" + P "sizeof" ) local Type = K ( 'Name.Type' , P "bool" + P "char" + P "char16_t" + P "char32_t" + P "double" + P "float" + P "int" + P "int8_t" + P "int16_t" + P "int32_t" + P "int64_t" + P "long" + P "short" + P "signed" + P "unsigned" + P "void" + P "wchar_t" ) local DefFunction = Type * Space * Q ( "*" ) ^ -1 * K ( 'Name.Function.Internal' , identifier ) * SkipSpace * # P "(" % \end{macrocode} % We remind that the marker |#| of \textsc{lpeg} specifies that the pattern will be % detected but won't consume any character. % % \bigskip % The following \textsc{lpeg} |DefClass| will be used to detect the definition of a % new class (the name of that new class will be formatted with the \pkg{piton} % style |Name.Class|). % % \smallskip % Example:\enskip \piton{class myclass:} % \begin{macrocode} local DefClass = K ( 'Keyword' , P "class" ) * Space * K ( 'Name.Class' , identifier ) % \end{macrocode} % % If the word |class| is not followed by a identifier, it will be catched as % keyword by the \textsc{lpeg} |Keyword| (useful if we want to type a % list of keywords). % % \bigskip % \paragraph{The strings of C} % % \begin{macrocode} local String = WithStyle ( 'String.Long' , Q "\"" * ( VisualSpace + K ( 'String.Interpol' , P "%" * ( S "difcspxXou" + P "ld" + P "li" + P "hd" + P "hi" ) ) + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 ) ) ^ 0 * Q "\"" ) % \end{macrocode} % % \bigskip % \paragraph{Beamer} % % The following \textsc{lpeg} |balanced_braces| will be used for the (mandatory) % argument of the commands |\only| and \emph{al.} of Beamer. It's necessary to % use a \emph{grammar} because that pattern mainly checks the correct nesting of % the delimiters (and it's known in the theory of formal languages that this % can't be done with regular expressions \emph{stricto sensu} only). % \begin{macrocode} local balanced_braces = P { "E" , E = ( P "{" * V "E" * P "}" + String + ( 1 - S "{}" ) ) ^ 0 } % \end{macrocode} % % % \bigskip % \begin{macrocode} if piton_beamer then Beamer = L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 ) + Ct ( Cc "Open" * C ( ( P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible" + P "\\invisible" + P "\\action" ) * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" ) * Cc "}" ) * ( balanced_braces / (function (s) return MainLoopC:match(s) end ) ) * P "}" * Ct ( Cc "Close" ) + OneBeamerEnvironment ( "uncoverenv" , MainLoopC ) + OneBeamerEnvironment ( "onlyenv" , MainLoopC ) + OneBeamerEnvironment ( "visibleenv" , MainLoopC ) + OneBeamerEnvironment ( "invisibleenv" , MainLoopC ) + OneBeamerEnvironment ( "alertenv" , MainLoopC ) + OneBeamerEnvironment ( "actionenv" , MainLoopC ) + L ( % \end{macrocode} % For |\\alt|, the specification of the overlays (between angular brackets) is mandatory. % \begin{macrocode} ( P "\\alt" ) * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}" ) + L ( % \end{macrocode} % For |\\temporal|, the specification of the overlays (between angular brackets) is mandatory. % \begin{macrocode} ( P "\\temporal" ) * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}" ) end % \end{macrocode} % % \begin{macrocode} DetectedCommands = Ct ( Cc "Open" * C ( piton.ListCommands * P "{" ) * Cc "}" ) * ( balanced_braces / (function (s) return MainLoopC:match(s) end ) ) * P "}" * Ct ( Cc "Close" ) % \end{macrocode} % % \bigskip % \begin{macrocode} CleanLPEGs['c'] = Ct ( ( piton.ListCommands * P "{" * ( balanced_braces / ( function (s) return CleanLPEGs['c']:match(s) end ) ) * P "}" + EscapeClean + C ( P ( 1 ) ) ) ^ 0 ) / table.concat % \end{macrocode} % % \bigskip % \paragraph{EOL} % % % The following \textsc{lpeg} |EOL| is for the end of lines. % \begin{macrocode} local EOL = P "\r" * ( ( space^0 * -1 ) + % \end{macrocode} % We recall that each line in the Python code we have to parse will be sent % back to LaTeX between a pair |\@@_begin_line:| -- % |\@@_end_line:|\footnote{Remember that the \texttt{\textbackslash % @@\_end\_line:} must be explicit because it will be used as marker in order to % delimit the argument of the command \texttt{\textbackslash @@\_begin\_line:}}. % \begin{macrocode} Ct ( Cc "EOL" * Ct ( Lc "\\@@_end_line:" * BeamerEndEnvironments * BeamerBeginEnvironments * PromptHastyDetection * Lc "\\@@_newline: \\@@_begin_line:" * Prompt ) ) ) * SpaceIndentation ^ 0 % \end{macrocode} % % \bigskip % \paragraph{The directives of the preprocessor} % % \begin{macrocode} local Preproc = K ( 'Preproc' , P "#" * (1 - P "\r" ) ^ 0 ) * ( EOL + -1 ) % \end{macrocode} % % % \bigskip % \paragraph{The comments in the C listings} % % We define different \textsc{lpeg} dealing with comments in the C listings. % \begin{macrocode} local CommentMath = P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" local Comment = WithStyle ( 'Comment' , Q ( P "//" ) * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) * ( EOL + -1 ) local LongComment = WithStyle ( 'Comment' , Q ( P "/*" ) * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0 * Q ( P "*/" ) ) -- $ % \end{macrocode} % % % \bigskip % The following \textsc{lpeg} |CommentLaTeX| is for what is called in that % document the ``LaTeX comments''. Since the elements that will be catched must % be sent to LaTeX with standard LaTeX catcodes, we put the capture (done by % the function~|C|) in a table (by using~|Ct|, which is an alias for |lpeg.Ct|). % \begin{macrocode} local CommentLaTeX = P(piton.comment_latex) * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces" * L ( ( 1 - P "\r" ) ^ 0 ) * Lc "}}" * ( EOL + -1 ) % \end{macrocode} % % % % % \bigskip % \paragraph{The main LPEG for the language C} % % First, the main loop : % \begin{macrocode} local MainC = EOL + Space + Tab + Escape + EscapeMath + CommentLaTeX + Beamer + DetectedCommands + Preproc + Comment + LongComment + Delim + Operator + String + Punct + DefFunction + DefClass + Type * ( Q ( "*" ) ^ -1 + Space + Punct + Delim + EOL + -1 ) + Keyword * ( Space + Punct + Delim + EOL + -1 ) + Builtin * ( Space + Punct + Delim + EOL + -1 ) + Identifier + Number + Word % \end{macrocode} % % Here, we must not put |local|! % \begin{macrocode} MainLoopC = ( ( space^1 * -1 ) + MainC ) ^ 0 % \end{macrocode} % % \bigskip % We recall that each line in the C code to parse will be sent back to % LaTeX between a pair |\@@_begin_line:| -- |\@@_end_line:|\footnote{Remember % that the \texttt{\textbackslash @@\_end\_line:} must be explicit because it % will be used as marker in order to delimit the argument of the command % \texttt{\textbackslash @@\_begin\_line:}}. % \begin{macrocode} languageC = Ct ( ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1 * BeamerBeginEnvironments * Lc '\\@@_begin_line:' * SpaceIndentation ^ 0 * MainLoopC * -1 * Lc '\\@@_end_line:' ) % \end{macrocode} % % \begin{macrocode} languages['c'] = languageC % \end{macrocode} % % % \bigskip % \subsubsection{The LPEG language SQL} % % \bigskip % In the identifiers, we will be able to catch those contening spaces, that is % to say like |"last name"|. % \begin{macrocode} local identifier = letter * ( alphanum + P "-" ) ^ 0 + P '"' * ( ( alphanum + space - P '"' ) ^ 1 ) * P '"' local Operator = K ( 'Operator' , P "=" + P "!=" + P "<>" + P ">=" + P ">" + P "<=" + P "<" + S "*+/" ) % \end{macrocode} % % In SQL, the keywords are case-insensitive. That's why we have a little % complication. We will catch the keywords with the identifiers and, then, % distinguish the keywords with a Lua function. However, some keywords will be % catched in special LPEG because we want to detect the names of the SQL tables. % \begin{macrocode} local function Set (list) local set = {} for _, l in ipairs(list) do set[l] = true end return set end local set_keywords = Set { "ADD" , "AFTER" , "ALL" , "ALTER" , "AND" , "AS" , "ASC" , "BETWEEN" , "BY" , "CHANGE" , "COLUMN" , "CREATE" , "CROSS JOIN" , "DELETE" , "DESC" , "DISTINCT" , "DROP" , "FROM" , "GROUP" , "HAVING" , "IN" , "INNER" , "INSERT" , "INTO" , "IS" , "JOIN" , "LEFT" , "LIKE" , "LIMIT" , "MERGE" , "NOT" , "NULL" , "ON" , "OR" , "ORDER" , "OVER" , "RIGHT" , "SELECT" , "SET" , "TABLE" , "THEN" , "TRUNCATE" , "UNION" , "UPDATE" , "VALUES" , "WHEN" , "WHERE" , "WITH" } local set_builtins = Set { "AVG" , "COUNT" , "CHAR_LENGHT" , "CONCAT" , "CURDATE" , "CURRENT_DATE" , "DATE_FORMAT" , "DAY" , "LOWER" , "LTRIM" , "MAX" , "MIN" , "MONTH" , "NOW" , "RANK" , "ROUND" , "RTRIM" , "SUBSTRING" , "SUM" , "UPPER" , "YEAR" } % \end{macrocode} % % The \textsc{lpeg} |Identifer| will catch the identifiers of the fields % but also the keywords and the built-in functions of SQL. If will \emph{not} % catch the names of the SQL tables. % \begin{macrocode} local Identifier = C ( identifier ) / ( function (s) if set_keywords[string.upper(s)] -- the keywords are case-insensitive in SQL % \end{macrocode} % Remind that, in Lua, it's possible to return \emph{several} values. % \begin{macrocode} then return { "{\\PitonStyle{Keyword}{" } , { luatexbase.catcodetables.other , s } , { "}}" } else if set_builtins[string.upper(s)] then return { "{\\PitonStyle{Name.Builtin}{" } , { luatexbase.catcodetables.other , s } , { "}}" } else return { "{\\PitonStyle{Name.Field}{" } , { luatexbase.catcodetables.other , s } , { "}}" } end end end ) % \end{macrocode} % % \bigskip % \paragraph{The strings of SQL} % % \begin{macrocode} local String = K ( 'String.Long' , P "'" * ( 1 - P "'" ) ^ 1 * P "'" ) % \end{macrocode} % % \bigskip % \paragraph{Beamer} % % The following \textsc{lpeg} |balanced_braces| will be used for the (mandatory) % argument of the commands |\only| and \emph{al.} of Beamer. It's necessary to % use a \emph{grammar} because that pattern mainly checks the correct nesting of % the delimiters (and it's known in the theory of formal languages that this % can't be done with regular expressions \emph{stricto sensu} only). % \begin{macrocode} local balanced_braces = P { "E" , E = ( P "{" * V "E" * P "}" + String + ( 1 - S "{}" ) ) ^ 0 } % \end{macrocode} % % % \bigskip % \begin{macrocode} if piton_beamer then Beamer = L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 ) + Ct ( Cc "Open" * C ( ( P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible" + P "\\invisible" + P "\\action" ) * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" ) * Cc "}" ) * ( balanced_braces / (function (s) return MainLoopSQL:match(s) end ) ) * P "}" * Ct ( Cc "Close" ) + OneBeamerEnvironment ( "uncoverenv" , MainLoopSQL ) + OneBeamerEnvironment ( "onlyenv" , MainLoopSQL ) + OneBeamerEnvironment ( "visibleenv" , MainLoopSQL ) + OneBeamerEnvironment ( "invisibleenv" , MainLoopSQL ) + OneBeamerEnvironment ( "alertenv" , MainLoopSQL ) + OneBeamerEnvironment ( "actionenv" , MainLoopSQL ) + L ( % \end{macrocode} % For |\\alt|, the specification of the overlays (between angular brackets) is mandatory. % \begin{macrocode} ( P "\\alt" ) * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}" ) + L ( % \end{macrocode} % For |\\temporal|, the specification of the overlays (between angular brackets) is mandatory. % \begin{macrocode} ( P "\\temporal" ) * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}" ) end % \end{macrocode} % % \begin{macrocode} DetectedCommands = Ct ( Cc "Open" * C ( piton.ListCommands * P "{" ) * Cc "}" ) * ( balanced_braces / (function (s) return MainLoopSQL:match(s) end ) ) * P "}" * Ct ( Cc "Close" ) % \end{macrocode} % % \bigskip % \begin{macrocode} CleanLPEGs['sql'] = Ct ( ( piton.ListCommands * P "{" * ( balanced_braces / ( function (s) return CleanLPEGs['sql']:match(s) end ) ) * P "}" + EscapeClean + C ( P ( 1 ) ) ) ^ 0 ) / table.concat % \end{macrocode} % % \bigskip % \paragraph{EOL} % % \bigskip % The following \textsc{lpeg} |EOL| is for the end of lines. % \begin{macrocode} local EOL = P "\r" * ( ( space^0 * -1 ) + % \end{macrocode} % We recall that each line in the SQL code we have to parse will be sent % back to LaTeX between a pair |\@@_begin_line:| -- % |\@@_end_line:|\footnote{Remember that the \texttt{\textbackslash % @@\_end\_line:} must be explicit because it will be used as marker in order to % delimit the argument of the command \texttt{\textbackslash @@\_begin\_line:}}. % \begin{macrocode} Ct ( Cc "EOL" * Ct ( Lc "\\@@_end_line:" * BeamerEndEnvironments * BeamerBeginEnvironments * Lc "\\@@_newline: \\@@_begin_line:" ) ) ) * SpaceIndentation ^ 0 % \end{macrocode} % % % % \bigskip % \paragraph{The comments in the SQL listings} % % We define different \textsc{lpeg} dealing with comments in the SQL listings. % \begin{macrocode} local CommentMath = P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" local Comment = WithStyle ( 'Comment' , Q ( P "--" ) -- syntax of SQL92 * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) * ( EOL + -1 ) local LongComment = WithStyle ( 'Comment' , Q ( P "/*" ) * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0 * Q ( P "*/" ) ) -- $ % \end{macrocode} % % % \bigskip % The following \textsc{lpeg} |CommentLaTeX| is for what is called in that % document the ``LaTeX comments''. Since the elements that will be catched must % be sent to LaTeX with standard LaTeX catcodes, we put the capture (done by % the function~|C|) in a table (by using~|Ct|, which is an alias for |lpeg.Ct|). % \begin{macrocode} local CommentLaTeX = P(piton.comment_latex) * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces" * L ( ( 1 - P "\r" ) ^ 0 ) * Lc "}}" * ( EOL + -1 ) % \end{macrocode} % % % % % \bigskip % \paragraph{The main LPEG for the language SQL} % % % \begin{macrocode} local function LuaKeyword ( name ) return Lc ( "{\\PitonStyle{Keyword}{" ) * Q ( Cmt ( C ( identifier ) , function(s,i,a) return string.upper(a) == name end ) ) * Lc ( "}}" ) end % \end{macrocode} % % \begin{macrocode} local TableField = K ( 'Name.Table' , identifier ) * Q ( P "." ) * K ( 'Name.Field' , identifier ) local OneField = ( Q ( P "(" * ( 1 - P ")" ) ^ 0 * P ")" ) + K ( 'Name.Table' , identifier ) * Q ( P "." ) * K ( 'Name.Field' , identifier ) + K ( 'Name.Field' , identifier ) ) * ( Space * LuaKeyword ( "AS" ) * Space * K ( 'Name.Field' , identifier ) ) ^ -1 * ( Space * ( LuaKeyword ( "ASC" ) + LuaKeyword ( "DESC" ) ) ) ^ -1 local OneTable = K ( 'Name.Table' , identifier ) * ( Space * LuaKeyword ( "AS" ) * Space * K ( 'Name.Table' , identifier ) ) ^ -1 local WeCatchTableNames = LuaKeyword ( "FROM" ) * ( Space + EOL ) * OneTable * ( SkipSpace * Q ( P "," ) * SkipSpace * OneTable ) ^ 0 + ( LuaKeyword ( "JOIN" ) + LuaKeyword ( "INTO" ) + LuaKeyword ( "UPDATE" ) + LuaKeyword ( "TABLE" ) ) * ( Space + EOL ) * OneTable % \end{macrocode} % % % First, the main loop : % \begin{macrocode} local MainSQL = EOL + Space + Tab + Escape + EscapeMath + CommentLaTeX + Beamer + DetectedCommands + Comment + LongComment + Delim + Operator + String + Punct + WeCatchTableNames + ( TableField + Identifier ) * ( Space + Operator + Punct + Delim + EOL + -1 ) + Number + Word % \end{macrocode} % % Here, we must not put |local|! % \begin{macrocode} MainLoopSQL = ( ( space^1 * -1 ) + MainSQL ) ^ 0 % \end{macrocode} % % \bigskip % We recall that each line in the C code to parse will be sent back to % LaTeX between a pair |\@@_begin_line:| -- |\@@_end_line:|\footnote{Remember % that the \texttt{\textbackslash @@\_end\_line:} must be explicit because it % will be used as marker in order to delimit the argument of the command % \texttt{\textbackslash @@\_begin\_line:}}. % \begin{macrocode} languageSQL = Ct ( ( ( space - P "\r" ) ^ 0 * P "\r" ) ^ -1 * BeamerBeginEnvironments * Lc '\\@@_begin_line:' * SpaceIndentation ^ 0 * MainLoopSQL * -1 * Lc '\\@@_end_line:' ) % \end{macrocode} % % \begin{macrocode} languages['sql'] = languageSQL % \end{macrocode} % % \subsubsection{The LPEG language Minimal} % % \begin{macrocode} local Punct = Q ( S ",:;!\\" ) local CommentMath = P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" local Comment = WithStyle ( 'Comment' , Q ( P "#" ) * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) * ( EOL + -1 ) local String = WithStyle ( 'String.Short' , Q "\"" * ( VisualSpace + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 ) ) ^ 0 * Q "\"" ) local balanced_braces = P { "E" , E = ( P "{" * V "E" * P "}" + String + ( 1 - S "{}" ) ) ^ 0 } if piton_beamer then Beamer = L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 ) + Ct ( Cc "Open" * C ( ( P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible" + P "\\invisible" + P "\\action" ) * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" ) * Cc "}" ) * ( balanced_braces / (function (s) return MainLoopMinimal:match(s) end ) ) * P "}" * Ct ( Cc "Close" ) + OneBeamerEnvironment ( "uncoverenv" , MainLoopMinimal ) + OneBeamerEnvironment ( "onlyenv" , MainLoopMinimal ) + OneBeamerEnvironment ( "visibleenv" , MainLoopMinimal ) + OneBeamerEnvironment ( "invisibleenv" , MainLoopMinimal ) + OneBeamerEnvironment ( "alertenv" , MainLoopMinimal ) + OneBeamerEnvironment ( "actionenv" , MainLoopMinimal ) + L ( ( P "\\alt" ) * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}" ) + L ( ( P "\\temporal" ) * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}{" ) * K ( 'ParseAgain.noCR' , balanced_braces ) * L ( P "}" ) end DetectedCommands = Ct ( Cc "Open" * C ( piton.ListCommands * P "{" ) * Cc "}" ) * ( balanced_braces / (function (s) return MainLoopMinimal:match(s) end ) ) * P "}" * Ct ( Cc "Close" ) CleanLPEGs['minimal'] = Ct ( ( piton.ListCommands * P "{" * ( balanced_braces / ( function (s) return CleanLPEGs['minimal']:match(s) end ) ) * P "}" + EscapeClean + C ( P ( 1 ) ) ) ^ 0 ) / table.concat local EOL = P "\r" * ( ( space^0 * -1 ) + Ct ( Cc "EOL" * Ct ( Lc "\\@@_end_line:" * BeamerEndEnvironments * BeamerBeginEnvironments * Lc "\\@@_newline: \\@@_begin_line:" ) ) ) * SpaceIndentation ^ 0 local CommentMath = P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" -- $ local CommentLaTeX = P(piton.comment_latex) * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces" * L ( ( 1 - P "\r" ) ^ 0 ) * Lc "}}" * ( EOL + -1 ) local identifier = letter * alphanum ^ 0 local Identifier = K ( 'Identifier' , identifier ) local Delim = Q ( S "{[()]}" ) local MainMinimal = EOL + Space + Tab + Escape + EscapeMath + CommentLaTeX + Beamer + DetectedCommands + Comment + Delim + String + Punct + Identifier + Number + Word MainLoopMinimal = ( ( space^1 * -1 ) + MainMinimal ) ^ 0 languageMinimal = Ct ( ( ( space - P "\r" ) ^ 0 * P "\r" ) ^ -1 * BeamerBeginEnvironments * Lc '\\@@_begin_line:' * SpaceIndentation ^ 0 * MainLoopMinimal * -1 * Lc '\\@@_end_line:' ) languages['minimal'] = languageMinimal % \bigskip % \subsubsection{The function Parse} % % \medskip % The function |Parse| is the main function of the package \pkg{piton}. It % parses its argument and sends back to LaTeX the code with interlaced % formatting LaTeX instructions. In fact, everything is done by the % \textsc{lpeg} corresponding to the considered language (|languages[language]|) % which returns as capture a Lua table containing data to send to LaTeX. % % \bigskip % \begin{macrocode} function piton.Parse(language,code) local t = languages[language] : match ( code ) if t == nil then tex.sprint("\\PitonSyntaxError") return -- to exit in force the function end local left_stack = {} local right_stack = {} for _ , one_item in ipairs(t) do if one_item[1] == "EOL" then for _ , s in ipairs(right_stack) do tex.sprint(s) end for _ , s in ipairs(one_item[2]) do tex.tprint(s) end for _ , s in ipairs(left_stack) do tex.sprint(s) end else % \end{macrocode} % % Here is an example of an item beginning with |"Open"|. % % |{ "Open" , "\begin{uncover}<2>" , "\end{cover}" }| % % In order to deal with the ends of lines, we have to close the environment % (|{cover}| in this example) at the end of each line and reopen it at the % beginning of the new line. That's why we use two Lua stacks, called % |left_stack| and |right_stack|. |left_stack| will be for the elements like % |\begin{uncover}<2>| and |right_stack| will be for the elements like % |\end{cover}|. % \begin{macrocode} if one_item[1] == "Open" then tex.sprint( one_item[2] ) table.insert(left_stack,one_item[2]) table.insert(right_stack,one_item[3]) else if one_item[1] == "Close" then tex.sprint( right_stack[#right_stack] ) left_stack[#left_stack] = nil right_stack[#right_stack] = nil else tex.tprint(one_item) end end end end end % \end{macrocode} % % % % \bigskip % The function |ParseFile| will be used by the LaTeX command |\PitonInputFile|. % That function merely reads the whole file (that is to say all its lines) and % then apply the function~|Parse| to the resulting Lua string. % \begin{macrocode} function piton.ParseFile(language,name,first_line,last_line) local s = '' local i = 0 for line in io.lines(name) do i = i + 1 if i >= first_line then s = s .. '\r' .. line end if i >= last_line then break end end % \end{macrocode} % We extract the BOM of utf-8, if present. % \begin{macrocode} if string.byte(s,1) == 13 then if string.byte(s,2) == 239 then if string.byte(s,3) == 187 then if string.byte(s,4) == 191 then s = string.sub(s,5,-1) end end end end piton.Parse(language,s) end % \end{macrocode} % % \bigskip % \subsubsection{Two variants of the function Parse with integrated preprocessors} % % The following command will be used by the user command |\piton|. % For that command, we have to undo the duplication of the symbols |#|. % \begin{macrocode} function piton.ParseBis(language,code) local s = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( code ) return piton.Parse(language,s) end % \end{macrocode} % % \bigskip % The following command will be used when we have to parse some small chunks of % code that have yet been parsed. They are re-scanned by LaTeX because it has % been required by |\@@_piton:n| in the \pkg{piton} style of the syntaxic % element. In that case, you have to remove the potential |\@@_breakable_space:| % that have been inserted when the key |break-lines| is in force. % \begin{macrocode} function piton.ParseTer(language,code) local s = ( Cs ( ( P '\\@@_breakable_space:' / ' ' + 1 ) ^ 0 ) ) : match ( code ) return piton.Parse(language,s) end % \end{macrocode} % % % \bigskip % \subsubsection{Preprocessors of the function Parse for gobble} % % We deal now with preprocessors of the function |Parse| which are needed when % the ``gobble mechanism'' is used. % % % \bigskip % The function |gobble| gobbles $n$ characters on the left of the code. It uses % a \textsc{lpeg} that we have to compute dynamically because if depends on the % value of~$n$. % \begin{macrocode} local function gobble(n,code) if n==0 then return code else return ( Ct ( ( 1 - P "\r" ) ^ (-n) * C ( ( 1 - P "\r" ) ^ 0 ) * ( C ( P "\r" ) * ( 1 - P "\r" ) ^ (-n) * C ( ( 1 - P "\r" ) ^ 0 ) ) ^ 0 ) / table.concat ) : match ( code ) end end % \end{macrocode} % % % % \bigskip % The following function |sum| will be used in the following \textsc{lpeg} % |AutoGobbleLPEG|, |TabsAutoGobbleLPEG| and |EnvGobbleLPEG|. It computes the % sum of all its arguments. % \begin{macrocode} local function count_captures(...) local acc = 0 for _ in ipairs({...}) do acc = acc + 1 end return acc end % \end{macrocode} % % \bigskip % The following \textsc{lpeg} returns as capture the minimal number of spaces at % the beginning of the lines of code. % begin{macrocode} % \begin{macrocode} local AutoGobbleLPEG = ( ( % \end{macrocode} % We don't take into account the empty lines (those containing only spaces). % \begin{macrocode} P " " ^ 0 * P "\r" + C ( P " " ) ^ 0 / count_captures * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0 % \end{macrocode} % Now for the last line of the Python code... % \begin{macrocode} * ( C ( P " " ) ^ 0 / count_captures * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 ) / math.min % \end{macrocode} % % \bigskip % The following \textsc{lpeg} is similar but works with the indentations. % \begin{macrocode} local TabsAutoGobbleLPEG = ( ( P "\t" ^ 0 * P "\r" + C ( P " " ) ^ 0 / count_captures * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0 * ( C ( P " " ) ^ 0 / count_captures * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 ) / math.min % \end{macrocode} % % % % \bigskip % The following \textsc{lpeg} returns as capture the number of spaces at the % last line, that is to say before the |\end{Piton}| (and usually it's also the % number of spaces before the corresponding |\begin{Piton}| because that's the % traditionnal way to indent in LaTeX). % \begin{macrocode} local EnvGobbleLPEG = ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0 * ( C ( P " " ) ^ 0 / count_captures ) * -1 % \end{macrocode} % % \bigskip % \begin{macrocode} local function remove_before_cr(input_string) local match_result = P("\r") : match(input_string) if match_result then return string.sub(input_string, match_result ) else return input_string end end % \end{macrocode} % % \bigskip % \begin{macrocode} function piton.GobbleParse(language,n,code) code = remove_before_cr(code) if n==-1 then n = AutoGobbleLPEG : match(code) else if n==-2 then n = EnvGobbleLPEG : match(code) else if n==-3 then n = TabsAutoGobbleLPEG : match(code) end end end piton.last_code = gobble(n,code) piton.Parse(language,piton.last_code) piton.last_language = language % \end{macrocode} % Now, if the final user has used the key |write| to write the code of the % environment on an external file. % \begin{macrocode} if piton.write ~= '' then local file = assert(io.open(piton.write,piton.write_mode)) file:write(piton.get_last_code()) file:close() end end % \end{macrocode} % % \bigskip % The following Lua function is provided to the developper. % \begin{macrocode} function piton.get_last_code ( ) return CleanLPEGs[piton.last_language] : match(piton.last_code) end % \end{macrocode} % % % \bigskip % \subsubsection{To count the number of lines} % % \medskip % \begin{macrocode} function piton.CountLines(code) local count = 0 for i in code : gmatch ( "\r" ) do count = count + 1 end tex.sprint( luatexbase.catcodetables.expl , '\\int_set:Nn \\l_@@_nb_lines_int {' .. count .. '}' ) end % \end{macrocode} % % \begin{macrocode} function piton.CountNonEmptyLines(code) local count = 0 count = ( ( ( ( ( P " " ) ^ 0 * P "\r" + ( 1 - P "\r" ) ^ 0 * C ( P "\r" ) ) ^ 0 * (1 - P "\r" ) ^ 0 ) / count_captures ) * -1 ) : match (code) tex.sprint( luatexbase.catcodetables.expl , '\\int_set:Nn \\l_@@_nb_non_empty_lines_int {' .. count .. '}' ) end % \end{macrocode} % % \bigskip % \begin{macrocode} function piton.CountLinesFile(name) local count = 0 io.open(name) for line in io.lines(name) do count = count + 1 end tex.sprint( luatexbase.catcodetables.expl , '\\int_set:Nn \\l_@@_nb_lines_int {' .. count .. '}' ) end % \end{macrocode} % % % \bigskip % \begin{macrocode} function piton.CountNonEmptyLinesFile(name) local count = 0 for line in io.lines(name) do if not ( ( ( P " " ) ^ 0 * -1 ) : match ( line ) ) then count = count + 1 end end tex.sprint( luatexbase.catcodetables.expl , '\\int_set:Nn \\l_@@_nb_non_empty_lines_int {' .. count .. '}' ) end % \end{macrocode} % % % \bigskip % The following function stores in |\l_@@_first_line_int| and % |\l_@@_last_line_int| the numbers of lines of the file |file_name| % corresponding to the strings |marker_beginning| and |marker_end|. % \begin{macrocode} function piton.ComputeRange(marker_beginning,marker_end,file_name) local s = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( marker_beginning ) local t = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( marker_end ) local first_line = -1 local count = 0 local last_found = false for line in io.lines(file_name) do if first_line == -1 then if string.sub(line,1,#s) == s then first_line = count end else if string.sub(line,1,#t) == t then last_found = true break end end count = count + 1 end if first_line == -1 then tex.sprint("\\PitonBeginMarkerNotFound") else if last_found == false then tex.sprint("\\PitonEndMarkerNotFound") end end tex.sprint( luatexbase.catcodetables.expl , '\\int_set:Nn \\l_@@_first_line_int {' .. first_line .. ' + 2 }' .. '\\int_set:Nn \\l_@@_last_line_int {' .. count .. ' }' ) end % % \end{macrocode} % % % % \vspace{1cm} % \section{History} % % The successive versions of the file |piton.sty| provided by TeXLive are available on the % \textsc{svn} server of TeXLive:\par\nobreak % % \smallskip % { % \small % \nolinkurl{https://tug.org/svn/texlive/trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty} % } % % \medskip % The development of the extension \pkg{piton} is done on the following GitHub % repository: % % \verb|https://github.com/fpantigny/piton| % % \subsection*{Changes between versions 2.5 and 2.6} % % API: |piton.last_code| and |\g_piton_last_code_tl| are provided. % % \subsection*{Changes between versions 2.4 and 2.5} % % New key |path-write| % % \subsection*{Changes between versions 2.3 and 2.4} % % The key |identifiers| of the command |\PitonOptions| is now deprecated and % replaced by the new command |\SetPitonIdentifier|. % % A new special language called ``minimal'' has been added. % % New key |detected-commands|. % % \subsection*{Changes between versions 2.2 and 2.3} % % New key |detected-commands| % % The variable |\l_piton_language_str| is now public. % % % New key |write|. % % \subsection*{Changes between versions 2.1 and 2.2} % % New key |path| for |\PitonOptions|. % % New language SQL. % % It's now possible to define styles locally to a given language (with the % optional argument of |\SetPitonStyle|). % % \subsection*{Changes between versions 2.0 and 2.1} % % The key |line-numbers| has now subkeys |line-numbers/skip-empty-lines|, % |line-numbers/label-empty-lines|, etc. % % The key |all-line-numbers| is deprecated: use % |line-numbers/skip-empty-lines=false|. % % New system to import, with |\PitonInputFile|, only a part (of the file) % delimited by textual markers. % % New keys |begin-escape|, |end-escape|, |begin-escape-math| and |end-escape-math|. % % The key |escape-inside| is deprecated: use |begin-escape| and |end-escape|. % % % \subsection*{Changes between versions 1.6 and 2.0} % % The extension \pkg{piton} nows supports the computer languages OCaml and C % (and, of course, Python). % % \subsection*{Changes between versions 1.5 and 1.6} % % New key |width| (for the total width of the listing). % % New style |UserFunction| to format the names of the Python functions % previously defined by the user. Command |\PitonClearUserFunctions| to clear % the list of such functions names. % % \subsection*{Changes between versions 1.4 and 1.5} % % New key |numbers-sep|. % % % \subsection*{Changes between versions 1.3 and 1.4} % % New key |identifiers| in |\PitonOptions|. % % New command |\PitonStyle|. % % |background-color| now accepts as value a \emph{list} of colors. % % \subsection*{Changes between versions 1.2 and 1.3} % % When the class Beamer is used, the environment |{Piton}| and the command % |\PitonInputFile| are ``overlay-aware'' (that is to say, they accept a % specification of overlays between angular brackets). % % New key |prompt-background-color| % % It's now possible to use the command |\label| to reference a line of code in % an environment |{Piton}|. % % A new command |\|␣ is available in the argument of the command |\piton{...}| to % insert a space (otherwise, several spaces are replaced by a single space). % % \subsection*{Changes between versions 1.1 and 1.2} % % New keys |break-lines-in-piton| and |break-lines-in-Piton|. % % New key |show-spaces-in-string| and modification of the key |show-spaces|. % % When the class \cls{beamer} is used, the environements |{uncoverenv}|, % |{onlyenv}|, |{visibleenv}| and |{invisibleenv}| % % % \subsection*{Changes between versions 1.0 and 1.1} % % The extension \pkg{piton} detects the class \cls{beamer} and activates the % commands |\action|, |\alert|, |\invisible|, |\only|, |\uncover| and |\visible| % in the environments |{Piton}| when the class \cls{beamer} is used. % % \subsection*{Changes between versions 0.99 and 1.0} % % New key |tabs-auto-gobble|. % % \subsection*{Changes between versions 0.95 and 0.99} % % New key |break-lines| to allow breaks of the lines of code (and other keys to % customize the appearance). % % \subsection*{Changes between versions 0.9 and 0.95} % % New key |show-spaces|. % % The key |left-margin| now accepts the special value |auto|. % % New key |latex-comment| at load-time and replacement of |##| by |#>| % % New key |math-comments| at load-time. % % New keys |first-line| and |last-line| for the command |\InputPitonFile|. % % \subsection*{Changes between versions 0.8 and 0.9} % % New key |tab-size|. % % Integer value for the key |splittable|. % % \subsection*{Changes between versions 0.7 and 0.8} % % New keys |footnote| and |footnotehyper| at load-time. % % New key |left-margin|. % % \subsection*{Changes between versions 0.6 and 0.7} % % New keys |resume|, |splittable| and |background-color| in |\PitonOptions|. % % The file |piton.lua| has been embedded in the file |piton.sty|. That means % that the extension \pkg{piton} is now entirely contained in the file |piton.sty|. % % % % \tableofcontents % % \end{document} % % % Local Variables: % TeX-fold-mode: t % TeX-fold-preserve-comments: nil % flyspell-mode: nil % fill-column: 80 % End: