diff options
Diffstat (limited to 'Master/texmf-dist/source')
40 files changed, 22786 insertions, 15610 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx index b9a053a8a27..179f45d11c8 100644 --- a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx @@ -34,22 +34,23 @@ %% ----------------------------------------------------------------------- % %<*driver|package> -\RequirePackage{l3names}[2011/12/30] -%<package>\@ifpackagelater{l3names}{2011/12/30} +\RequirePackage{l3names}[2012/07/15] +%<package>\@ifpackagelater{l3names}{2012/07/15} %<package> {} -%<package> { +%<package> {% %<package> \PackageError{expl3}{Mismatched LaTeX3 packages detected.} -%<package> { +%<package> {% %<package> Please install an up to date version of l3kernel -%<package> using your TeX package manager or from CTAN.\\ \\ -%<package> Loading expl3 will abort! -%<package> } +%<package> using your TeX package manager or from CTAN.% +%<package> \MessageBreak \MessageBreak +%<package> Loading expl3 will abort!% +%<package> }% %<package> \endinput %<package> } \def\ExplFileName{expl3} \def\ExplFileDescription{L3 Experimental code bundle wrapper} -\def\ExplFileDate{2012/04/23} -\def\ExplFileVersion{3570} +\def\ExplFileDate{2012/07/16} +\def\ExplFileVersion{3990} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -163,8 +164,8 @@ % One problem with more traditional \TeX{} coding conventions (as % described in~\cite{A-W:K-TB}) is that the names and syntax of \TeX{}'s % primitive formatting commands are ingeniously designed to be -% \enquote{natural} when used directly by the author as document mark-up or in -% macros. Ironically, the ubiquity (and widely recognised +% \enquote{natural} when used directly by the author as document mark-up +% or in macros. Ironically, the ubiquity (and widely recognised % superiority) of logical mark-up has meant that such explicit % formatting commands are almost never needed in documents or in % author-defined macros. Thus they are used almost exclusively by @@ -309,6 +310,88 @@ % inferred from the presence or absence of a |g|. See the next subsection for % more detail on variable scope. % +% \subsubsection{Separating private and public material} +% +% One of the issues with the \TeX{} language is that it doesn't support +% name spaces and encapsulation other than by convention. As a result +% nearly every internal command in the \LaTeXe{} kernel has eventually +% be used by extension packages as an entry point for modifications or +% extensions. The consequences of this is that nowadays it is next to +% impossible to change anything in the \LaTeXe{} kernel (even if it is +% clearly just an internal command) without breaking something. +% +% In \pkg{expl3} we hope to improve this situation drastically by +% clearly separating public interfaces (that extension packages can use +% and rely on) and private functions and variables (that should not +% appear outside of their module). There is (nearly) no way to enforce +% this without severe computing overhead, so we implement it only +% through a naming convention, and some support mechanisms. However, we +% think that this naming convention is easy to understand and to follow, +% so that we are confident that this will adopted and provides the +% desired results. +% +% Functions created by a module may either be \enquote{public} (documented +% with a defined interface) or \enquote{private} (to be used only within +% that module, and thus not formally documented). It is important that +% only documented interfaces are used; at the same time, it is necessary to +% show within the name of a function or variable whether it is public +% or private. +% +% To allow clear separation of these two cases, the following convention +% is used. Private functions should be defined with |__| added to the beginning +% of the module name. Thus +% \begin{verbatim} +% \module_foo:nnn +% \end{verbatim} +% is a public function which should be documented while +% \begin{verbatim} +% \__module_foo:nnn +% \end{verbatim} +% is private to the module, and should \emph{not} be used outside of that +% module. +% +% In the same way, private variables should use two "__" at the start of the +% module name, such that +% \begin{verbatim} +% \l_module_foo_tl +% \end{verbatim} +% is a public variable and +% \begin{verbatim} +% \l__module_foo_tl +% \end{verbatim} +% is private. +% +% \subsubsection{Using \texttt{@@} and \pkg{l3docstrip} to mark private code} +% +% The formal syntax for internal functions allows clear separation of public +% and private code, but includes redundant information (every internal function +% or variable includes \texttt{__\meta{module}}). To aid programmers, the +% \pkg{l3docstrip} program introduces the syntax +% \begin{quote} +% \ttfamily +% |%<@@=|\meta{module}|>| +% \end{quote} +% which then allows |@@| (and |_@@| in case of variables) to be used as +% a place holder for \texttt{__\meta{module}} in code. Thus for example +% \begin{verbatim} +% %<@@=foo> +% % \begin{macrocode} +% \cs_new:Npn \@@_function:n #1 +% ... +% \tl_new:N \l_@@_my_tl +% % \end{macrocode} +% \end{verbatim} +% will be converted by \pkg{l3docstrip} to +% \begin{verbatim} +% \cs_new:Npn \__foo_function:n #1 +% ... +% \tl_new:N \l__foo_my_tl +% \end{verbatim} +% on extraction. As you can see both |_@@| and |@@| are mapped to +% \texttt{__\meta{module}}, because we think that this helps to +% distinguish variables from functions in the source when the |@@| +% convention is used. +% % \subsubsection{Variables: scope and type} % % The \meta{scope} part of the name describes how the variable can be @@ -323,11 +406,11 @@ % \end{arg-description} % % Separate functions are provided to assign data to local and global -% variables; for example, |\tl_set:Nn| and |\tl_gset:Nn| respectively +% variables; for example, \cs{tl_set:Nn} and \cs{tl_gset:Nn} respectively % set the value of a local or global \enquote{token list} variable. -% Note that it is a poor \TeX{} practise to intermix local and global -% assignments to a variable; otherwise you risk exhausting the save stack. -% \unskip\footnote{See \emph{The \TeX{}book}, p.\,301, for further +% Note that it is a poor \TeX{} practice to intermix local and global +% assignments to a variable; otherwise you risk exhausting the save +% stack.\footnote{See \emph{The \TeX{}book}, p.\,301, for further % information.} % % The \meta{type} will be in the list of available @@ -335,7 +418,7 @@ % needed then this will not be the case. However, it is hoped that only % the kernel team will need to create new data types.} these include the % primitive \TeX{} data-types, such as the various registers, but to -% these will be added data-types built within the \LaTeX{} programming +% these are added data-types built within the \LaTeX{} programming % system. % % The data types in \LaTeX3 are: @@ -349,27 +432,25 @@ % \item[dim] \enquote{rigid} lengths; % \item[fp] floating-point values; % \item[ior] an input stream (for reading from a file); -% \item[iow] an output stream (for writing from a file); +% \item[iow] an output stream (for writing to a file); % \item[int] integer-valued count register; +% \item[muskip] math mode \enquote{rubber} lengths; % \item[prop] property list; % \item[seq] sequence: a data-type used to implement lists (with % access at both ends) and stacks; % \item[skip] \enquote{rubber} lengths; -% \item[stream] an input or output stream (for reading from or writing -% to, respectively); % \item[tl] \enquote{token list variables}: placeholders for token lists. % \end{description} % When the \meta{type} and \meta{module} are identical (as often happens in % the more basic modules) the \meta{module} part is often omitted for % aesthetic reasons. % -% The name \enquote{token list} may cause confusion, and so some background is -% useful. \TeX{} works with tokens and lists of tokens, rather than -% characters. It provides two ways to store these token lists: within -% macros and as token registers (|toks|). The implementation in \LaTeX3 means -% that -% |toks| are not required, and that all operations for storing tokens can us -% the |tl| variable type. +% The name \enquote{token list} may cause confusion, and so some +% background is useful. \TeX{} works with tokens and lists of tokens, +% rather than characters. It provides two ways to store these token +% lists: within macros and as token registers (|toks|). The +% implementation in \LaTeX3 means that |toks| are not required, and that +% all operations for storing tokens can use the |tl| variable type. % % Experienced \TeX{} programmers will notice that some of the variable % types listed are native \TeX{} registers whilst others are not. In @@ -400,16 +481,16 @@ % then using the sequence functions which work in a stack manner % (\cs{seq_push:Nn}, \emph{etc}.). % -% Due to the nature of the underlying \TeX{} implementation, it is -% possible to assign values to token list variables and comma lists -% without first declaring them. However, this is \emph{not supported -% behaviour}. The \LaTeX3 coding convention is that all variables must -% be declared before use. +% Due to the nature of the underlying \TeX{} implementation, it is +% possible to assign values to token list variables and comma lists +% without first declaring them. However, this is \emph{not supported +% behaviour}. The \LaTeX3 coding convention is that all variables must +% be declared before use. % -% The \pkg{expl3} package can be loaded with the |check-declarations| option -% to verify that all variables are declared before use. This has a -% performance implication and is therefore intended for testing during -% development and not for use in production documents. +% The \pkg{expl3} package can be loaded with the |check-declarations| +% option to verify that all variables are declared before use. This has +% a performance implication and is therefore intended for testing during +% development and not for use in production documents. % % \subsubsection{Functions: argument specifications} % @@ -443,13 +524,12 @@ % \end{arg-description} % There are two other specifiers with more general meanings: % \begin{arg-description} -% \item[D] This means: \textbf{Do not use}. This special case is used -% for \TeX{} primitives and other commands that are provided for use -% only while bootstrapping the \LaTeX{} kernel. Programmers outside -% the kernel team should not use these functions! +% \item[D] This means: \textbf{Do not use}. This special case is used +% for \TeX{} primitives. Programmers outside the kernel team should +% not use these functions! % \item[w] This means that the argument syntax is \enquote{weird} in that it % does not follow any standard rule. It is used for functions with -% arguments that take non standard forms: examples are \TeX-level +% arguments that take non standard forms: examples are \TeX{}-level % delimited arguments and the boolean tests needed after certain % primitive |\if|\ldots{} commands. % \end{arg-description} @@ -468,13 +548,11 @@ % % Let's take a look at some typical operations one might want to % perform. Suppose we maintain a stack of open files and we use the -% stack |\g_ior_file_name_seq| to keep track of them (|io| is the -% file reading and writing module: it uses the module prefix -% \texttt{ior} for reading functions and variables). The basic -% operation here is to push a name onto this stack which could be -% done by the operation +% stack |\g_ior_file_name_seq| to keep track of them (\texttt{ior} is +% the prefix used for the file reading module). The basic operation here +% is to push a name onto this stack which could be done by the operation % \begin{quote} -% |\seq_gpush:Nn \g_ior_file_name_seq {#1}| +% \cs{seq_gpush:Nn} |\g_ior_file_name_seq {#1}| % \end{quote} % where |#1| is the filename. In other words, this operation would % push the file name as is onto the stack. @@ -483,20 +561,20 @@ % a variable of some sort, say |\l_ior_curr_file_tl|. In this case we % want to retrieve the value of the variable. If we simply use % \begin{quote} -% |\seq_gpush:Nn \g_io_file_name_seq \l_io_curr_file_tl| +% \cs{seq_gpush:Nn} |\g_ior_file_name_seq| |\l_ior_curr_file_tl| % \end{quote} % we will not get the value of the variable pushed onto the stack, % only the variable name itself. Instead a suitable number of -% |\exp_after:wN| would be necessary (together with extra braces) to +% \cs{exp_after:wN} would be necessary (together with extra braces) to % change the order of expansion,\footnote{\cs{exp_after:wN} is -% the \LaTeX3 name for the \TeX{} \tn{expandafter} primitive.}, \emph{i.e.} +% the \LaTeX3 name for the \TeX{} \tn{expandafter} primitive.} \emph{i.e.} % \begin{quote} -% |\exp_after:wN| \\ -% | \seq_gpush:Nn| \\ -% |\exp_after:wN| \\ -% | \g_io_file_name_seq| \\ -% |\exp_after:wN| \\ -% | { \l_io_curr_file_tl }| +% \cs{exp_after:wN} \\ +% | |\cs{seq_gpush:Nn} \\ +% \cs{exp_after:wN} \\ +% | \g_ior_file_name_seq| \\ +% \cs{exp_after:wN} \\ +% | { \l_ior_curr_file_tl }| % \end{quote} % % The above example is probably the simplest case but already shows @@ -512,7 +590,7 @@ % just uses different letters in the arg-spec part of the function to % mark the desired behaviour. In the above example one would write % \begin{quote} -% |\seq_gpush:NV \g_io_file_name_seq \l_io_curr_file_tl| +% \cs{seq_gpush:NV} |\g_ior_file_name_seq \l_ior_curr_file_tl| % \end{quote} % to achieve the desired effect. Here the |V| (the second argument) % is for \enquote{retrieve the value of the variable} before passing it to @@ -524,14 +602,15 @@ % \item[c] Character string used as a command name.\\ The argument (a % token or braced token list) must, when fully expanded, produce a % sequence of characters which is then used to construct a command -% name (\emph{via}~|\csname| \ldots |\endcsname|). This command name is the +% name (\emph{via}~\tn{csname} \ldots \tn{endcsname}). +% This command name is the % single token that is passed to the function as the argument. Hence % \begin{quote} -% |\seq_gpush:cV { g_file_name_seq } \l_tmpa_tl| +% \cs{seq_gpush:cV} |{ g_file_name_seq }| \cs{l_tmpa_tl} % \end{quote} % is equivalent to % \begin{quote} -% |\seq_gpush:NV \g_file_name_seq \l_tmpa_tl"| +% \cs{seq_gpush:NV} |\g_file_name_seq| \cs{l_tmpa_tl}. % \end{quote} % Remember that \texttt{c} arguments are \emph{fully expanded} by % \TeX{} when creating csnames. This means that (a) the entire @@ -539,13 +618,14 @@ % converted to their content. So the preceding examples are also % equivalent to % \begin{quote} -% |\tl_new:N \g_file_seq_name_tl| \\ -% |\tl_gset:Nn \g_file_seq_name_tl { g_file_name_seq }| \\ -% |\seq_gpush:cV { \g_file_seq_name_tl } \l_tmpa_tl|. +% \cs{tl_new:N} |\g_file_seq_name_tl| \\ +% \cs{tl_gset:Nn} |\g_file_seq_name_tl { g_file_name_seq }| \\ +% \cs{seq_gpush:cV} |{| \cs{tl_use:N} |\g_file_seq_name_tl }| \cs{l_tmpa_tl}. % \end{quote} -% (Token list variables are expandable and do not require an -% accessor function. Other variable types require the appropriate -% \cs{<var>_use:N} functions to be used in this context.) +% (Token list variables are expandable and we could omit the +% accessor function \cs{tl_use:N}. Other variable types require the +% appropriate \cs{<var>_use:N} functions to be used in this +% context.) % \item[V] Value of a variable.\\ % This means that the contents of the register in question is used as the % argument, be it an integer, a length-type register, a token list variable @@ -557,21 +637,22 @@ % resulting register to the function. % \item[x] Fully-expanded token or braced token list.\\ % This means that the argument is expanded as in the replacement -% text of an~|\edef|, and the expansion is passed to the function as -% a braced token list. This means that expansion takes place until -% only unexpandable tokens are left. -% \item[o] One-level-expanded token or braced token list.\\ +% text of an~\tn{edef}, and the expansion is passed to the function as +% a braced token list. Expansion takes place until only unexpandable +% tokens are left. |x|-type arguments cannot be nested. +% \item[o] One-level-expanded token or braced token list.\\ % This means that the argument is expanded one level, as by % \tn{expandafter}, and the expansion is passed to the function as a % braced token list. Note that if the original argument is a braced % token list then only the first token in that list is expanded. % In general, using \texttt{V} should be preferred to using % \texttt{o} for simple variable retrieval. -% \item[f] Almost the same as the |x| type except here the token list +% \item[f] Expanding the first token recursively in a braced token +% list.\\ Almost the same as the |x| type except here the token list % is expanded fully until the first unexpandable token is found and % the rest is left unchanged. Note that if this function finds a % space at the beginning of the argument it will gobble it and not -% expand the next argument. +% expand the next token. % \end{description} % % \subsection{Simpler means better} @@ -587,15 +668,15 @@ % \csname\cf@encoding \string#1\expandafter\endcsname % \csname ?\string#1\endcsname % \end{verbatim} -% This first piece of code is in essence simply a global |\let| whose -% two arguments firstly have to be constructed before |\let| is +% This first piece of code is in essence simply a global \tn{let} whose +% two arguments firstly have to be constructed before \tn{let} is % executed. The |#1| is a control sequence name such as % |\textcurrency|. The token to be defined is obtained by % concatenating the characters of the current font encoding stored in % |\cf@encoding|, which has to be fully expanded, and the name of the % symbol. The second token is the same except it uses the default -% encoding |?|. The result is a mess of interwoven |\expandafter| -% and |\csname| beloved of all \TeX{} programmers, and the code is +% encoding |?|. The result is a mess of interwoven \tn{expandafter} +% and \tn{csname} beloved of all \TeX{} programmers, and the code is % essentially unreadable. % % Using the conventions and functionality outlined here, the task would @@ -604,7 +685,7 @@ % \cs_gset_eq:cc % { \cf@encoding \token_to_str:N #1 } { ? \token_to_str:N #1 } % \end{verbatim} -% The command |\cs_gset_eq:cc| is a global~|\let| that generates +% The command \cs{cs_gset_eq:cc} is a global~\tn{let} that generates % command names out of both of its arguments before making the % definition. This produces code that is far more readable and more % likely to be correct first time. (\cs{token_to_str:N} is the \LaTeX3 @@ -623,29 +704,33 @@ % \end{verbatim} % This piece of code is part of the definition of another function. It % first produces two things: a token list, by expanding |\group@list| once; -% and a token whose name comes from~`|sym#3|'. Then the function~|\in@| +% and a token whose name comes from~`|sym#3|'. Then the function~\cs{in@} % is called and this tests if its first argument occurs in the token list % of its second argument. % % Again we can improve enormously on the code. First we shall rename -% the function~|\in@| according to our conventions. A function such as -% this but taking two normal \enquote{\texttt{n}} arguments might reasonably be -% named |\seq_test_in:Nn|; thus the variant function we need will be -% defined with the appropriate argument types and its name will be -% |\seq_test_in:cV|. Now this code fragment will be simply: +% the function~\cs{in@}, which tests if its first argument appears +% within its second argument, according to our conventions. Such a +% function takes two normal \enquote{\texttt{n}} arguments and operates +% on token lists: it might reasonably be named |\tl_test_in:nn|. Thus +% the variant function we need will be defined with the appropriate +% argument types and its name will be |\tl_test_in:cV|. Now this code +% fragment will be simply: % \begin{verbatim} -% \seq_test_in:cV { sym #3 } \l_group_seq +% \tl_test_in:cV { sym #3 } \group@list % \end{verbatim} -% Note that, in addition to the lack of |\expandafter|, the space after -% the~|}| will be silently ignored since all white space is ignored in -% this programming environment. +% This code could be improved further by using a sequence |\l_group_seq| +% rather than the bare token list |\group@list|. Note that, in addition +% to the lack of \tn{expandafter}, the space after the~|}| will be +% silently ignored since all white space is ignored in this programming +% environment. % % \subsection{New functions from old} % % For many common functions the \LaTeX3 kernel will provide variants % with a range of argument forms, and similarly it is expected that % extension packages providing new functions will make them available in -% the all the commonly needed forms. +% all the commonly needed forms. % % However, there will be occasions where it is necessary to construct a % new such variant form; therefore the expansion module provides a @@ -690,7 +775,7 @@ % |\demo_cmd_b:xcxcx|, a variant of an existing function % |\demo_cmd_b:nnnnn|, that fully % expands arguments 1,~3 and~5, and produces commands to pass as -% arguments 2 and~4 using~|\csname|. +% arguments 2 and~4 using~\tn{csname}. % The definition you need is simply % \begin{verbatim} % \cs_generate_variant:Nn \demo_cmd_b:nnnnn { xcxcx } @@ -715,10 +800,10 @@ % \pkg{expl3}. % \end{bfseries} % -% New modules will be added to the distributed version of \pkg{expl3} -% as they reach maturity. At present, the \pkg{expl3} bundle consists -% of a number of modules, most of which are loaded by including the -% line: +% New modules will be added to the distributed version of \pkg{expl3} +% as they reach maturity. At present, the \pkg{expl3} bundle consists +% of a number of modules, most of which are loaded by including the +% line: % \begin{verbatim} % \RequirePackage{expl3} % \end{verbatim} @@ -765,7 +850,7 @@ % } % \explpkg{l3prg}{ % Program control structures such as boolean data type |bool|, generic -% do-while loops, case-switches, sorting routines and stepwise loops. +% do-while loops, and conditional flow. % } % \explpkg{l3prop}{ % This implements the data-type for \enquote{property lists} that are used, in @@ -781,8 +866,9 @@ % This implements data-types such as queues and stacks. % } % \explpkg{l3skip}{ -% Implements the \enquote{rubber length} datatype \texttt{skip} and the -% \enquote{rigid length} datatype |dim|. +% Implements the \enquote{rubber length} datatype \texttt{skip}, the +% \enquote{rigid length} datatype |dim|, and the math mode +% \enquote{rubber length} datatype \texttt{muskip}. % } % \explpkg{l3tl}{ % This implements a basic data-type, called a \textit{token-list @@ -809,8 +895,9 @@ % For example, you may well need \tn{@ifpackageloaded}, as there % is currently no native \LaTeX3 package loading module. % \item User level macros should be generated using the mechanism -% available in the \pkg{xparse} package, which is available from CTAN -% or the \LaTeX3 SVN repository. +% available in the \pkg{xparse} package, which is part of the +% \texttt{l3package} bundle, available from CTAN or the \LaTeX3 SVN +% repository. % \item At an internal level, most functions should be generated % \tn{long} (using \cs{cs_new:Npn}) rather than \enquote{short} (using % \cs{cs_new_nopar:Npn}). However, functions which take no arguments @@ -818,7 +905,7 @@ % \item Where possible, declare all variables and functions (using % \cs{cs_new:Npn}, \cs{tl_new:N}, etc.) before use. % \item Prefer \enquote{higher-level} functions over \enquote{lower-level}, -% where possible. So for example use \cs{cs_if_exist:N(TF)} in preference +% where possible. So for example use \cs{cs_if_exist:N(TF)} and not % \cs{if_cs_exist:N}. % \item Use space to make code readable. In general, we recommend % a layout such as: @@ -826,8 +913,8 @@ % \cs_new:Npn \foo_bar:Nn #1#2 % { % \cs_if_exist:NTF #1 -% { \foo_bar_aux_i:n {#2} } -% { \foo_bar_aux_ii:nn {#2} { literal } } +% { \__foo_bar_aux_i:n {#2} } +% { \__foo_bar_aux_ii:nn {#2} { literal } } % } % \end{verbatim} % where spaces are used around |{| and |}| except for isolated @@ -862,11 +949,11 @@ % function name in the \texttt{.log} file. This is useful for debugging % purposes, as it means that there is a complete list of all functions % created by each module loaded (with the exceptions of a very small number -% required by he bootstrap code for \LaTeX3). +% required by the bootstrap code for \LaTeX3). % % \DescribeOption{native-drivers} % The \texttt{native-drivers} option instructs \LaTeX3 not to use the \LaTeXe{} -% graphics and colour driver code. Setting this option \texttt{true} uses the +% graphics driver code. Setting this option \texttt{true} uses the % driver code intended for a \LaTeX3 format. % % \section{The \LaTeX3 Project} @@ -890,8 +977,8 @@ % \begin{itemize} % \item Michael Downes % \item Denys Duchier -% \item Alan Jeffrey % \item Morten H{\o}gholm +% \item Alan Jeffrey % \item Martin Schr{\"o}der % \end{itemize} % @@ -945,7 +1032,7 @@ % \end{macrocode} % % \begin{macro}[aux]{\expl@create@bool@option} -% \begin{variable} +% \begin{variable}[int] % { % \l@expl@check@declarations@bool , % \l@expl@log@functions@bool , @@ -965,84 +1052,74 @@ \expl@create@bool@option { check-declarations } \l@expl@check@declarations@bool \expl@create@bool@option { log-functions } \l@expl@log@functions@bool \expl@create@bool@option { native-drivers } \l@expl@native@drivers@bool -\ProcessOptions \relax \let \expl@create@bool@option \@undefined +\ProcessOptions \relax % \end{macrocode} % \end{variable} % \end{macro} % -% \begin{macrocode} -\ifodd \l@expl@native@drivers@bool \relax -\else - \RequirePackage { color , graphics } -\fi -% \end{macrocode} -% % We already loaded \pkg{l3names} at the beginning of the \texttt{dtx} file. % We now load the base of \LaTeX3, stopping once token list variables are % defined. % \begin{macrocode} -\RequirePackage{ l3basics, l3expan, l3tl } +\RequirePackage { l3basics, l3expan, l3tl } % \end{macrocode} % -% \begin{macro}{\cs_check_exists:N} +% \begin{macro}[int]{\__cs_check_exists:N} % When used as a package, there is an option to be picky and to % check definitions exist. This part of the process is done now, so that % variable types based on |tl| (for example |clist|, |seq| and |prop|) will % inherit the appropriate definitions. % \begin{macrocode} \ifodd \l@expl@check@declarations@bool \relax - \cs_new_protected:Npn \cs_check_exists:N #1 + \cs_new_protected:Npn \__cs_check_exists:N #1 { \cs_if_exist:NF #1 { - \msg_kernel_error:nnx { check } { non-declared-variable } + \__msg_kernel_error:nnx { check } { non-declared-variable } { \token_to_str:N #1 } } } \cs_set_protected:Npn \tl_set:Nn #1#2 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \cs_set_nopar:Npx #1 { \exp_not:n {#2} } } \cs_set_protected:Npn \tl_set:Nx #1#2 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \cs_set_nopar:Npx #1 {#2} } \cs_set_protected:Npn \tl_gset:Nn #1#2 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } } \cs_set_protected:Npn \tl_gset:Nx #1#2 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \cs_gset_nopar:Npx #1 {#2} } \cs_set_protected:Npn \tl_set_eq:NN #1#2 { - \cs_check_exists:N #1 - \cs_check_exists:N #2 + \__cs_check_exists:N #1 + \__cs_check_exists:N #2 \cs_set_eq:NN #1 #2 } \cs_set_protected:Npn \tl_gset_eq:NN #1#2 { - \cs_check_exists:N #1 - \cs_check_exists:N #2 + \__cs_check_exists:N #1 + \__cs_check_exists:N #2 \cs_gset_eq:NN #1 #2 } \fi % \end{macrocode} % \end{macro} % -% The rest of the code can now be loaded. +% The second part of the file can now be loaded, stopping once the boolean +% data type is defined. % \begin{macrocode} -\RequirePackage{ - l3seq, - l3int, - l3quark, - l3prg} +\RequirePackage { l3seq, l3int, l3quark, l3prg } % \end{macrocode} % % Booleans are not based on token lists but do need checking: another @@ -1051,62 +1128,65 @@ \ifodd \l@expl@check@declarations@bool \relax \cs_set_protected:Npn \bool_set_true:N #1 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \cs_set_eq:NN #1 \c_true_bool } \cs_set_protected:Npn \bool_set_false:N #1 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \cs_set_eq:NN #1 \c_false_bool } \cs_set_protected:Npn \bool_gset_true:N #1 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \cs_gset_eq:NN #1 \c_true_bool } \cs_set_protected:Npn \bool_gset_false:N #1 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \cs_gset_eq:NN #1 \c_false_bool } \cs_set_protected:Npn \bool_set_eq:NN #1 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \cs_set_eq:NN #1 } \cs_set_protected:Npn \bool_gset_eq:NN #1 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \cs_gset_eq:NN #1 } \cs_set_protected:Npn \bool_set:Nn #1#2 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \tex_chardef:D #1 = \bool_if_p:n {#2} } \cs_set_protected:Npn \bool_gset:Nn #1#2 { - \cs_check_exists:N #1 + \__cs_check_exists:N #1 \tex_global:D \tex_chardef:D #1 = \bool_if_p:n {#2} } \fi % \end{macrocode} % +% Now everything else can be loaded. % \begin{macrocode} -\RequirePackage{ - l3clist, - l3token, - l3prop, - l3msg, - l3file, - l3skip, - l3keys, - l3fp, - l3box, - l3coffins, - l3color, - l3luatex -} +\RequirePackage + { + l3clist, + l3token, + l3prop, + l3msg, + l3file, + l3skip, + l3keys, + l3fp, + l3box, + l3coffins, + l3color, + l3luatex, + l3candidates + } % \end{macrocode} % % The error message for variables cannot be created before now: this means that @@ -1114,11 +1194,11 @@ % \begin{macrocode} \bool_if:nT { \l@expl@check@declarations@bool } { - \msg_kernel_new:nnnn { check } { non-declared-variable } + \__msg_kernel_new:nnnn { check } { non-declared-variable } { The~variable~#1~has~not~been~declared~\msg_line_context:. } { Checking~is~active,~and~you~have~tried~do~so~something~like: \\ - \ \ \tl_set:Nn ~ #1 ~ \iow_char:N \{ ~ ... ~ \iow_char:N \} \\ + \ \ \tl_set:Nn ~ #1 ~ \{ ~ ... ~ \} \\ without~first~having: \\ \ \ \tl_new:N ~ #1 \\ \\ @@ -1128,10 +1208,19 @@ % \end{macrocode} % % \begin{macro}{\color} -% If the native drivers are being used, they can be loaded now. The -% \cs{color} macro must be defined for showing coffin poles, so +% The \cs{color} macro must be defined for showing coffin poles, so % a no-op version is provided here. % \begin{macrocode} +\AtBeginDocument + { + \cs_if_exist:NF \color + { \DeclareRobustCommand \color [2] [ ] { } } + } +% \end{macrocode} +% \end{macro} +% +% If the native drivers are being used, they can be loaded now. +% \begin{macrocode} \bool_if:nTF { \l@expl@native@drivers@bool } { \xetex_if_engine:TF @@ -1144,14 +1233,8 @@ \file_input:n { l3dvips.def } \fi } - \AtBeginDocument - { - \cs_if_free:NT \color - { \DeclareRobustCommand \color [2] [ ] { } } - } } % \end{macrocode} -% \end{macro} % \begin{macro} % { % \box_rotate:Nn, @@ -1160,10 +1243,24 @@ % \box_resize_to_wd:Nn, % \box_scale:Nnn % } -% If not, alter various definitions to use the \pkg{graphicx} package -% instead. +% If not, alter various definitions to use the \pkg{graphics} package +% instead. The package is loaded right at the start of the hook +% as there is otherwise a potential issue with \pkg{(x)color}: see +% \url{http://groups.google.com/group/comp.text.tex/msg/c9de8913c756ef4c}. % \begin{macrocode} { + \tl_gput_left:Nn \@begindocumenthook { \RequirePackage { graphics } } + \__msg_kernel_new:nnnn { box } { clipping-not-available } + { Box~clipping~not~available. } + { + The~\box_clip:N~function~is~only~available~when~loading~expl3~ + with~the~"native-drivers"~option. + } + \cs_set_protected:Npn \box_clip:N #1 + { + \hbox_set:Nn #1 { \box_use:N #1 } + \__msg_kernel_error:nn { box } { clipping-not-available } + } \cs_set_protected:Npn \box_rotate:Nn #1#2 { \hbox_set:Nn #1 { \rotatebox {#2} { \box_use:N #1 } } } \cs_set_protected:Npn \box_resize:Nnn #1#2#3 @@ -1171,8 +1268,8 @@ \hbox_set:Nn #1 { \resizebox * - { \etex_dimexpr:D #2 \scan_stop: } - { \etex_dimexpr:D #3 \scan_stop: } + { \__dim_eval:w #2 \__dim_eval_end: } + { \__dim_eval:w #3 \__dim_eval_end: } { \box_use:N #1 } } } @@ -1180,7 +1277,7 @@ { \hbox_set:Nn #1 { - \resizebox * { ! } { \etex_dimexpr:D #2 \scan_stop: } + \resizebox * { ! } { \__dim_eval:w #2 \__dim_eval_end: } { \box_use:N #1 } } } @@ -1188,12 +1285,19 @@ { \hbox_set:Nn #1 { - \resizebox * { \etex_dimexpr:D #2 \scan_stop: } { ! } + \resizebox * { \__dim_eval:w #2 \__dim_eval_end: } { ! } { \box_use:N #1 } } } \cs_set_protected:Npn \box_scale:Nnn #1#2#3 - { \hbox_set:Nn #1 { \scalebox {#2} [#3] { \box_use:N #1 } } } + { + \hbox_set:Nn #1 + { + \exp_last_unbraced:Nx \scalebox + { { \fp_eval:n {#2} } [ \fp_eval:n {#3} ] } + { \box_use:N #1 } + } + } } % \end{macrocode} % \end{macro} @@ -1205,7 +1309,7 @@ % \begin{macrocode} \cs_set_protected_nopar:Npn \ExplSyntaxOn { - \bool_if:NF \l_expl_status_bool + \bool_if:NF \l__kernel_expl_bool { \cs_set_protected_nopar:Npx \ExplSyntaxOff { @@ -1220,7 +1324,7 @@ \char_set_catcode:nn { 124 } { \char_value_catcode:n { 124 } } \char_set_catcode:nn { 126 } { \char_value_catcode:n { 126 } } \tex_endlinechar:D = \tex_the:D \tex_endlinechar:D \scan_stop: - \bool_set_false:N \l_expl_status_bool + \bool_set_false:N \l__kernel_expl_bool \cs_set_protected_nopar:Npn \ExplSyntaxOff { } } } @@ -1235,7 +1339,7 @@ \char_set_catcode_other:n { 124 } % pipe \char_set_catcode_space:n { 126 } % tilde \tex_endlinechar:D = 32 \scan_stop: - \bool_set_true:N \l_expl_status_bool + \bool_set_true:N \l__kernel_expl_bool } \cs_set_protected_nopar:Npx \ExplSyntaxOff { @@ -1251,4 +1355,4 @@ % % \end{implementation} % -% \PrintIndex +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx b/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx index d9e59a686a7..6d8f58c86b0 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3alloc.dtx Copyright (C) 1990-2011 The LaTeX3 Project +%% File: l3alloc.dtx Copyright (C) 1990-2012 The LaTeX3 Project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3alloc.dtx 3355 2012-02-09 07:18:22Z joseph $ - {L3 Experimental register allocation} +\GetIdInfo$Id: l3alloc.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Register allocation} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -67,7 +67,7 @@ % % \begin{documentation} % -% Note that this module is only used for generating an pkg{expl3}-based +% Note that this module is only used for generating an \pkg{expl3}-based % format. Under \LaTeX{}, the \pkg{etex} package is used for allocation % management. % @@ -83,24 +83,29 @@ % \item \TeX{} supports no more than 16 I/O streams for reading % (\tn{read}) and 16 I/O streams for writing (\tn{write}), % \item \TeX{} supports no more than 256 inserts. -% \item The other registers (\tn{count}, \tn{dimen}, -% \tn{skip}, \tn{muskip}, \tn{box}, and \tn{toks}) -% range from 0 to 32768, but registers numbered above 255 are +% \item The other registers (\tn{count}, \tn{dimen}, \tn{skip}, +% \tn{muskip}, \tn{box}, and \tn{toks}) range from 0 to 32767 +% (65535 for \LuaTeX{}), but registers numbered above 255 are % accessed somewhat less efficiently. % \item Registers could be allocated both globally and locally; the -% use of registers could also be globally or locally. Here we +% use of registers could also be global or local. Here we % provide support for globally allocated registers for both % global and local use. -% \end{itemize} +% \end{itemize} % We also need to allow for some bookkeeping: we need to know which % register was allocated last and which registers can not be % allocated by the standard mechanisms. % -% \begin{function}[updated = 2011-09-05]{\alloc_new:nnnN} +% \section{Internal functions} +% +% Register-based allocation is a low-level process, and is therefore +% only to be used as part of kernel code. +% +% \begin{function}[updated = 2011-09-05]{\__alloc_new:nnnN} % \begin{syntax} -% \cs{alloc_new:nnnN} \Arg{type} \Arg{min} \Arg{max} \meta{function} +% \cs{__alloc_new:nnnN} \Arg{type} \Arg{min} \Arg{max} \meta{function} % \end{syntax} -% Shorthand for allocating new registers. Defines \cs{<type>_new:N} as +% Shorthand for allocating new registers. Defines \cs{\meta{type}_new:N} as % and allocator function of the specified \meta{type}, indexed up from % \meta{min} to a \meta{max}, and with assignment carried out by % the \meta{function}. This process will create two token lists, @@ -110,20 +115,18 @@ % numbers which should not be used. % \end{function} % -% \section{Internal functions} -% -% \begin{function}[updated = 2011-09-05]{\alloc_setup_type:nnn} +% \begin{function}[updated = 2011-09-05]{\__alloc_setup_type:nnn} % \begin{syntax} -% \cs{alloc_setup_type:nnn} \Arg{type} \Arg{min} \Arg{max} +% \cs{__alloc_setup_type:nnn} \Arg{type} \Arg{min} \Arg{max} % \end{syntax} % Sets up the storage needed for the administration of registers of % \Arg{type}, which will start allocating at \meta{min} and will issue % an error if there is an attempt to allocate past the \meta{max}. % \end{function} % -% \begin{function}{\alloc_reg:nNN} +% \begin{function}{\__alloc_reg:nNN} % \begin{syntax} -% \cs{alloc_reg:nNN} \Arg{type} \meta{function} \meta{register} +% \cs{__alloc_reg:nNN} \Arg{type} \meta{function} \meta{register} % \end{syntax} % Preforms the allocation for a new \meta{register} of \meta{type}, % using the allocator \meta{function} (which will be either a @@ -140,28 +143,33 @@ %<*initex> % \end{macrocode} % -% \begin{macro}{\alloc_new:nnnN} +% \begin{macrocode} +%<@@=alloc> +% \end{macrocode} +% +% \begin{macro}[int]{\@@_new:nnnN} % Shorthand for defining new register types and their allocators: % \begin{macrocode} -\cs_new_protected:Npn \alloc_new:nnnN #1#2#3#4 +\cs_new_protected:Npn \@@_new:nnnN #1#2#3#4 { - \alloc_setup_type:nnn {#1} {#2} {#3} - \cs_new:cpn { #1 _new:N } ##1 { \alloc_reg:nNN {#1} #4 ##1 } + \@@_setup_type:nnn {#1} {#2} {#3} + \cs_new:cpn { #1 _new:N } ##1 { \@@_reg:nNN {#1} #4 ##1 } } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\alloc_setup_type:nnn} +% \begin{macro}[int]{\@@_setup_type:nnn} % For each type of register we need to \enquote{counters} that hold the % last allocated global register, plus a constant for the maximum % allocation. We also need a sequence to store the \enquote{exceptions}. +% All of those variables are internal to the module |#1|. % \begin{macrocode} -\cs_new_protected:Npn \alloc_setup_type:nnn #1#2#3 +\cs_new_protected:Npn \@@_setup_type:nnn #1#2#3 { - \tl_new:c { g_ #1 _allocation_tl } - \tl_gset:cx { g_ #1 _allocation_tl } { \int_eval:n {#2} } - \tl_const:cx { c_ #1 _allocation_max_tl } { \int_eval:n {#3} } - \seq_new:c { g_ #1 _allocation_seq } + \tl_new:c { g__ #1 _allocation_tl } + \tl_gset:cx { g__ #1 _allocation_tl } { \int_eval:n {#2} } + \tl_const:cx { c__ #1 _allocation_max_tl } { \int_eval:n {#3} } + \seq_new:c { g__ #1 _allocation_seq } } % \end{macrocode} % \end{macro} @@ -176,44 +184,44 @@ % \end{macro} % % \begin{macro} -% {box_new:N, \dim_new:N, \int_new:N, \muskip_new:N \skip_new:N} +% {\box_new:N, \dim_new:N, \int_new:N, \muskip_new:N \skip_new:N} % To get everything to work correctly for inserts, some register types % need to have their allocators set up \enquote{early}. It therefore % makes sense to collect most of them together here. % \begin{macrocode} \luatex_if_engine:TF - { \alloc_new:nnnN { box } \c_zero \c_max_register_int \tex_chardef:D } - { \alloc_new:nnnN { box } \c_zero \c_max_register_int \tex_mathchardef:D } -\alloc_new:nnnN { dim } \c_zero \c_max_register_int \tex_dimendef:D -\alloc_new:nnnN { int } { 11 } \c_max_register_int \tex_countdef:D -\alloc_new:nnnN { muskip } \c_zero \c_max_register_int \tex_muskipdef:D -\alloc_new:nnnN { skip } \c_zero \c_max_register_int \tex_skipdef:D + { \@@_new:nnnN { box } \c_zero \c_max_register_int \tex_chardef:D } + { \@@_new:nnnN { box } \c_zero \c_max_register_int \tex_mathchardef:D } +\@@_new:nnnN { dim } \c_zero \c_max_register_int \tex_dimendef:D +\@@_new:nnnN { int } { 11 } \c_max_register_int \tex_countdef:D +\@@_new:nnnN { muskip } \c_zero \c_max_register_int \tex_muskipdef:D +\@@_new:nnnN { skip } \c_zero \c_max_register_int \tex_skipdef:D % \end{macrocode} % \end{macro} % % \begin{macro}{\insert_new:N} -% \begin{macro}[aux]{\alloc_reserve_insert:n} +% \begin{macro}[aux]{\@@_reserve_insert:n} % For inserts, there is a need to reserve space in various other registers. % \begin{macrocode} -\alloc_new:nnnN { insert } { 221 } { 254 } \tex_chardef:D +\@@_new:nnnN { insert } { 221 } { 254 } \tex_chardef:D \group_begin: - \cs_set_protected:Npn \alloc_reserve_insert:n #1 + \cs_set_protected:Npn \@@_reserve_insert:n #1 { - \tex_ifnum:D #1 > \c_insert_allocation_max_tl \scan_stop: + \tex_ifnum:D #1 > \c__insert_allocation_max_tl \scan_stop: \exp_after:wN \use_none:n \tex_else:D \exp_after:wN \use:n \tex_fi:D { - \seq_put_right:Nn \g_box_allocation_seq {#1} - \seq_put_right:Nn \g_dim_allocation_seq {#1} - \seq_put_right:Nn \g_int_allocation_seq {#1} - \seq_put_right:Nn \g_skip_allocation_seq {#1} - \exp_args:Nf \alloc_reserve_insert:n + \seq_put_right:Nn \g__box_allocation_seq {#1} + \seq_put_right:Nn \g__dim_allocation_seq {#1} + \seq_put_right:Nn \g__int_allocation_seq {#1} + \seq_put_right:Nn \g__skip_allocation_seq {#1} + \exp_args:Nf \@@_reserve_insert:n { \etex_numexpr:D #1 + 1 \scan_stop: } } } - \alloc_reserve_insert:n { 221 } + \@@_reserve_insert:n { 221 } \group_end: % \end{macrocode} % \end{macro} @@ -222,45 +230,45 @@ % Box $255$ is reserved by \TeX{} for output, so is protected here from % use by the allocator. % \begin{macrocode} -\seq_put_right:Nn \g_box_allocation_seq { 255 } +\seq_put_right:Nn \g__box_allocation_seq { 255 } % \end{macrocode} % -% \begin{macro}[int]{\alloc_reg:nNN} +% \begin{macro}[int]{\@@_reg:nNN} % This internal macro performs the actual allocation. % \begin{macrocode} -\cs_new_protected:Npn \alloc_reg:nNN #1#2#3 +\cs_new_protected:Npn \@@_reg:nNN #1#2#3 { - \chk_if_free_cs:N #3 - \tex_global:D #2 #3 \tl_use:c { g_ #1 _allocation_tl } \scan_stop: + \__chk_if_free_cs:N #3 + \tex_global:D #2 #3 \tl_use:c { g__ #1 _allocation_tl } \scan_stop: \iow_log:x { \token_to_str:N #3 ~=~ #1 ~register~ - \tl_use:c { g_ #1 _allocation_tl } + \tl_use:c { g__ #1 _allocation_tl } } - \alloc_next:n {#1} + \@@_next:n {#1} } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\alloc_next:n} +% \begin{macro}[aux]{\@@_next:n} % Finding the next register to use is a question of doing an increment % then a check: if we run out of registers then it is a fatal error, so % there is no need to unwind the change. (The check could be done % first but that needs an additional calculation.) There is a built-in % loop to handle reserved allocation positions. % \begin{macrocode} -\cs_new_protected:Npn \alloc_next:n #1 +\cs_new_protected:Npn \@@_next:n #1 { - \tl_gset:cx { g_ #1 _allocation_tl } - { \int_eval:n { \tl_use:c { g_ #1 _allocation_tl } + 1 } } + \tl_gset:cx { g__ #1 _allocation_tl } + { \int_eval:n { \tl_use:c { g__ #1 _allocation_tl } + 1 } } \int_compare:nNnTF - { \tl_use:c { g_ #1 _allocation_tl } } - > { \tl_use:c { c_ #1 _allocation_max_tl } } - { \msg_kernel_fatal:nnx { kernel } { out-of-registers } {#1} } + { \tl_use:c { g__ #1 _allocation_tl } } + > { \tl_use:c { c__ #1 _allocation_max_tl } } + { \__msg_kernel_fatal:nnx { kernel } { out-of-registers } {#1} } { - \seq_if_in:cxT { g_ #1 _allocation_seq } - { \tl_use:c { g_ #1 _allocation_tl } } - { \alloc_next:n {#1} } + \seq_if_in:cxT { g__ #1 _allocation_seq } + { \tl_use:c { g__ #1 _allocation_tl } } + { \@@_next:n {#1} } } } % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx index f6be95ab725..549ec6de6f8 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3basics.dtx 3491 2012-03-04 06:13:18Z bruno $ - {L3 Experimental basic definitions} +\GetIdInfo$Id: l3basics.dtx 3987 2012-07-15 21:57:39Z joseph $ + {L3 Basic definitions} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -155,36 +155,36 @@ % for the formal parameters (|#1|, |#2|, \ldots). % \begin{description} % \item[\texttt{new}] -% Create a new function with the \texttt{new} primitives, +% Create a new function with the \texttt{new} scope, % such as \cs{cs_new:Npn}. The definition is global and will result in % an error if it is already defined. % \item[\texttt{set}] -% Create a new function with the \texttt{set} primitives, +% Create a new function with the \texttt{set} scope, % such as \cs{cs_set:Npn}. The definition is restricted to the current % \TeX{} group and will not result in an error if the function is already % defined. % \item[\texttt{gset}] -% Create a new function with the \texttt{gset} primitives, +% Create a new function with the \texttt{gset} scope, % such as \cs{cs_gset:Npn}. The definition is global and % will not result in an error if the function is already defined. % \end{description} % -% Within each set of primitives there are different ways to define a function. +% Within each set of scope there are different ways to define a function. % The differences depend on restrictions on the actual parameters and % the expandability of the resulting function. % \begin{description} % \item[\texttt{nopar}] -% Create a new function with the \texttt{nopar} primitives, +% Create a new function with the \texttt{nopar} restriction, % such as \cs{cs_set_nopar:Npn}. The parameter may not contain % \cs{par} tokens. % \item[\texttt{protected}] -% Create a new function with the \texttt{protected} primitives, +% Create a new function with the \texttt{protected} restriction, % such as \cs{cs_set_protected:Npn}. The parameter may contain % \cs{par} tokens but the function will not expand within an % \texttt{x}-type expansion. % \end{description} % -% \subsection{Defining new functions using primitive parameter text} +% \subsection{Defining new functions using parameter text} % % \begin{function}{\cs_new:Npn, \cs_new:cpn, \cs_new:Npx, \cs_new:cpx} % \begin{syntax} @@ -613,11 +613,11 @@ % \begin{function} % {\cs_new_eq:NN, \cs_new_eq:Nc, \cs_new_eq:cN, \cs_new_eq:cc} % \begin{syntax} -% \cs{cs_new_eq:NN} \meta{cs 1} \meta{cs 2} -% \cs{cs_new_eq:NN} \meta{cs 1} \meta{token} +% \cs{cs_new_eq:NN} \meta{cs_1} \meta{cs_2} +% \cs{cs_new_eq:NN} \meta{cs_1} \meta{token} % \end{syntax} -% Globally creates \meta{control sequence 1} and sets it to have the same -% meaning as \meta{control sequence 2} or <token>. +% Globally creates \meta{control sequence_1} and sets it to have the same +% meaning as \meta{control sequence_2} or <token>. % The second control sequence may % subsequently be altered without affecting the copy. % \end{function} @@ -625,28 +625,28 @@ % \begin{function} % {\cs_set_eq:NN, \cs_set_eq:Nc, \cs_set_eq:cN, \cs_set_eq:cc} % \begin{syntax} -% \cs{cs_set_eq:NN} \meta{cs 1} \meta{cs 2} -% \cs{cs_set_eq:NN} \meta{cs 1} \meta{token} +% \cs{cs_set_eq:NN} \meta{cs_1} \meta{cs_2} +% \cs{cs_set_eq:NN} \meta{cs_1} \meta{token} % \end{syntax} -% Sets \meta{control sequence 1} to have the same meaning as -% \meta{control sequence 2} (or <token>). +% Sets \meta{control sequence_1} to have the same meaning as +% \meta{control sequence_2} (or <token>). % The second control sequence may subsequently be % altered without affecting the copy. The assignment of a meaning -% to the \meta{control sequence 1} is restricted to the current +% to the \meta{control sequence_1} is restricted to the current % \TeX{} group level. % \end{function} % % \begin{function} % {\cs_gset_eq:NN, \cs_gset_eq:Nc, \cs_gset_eq:cN, \cs_gset_eq:cc} % \begin{syntax} -% \cs{cs_gset_eq:NN} \meta{cs 1} \meta{cs 2} -% \cs{cs_gset_eq:NN} \meta{cs 1} \meta{token} +% \cs{cs_gset_eq:NN} \meta{cs_1} \meta{cs_2} +% \cs{cs_gset_eq:NN} \meta{cs_1} \meta{token} % \end{syntax} -% Globally sets \meta{control sequence 1} to have the same meaning as -% \meta{control sequence 2} (or <token>). +% Globally sets \meta{control sequence_1} to have the same meaning as +% \meta{control sequence_2} (or <token>). % The second control sequence may subsequently be % altered without affecting the copy. The assignment of a meaning to -% the \meta{control sequence 1} is \emph{not} restricted to the current +% the \meta{control sequence_1} is \emph{not} restricted to the current % \TeX{} group level: the assignment is global. % \end{function} % @@ -938,56 +938,6 @@ % in the input stream for further processing. % \end{function} % -% \subsection{Decomposing control sequences} -% -% \begin{function}[EXP]{\cs_get_arg_count_from_signature:N} -% \begin{syntax} -% \cs{cs_get_arg_count_from_signature:N} \meta{function} -% \end{syntax} -% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part -% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). -% The \meta{number} of tokens in the \meta{signature} is then left in -% the input stream. If there was no \meta{signature} then the result is -% the marker value $-1$. -% \end{function} -% -% \begin{function}[EXP]{\cs_get_function_name:N} -% \begin{syntax} -% \cs{cs_get_function_name:N} \meta{function} -% \end{syntax} -% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part -% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). -% The \meta{name} is then left in the input stream without the escape -% character present made up of tokens with category code $12$ -% (other). -% \end{function} -% -% \begin{function}[EXP]{\cs_get_function_signature:N} -% \begin{syntax} -% \cs{cs_get_function_signature:N} \meta{function} -% \end{syntax} -% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part -% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). -% The \meta{signature} is then left in the input stream made up of -% tokens with category code $12$ (other). -% \end{function} -% -% \begin{function}[EXP]{\cs_split_function:NN} -% \begin{syntax} -% \cs{cs_split_function:NN} \meta{function} \meta{processor} -% \end{syntax} -% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part -% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). -% This information is then placed in the input stream after the -% \meta{processor} function in three parts: the \meta{name}, the -% \meta{signature} and a logic token indicating if a colon was found -% (to differentiate variables from function names). The \meta{name} -% will not include the escape character, and both the \meta{name} and -% \meta{signature} are made up of tokens with category code $12$ -% (other). The \meta{processor} should be a function with argument -% specification \texttt{:nnN} (plus any trailing arguments needed). -% \end{function} -% % \section{Predicates and conditionals} % \label{sec:predicates} % @@ -1031,7 +981,7 @@ % are expandable and have names that end with |_p| in the % description part. For example, % \begin{quote} -% |\cs_if_free_p:N| +% \cs{cs_if_free_p:N} % \end{quote} % would be a predicate function for the same type of test as the % conditional described above. It would return \enquote{true} if its @@ -1100,7 +1050,7 @@ % \begin{function}[EXP,pTF] % { % \str_if_eq:nn, \str_if_eq:Vn, \str_if_eq:on, \str_if_eq:no, -% \str_if_eq:nV, \str_if_eq:VV, \str_if_eq:xx +% \str_if_eq:nV, \str_if_eq:VV % } % \begin{syntax} % \cs{str_if_eq_p:nn} \Arg{tl_1} \Arg{tl_2} @@ -1110,11 +1060,63 @@ % basis, and is \texttt{true} if the two lists contain the same % characters in the same order. Thus for example % \begin{verbatim} -% \str_if_eq_p:xx { abc } { \tl_to_str:n { abc } } +% \str_if_eq_p:no { abc } { \tl_to_str:n { abc } } +% \end{verbatim} +% is logically \texttt{true}. +% \end{function} +% +% \begin{function}[EXP,pTF, added = 2012-06-05]{\str_if_eq_x:nn} +% \begin{syntax} +% \cs{str_if_eq_x_p:nn} \Arg{tl_1} \Arg{tl_2} +% \cs{str_if_eq_x:nnTF} \Arg{tl_1} \Arg{tl_2} \Arg{true code} \Arg{false code} +% \end{syntax} +% Compares the full expansion of two \meta{token lists} on a character by +% character basis, and is \texttt{true} if the two lists contain the same +% characters in the same order. Thus for example +% \begin{verbatim} +% \str_if_eq_x_p:nn { abc } { \tl_to_str:n { abc } } % \end{verbatim} -% is logically \texttt{true}. All versions of these functions are fully -% expandable (including those involving an \texttt{x}-type -% expansion). +% is logically \texttt{true}. +% \end{function} +% +% \begin{function}[added = 2012-06-03, EXP]{\str_case:nnn, \str_case:onn} +% \begin{syntax} +% \cs{str_case:nnn} \Arg{test string} \\ +% ~~|{| \\ +% ~~~~\Arg{string case_1} \Arg{code case_1} \\ +% ~~~~\Arg{string case_2} \Arg{code case_2} \\ +% ~~~~\ldots \\ +% ~~~~\Arg{string case_n} \Arg{code case_n} \\ +% ~~|}| \\ +% ~~\Arg{else code} +% \end{syntax} +% This function compares the \meta{test string} in turn with each +% of the \meta{string cases}. If the two are equal (as described for +% \cs{str_if_eq:nnTF} then the +% associated \meta{code} is left in the input stream. If none of +% the tests are \texttt{true} then the \texttt{else code} will be +% left in the input stream. +% \end{function} +% +% \begin{function}[added = 2012-06-05, EXP]{\str_case_x:nnn} +% \begin{syntax} +% \cs{str_case_x:nnn} \Arg{test string} \\ +% ~~|{| \\ +% ~~~~\Arg{string case_1} \Arg{code case_1} \\ +% ~~~~\Arg{string case_2} \Arg{code case_2} \\ +% ~~~~\ldots \\ +% ~~~~\Arg{string case_n} \Arg{code case_n} \\ +% ~~|}| \\ +% ~~\Arg{else code} +% \end{syntax} +% This function comapres the full expansion of the \meta{test string} +% in turn with the full expansion of the \meta{string cases}. If the two +% full expansions are equal (as described for \cs{str_if_eq:nnTF} then the +% associated \meta{code} is left in the input stream. If none of the tests +% are \texttt{true} then the \texttt{else code} will be left in the input +% stream. The \meta{test string} is expanded in each comparison, and must +% always yield the same result: for example, random numbers should +% not be used within this string. % \end{function} % % \subsection{Engine-specific conditionals} @@ -1146,7 +1148,7 @@ % expand whatever comes after them and others don't. Hence the names % for these underlying functions will often contain a |:w| part but % higher level functions are often available. See for instance -% |\int_compare_p:nNn| which is a wrapper for |\if_num:w|. +% \cs{int_compare_p:nNn} which is a wrapper for \cs{if_int_compare:w}. % % Certain conditionals deal with specific data types like boxes and % fonts and are described there. The ones described below are either @@ -1167,7 +1169,7 @@ % for more. % \begin{texnote} % These are equivalent to their corresponding \TeX\ primitive -% conditionals; |\reverse_if:N| is \eTeX's |\unless|. +% conditionals; \cs{reverse_if:N} is \eTeX's \tn{unless}. % \end{texnote} % \end{function} % @@ -1180,7 +1182,7 @@ % <arg_1> and <arg_2> could be functions, variables, tokens; in all cases the % \emph{unexpanded} definitions are compared. % \begin{texnote} -% This is \TeX{}'s |\ifx|. +% This is \TeX{}'s \tn{ifx}. % \end{texnote} % \end{function} % @@ -1223,45 +1225,105 @@ % % \section{Internal kernel functions} % -% \begin{function}{\chk_if_exist_cs:N, \chk_if_exist_cs:c} +% \begin{function}{\__chk_if_exist_cs:N, \__chk_if_exist_cs:c} % \begin{syntax} -% \cs{chk_if_exist_cs:N} \meta{cs} +% \cs{__chk_if_exist_cs:N} \meta{cs} % \end{syntax} % This function checks that \meta{cs} exists according to the % criteria for \cs{cs_if_exist_p:N}, and if not raises a kernel-level % error. % \end{function} % -% \begin{function}{\chk_if_free_cs:N, \chk_if_free_cs:c} +% \begin{function}{\__chk_if_free_cs:N, \__chk_if_free_cs:c} % \begin{syntax} -% \cs{chk_if_free_cs:N} \meta{cs} +% \cs{__chk_if_free_cs:N} \meta{cs} % \end{syntax} % This function checks that \meta{cs} is free according to the % criteria for \cs{cs_if_free_p:N}, and if not raises a kernel-level % error. % \end{function} % -% \section{Experimental functions} +% \begin{function}[EXP]{\__cs_count_signature:N, \__cs_count_signature:c} +% \begin{syntax} +% \cs{__cs_count_signature:N} \meta{function} +% \end{syntax} +% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part +% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). +% The \meta{number} of tokens in the \meta{signature} is then left in +% the input stream. If there was no \meta{signature} then the result is +% the marker value $-1$. +% \end{function} % -% \begin{function}[EXP,TF,added=2011-10-10] -% {\cs_if_exist_use:N, \cs_if_exist_use:c} +% \begin{function}[EXP]{\__cs_split_function:NN} % \begin{syntax} -% \cs{cs_if_exist_use:NTF} \meta{control sequence} \Arg{true code} \Arg{false code} +% \cs{__cs_split_function:NN} \meta{function} \meta{processor} % \end{syntax} -% If the \meta{control sequence} exists, leave it in the input stream, -% followed by the \meta{true code} (unbraced). Otherwise, leave the -% \meta{false} code in the input stream. For example, -% \begin{verbatim} -% \cs_set:Npn \mypkg_use_character:N #1 -% { \cs_if_exist_use:cF { mypkg_#1:n } { \mypkg_default:N #1 } } -% \end{verbatim} -% calls the function |\mypkg_#1:n| if it exists, and falls back to -% a default action otherwise. This could also be done (more slowly) -% using \cs{prg_case_str:xxn}. -% \begin{texnote} -% The \texttt{c} variants do not introduce the \meta{control sequence} -% in the hash table if it is not there. -% \end{texnote} +% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part +% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). +% This information is then placed in the input stream after the +% \meta{processor} function in three parts: the \meta{name}, the +% \meta{signature} and a logic token indicating if a colon was found +% (to differentiate variables from function names). The \meta{name} +% will not include the escape character, and both the \meta{name} and +% \meta{signature} are made up of tokens with category code $12$ +% (other). The \meta{processor} should be a function with argument +% specification \texttt{:nnN} (plus any trailing arguments needed). +% \end{function} +% +% \begin{function}[EXP]{\__cs_get_function_name:N} +% \begin{syntax} +% \cs{__cs_get_function_name:N} \meta{function} +% \end{syntax} +% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part +% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). +% The \meta{name} is then left in the input stream without the escape +% character present made up of tokens with category code $12$ +% (other). +% \end{function} +% +% \begin{function}[EXP]{\__cs_get_function_signature:N} +% \begin{syntax} +% \cs{__cs_get_function_signature:N} \meta{function} +% \end{syntax} +% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part +% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). +% The \meta{signature} is then left in the input stream made up of +% tokens with category code $12$ (other). +% \end{function} +% +% \begin{function}{\__cs_tmp:w} +% Function used for various short-term usages, for instance defining +% functions whose definition involves tokens which are hard to insert +% normally (spaces, charactes with category other). +% \end{function} +% +% \begin{function}{\__kernel_register_show:N, \__kernel_register_show:c} +% \begin{syntax} +% \cs{\__kernel_register_show:N} \meta{register} +% \end{syntax} +% Used to show the contents of a \TeX{} register at the terminal, formatted +% such that internal parts of the mechanism are not visible. +% \end{function} +% +% \begin{function}{\__prg_case_end:nw} +% \begin{syntax} +% \cs{__prg_case_end:nw} \Arg{code} \meta{tokens} \cs{q_recursion_stop} +% \end{syntax} +% Used to terminate case statements (\cs{int_case:nnn}, \emph{etc.}) +% by removing trailing \meta{tokens} and the end marker +% \cs{q_recursion_stop}, and inserting the \meta{code} for the successful +% case. +% \end{function} +% +% \begin{function}{\__str_if_eq_x_return:nn} +% \begin{syntax} +% \cs{__str_if_eq_x_return:nn} \Arg{tl_1} \Arg{tl_2} +% \end{syntax} +% Compares the full expansion of two \meta{token lists} on a character by +% character basis, and is \texttt{true} if the two lists contain the same +% characters in the same order. Either \cs{prg_return_true:} or +% \cs{prg_return_false:} is then left in the input stream. This is a version +% of \cs{str_if_eq_x:nn(TF)} coded for speed. % \end{function} % % \end{documentation} @@ -1278,7 +1340,7 @@ %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -1370,11 +1432,11 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[EXP]{\if_int_compare:w, \int_to_roman:w} +% \begin{macro}[EXP]{\if_int_compare:w, \__int_to_roman:w} % For integers. % \begin{macrocode} \tex_let:D \if_int_compare:w \tex_ifnum:D -\tex_let:D \int_to_roman:w \tex_romannumeral:D +\tex_let:D \__int_to_roman:w \tex_romannumeral:D % \end{macrocode} % \end{macro} % @@ -1385,15 +1447,6 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\tex_global:D, \tex_long:D, \etex_protected:D} -% Three prefixes for assignments. -% \begin{macrocode} -\tex_let:D \tex_global:D \tex_global:D -\tex_let:D \tex_long:D \tex_long:D -\tex_let:D \tex_protected:D \etex_protected:D -% \end{macrocode} -% \end{macro} -% % \begin{macro}[EXP]{\exp_args:Nc} % Discussed in \pkg{l3expan}, but needed much earlier. % \begin{macrocode} @@ -1403,15 +1456,16 @@ % % \begin{macro}[EXP]{\token_to_str:c, \cs_meaning:c} % \begin{macro}{\cs_show:c} -% A small number of variants by hand. Some of the necessary functions +% A small number of variants defined by hand. +% Some of the necessary functions % (\cs{use_i:nn}, \cs{use_ii:nn}, and \cs{exp_args:NNc}) are not % defined at that point yet, but will be defined before those variants % are used. The \cs{cs_meaning:c} command must check for an undefined % control sequence to avoid defining it mistakenly. The % \cs{cs_show:c} command is \enquote{protected} because its action is % not expandable. Also, the conversion of its argument to a control -% sequence is done within a group to avoid converting it to -% \tn{relax}. +% sequence is done within a group to avoid showing \tn{relax} for +% undefined control sequences. % \begin{macrocode} \tex_def:D \token_to_str:c { \exp_args:Nc \token_to_str:N } \tex_long:D \tex_def:D \cs_meaning:c #1 @@ -1424,7 +1478,7 @@ { \exp_args:Nc \cs_meaning:N {#1} } { \tl_to_str:n {undefined} } } -\tex_protected:D \tex_def:D \cs_show:c +\etex_protected:D \tex_def:D \cs_show:c { \group_begin: \exp_args:NNc \group_end: \cs_show:N } % \end{macrocode} % \end{macro} @@ -1434,17 +1488,17 @@ % % \begin{variable}{\c_minus_one, \c_zero, \c_sixteen} % \begin{variable}{\c_six, \c_seven, \c_twelve} -% We need the constants |\c_minus_one| and |\c_sixteen| now for -% writing information to the log and the terminal and |\c_zero| +% We need the constants \cs{c_minus_one} and \cs{c_sixteen} now for +% writing information to the log and the terminal and \cs{c_zero} % which is used by some functions in the \textsf{l3alloc} module. The % rest are defined in the \textsf{l3int} module -- at least for the -% ones that can be defined with |\tex_chardef:D| or -% |\tex_mathchardef:D|. For other constants the \textsf{l3int} module is +% ones that can be defined with \cs{tex_chardef:D} or +% \cs{tex_mathchardef:D}. For other constants the \textsf{l3int} module is % required but it can't be used until the allocation has been set % up properly! The actual allocation mechanism is in % \textsf{l3alloc} and as \TeX{} wants to reserve count registers % 0--9, the first available one is~10 so we use that for -% |\c_minus_one|. +% \cs{c_minus_one}. % \begin{macrocode} %<*package> \tex_let:D \c_minus_one \m@ne @@ -1453,18 +1507,18 @@ \tex_countdef:D \c_minus_one = 10 ~ \c_minus_one = -1 ~ %</initex> -\tex_chardef:D \c_sixteen = 16~ -\tex_chardef:D \c_zero = 0~ -\tex_chardef:D \c_six = 6~ -\tex_chardef:D \c_seven = 7~ -\tex_chardef:D \c_twelve = 12~ +\tex_chardef:D \c_sixteen = 16 ~ +\tex_chardef:D \c_zero = 0 ~ +\tex_chardef:D \c_six = 6 ~ +\tex_chardef:D \c_seven = 7 ~ +\tex_chardef:D \c_twelve = 12 ~ % \end{macrocode} % \end{variable} % \end{variable} % % \begin{variable}{\c_max_register_int} % This is here as this particular integer is needed both in package -% mode and to bootstrap \pkg{l3alloc}. +% mode and to bootstrap \pkg{l3alloc}, and is documented in \pkg{l3int}. % \begin{macrocode} \etex_ifdefined:D \luatex_luatexversion:D \tex_chardef:D \c_max_register_int = 65 535 ~ @@ -1486,24 +1540,24 @@ % \cs_set_protected_nopar:Npn , \cs_set_protected_nopar:Npx , % \cs_set_protected:Npn , \cs_set_protected:Npx % } -% All assignment functions in \LaTeX3 should be naturally robust; +% All assignment functions in \LaTeX3 should be naturally protected; % after all, the \TeX{} primitives for assignments are and it can be % a cause of problems if others aren't. % \begin{macrocode} \tex_let:D \cs_set_nopar:Npn \tex_def:D \tex_let:D \cs_set_nopar:Npx \tex_edef:D -\tex_protected:D \cs_set_nopar:Npn \cs_set:Npn +\etex_protected:D \cs_set_nopar:Npn \cs_set:Npn { \tex_long:D \cs_set_nopar:Npn } -\tex_protected:D \cs_set_nopar:Npn \cs_set:Npx +\etex_protected:D \cs_set_nopar:Npn \cs_set:Npx { \tex_long:D \cs_set_nopar:Npx } -\tex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npn - { \tex_protected:D \cs_set_nopar:Npn } -\tex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npx - { \tex_protected:D \cs_set_nopar:Npx } +\etex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npn + { \etex_protected:D \cs_set_nopar:Npn } +\etex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npx + { \etex_protected:D \cs_set_nopar:Npx } \cs_set_protected_nopar:Npn \cs_set_protected:Npn - { \tex_protected:D \tex_long:D \cs_set_nopar:Npn } + { \etex_protected:D \tex_long:D \cs_set_nopar:Npn } \cs_set_protected_nopar:Npn \cs_set_protected:Npx - { \tex_protected:D \tex_long:D \cs_set_nopar:Npx } + { \etex_protected:D \tex_long:D \cs_set_nopar:Npx } % \end{macrocode} % \end{macro} % @@ -1523,13 +1577,13 @@ \cs_set_protected_nopar:Npn \cs_gset:Npx { \tex_long:D \cs_gset_nopar:Npx } \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npn - { \tex_protected:D \cs_gset_nopar:Npn } + { \etex_protected:D \cs_gset_nopar:Npn } \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npx - { \tex_protected:D \cs_gset_nopar:Npx } + { \etex_protected:D \cs_gset_nopar:Npx } \cs_set_protected_nopar:Npn \cs_gset_protected:Npn - { \tex_protected:D \tex_long:D \cs_gset_nopar:Npn } + { \etex_protected:D \tex_long:D \cs_gset_nopar:Npn } \cs_set_protected_nopar:Npn \cs_gset_protected:Npx - { \tex_protected:D \tex_long:D \cs_gset_nopar:Npx } + { \etex_protected:D \tex_long:D \cs_gset_nopar:Npx } % \end{macrocode} % \end{macro} % @@ -1544,18 +1598,18 @@ % % \begin{macro}{\use:x} % Fully expands its argument and passes it to the input stream. Uses -% the reserved \cs{l_exp_internal_tl} which will be set up in \pkg{l3expan}. +% the reserved \cs{l__exp_internal_tl} which will be set up in \pkg{l3expan}. % \begin{macrocode} \cs_set_protected:Npn \use:x #1 { - \cs_set_nopar:Npx \l_exp_internal_tl {#1} - \l_exp_internal_tl + \cs_set_nopar:Npx \l__exp_internal_tl {#1} + \l__exp_internal_tl } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\use:n, \use:nn, \use:nnn, \use:nnnn} -% These macro grabs its arguments and returns it back to the input +% These macros grab their arguments and returns them back to the input % (with outer braces removed). % \begin{macrocode} \cs_set:Npn \use:n #1 {#1} @@ -1663,20 +1717,25 @@ % testing and processing must return the \meta{state} this leaves % \TeX{} in. Therefore, a simple user interface could be something like % \begin{verbatim} -% \if_meaning:w #1#2 \prg_return_true: \else: -% \if_meaning:w #1#3 \prg_return_true: \else: -% \prg_return_false: -% \fi: \fi: +% \if_meaning:w #1#2 +% \prg_return_true: +% \else: +% \if_meaning:w #1#3 +% \prg_return_true: +% \else: +% \prg_return_false: +% \fi: +% \fi: % \end{verbatim} % Usually, a \TeX{} programmer would have to insert a number of -% |\exp_after:wN|s to ensure the state value is returned at exactly +% \cs{exp_after:wN}s to ensure the state value is returned at exactly % the point where the last conditional is finished. However, that % obscures the code and forces the \TeX{} programmer to prove that % he/she knows the $2^{n}-1$ table. We therefore provide the simpler % interface. % % \begin{macro}[EXP]{\prg_return_true:, \prg_return_false:} -% The idea here is that \cs{int_to_roman:w} will expand fully any +% The idea here is that \cs{__int_to_roman:w} will expand fully any % \cs{else:} and the \cs{fi:} that are waiting to be discarded, % before reaching the \cs{c_zero} which will leave the expansion null. % The code can then leave either the first or second argument in the @@ -1685,9 +1744,9 @@ % to see this. % \begin{macrocode} \cs_set_nopar:Npn \prg_return_true: - { \exp_after:wN \use_i:nn \int_to_roman:w } + { \exp_after:wN \use_i:nn \__int_to_roman:w } \cs_set_nopar:Npn \prg_return_false: - { \exp_after:wN \use_ii:nn \int_to_roman:w} + { \exp_after:wN \use_ii:nn \__int_to_roman:w} % \end{macrocode} % An extended state space could be implemented by including a more % elaborate function in place of \cs{use_i:nn}/\cs{use_ii:nn}. Provided @@ -1701,29 +1760,29 @@ % \prg_set_protected_conditional:Npnn , % \prg_new_protected_conditional:Npnn , % } -% \begin{macro}[aux]{\prg_generate_conditional_parm_aux:NNpnn} +% \begin{macro}[aux]{\__prg_generate_conditional_parm:nnNpnn} % The user functions for the types using parameter text from the % programmer. The various functions only differ by which function is % used for the assignment. For those |Npnn| type functions, we must % grab the parameter text, reading everything up to a left brace % before continuing. Then split the base function into name and % signature, and feed \Arg{name} \Arg{signature} \meta{boolean} -% \meta{defining~function} |{parm}| \Arg{parameters} |{TF,...}| +% \Arg{set~or~new} \Arg{maybe~protected} \Arg{parameters} |{TF,...}| % \Arg{code} to the auxiliary function responsible for defining all % conditionals. % \begin{macrocode} \cs_set_protected_nopar:Npn \prg_set_conditional:Npnn - { \prg_generate_conditional_parm_aux:NNpnn \cs_set:Npn } + { \__prg_generate_conditional_parm:nnNpnn { set } { } } \cs_set_protected_nopar:Npn \prg_new_conditional:Npnn - { \prg_generate_conditional_parm_aux:NNpnn \cs_new:Npn } + { \__prg_generate_conditional_parm:nnNpnn { new } { } } \cs_set_protected_nopar:Npn \prg_set_protected_conditional:Npnn - { \prg_generate_conditional_parm_aux:NNpnn \cs_set_protected:Npn } + { \__prg_generate_conditional_parm:nnNpnn { set } { _protected } } \cs_set_protected_nopar:Npn \prg_new_protected_conditional:Npnn - { \prg_generate_conditional_parm_aux:NNpnn \cs_new_protected:Npn } -\cs_set_protected:Npn \prg_generate_conditional_parm_aux:NNpnn #1#2#3# + { \__prg_generate_conditional_parm:nnNpnn { new } { _protected } } +\cs_set_protected:Npn \__prg_generate_conditional_parm:nnNpnn #1#2#3#4# { - \cs_split_function:NN #2 \prg_generate_conditional_aux:nnNNnnnn - #1 { parm } {#3} + \__cs_split_function:NN #3 \__prg_generate_conditional:nnNnnnnn + {#1} {#2} {#4} } % \end{macrocode} % \end{macro} @@ -1736,204 +1795,248 @@ % \prg_set_protected_conditional:Nnn , % \prg_new_protected_conditional:Nnn , % } -% \begin{macro}[aux]{\prg_generate_conditional_count_aux:NNnn} +% \begin{macro}[aux] +% { +% \__prg_generate_conditional_count:nnNnn , +% \__prg_generate_conditional_count:nnNnnnn +% } % The user functions for the types automatically inserting the correct % parameter text based on the signature. The various functions only -% differ by which function is used for the assignment. For those |Nnn| -% type functions, we calculate the number of arguments. Then split the -% base function into name and signature, and feed \Arg{name} -% \Arg{signature} \meta{boolean} \meta{defining~function} |{count}| -% \Arg{arg~count} |{TF,...}| \Arg{code} to the auxiliary function -% responsible for defining all conditionals. +% differ by which function is used for the assignment. Split the base +% function into name and signature. The second auxiliary generates +% the parameter text from the number of letters in the signature. +% Then feed \Arg{name} \Arg{signature} \meta{boolean} \Arg{set~or~new} +% \Arg{maybe~protected} \Arg{parameters} |{TF,...}| \Arg{code} to the +% auxiliary function responsible for defining all conditionals. If +% the \meta{signature} has more than $9$ letters, the definition is +% aborted since \TeX{} macros have at most $9$ arguments. The +% erroneous case where the function name contains no colon is captured +% later. % \begin{macrocode} \cs_set_protected_nopar:Npn \prg_set_conditional:Nnn - { \prg_generate_conditional_count_aux:NNnn \cs_set:Npn } + { \__prg_generate_conditional_count:nnNnn { set } { } } \cs_set_protected_nopar:Npn \prg_new_conditional:Nnn - { \prg_generate_conditional_count_aux:NNnn \cs_new:Npn } + { \__prg_generate_conditional_count:nnNnn { new } { } } \cs_set_protected_nopar:Npn \prg_set_protected_conditional:Nnn - { \prg_generate_conditional_count_aux:NNnn \cs_set_protected:Npn } + { \__prg_generate_conditional_count:nnNnn { set } { _protected } } \cs_set_protected_nopar:Npn \prg_new_protected_conditional:Nnn - { \prg_generate_conditional_count_aux:NNnn \cs_new_protected:Npn } -\cs_set_protected:Npn \prg_generate_conditional_count_aux:NNnn #1#2 + { \__prg_generate_conditional_count:nnNnn { new } { _protected } } +\cs_set_protected:Npn \__prg_generate_conditional_count:nnNnn #1#2#3 + { + \__cs_split_function:NN #3 \__prg_generate_conditional_count:nnNnnnn + {#1} {#2} + } +\cs_set_protected:Npn \__prg_generate_conditional_count:nnNnnnn #1#2#3#4#5 { - \exp_args:Nnf \use:n + \__cs_parm_from_arg_count:nnF + { \__prg_generate_conditional:nnNnnnnn {#1} {#2} #3 {#4} {#5} } + { \tl_count:n {#2} } { - \cs_split_function:NN #2 \prg_generate_conditional_aux:nnNNnnnn - #1 { count } + \__msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } + { \token_to_str:c { #1 : #2 } } + { \tl_count:n {#2} } + \use_none:nn } - { \cs_get_arg_count_from_signature:N #2 } } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}{\prg_set_eq_conditional:NNn,\prg_new_eq_conditional:NNn} -% The obvious setting-equal functions. -% \begin{macrocode} -\cs_set_protected:Npn \prg_set_eq_conditional:NNn #1#2#3 - { \prg_set_eq_conditional_aux:NNNn \cs_set_eq:cc #1#2 {#3} } -\cs_set_protected:Npn \prg_new_eq_conditional:NNn #1#2#3 - { \prg_set_eq_conditional_aux:NNNn \cs_new_eq:cc #1#2 {#3} } -% \end{macrocode} -% \end{macro} -% % \begin{macro}[aux] % { -% \prg_generate_conditional_aux:nnNNnnnn, -% \prg_generate_conditional_aux:nnw +% \__prg_generate_conditional:nnNnnnnn, +% \__prg_generate_conditional:nnnnnnw % } % The workhorse here is going through a list of desired forms, \emph{i.e.}, % |p|, |TF|, |T| and |F|. The first three arguments come from splitting up % the base form of the conditional, which gives the name, signature % and a boolean to signal whether or not there was a colon in the -% name. For the time being, we do not use this piece of information -% but could well throw an error. The fourth argument is how to -% define this function, the fifth is the text |parm| or |count| for -% which version to use to define the functions, the sixth is the -% parameters to use (possibly empty) or number of arguments, the -% seventh is the list of forms to define, the eight is the +% name. In the absence of a colon, we throw an error and don't define +% any conditional. The fourth and fifth arguments build up the +% defining function. The sixth is the parameters to use (possibly +% empty), the seventh is the list of forms to define, the eigth is the % replacement text which we will augment when defining the forms. % \begin{macrocode} -\cs_set_protected:Npn \prg_generate_conditional_aux:nnNNnnnn #1#2#3#4#5#6#7#8 +\cs_set_protected:Npn \__prg_generate_conditional:nnNnnnnn #1#2#3#4#5#6#7#8 { - \prg_generate_conditional_aux:nnw {#5} - { - #4 {#1} {#2} {#6} {#8} - } - #7 , ? , \q_recursion_stop + \if_meaning:w \c_true_bool #3 + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { + \__prg_generate_conditional:nnnnnnw + {#4} {#5} {#1} {#2} {#6} {#8} + #7 , , \q_recursion_stop + } + { + \__msg_kernel_error:nnx { kernel } { missing-colon } + { \token_to_str:c {#1} } + } } % \end{macrocode} -% Looping through the list of desired forms. First is the text |parm| -% or |count|, second is five arguments packed together and third is -% the form. Use text and form to call the correct type. +% Looping through the list of desired forms. First are six arguments +% and seventh is the form. Use the form to call the +% correct type. If the form does not exist, the \cs{use:c} +% construction results in \tn{relax}, and the error message is +% displayed, then \cs{use_none:nnnnnnn} cleans up. Otherwise, the +% error message is removed by the variant form. % \begin{macrocode} -\cs_set_protected:Npn \prg_generate_conditional_aux:nnw #1#2#3 , +\cs_set_protected:Npn \__prg_generate_conditional:nnnnnnw #1#2#3#4#5#6#7 , { - \if:w ?#3 + \if_catcode:w \scan_stop: \etex_detokenize:D {#7} \scan_stop: \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: - \use:c { prg_generate_#3_form_#1:Nnnnn } #2 - \prg_generate_conditional_aux:nnw {#1} {#2} + \use:c { __prg_generate_ \etex_detokenize:D {#7} _form:wnnnnnn } + \__msg_kernel_error:nnxx + { kernel } { conditional-form-unknown } + { \tl_to_str:n {#7} } { \token_to_str:c { #3 : #4 } } + \use_none:nnnnnnn + \q_stop + {#1} {#2} {#3} {#4} {#5} {#6} + \__prg_generate_conditional:nnnnnnw {#1} {#2} {#3} {#4} {#5} {#6} } % \end{macrocode} % \end{macro} % % \begin{macro}[aux] % { -% \prg_generate_p_form_parm:Nnnnn, -% \prg_generate_TF_form_parm:Nnnnn, -% \prg_generate_T_form_parm:Nnnnn, -% \prg_generate_F_form_parm:Nnnnn +% \__prg_generate_p_form:wnnnnnn, +% \__prg_generate_TF_form:wnnnnnn, +% \__prg_generate_T_form:wnnnnnn, +% \__prg_generate_F_form:wnnnnnn % } -% How to generate the various forms. The |parm| types here takes the -% following arguments: 1: how to define (an N-type), 2: name, 3: -% signature, 4: parameter text (or empty), 5: replacement. Remember that -% the logic-returning functions expect two arguments to be present after -% \cs{c_zero}: notice the construction of the different variants -% relies on this, and that the |TF| variant will be slightly faster -% than the |T| version. -% \begin{macrocode} -\cs_set_protected:Npn \prg_generate_p_form_parm:Nnnnn #1#2#3#4#5 +% How to generate the various forms. Those functions take the +% following arguments: 1: \texttt{set} or \texttt{new}, 2: empty or +% \texttt{\_protected}, 3: function name 4: signature, 5: parameter +% text (or empty), 6: replacement. Remember that the logic-returning +% functions expect two arguments to be present after \cs{c_zero}: +% notice the construction of the different variants relies on this, +% and that the |TF| variant will be slightly faster than the |T| +% version. The |p| form is only valid for expandable tests, we check +% for that by making sure that the second argument is empty. +% \begin{macrocode} +\cs_set_protected:Npn \__prg_generate_p_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 { - \exp_args:Nc #1 { #2 _p: #3 } #4 + \if_meaning:w \scan_stop: #3 \scan_stop: + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: { - #5 \c_zero - \c_true_bool \c_false_bool + \exp_args:Nc \exp_args:Nc { cs_ #2 #3 :Npn } { #4 _p: #5 } #6 + { #7 \c_zero \c_true_bool \c_false_bool } } - } -\cs_set_protected:Npn \prg_generate_T_form_parm:Nnnnn #1#2#3#4#5 - { - \exp_args:Nc #1 { #2 : #3 T } #4 { - #5 \c_zero - \use:n \use_none:n + \__msg_kernel_error:nnx { kernel } { protected-predicate } + { \token_to_str:c { #4 _p: #5 } } } } -\cs_set_protected:Npn \prg_generate_F_form_parm:Nnnnn #1#2#3#4#5 +\cs_set_protected:Npn \__prg_generate_T_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 { - \exp_args:Nc #1 { #2 : #3 F } #4 - { - #5 \c_zero - { } - } + \exp_args:Nc \exp_args:Nc { cs_ #2 #3 :Npn } { #4 : #5 T } #6 + { #7 \c_zero \use:n \use_none:n } } -\cs_set_protected:Npn \prg_generate_TF_form_parm:Nnnnn #1#2#3#4#5 +\cs_set_protected:Npn \__prg_generate_F_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 { - \exp_args:Nc #1 { #2 : #3 TF } #4 - { #5 \c_zero } + \exp_args:Nc \exp_args:Nc { cs_ #2 #3 :Npn } { #4 : #5 F } #6 + { #7 \c_zero { } } + } +\cs_set_protected:Npn \__prg_generate_TF_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 + { + \exp_args:Nc \exp_args:Nc { cs_ #2 #3 :Npn } { #4 : #5 TF } #6 + { #7 \c_zero } } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux] -% { -% \prg_generate_p_form_count:Nnnnn, -% \prg_generate_TF_form_count:Nnnnn, -% \prg_generate_T_form_count:Nnnnn, -% \prg_generate_F_form_count:Nnnnn -% } -% The |count| form is similar, but of course requires a number rather -% than a primitive argument specification. +% \begin{macro}{\prg_set_eq_conditional:NNn,\prg_new_eq_conditional:NNn} +% The setting-equal functions. Split the base function to be copied, +% and feed a first auxiliary \Arg{name} \Arg{signature} \meta{boolean} +% \meta{copying~function} \meta{new~function} \Arg{conditions}. % \begin{macrocode} -\cs_set_protected:Npn \prg_generate_p_form_count:Nnnnn #1#2#3#4#5 +\cs_set_protected:Npn \prg_set_eq_conditional:NNn #1#2 { - \cs_generate_from_arg_count:cNnn { #2 _p: #3 } #1 {#4} - { - #5 \c_zero - \c_true_bool \c_false_bool - } + \__cs_split_function:NN #2 \__prg_set_eq_conditional:nnNNNn + \cs_set_eq:cc #1 } -\cs_set_protected:Npn \prg_generate_T_form_count:Nnnnn #1#2#3#4#5 +\cs_set_protected:Npn \prg_new_eq_conditional:NNn #1#2 { - \cs_generate_from_arg_count:cNnn { #2 : #3 T } #1 {#4} - { - #5 \c_zero - \use:n \use_none:n - } - } -\cs_set_protected:Npn \prg_generate_F_form_count:Nnnnn #1#2#3#4#5 - { - \cs_generate_from_arg_count:cNnn { #2 : #3 F } #1 {#4} - { - #5 \c_zero - { } - } - } -\cs_set_protected:Npn \prg_generate_TF_form_count:Nnnnn #1#2#3#4#5 - { - \cs_generate_from_arg_count:cNnn { #2 : #3 TF } #1 {#4} - { #5 \c_zero } + \__cs_split_function:NN #2 \__prg_set_eq_conditional:nnNNNn + \cs_new_eq:cc #1 } % \end{macrocode} % \end{macro} % % \begin{macro}[aux] -% {\prg_set_eq_conditional_aux:NNNn, \prg_set_eq_conditional_aux:NNNw} +% { +% \__prg_set_eq_conditional:nnNNNn , +% \__prg_set_eq_conditional:nnNnnNNw , +% \__prg_set_eq_conditional_loop:nnnnNw +% } % \begin{macro}[aux, EXP] % { -% \prg_conditional_form_p:nnn , -% \prg_conditional_form_TF:nnn , -% \prg_conditional_form_T:nnn , -% \prg_conditional_form_F:nnn , +% \__prg_conditional_p_form:nnn , +% \__prg_conditional_TF_form:nnn , +% \__prg_conditional_T_form:nnn , +% \__prg_conditional_F_form:nnn , % } -% Manual clist loop over argument |#4|. -% \begin{macrocode} -\cs_set_protected:Npn \prg_set_eq_conditional_aux:NNNn #1#2#3#4 - { \prg_set_eq_conditional_aux:NNNw #1#2#3#4 , ? , \q_recursion_stop } -\cs_set_protected:Npn \prg_set_eq_conditional_aux:NNNw #1#2#3#4 , +% Split the function to be defined, and setup a manual clist loop over +% argument |#6| of the first auxiliary. The second auxiliary receives +% twice three arguments coming from splitting the function to be +% defined and the function to copy. Make sure that both functions +% contained a colon, otherwise we don't know how to build +% conditionals, hence abort. Call the looping macro, with arguments +% \Arg{name_1} \Arg{signature_1} \Arg{name_2} \Arg{signature_2} +% \meta{copying~function} and followed by the comma list. At each +% step in the loop, make sure that the conditional form we copy is +% defined, and copy it, otherwise abort. +% \begin{macrocode} +\cs_set_protected:Npn \__prg_set_eq_conditional:nnNNNn #1#2#3#4#5#6 { - \if:w ? #4 \scan_stop: + \__cs_split_function:NN #5 \__prg_set_eq_conditional:nnNnnNNw + {#1} {#2} #3 #4 + #6 , \scan_stop: , \q_recursion_stop + } +\cs_set_protected:Npn \__prg_set_eq_conditional:nnNnnNNw #1#2#3#4#5#6 + { + \if_meaning:w \c_false_bool #3 + \__msg_kernel_error:nnx { kernel } { missing-colon } + { \token_to_str:c {#1} } + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + \if_meaning:w \c_false_bool #6 + \__msg_kernel_error:nnx { kernel } { missing-colon } + { \token_to_str:c {#4} } \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: - #1 - { \exp_args:NNc \cs_split_function:NN #2 { prg_conditional_form_#4:nnn } } - { \exp_args:NNc \cs_split_function:NN #3 { prg_conditional_form_#4:nnn } } - \prg_set_eq_conditional_aux:NNNw #1 {#2} {#3} + \__prg_set_eq_conditional_loop:nnnnNw {#1} {#2} {#4} {#5} + } +\cs_set_protected:Npn \__prg_set_eq_conditional_loop:nnnnNw #1#2#3#4#5#6 , + { + \if_meaning:w \scan_stop: #6 \scan_stop: + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + \cs_if_exist:cTF + { \use:c { __prg_conditional_ #6 _form:nn } {#3} {#4} } + { + #5 + { \use:c { __prg_conditional_ #6 _form:nn } {#1} {#2} } + { \use:c { __prg_conditional_ #6 _form:nn } {#3} {#4} } + } + { + \__msg_kernel_error:nnx { kernel } { command-not-defined } + { + \token_to_str:c + { \use:c { __prg_conditional_ #6 _form:nn } {#3} {#4} } + } + } + \__prg_set_eq_conditional_loop:nnnnNw {#1} {#2} {#3} {#4} #5 } -\cs_set:Npn \prg_conditional_form_p:nnn #1#2#3 { #1 _p : #2 } -\cs_set:Npn \prg_conditional_form_TF:nnn #1#2#3 { #1 : #2 TF } -\cs_set:Npn \prg_conditional_form_T:nnn #1#2#3 { #1 : #2 T } -\cs_set:Npn \prg_conditional_form_F:nnn #1#2#3 { #1 : #2 F } +\cs_set:Npn \__prg_conditional_p_form:nn #1#2 { #1 _p : #2 } +\cs_set:Npn \__prg_conditional_TF_form:nn #1#2 { #1 : #2 TF } +\cs_set:Npn \__prg_conditional_T_form:nn #1#2 { #1 : #2 T } +\cs_set:Npn \__prg_conditional_F_form:nn #1#2 { #1 : #2 F } % \end{macrocode} % \end{macro} % \end{macro} @@ -1941,7 +2044,7 @@ % All that is left is to define the canonical boolean true and false. % I think Michael originated the idea of expandable boolean tests. At % first these were supposed to expand into either \texttt{TT} or -% \texttt{TF} to be tested using |\if:w| but this was later changed to +% \texttt{TF} to be tested using \cs{if:w} but this was later changed to % |00| and |01|, so they could be used in logical % operations. Later again they were changed to being numerical % constants with values of $1$ for true and $0$ for false. We need @@ -1950,22 +2053,22 @@ % \begin{variable}{\c_true_bool, \c_false_bool} % Here are the canonical boolean values. % \begin{macrocode} -\tex_chardef:D \c_true_bool = 1~ -\tex_chardef:D \c_false_bool = 0~ +\tex_chardef:D \c_true_bool = 1 ~ +\tex_chardef:D \c_false_bool = 0 ~ % \end{macrocode} % \end{variable} % % \subsection{Dissecting a control sequence} % % \begin{macro}[EXP]{\cs_to_str:N} -% \begin{macro}[aux, EXP]{\cs_to_str_aux:N, \cs_to_str_aux:w} +% \begin{macro}[aux, EXP]{\__cs_to_str:N, \__cs_to_str:w} % This converts a control sequence into the character string of its % name, removing the leading escape character. This turns out to be % a non-trivial matter as there a different cases: % \begin{itemize} % \item The usual case of a printable escape character; % \item the case of a non-printable escape characters, e.g., when -% the value of |\tex_escapechar:D| is negative; +% the value of the \tn{escapechar} is negative; % \item when the escape character is a space. % \end{itemize} % One approach to solve this is to test how many tokens result from @@ -1979,109 +2082,97 @@ % a little more intricate still. When the escape character is printable, % \verb*|\token_to_str:N \ | yields the escape character itself and a space. % The character codes are different, thus the \cs{if:w} test is false, -% and \TeX{} reads \cs{cs_to_str_aux:N} after turning the following +% and \TeX{} reads \cs{__cs_to_str:N} after turning the following % control sequence into a string; this auxiliary removes the escape -% character, and stops the expansion of the initial \cs{int_to_roman:w}. +% character, and stops the expansion of the initial \cs{__int_to_roman:w}. % The second case is that the escape character is not printable. Then % the \cs{if:w} test is unfinished after reading a the space from -% \verb*|\token_to_str:N \ |, and the auxiliary \cs{cs_to_str_aux:w} +% \verb*|\token_to_str:N \ |, and the auxiliary \cs{__cs_to_str:w} % is expanded, feeding |-| as a second character for the test; % the test is false, and \TeX{} skips to \cs{fi:}, then performs -% \cs{token_to_str:N}, and stops the \cs{int_to_roman:w} with \cs{c_zero}. +% \cs{token_to_str:N}, and stops the \cs{__int_to_roman:w} with \cs{c_zero}. % The last case is that the escape character is itself a space. In this -% case, the \cs{if:w} test is true, and the auxiliary \cs{cs_to_str_aux:w} -% comes into play, inserting |-\int_value:w|, which expands \cs{c_zero} -% to the character |0|. The initial \cs{int_to_roman:w} then sees +% case, the \cs{if:w} test is true, and the auxiliary \cs{__cs_to_str:w} +% comes into play, inserting |-\__int_value:w|, which expands \cs{c_zero} +% to the character |0|. The initial \cs{__int_to_roman:w} then sees % |0|, which is not a terminated number, followed by the escape character, % a space, which is removed, terminating the argument of -% \cs{int_to_roman:w}. +% \cs{__int_to_roman:w}. % In all three cases, \cs{cs_to_str:N} takes two expansion steps % to be fully expanded. % \begin{macrocode} \cs_set_nopar:Npn \cs_to_str:N { - \int_to_roman:w - \if:w \token_to_str:N \ \cs_to_str_aux:w \fi: - \exp_after:wN \cs_to_str_aux:N \token_to_str:N + \__int_to_roman:w + \if:w \token_to_str:N \ \__cs_to_str:w \fi: + \exp_after:wN \__cs_to_str:N \token_to_str:N } -\cs_set:Npn \cs_to_str_aux:N #1 { \c_zero } -\cs_set:Npn \cs_to_str_aux:w #1 \cs_to_str_aux:N - { - \int_value:w \fi: \exp_after:wN \c_zero } +\cs_set:Npn \__cs_to_str:N #1 { \c_zero } +\cs_set:Npn \__cs_to_str:w #1 \__cs_to_str:N + { - \__int_value:w \fi: \exp_after:wN \c_zero } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[EXP]{\cs_split_function:NN} +% \begin{macro}[EXP, int]{\__cs_split_function:NN} % \begin{macro}[aux, EXP] -% {\cs_split_function_aux:w, \cs_split_function_auxii:w} +% {\__cs_split_function_i:w, \__cs_split_function_ii:w} % This function takes a function name and splits it into name with % the escape char removed and argument specification. In addition to % this, a third argument, a boolean \meta{true} or \meta{false} is % returned with \meta{true} for when there is a colon in the function % and \meta{false} if there is not. Lastly, the second argument of -% \cs{cs_split_function:NN} is supposed to be a function +% \cs{__cs_split_function:NN} is supposed to be a function % taking three variables, one for name, one for signature, and one % for the boolean. For example, -% |\cs_split_function:NN\foo_bar:cnx\use_i:nnn| as input -% becomes |\use_i:nnn {foo_bar}{cnx}\c_true_bool|. -% -% Can't use a literal |:| because it has the wrong catcode here, so -% it's transformed from |@| with |\tex_lowercase:D|. +% |\__cs_split_function:NN \foo_bar:cnx \use_i:nnn| as input +% becomes |\use_i:nnn {foo_bar} {cnx} \c_true_bool|. +% +% We can't use a literal |:| because it has the wrong catcode here, so +% it's transformed from |@| with \cs{tex_lowercase:D}. +% +% First ensure that we actually get a properly evaluated string by +% expanding \cs{cs_to_str:N} twice. If the function contained a +% colon, the auxiliary takes as |#1| the function name, delimited by +% the first colon, then the signature |#2|, delimited by \cs{q_mark}, +% then \cs{c_true_bool} as |#3|, and |#4| cleans up until \cs{q_stop}. +% Otherwise, the |#1| contains the function name and \cs{q_mark} +% \cs{c_true_bool}, |#2| is empty, |#3| is \cs{c_false_bool}, and |#4| +% cleans up. In both cases, |#5| is the \meta{processor}. The second +% auxiliary trims the trailing \cs{q_mark} from the function name if +% present (that is, if the original function had no colon). % \begin{macrocode} \group_begin: - \tex_lccode:D `\@ = `\: \scan_stop: - \tex_catcode:D `\@ = 12~ +\tex_lccode:D `\@ = `\: \scan_stop: +\tex_catcode:D `\@ = 12 ~ \tex_lowercase:D { \group_end: -% \end{macrocode} -% First ensure that we actually get a properly evaluated str -% by expanding \cs{cs_to_str:N} twice. Insert -% extra colon to catch the error cases. -% \begin{macrocode} - \cs_set:Npn \cs_split_function:NN #1#2 + \cs_set:Npn \__cs_split_function:NN #1 { \exp_after:wN \exp_after:wN - \exp_after:wN \cs_split_function_aux:w - \cs_to_str:N #1 @ a \q_stop #2 - } -% \end{macrocode} -% If no colon in the name, |#2| is |a| with catcode 11 and |#3| is -% empty. If colon in the name, then either |#2| is a colon or the -% first letter of the signature. The letters here have catcode 12. -% If a colon was given we need to a) split off the colon and quark at -% the end and b) ensure we return the name, signature and boolean true -% We can't use \cs{quark_if_no_value:NTF} yet but this is very safe -% anyway as all tokens have catcode~12. -% \begin{macrocode} - \cs_set:Npn \cs_split_function_aux:w #1 @ #2#3 \q_stop #4 - { - \if_meaning:w a #2 - \exp_after:wN \use_i:nn - \else: - \exp_after:wN\use_ii:nn - \fi: - { #4 {#1} { } \c_false_bool } - { \cs_split_function_auxii:w #2#3 \q_stop #4 {#1} } + \exp_after:wN \__cs_split_function_i:w + \cs_to_str:N #1 \q_mark \c_true_bool + @ \q_mark \c_false_bool + \q_stop } - \cs_set:Npn \cs_split_function_auxii:w #1 @a \q_stop #2#3 - { #2{#3}{#1}\c_true_bool } -% \end{macrocode} -% End of lowercase -% \begin{macrocode} + \cs_set:Npn \__cs_split_function_i:w #1 @ #2 \q_mark #3#4 \q_stop #5 + { \__cs_split_function_ii:w #5 #1 \q_mark \q_stop {#2} #3 } + \cs_set:Npn \__cs_split_function_ii:w #1#2 \q_mark #3 \q_stop + { #1 {#2} } } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[EXP]{\cs_get_function_name:N, \cs_get_function_signature:N} -% Now returning the name is trivial: just discard the last two -% arguments. Similar for signature. +% \begin{macro}[EXP, int] +% {\__cs_get_function_name:N, \__cs_get_function_signature:N} +% Simple wrappers. % \begin{macrocode} -\cs_set:Npn \cs_get_function_name:N #1 - { \cs_split_function:NN #1 \use_i:nnn } -\cs_set:Npn \cs_get_function_signature:N #1 - { \cs_split_function:NN #1 \use_ii:nnn } +\cs_set:Npn \__cs_get_function_name:N #1 + { \__cs_split_function:NN #1 \use_i:nnn } +\cs_set:Npn \__cs_get_function_signature:N #1 + { \__cs_split_function:NN #1 \use_ii:nnn } % \end{macrocode} % \end{macro} % @@ -2089,15 +2180,15 @@ % % A control sequence is said to \emph{exist} (to be used) if has an entry in % the hash table and its meaning is different from the primitive -% |\tex_relax:D| token. A control sequence is said to be \emph{free} +% \tn{relax} token. A control sequence is said to be \emph{free} % (to be defined) if it does not already exist. % % \begin{macro}[pTF, EXP]{\cs_if_exist:N,\cs_if_exist:c} % Two versions for checking existence. For the |N| form we firstly -% check for |\scan_stop:| and then if it is in the hash -% table. There is no problem when inputting something like |\else:| -% or |\fi:| as \TeX{} will only ever skip input in case the token -% tested against is |\scan_stop:|. +% check for \cs{scan_stop:} and then if it is in the hash +% table. There is no problem when inputting something like \cs{else:} +% or \cs{fi:} as \TeX{} will only ever skip input in case the token +% tested against is \cs{scan_stop:}. % \begin{macrocode} \prg_set_conditional:Npnn \cs_if_exist:N #1 { p , T , F , TF } { @@ -2113,7 +2204,7 @@ } % \end{macrocode} % For the |c| form we firstly check if it is in the hash table and -% then for |\scan_stop:| so that we do not add it to the hash table +% then for \cs{scan_stop:} so that we do not add it to the hash table % unless it was already there. Here we have to be careful as the text % to be skipped if the first test is false may contain tokens that % disturb the scanner. Therefore, we ensure that the second test is @@ -2226,14 +2317,14 @@ % \end{macrocode} % \end{macro} % -% \begin{macro} -% {\msg_kernel_error:nnxx, \msg_kernel_error:nnx, \msg_kernel_error:nn} +% \begin{macro}[int] +% {\__msg_kernel_error:nnxx, \__msg_kernel_error:nnx, \__msg_kernel_error:nn} % If an internal error occurs before \LaTeX3 has loaded \pkg{l3msg} then % the code should issue a usable if terse error message and halt. This % can only happen if a coding error is made by the team, so this is % a reasonable response. % \begin{macrocode} -\cs_set_protected:Npn \msg_kernel_error:nnxx #1#2#3#4 +\cs_set_protected:Npn \__msg_kernel_error:nnxx #1#2#3#4 { \tex_errmessage:D { @@ -2245,10 +2336,10 @@ } \tex_end:D } -\cs_set_protected:Npn \msg_kernel_error:nnx #1#2#3 - { \msg_kernel_error:nnxx {#1} {#2} {#3} { } } -\cs_set_protected:Npn \msg_kernel_error:nn #1#2 - { \msg_kernel_error:nnxx {#1} {#2} { } { } } +\cs_set_protected:Npn \__msg_kernel_error:nnx #1#2#3 + { \__msg_kernel_error:nnxx {#1} {#2} {#3} { } } +\cs_set_protected:Npn \__msg_kernel_error:nn #1#2 + { \__msg_kernel_error:nnxx {#1} {#2} { } { } } % \end{macrocode} % \end{macro} % @@ -2256,11 +2347,11 @@ % Another one from \pkg{l3msg} which will be altered later. % \begin{macrocode} \cs_set_nopar:Npn \msg_line_context: - { on~line~\tex_the:D \tex_inputlineno:D } + { on~line~ \tex_the:D \tex_inputlineno:D } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\chk_if_free_cs:N, \chk_if_free_cs:c} +% \begin{macro}[int]{\__chk_if_free_cs:N, \__chk_if_free_cs:c} % This command is called by \cs{cs_new_nopar:Npn} and \cs{cs_new_eq:NN} % \emph{etc.}\ % to make sure that the argument sequence is not already in use. If @@ -2269,46 +2360,46 @@ % issued. We have to make sure we don't put the argument into the % conditional processing since it may be an |\if...| type function! % \begin{macrocode} -\cs_set_protected:Npn \chk_if_free_cs:N #1 +\cs_set_protected:Npn \__chk_if_free_cs:N #1 { \cs_if_free:NF #1 { - \msg_kernel_error:nnxx { kernel } { command-already-defined } + \__msg_kernel_error:nnxx { kernel } { command-already-defined } { \token_to_str:N #1 } { \token_to_meaning:N #1 } } } %<*package> \tex_ifodd:D \l@expl@log@functions@bool - \cs_set_protected:Npn \chk_if_free_cs:N #1 + \cs_set_protected:Npn \__chk_if_free_cs:N #1 { \cs_if_free:NF #1 { - \msg_kernel_error:nnxx { kernel } { command-already-defined } + \__msg_kernel_error:nnxx { kernel } { command-already-defined } { \token_to_str:N #1 } { \token_to_meaning:N #1 } } \iow_log:x { Defining~\token_to_str:N #1~ \msg_line_context: } } \fi: %</package> -\cs_set_protected_nopar:Npn \chk_if_free_cs:c - { \exp_args:Nc \chk_if_free_cs:N } +\cs_set_protected_nopar:Npn \__chk_if_free_cs:c + { \exp_args:Nc \__chk_if_free_cs:N } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\chk_if_exist_cs:N, \chk_if_exist_cs:c} -% This function issues a warning message when the control sequence +% \begin{macro}[int]{\__chk_if_exist_cs:N, \__chk_if_exist_cs:c} +% This function issues an error message when the control sequence % in its argument does not exist. % \begin{macrocode} -\cs_set_protected:Npn \chk_if_exist_cs:N #1 +\cs_set_protected:Npn \__chk_if_exist_cs:N #1 { \cs_if_exist:NF #1 { - \msg_kernel_error:nnxx { kernel } { command-not-defined } - { \token_to_str:N #1 } { \token_to_meaning:N #1 } + \__msg_kernel_error:nnx { kernel } { command-not-defined } + { \token_to_str:N #1 } } } -\cs_set_protected_nopar:Npn \chk_if_exist_cs:c - { \exp_args:Nc \chk_if_exist_cs:N } +\cs_set_protected_nopar:Npn \__chk_if_exist_cs:c + { \exp_args:Nc \__chk_if_exist_cs:N } % \end{macrocode} % \end{macro} % @@ -2324,22 +2415,22 @@ % Function which check that the control sequence is free before % defining it. % \begin{macrocode} -\cs_set:Npn \cs_tmp:w #1#2 +\cs_set:Npn \__cs_tmp:w #1#2 { \cs_set_protected:Npn #1 ##1 { - \chk_if_free_cs:N ##1 + \__chk_if_free_cs:N ##1 #2 ##1 } } -\cs_tmp:w \cs_new_nopar:Npn \cs_gset_nopar:Npn -\cs_tmp:w \cs_new_nopar:Npx \cs_gset_nopar:Npx -\cs_tmp:w \cs_new:Npn \cs_gset:Npn -\cs_tmp:w \cs_new:Npx \cs_gset:Npx -\cs_tmp:w \cs_new_protected_nopar:Npn \cs_gset_protected_nopar:Npn -\cs_tmp:w \cs_new_protected_nopar:Npx \cs_gset_protected_nopar:Npx -\cs_tmp:w \cs_new_protected:Npn \cs_gset_protected:Npn -\cs_tmp:w \cs_new_protected:Npx \cs_gset_protected:Npx +\__cs_tmp:w \cs_new_nopar:Npn \cs_gset_nopar:Npn +\__cs_tmp:w \cs_new_nopar:Npx \cs_gset_nopar:Npx +\__cs_tmp:w \cs_new:Npn \cs_gset:Npn +\__cs_tmp:w \cs_new:Npx \cs_gset:Npx +\__cs_tmp:w \cs_new_protected_nopar:Npn \cs_gset_protected_nopar:Npn +\__cs_tmp:w \cs_new_protected_nopar:Npx \cs_gset_protected_nopar:Npx +\__cs_tmp:w \cs_new_protected:Npn \cs_gset_protected:Npn +\__cs_tmp:w \cs_new_protected:Npx \cs_gset_protected:Npx % \end{macrocode} % \end{macro} % @@ -2360,14 +2451,14 @@ % \cs{cs_set_nopar:Npn}. This means that there might be a parameter % string between the two arguments. % \begin{macrocode} -\cs_set:Npn \cs_tmp:w #1#2 +\cs_set:Npn \__cs_tmp:w #1#2 { \cs_new_protected_nopar:Npn #1 { \exp_args:Nc #2 } } -\cs_tmp:w \cs_set_nopar:cpn \cs_set_nopar:Npn -\cs_tmp:w \cs_set_nopar:cpx \cs_set_nopar:Npx -\cs_tmp:w \cs_gset_nopar:cpn \cs_gset_nopar:Npn -\cs_tmp:w \cs_gset_nopar:cpx \cs_gset_nopar:Npx -\cs_tmp:w \cs_new_nopar:cpn \cs_new_nopar:Npn -\cs_tmp:w \cs_new_nopar:cpx \cs_new_nopar:Npx +\__cs_tmp:w \cs_set_nopar:cpn \cs_set_nopar:Npn +\__cs_tmp:w \cs_set_nopar:cpx \cs_set_nopar:Npx +\__cs_tmp:w \cs_gset_nopar:cpn \cs_gset_nopar:Npn +\__cs_tmp:w \cs_gset_nopar:cpx \cs_gset_nopar:Npx +\__cs_tmp:w \cs_new_nopar:cpn \cs_new_nopar:Npn +\__cs_tmp:w \cs_new_nopar:cpx \cs_new_nopar:Npx % \end{macrocode} % \end{macro} % @@ -2380,12 +2471,12 @@ % Variants of the \cs{cs_set:Npn} versions which make a csname out % of the first arguments. We may also do this globally. % \begin{macrocode} -\cs_tmp:w \cs_set:cpn \cs_set:Npn -\cs_tmp:w \cs_set:cpx \cs_set:Npx -\cs_tmp:w \cs_gset:cpn \cs_gset:Npn -\cs_tmp:w \cs_gset:cpx \cs_gset:Npx -\cs_tmp:w \cs_new:cpn \cs_new:Npn -\cs_tmp:w \cs_new:cpx \cs_new:Npx +\__cs_tmp:w \cs_set:cpn \cs_set:Npn +\__cs_tmp:w \cs_set:cpx \cs_set:Npx +\__cs_tmp:w \cs_gset:cpn \cs_gset:Npn +\__cs_tmp:w \cs_gset:cpx \cs_gset:Npx +\__cs_tmp:w \cs_new:cpn \cs_new:Npn +\__cs_tmp:w \cs_new:cpx \cs_new:Npx % \end{macrocode} % \end{macro} % @@ -2398,12 +2489,12 @@ % Variants of the \cs{cs_set_protected_nopar:Npn} versions which make % a csname out of the first arguments. We may also do this globally. % \begin{macrocode} -\cs_tmp:w \cs_set_protected_nopar:cpn \cs_set_protected_nopar:Npn -\cs_tmp:w \cs_set_protected_nopar:cpx \cs_set_protected_nopar:Npx -\cs_tmp:w \cs_gset_protected_nopar:cpn \cs_gset_protected_nopar:Npn -\cs_tmp:w \cs_gset_protected_nopar:cpx \cs_gset_protected_nopar:Npx -\cs_tmp:w \cs_new_protected_nopar:cpn \cs_new_protected_nopar:Npn -\cs_tmp:w \cs_new_protected_nopar:cpx \cs_new_protected_nopar:Npx +\__cs_tmp:w \cs_set_protected_nopar:cpn \cs_set_protected_nopar:Npn +\__cs_tmp:w \cs_set_protected_nopar:cpx \cs_set_protected_nopar:Npx +\__cs_tmp:w \cs_gset_protected_nopar:cpn \cs_gset_protected_nopar:Npn +\__cs_tmp:w \cs_gset_protected_nopar:cpx \cs_gset_protected_nopar:Npx +\__cs_tmp:w \cs_new_protected_nopar:cpn \cs_new_protected_nopar:Npn +\__cs_tmp:w \cs_new_protected_nopar:cpx \cs_new_protected_nopar:Npx % \end{macrocode} % \end{macro} % @@ -2416,12 +2507,12 @@ % Variants of the \cs{cs_set_protected:Npn} versions which make a csname % out of the first arguments. We may also do this globally. % \begin{macrocode} -\cs_tmp:w \cs_set_protected:cpn \cs_set_protected:Npn -\cs_tmp:w \cs_set_protected:cpx \cs_set_protected:Npx -\cs_tmp:w \cs_gset_protected:cpn \cs_gset_protected:Npn -\cs_tmp:w \cs_gset_protected:cpx \cs_gset_protected:Npx -\cs_tmp:w \cs_new_protected:cpn \cs_new_protected:Npn -\cs_tmp:w \cs_new_protected:cpx \cs_new_protected:Npx +\__cs_tmp:w \cs_set_protected:cpn \cs_set_protected:Npn +\__cs_tmp:w \cs_set_protected:cpx \cs_set_protected:Npx +\__cs_tmp:w \cs_gset_protected:cpn \cs_gset_protected:Npn +\__cs_tmp:w \cs_gset_protected:cpx \cs_gset_protected:Npx +\__cs_tmp:w \cs_new_protected:cpn \cs_new_protected:Npn +\__cs_tmp:w \cs_new_protected:cpx \cs_new_protected:Npx % \end{macrocode} % \end{macro} % @@ -2456,7 +2547,7 @@ \cs_new_protected_nopar:Npn \cs_gset_eq:cc { \exp_args:Ncc \cs_gset_eq:NN } \cs_new_protected:Npn \cs_new_eq:NN #1 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \tex_global:D \cs_set_eq:NN #1 } \cs_new_protected_nopar:Npn \cs_new_eq:cN { \exp_args:Nc \cs_new_eq:NN } @@ -2488,57 +2579,88 @@ % \end{macrocode} % \end{macro} % +% \subsection{Generating parameter text from argument count} +% +% \begin{macro}[int]{\__cs_parm_from_arg_count:nnF} +% \begin{macro}[aux]{\__cs_parm_from_arg_count_test:nnF} +% \LaTeX3 provides shorthands to define control sequences and +% conditionals with a simple parameter text, derived directly from the +% signature, or more generally from knowing the number of arguments, +% between~$0$ and~$9$. This function expands to its first argument, +% untouched, followed by a brace group containing the parameter text +% |{#|$1$\ldots{}|#|$n$|}|, where $n$ is the result of evaluating the +% second argument (as described in \cs{int_eval:n}). If the second +% argument gives a result outside the range $[0,9]$, the third +% argument is returned instead, normally an error message. Some of +% the functions use here are not defined yet, but will be defined +% before this function is called. +% \begin{macrocode} +\cs_set_protected:Npn \__cs_parm_from_arg_count:nnF #1#2 + { + \exp_args:Nx \__cs_parm_from_arg_count_test:nnF + { + \exp_after:wN \exp_not:n + \if_case:w \__int_eval:w #2 \__int_eval_end: + { } + \or: { ##1 } + \or: { ##1##2 } + \or: { ##1##2##3 } + \or: { ##1##2##3##4 } + \or: { ##1##2##3##4##5 } + \or: { ##1##2##3##4##5##6 } + \or: { ##1##2##3##4##5##6##7 } + \or: { ##1##2##3##4##5##6##7##8 } + \or: { ##1##2##3##4##5##6##7##8##9 } + \else: { \c_false_bool } + \fi: + } + {#1} + } +\cs_set_protected:Npn \__cs_parm_from_arg_count_test:nnF #1#2 + { + \if_meaning:w \c_false_bool #1 + \exp_after:wN \use_ii:nn + \else: + \exp_after:wN \use_i:nn + \fi: + { #2 {#1} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \subsection{Defining functions from a given number of arguments} % -% \begin{macro}[EXP]{\cs_get_arg_count_from_signature:N} -% \begin{macro}[aux, EXP] -% { -% \cs_get_arg_count_from_signature_aux:nnN, -% \cs_get_arg_count_from_signature_auxii:w -% } -% Counting the number of tokens in the signature, i.e., the number -% of arguments the function should take. If there is no signature, -% we return that there is $-1$ arguments to signal an error. -% Otherwise we insert the string |9876543210| after the signature. -% If the signature is empty, the number we want is $0$ so we remove -% the first nine tokens and return the tenth. Similarly, if the -% signature is |nnn| we want to remove the nine tokens |nnn987654| -% and return $3$. Therefore, we simply remove the first nine tokens -% and then return the tenth. -% \begin{macrocode} -\cs_new:Npn \cs_get_arg_count_from_signature:N #1 - { \cs_split_function:NN #1 \cs_get_arg_count_from_signature_aux:nnN } -\cs_new:Npn \cs_get_arg_count_from_signature_aux:nnN #1#2#3 +% \begin{macro}[EXP, int]{\__cs_count_signature:N, \__cs_count_signature:c} +% \begin{macro}[aux, EXP]{\__cs_count_signature:nnN} +% Counting the number of tokens in the signature, \emph{i.e.}, the +% number of arguments the function should take. Since this is not +% used in any time-critical function, we simply use \cs{tl_count:n} if +% there is a signature, otherwise $-1$ arguments to signal an error. +% We need a variant form right away. +% \begin{macrocode} +\cs_new:Npn \__cs_count_signature:N #1 + { \int_eval:n { \__cs_split_function:NN #1 \__cs_count_signature:nnN } } +\cs_new:Npn \__cs_count_signature:nnN #1#2#3 { \if_meaning:w \c_true_bool #3 - \exp_after:wN \use_i:nn + \tl_count:n {#2} \else: - \exp_after:wN\use_ii:nn + \c_minus_one \fi: - { - \exp_after:wN \cs_get_arg_count_from_signature_auxii:w - \use_none:nnnnnnnnn #2 9876543210 \q_stop - } - { -1 } -} -\cs_new:Npn \cs_get_arg_count_from_signature_auxii:w #1#2 \q_stop {#1} -% \end{macrocode} -% A variant form we need right away. -% \begin{macrocode} -\cs_new_nopar:Npn \cs_get_arg_count_from_signature:c - { \exp_args:Nc \cs_get_arg_count_from_signature:N } + } +\cs_new_nopar:Npn \__cs_count_signature:c + { \exp_args:Nc \__cs_count_signature:N } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[aux] +% \begin{macro} % { % \cs_generate_from_arg_count:NNnn, % \cs_generate_from_arg_count:cNnn, % \cs_generate_from_arg_count:Ncnn % } -% \begin{macro}[aux]{\cs_generate_from_arg_count_error_msg:Nn} -% \begin{macro}[aux]{\cs_generate_from_arg_count_aux:nwn} % We provide a constructor function for defining functions with a % given number of arguments. For this we need to choose the correct % parameter text and then use that when defining. Since \TeX{} @@ -2552,27 +2674,13 @@ % \begin{macrocode} \cs_new_protected:Npn \cs_generate_from_arg_count:NNnn #1#2#3#4 { - \if_case:w \int_eval:w #3 \int_eval_end: - \cs_generate_from_arg_count_aux:nwn {} - \or: \cs_generate_from_arg_count_aux:nwn {##1} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6##7} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6##7##8} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6##7##8##9} - \else: - \cs_generate_from_arg_count_error_msg:Nn #1 {#3} - \use_i:nnn - \fi: - {#2#1} - {#4} + \__cs_parm_from_arg_count:nnF { \use:nnn #2 #1 } {#3} + { + \__msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } + { \token_to_str:N #1 } { \int_eval:n {#3} } + } + {#4} } -\cs_new_protected:Npn - \cs_generate_from_arg_count_aux:nwn #1 #2 \fi: #3 - { \fi: #3 #1 } % \end{macrocode} % A variant form we need right away, plus one which is used elsewhere but % which is most logically created here. @@ -2582,17 +2690,6 @@ \cs_new_protected_nopar:Npn \cs_generate_from_arg_count:Ncnn { \exp_args:NNc \cs_generate_from_arg_count:NNnn } % \end{macrocode} -% The error message. Elsewhere we use the value of $-1$ to signal a -% missing colon in a function, so provide a hint for help on this. -% \begin{macrocode} -\cs_new_protected:Npn \cs_generate_from_arg_count_error_msg:Nn #1#2 - { - \msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } - { \token_to_str:N #1 } { \int_eval:n {#2} } - } -% \end{macrocode} -% \end{macro} -% \end{macro} % \end{macro} % % \subsection{Using the signature to define functions} @@ -2622,7 +2719,7 @@ % \cs_set_protected:Npn \cs_set:Nn #1#2 % { % \cs_generate_from_arg_count:NNnn #1 \cs_set:Npn -% { \cs_get_arg_count_from_signature:N #1 } {#2} +% { \__cs_count_signature:N #1 } {#2} % } % \end{verbatim} % In short, to define \cs{cs_set:Nn} we need just use \cs{cs_set:Npn}, @@ -2630,42 +2727,58 @@ % make it simpler by temporarily defining a function to do this for % us. % \begin{macrocode} -\cs_set:Npn \cs_tmp:w #1#2#3 +\cs_set:Npn \__cs_tmp:w #1#2#3 { - \cs_new_protected:cpx { cs_ #1 : #2 } ##1##2 + \cs_new_protected_nopar:cpx { cs_ #1 : #2 } { - \exp_not:N \cs_generate_from_arg_count:NNnn ##1 - \exp_after:wN \exp_not:N \cs:w cs_#1 : #3 \cs_end: - { \exp_not:N \cs_get_arg_count_from_signature:N ##1 }{##2} + \exp_not:N \__cs_generate_from_signature:NNn + \exp_after:wN \exp_not:N \cs:w cs_ #1 : #3 \cs_end: + } + } +\cs_new_protected:Npn \__cs_generate_from_signature:NNn #1#2 + { + \__cs_split_function:NN #2 \__cs_generate_from_signature:nnNNNn + #1 #2 + } +\cs_new_protected:Npn \__cs_generate_from_signature:nnNNNn #1#2#3#4#5#6 + { + \bool_if:NTF #3 + { + \cs_generate_from_arg_count:NNnn + #5 #4 { \tl_count:n {#2} } {#6} + } + { + \__msg_kernel_error:nnx { kernel } { missing-colon } + { \token_to_str:N #5 } } } % \end{macrocode} % Then we define the 24 variants beginning with |N|. % \begin{macrocode} -\cs_tmp:w { set } { Nn } { Npn } -\cs_tmp:w { set } { Nx } { Npx } -\cs_tmp:w { set_nopar } { Nn } { Npn } -\cs_tmp:w { set_nopar } { Nx } { Npx } -\cs_tmp:w { set_protected } { Nn } { Npn } -\cs_tmp:w { set_protected } { Nx } { Npx } -\cs_tmp:w { set_protected_nopar } { Nn } { Npn } -\cs_tmp:w { set_protected_nopar } { Nx } { Npx } -\cs_tmp:w { gset } { Nn } { Npn } -\cs_tmp:w { gset } { Nx } { Npx } -\cs_tmp:w { gset_nopar } { Nn } { Npn } -\cs_tmp:w { gset_nopar } { Nx } { Npx } -\cs_tmp:w { gset_protected } { Nn } { Npn } -\cs_tmp:w { gset_protected } { Nx } { Npx } -\cs_tmp:w { gset_protected_nopar } { Nn } { Npn } -\cs_tmp:w { gset_protected_nopar } { Nx } { Npx } -\cs_tmp:w { new } { Nn } { Npn } -\cs_tmp:w { new } { Nx } { Npx } -\cs_tmp:w { new_nopar } { Nn } { Npn } -\cs_tmp:w { new_nopar } { Nx } { Npx } -\cs_tmp:w { new_protected } { Nn } { Npn } -\cs_tmp:w { new_protected } { Nx } { Npx } -\cs_tmp:w { new_protected_nopar } { Nn } { Npn } -\cs_tmp:w { new_protected_nopar } { Nx } { Npx } +\__cs_tmp:w { set } { Nn } { Npn } +\__cs_tmp:w { set } { Nx } { Npx } +\__cs_tmp:w { set_nopar } { Nn } { Npn } +\__cs_tmp:w { set_nopar } { Nx } { Npx } +\__cs_tmp:w { set_protected } { Nn } { Npn } +\__cs_tmp:w { set_protected } { Nx } { Npx } +\__cs_tmp:w { set_protected_nopar } { Nn } { Npn } +\__cs_tmp:w { set_protected_nopar } { Nx } { Npx } +\__cs_tmp:w { gset } { Nn } { Npn } +\__cs_tmp:w { gset } { Nx } { Npx } +\__cs_tmp:w { gset_nopar } { Nn } { Npn } +\__cs_tmp:w { gset_nopar } { Nx } { Npx } +\__cs_tmp:w { gset_protected } { Nn } { Npn } +\__cs_tmp:w { gset_protected } { Nx } { Npx } +\__cs_tmp:w { gset_protected_nopar } { Nn } { Npn } +\__cs_tmp:w { gset_protected_nopar } { Nx } { Npx } +\__cs_tmp:w { new } { Nn } { Npn } +\__cs_tmp:w { new } { Nx } { Npx } +\__cs_tmp:w { new_nopar } { Nn } { Npn } +\__cs_tmp:w { new_nopar } { Nx } { Npx } +\__cs_tmp:w { new_protected } { Nn } { Npn } +\__cs_tmp:w { new_protected } { Nx } { Npx } +\__cs_tmp:w { new_protected_nopar } { Nn } { Npn } +\__cs_tmp:w { new_protected_nopar } { Nx } { Npx } % \end{macrocode} % \end{macro} % @@ -2684,49 +2797,40 @@ % \cs_new_protected:cn , \cs_new_protected:cx , % \cs_new_protected_nopar:cn , \cs_new_protected_nopar:cx , % } -% Then something similar for the |c| variants. -% \begin{verbatim} -% \cs_set_protected:Npn \cs_set:cn #1#2 -% { -% \cs_generate_from_arg_count:cNnn {#1} \cs_set:Npn -% { \cs_get_arg_count_from_signature:c {#1} } {#2} -% } -% \end{verbatim} -% The 24 |c| variants. +% The 24 |c| variants simply use \cs{exp_args:Nc}. % \begin{macrocode} -\cs_set:Npn \cs_tmp:w #1#2#3 +\cs_set:Npn \__cs_tmp:w #1#2 { - \cs_new_protected:cpx {cs_#1:#2} ##1##2 + \cs_new_protected_nopar:cpx { cs_ #1 : c #2 } { - \exp_not:N \cs_generate_from_arg_count:cNnn {##1} - \exp_after:wN \exp_not:N \cs:w cs_#1:#3 \cs_end: - { \exp_not:N \cs_get_arg_count_from_signature:c {##1} } {##2} + \exp_not:N \exp_args:Nc + \exp_after:wN \exp_not:N \cs:w cs_ #1 : N #2 \cs_end: } } -\cs_tmp:w { set } { cn } { Npn } -\cs_tmp:w { set } { cx } { Npx } -\cs_tmp:w { set_nopar } { cn } { Npn } -\cs_tmp:w { set_nopar } { cx } { Npx } -\cs_tmp:w { set_protected } { cn } { Npn } -\cs_tmp:w { set_protected } { cx } { Npx } -\cs_tmp:w { set_protected_nopar } { cn } { Npn } -\cs_tmp:w { set_protected_nopar } { cx } { Npx } -\cs_tmp:w { gset } { cn } { Npn } -\cs_tmp:w { gset } { cx } { Npx } -\cs_tmp:w { gset_nopar } { cn } { Npn } -\cs_tmp:w { gset_nopar } { cx } { Npx } -\cs_tmp:w { gset_protected } { cn } { Npn } -\cs_tmp:w { gset_protected } { cx } { Npx } -\cs_tmp:w { gset_protected_nopar } { cn } { Npn } -\cs_tmp:w { gset_protected_nopar } { cx } { Npx } -\cs_tmp:w { new } { cn } { Npn } -\cs_tmp:w { new } { cx } { Npx } -\cs_tmp:w { new_nopar } { cn } { Npn } -\cs_tmp:w { new_nopar } { cx } { Npx } -\cs_tmp:w { new_protected } { cn } { Npn } -\cs_tmp:w { new_protected } { cx } { Npx } -\cs_tmp:w { new_protected_nopar } { cn } { Npn } -\cs_tmp:w { new_protected_nopar } { cx } { Npx } +\__cs_tmp:w { set } { n } +\__cs_tmp:w { set } { x } +\__cs_tmp:w { set_nopar } { n } +\__cs_tmp:w { set_nopar } { x } +\__cs_tmp:w { set_protected } { n } +\__cs_tmp:w { set_protected } { x } +\__cs_tmp:w { set_protected_nopar } { n } +\__cs_tmp:w { set_protected_nopar } { x } +\__cs_tmp:w { gset } { n } +\__cs_tmp:w { gset } { x } +\__cs_tmp:w { gset_nopar } { n } +\__cs_tmp:w { gset_nopar } { x } +\__cs_tmp:w { gset_protected } { n } +\__cs_tmp:w { gset_protected } { x } +\__cs_tmp:w { gset_protected_nopar } { n } +\__cs_tmp:w { gset_protected_nopar } { x } +\__cs_tmp:w { new } { n } +\__cs_tmp:w { new } { x } +\__cs_tmp:w { new_nopar } { n } +\__cs_tmp:w { new_nopar } { x } +\__cs_tmp:w { new_protected } { n } +\__cs_tmp:w { new_protected } { x } +\__cs_tmp:w { new_protected_nopar } { n } +\__cs_tmp:w { new_protected_nopar } { x } % \end{macrocode} % \end{macro} % @@ -2758,25 +2862,25 @@ % % \subsection{Diagnostic wrapper functions} % -% \begin{macro}{\kernel_register_show:N, \kernel_register_show:c} -% Check that the variable, then apply the \tn{showthe} primitive to +% \begin{macro}[int]{\__kernel_register_show:N, \__kernel_register_show:c} +% Check that the variable exists, then apply the \tn{showthe} primitive to % the variable. The odd-looking \cs{use:n} gives a nicer output. % \begin{macrocode} -\cs_new:Npn \kernel_register_show:N #1 +\cs_new_protected:Npn \__kernel_register_show:N #1 { \cs_if_exist:NTF #1 { \tex_showthe:D \use:n {#1} } { - \msg_kernel_error:nnx { kernel } { variable-not-defined } + \__msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } -\cs_new_nopar:Npn \kernel_register_show:c - { \exp_args:Nc \kernel_register_show:N } +\cs_new_protected_nopar:Npn \__kernel_register_show:c + { \exp_args:Nc \__kernel_register_show:N } % \end{macrocode} % \end{macro} % -% \subsection{Engine specific definitions} +% \subsection{Engine specific definitions} % % \begin{macro}[pTF, EXP] % {\xetex_if_engine:, \luatex_if_engine:, \pdftex_if_engine:} @@ -2831,7 +2935,7 @@ % % \subsection{String comparisons} % -% \begin{macro}[pTF, EXP]{\str_if_eq:nn, \str_if_eq:xx} +% \begin{macro}[pTF, EXP]{\str_if_eq:nn, \str_if_eq_x:nn} % Modern engines provide a direct way of comparing two token lists, % but returning a number. This set of conditionals therefore make life % a bit clearer. The \texttt{nn} and \texttt{xx} versions are created @@ -2844,7 +2948,7 @@ = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } -\prg_new_conditional:Npnn \str_if_eq:xx #1#2 { p , T , F , TF } +\prg_new_conditional:Npnn \str_if_eq_x:nn #1#2 { p , T , F , TF } { \if_int_compare:w \pdftex_strcmp:D {#1} {#2} = \c_zero \prg_return_true: \else: \prg_return_false: \fi: @@ -2852,20 +2956,83 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}[int, EXP]{\__str_if_eq_x_return:nn} +% It turns out that we often need to compare a token list +% with the result of applying some function to it, and +% return with \cs{prg_return_true/false:}. This test is +% similar to \cs{str_if_eq:nnTF}, but hard-coded for speed. +% \begin{macrocode} +\cs_new:Npn \__str_if_eq_x_return:nn #1 #2 + { + \if_int_compare:w \pdftex_strcmp:D {#1} {#2} = \c_zero + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\str_case:nnn, \str_case_x:nnn} +% \begin{macro}[int, EXP]{\__prg_case_end:nw} +% \begin{macro}[aux, EXP] +% {\__str_case:nw, \__str_case_x:nw, \__str_case_end:nw} +% No calculations for strings, otherwise no surprises. +% \begin{macrocode} +\cs_new:Npn \str_case:nnn #1#2#3 + { + \tex_romannumeral:D + \__str_case:nw {#1} #2 {#1} {#3} \q_recursion_stop + } +\cs_new:Npn \__str_case:nw #1#2#3 + { + \str_if_eq:nnTF {#1} {#2} + { \__str_case_end:nw {#3} } + { \__str_case:nw {#1} } + } +\cs_new:Npn \str_case_x:nnn #1#2#3 + { + \tex_romannumeral:D + \__str_case_x:nw {#1} #2 {#1} {#3} \q_recursion_stop + } +\cs_new:Npn \__str_case_x:nw #1#2#3 + { + \str_if_eq_x:nnTF {#1} {#2} + { \__str_case_end:nw {#3} } + { \__str_case_x:nw {#1} } + } +% \end{macrocode} +% Here, |#1| will be the code needed, |#2| will be any remaining case +% or cases, and the \cs{c_zero} stops the \tn{romannumeral}. +% \begin{macrocode} +\cs_new:Npn \__prg_case_end:nw #1#2 \q_recursion_stop { \c_zero #1 } +\cs_new_eq:NN \__str_case_end:nw \__prg_case_end:nw +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% % \subsection{Breaking out of mapping functions} % -% \begin{macro}[EXP]{\prg_break_point:n, \prg_map_break:, \prg_map_break:n} +% \begin{macro}[EXP]{\__prg_break_point:Nn, \__prg_map_break:Nn} % In inline mappings, the nesting level must be reset % at the end of the mapping, even when the user decides % to break out. This is done by putting the code that -% must be performed as an argument of \cs{prg_break_point:n}. +% must be performed as an argument of \cs{__prg_break_point:Nn}. % The breaking functions are then defined to jump to -% that point and perform the argument of \cs{prg_break_point:n}, -% before the user's code (if any). +% that point and perform the argument of \cs{__prg_break_point:Nn}, +% before the user's code (if any). There is a check that we close the +% correct loop, otherwise we continue breaking. % \begin{macrocode} -\cs_new_eq:NN \prg_break_point:n \use:n -\cs_new:Npn \prg_map_break: #1 \prg_break_point:n #2 { #2 } -\cs_new:Npn \prg_map_break:n #1 #2 \prg_break_point:n #3 { #3 #1 } +\cs_new_eq:NN \__prg_break_point:Nn \use_ii:nn +\cs_new:Npn \__prg_map_break:Nn #1#2#3 \__prg_break_point:Nn #4#5 + { + #5 + \if_meaning:w #1 #4 + \exp_after:wN \use_iii:nnn + \fi: + \__prg_map_break:Nn #1 {#2} + } % \end{macrocode} % \end{macro} % @@ -2963,6 +3130,24 @@ % \end{macrocode} % \end{macro} % +% Deprecated 2012-06-05 for removal after 2012-12-31. +% +% \begin{macro}[pTF, EXP]{\str_if_eq:xx} +% Not really true \texttt{x}-type expansion +% \begin{macrocode} +\cs_new_eq:NN \str_if_eq_p:xx \str_if_eq_x_p:nn +\cs_new_eq:NN \str_if_eq:xxT \str_if_eq_x:nnT +\cs_new_eq:NN \str_if_eq:xxF \str_if_eq_x:nnF +\cs_new_eq:NN \str_if_eq:xxTF \str_if_eq_x:nnTF +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\chk_if_free_cs:N} +% \begin{macrocode} +\cs_new_eq:NN \chk_if_free_cs:N \__chk_if_free_cs:N +% \end{macrocode} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx index 43b2d11689f..1fb3ac9454f 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3bootstrap.dtx Copyright (C) 2011 The LaTeX3 project +%% File: l3bootstrap.dtx Copyright (C) 2011-2012 The LaTeX3 project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -33,22 +33,38 @@ %% %% ----------------------------------------------------------------------- % -%<*package> +%<*driver|package> +% \begin{macro}{\GetIdInfo} +% \begin{macro}[aux]{\GetIdInfoAuxI, \GetIdInfoAuxII, \GetIdInfoAuxIII} +% The idea here is to extract out the information needed from a standard +% \textsc{svn} \texttt{Id} line, but without a line that will get +% changed when the file is checked in. Hence the fact that there is +% not a line which includes both a dollar sign and the \texttt{Id} +% keyword together! +% \begin{macrocode} \protected\def\GetIdInfo - { + {% \begingroup - \catcode 32 = 10 \relax - \GetIdInfoAuxI + \catcode 32 = 10 % + \GetIdInfoAuxI } +% \end{macrocode} +% A first check for a completely empty \textsc{svn} field. If that is +% not the case, there is a second case when a file created using +% \texttt{svn cp} but has not been checked in. That leaves a special +% marker \texttt{-1} version, which has no further data. Dealing correctly +% with that is the reason for the space in the line to use +% \cs{GetIdInforAuxII}. +% \begin{macrocode} \protected\def\GetIdInfoAuxI$#1$#2% - { + {% \def\tempa{#1}% \def\tempb{Id}% \ifx\tempa\tempb \def\tempa {% \endgroup - \def\ExplFileDate{9999/99/99}% + \def\ExplFileDate{9999/12/31}% \def\ExplFileDescription{#2}% \def\ExplFileName{[unknown name]}% \def\ExplFileExtension{[unknown extension]}% @@ -58,34 +74,54 @@ \def\tempa {% \endgroup - \GetIdInfoAuxII$#1${#2}% + \def\ExplFileDescription{#2}% + \GetIdInfoAuxII$#1 $% }% \fi \tempa } -\protected\def\GetIdInfoAuxII$#1 #2.#3 #4 #5 #6 #7 #8$#9% +% \end{macrocode} +% Here, |#1| is |Id|, |#2| is the file name, |#3| is the extension, +% |#4| is the version, |#5| is the check in date and |#6| is the check in +% time and user, plus some trailing spaces. If |#4| is the marker |-1| value +% then |#5| and |#6| will be empty. +% \begin{macrocode} +\protected\def\GetIdInfoAuxII$#1 #2.#3 #4 #5 #6$% {% \def\ExplFileName{#2}% \def\ExplFileExtension{#3}% \def\ExplFileVersion{#4}% - \def\ExplFileDescription{#9}% - \GetIdInfoAuxIII#5\relax#3\relax#5\relax#6\relax + \begingroup + \def\tempa{#4}% + \def\tempb{-1}% + \ifx\tempa\tempb + \def\tempa + {% + \endgroup + \def\ExplFileDate{0000/00/00}% + }% + \else + \def\tempa + {% + \endgroup + \GetIdInfoAuxIII$#5$% + }% + \fi + \tempa } -\protected\def\GetIdInfoAuxIII#1#2#3#4#5#6\relax +% \end{macrocode} +% Convert an \textsc{svn}-style date into a \LaTeX{}-style one. +% \begin{macrocode} +\protected\def\GetIdInfoAuxIII$#1-#2-#3$% {% - \ifx#5/% - \expandafter\GetIdInfoAuxCVS - \else - \expandafter\GetIdInfoAuxSVN - \fi + \def\ExplFileDate{#1/#2/#3}% } -\protected\def\GetIdInfoAuxCVS#1,v\relax#2\relax#3\relax - {\def\ExplFileDate{#2}} -\protected\def\GetIdInfoAuxSVN#1\relax#2-#3-#4\relax#5Z\relax - {\def\ExplFileDate{#2/#3/#4}} -\GetIdInfo$Id: l3bootstrap.dtx 3110 2011-12-29 14:23:48Z joseph $ - {L3 experimental bootstrap code} -%</package> +% \end{macrocode} +% \end{macro} +% \end{macro} +\GetIdInfo$Id: l3bootstrap.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Bootstrap code} +%</driver|package> %<*driver> \documentclass[full]{l3doc} \begin{document} @@ -135,20 +171,7 @@ % and underscore (|_|) are treated as \enquote{letters}, thus allowing % access to the names of code functions and variables. Within this % environment, |~| is used to input a space. The \cs{ExplSyntaxOff} -% reverts to the document category code regim{\'e}. -% \end{function} -% -% \begin{function}{\ExplSyntaxNamesOn, \ExplSyntaxNamesOff} -% \begin{syntax} -% \cs{ExplSyntaxNamesOn} \meta{code} \cs{ExplSyntaxNamesOff} -% \end{syntax} -% The \cs{ExplSyntaxOn} function switches to a category code -% regim{\'e} in which the colon (|:|) and underscore (|_|) are treated as -% \enquote{letters}, thus allowing access to the names of code functions -% and variables. In contrast to \cs{ExplSyntaxOn}, using -% \cs{ExplSyntaxNamesOn} does not cause spaces to be ignored. -% The \cs{ExplSyntaxNamesOff} reverts to the document category code -% regim{\'e}. +% reverts to the document category code r{\'e}gime. % \end{function} % % \begin{function}{\ProvidesExplPackage, \ProvidesExplClass, \ProvidesExplFile} @@ -165,7 +188,7 @@ % \tn{makeatletter} within package and class code.) % \end{function} % -% \begin{function}{\GetIdInfo} +% \begin{function}[updated = 2012-06-04]{\GetIdInfo} % \begin{syntax} % |\RequirePackage{l3names}| % \cs{GetIdInfo} |$Id:| \meta{SVN info field} |$| \Arg{description} @@ -189,6 +212,23 @@ % \ProvidesExplPackage{\ExplFileName} % {\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} % \end{verbatim} +% +% \subsection{Internal functions and variables} +% +% \begin{function}{\__expl_package_check:} +% \begin{syntax} +% \cs{__expl_package_check:} +% \end{syntax} +% Used to ensure that all parts of \pkg{expl3} are loaded together +% (\emph{i.e.}~as part of \pkg{expl3}). Issues an error if a kernel package +% is loaded independently of the bundle. +% \end{function} +% +% \begin{variable}{\l__kernel_expl_bool} +% A boolean which records the current code syntax status: \texttt{true} if +% currently inside a code environment. This variable should only be +% set by \cs{ExplSyntaxOn}/\cs{ExplSyntaxOff}. +% \end{variable} % % \end{documentation} % @@ -198,6 +238,7 @@ % % \begin{macrocode} %<*initex|package> +%<@@=expl> % \end{macrocode} % % \subsection{Format-specific code} @@ -223,7 +264,7 @@ % \end{macrocode} % % For \LuaTeX{} the extra primitives need to be enabled before -% they can be use. No \tn{ifdefined} yet, so do it the old-fashioned +% they can be used. No \tn{ifdefined} yet, so do it the old-fashioned % way. The primitive \tn{strcmp} is simulated using some \Lua{} % code, which currently has to be applied to every job as the \Lua{} % code is not part of the format. Thanks to Taco Hoekwater for this @@ -267,7 +308,7 @@ %</initex> % \end{macrocode} % -% \subsection{Package-specific code} +% \subsection{Package-specific code part one} % % The package starts by identifying itself: the information itself is % taken from the SVN |Id| string at the start of the source file. @@ -303,6 +344,64 @@ \fi %</package> % \end{macrocode} +% +% \subsection{The \tn{pdfstrcmp} primitive in \XeTeX{}} +% +% Only \pdfTeX{} has a primitive called \tn{pdfstrcmp}. The \XeTeX{} +% version is just \tn{strcmp}, so there is some shuffling to do. +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup + \expandafter\ifx\csname pdfstrcmp\endcsname\relax + \let\pdfstrcmp\strcmp +\fi +% \end{macrocode} +% +% \subsection{Engine requirements} +% +% The code currently requires functionality equivalent to \tn{pdfstrcmp} +% in addition to \eTeX{}. The former is therefore used as a test for +% a suitable engine. +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname pdfstrcmp\endcsname\relax +%<*package> + \PackageError{expl3}{Required primitives not found} + {% + LaTeX3 requires the e-TeX primitives and \string\pdfstrcmp.\MessageBreak + \MessageBreak + These are available in engine versions:\MessageBreak + - pdfTeX 1.30\MessageBreak + - XeTeX 0.9994\MessageBreak + - LuaTeX 0.40\MessageBreak + or later.\MessageBreak + \MessageBreak + Loading of expl3 will abort!% + } + \expandafter\endinput +%</package> +%<*initex> + \newlinechar`\^^J\relax + \errhelp{% + LaTeX3 requires the e-TeX primitives and \pdfstrcmp.^^J% + ^^J% + These are available in engine versions:^^J% + - pdfTeX 1.30^^J% + - XeTeX 0.9994^^J% + - LuaTeX 0.40^^J% + or later.^^J% + ^^J% + For pdfTeX and XeTeX the '-etex' command-line switch is also + needed.^^J% + ^^J% + Format building will abort!% + } + \errmessage{Required primitives not found}% + \expandafter\end +%</initex> +\fi +% \end{macrocode} +% +% \subsection{Package-specific code part two} % % \begin{macro}{\ExplSyntaxOff, \ExplSyntaxOn} % Experimental syntax switching is set up here for the package-loading @@ -322,7 +421,7 @@ \catcode 124 = \the\catcode 124\relax \catcode 126 = \the\catcode 126\relax \endlinechar = \the\endlinechar\relax - \chardef\csname\detokenize{l_expl_status_bool}\endcsname = 0 \relax + \chardef\csname\detokenize{l__kernel_expl_bool}\endcsname = 0 \relax } \protected\edef\ExplSyntaxOn { @@ -335,82 +434,24 @@ \catcode 124 = 12 \relax \catcode 126 = 10 \relax \endlinechar = 32 \relax - \chardef\csname\detokenize{l_expl_status_bool}\endcsname = 1 \relax + \chardef\csname\detokenize{l__kernel_expl_bool}\endcsname = 1 \relax } %</package> % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_expl_status_bool} +% \begin{variable}{\l__kernel_expl_bool} % The status for experimental code syntax: this is off at present. This % code is used by both the package and the format. % \begin{macrocode} -\expandafter\chardef\csname\detokenize{l_expl_status_bool}\endcsname = 0 \relax +\expandafter\chardef\csname\detokenize{l__kernel_expl_bool}\endcsname = 0 \relax % \end{macrocode} -%\end{macro} +%\end{variable} % % \subsection{Dealing with package-mode meta-data} % % \begin{macro}{\GetIdInfo} -% \begin{macro}[aux] -% { -% \GetIdInfoFull, \GetIdInfoAuxI, \GetIdInfoAuxII, \GetIdInfoAuxIII, -% \GetIdInfoAuxCVS, \GetIdInfoAuxSVN -% } -% Functions for collecting up meta-data from the SVN information -% used by the \LaTeX3 Project. -% \begin{macrocode} -%<*package> -\protected\def\GetIdInfo - { - \begingroup - \catcode 32 = 10 \relax - \GetIdInfoAuxI - } -\protected\def\GetIdInfoAuxI$#1$#2% - { - \def\tempa{#1}% - \def\tempb{Id}% - \ifx\tempa\tempb - \def\tempa - {% - \endgroup - \def\ExplFileDate{9999/99/99}% - \def\ExplFileDescription{#2}% - \def\ExplFileName{[unknown name]}% - \def\ExplFileVersion{999}% - }% - \else - \def\tempa - {% - \endgroup - \GetIdInfoAuxII$#1${#2}% - }% - \fi - \tempa - } -\protected\def\GetIdInfoAuxII$#1 #2.#3 #4 #5 #6 #7 #8$#9% - {% - \def\ExplFileName{#2}% - \def\ExplFileVersion{#4}% - \def\ExplFileDescription{#9}% - \GetIdInfoAuxIII#5\relax#3\relax#5\relax#6\relax - } -\protected\def\GetIdInfoAuxIII#1#2#3#4#5#6\relax - {% - \ifx#5/% - \expandafter\GetIdInfoAuxCVS - \else - \expandafter\GetIdInfoAuxSVN - \fi - } -\protected\def\GetIdInfoAuxCVS#1,v\relax#2\relax#3\relax - {\def\ExplFileDate{#2}} -\protected\def\GetIdInfoAuxSVN#1\relax#2-#3-#4\relax#5Z\relax - {\def\ExplFileDate{#2/#3/#4}} -%</package> -% \end{macrocode} -% \end{macro} +% This is implemented right at the start of \texttt{l3bootstrap.dtx}. % \end{macro} % % \begin{macro}{\ProvidesExplPackage, \ProvidesExplClass, \ProvidesExplFile} @@ -448,16 +489,16 @@ \edef\@pushfilename {% \edef\expandafter\noexpand - \csname\detokenize{l_expl_status_stack_tl}\endcsname + \csname\detokenize{l_@@_status_stack_tl}\endcsname {% \noexpand\ifodd\expandafter\noexpand - \csname\detokenize{l_expl_status_bool}\endcsname + \csname\detokenize{l__kernel_expl_bool}\endcsname 1% \noexpand\else 0% \noexpand\fi \expandafter\noexpand - \csname\detokenize{l_expl_status_stack_tl}\endcsname + \csname\detokenize{l_@@_status_stack_tl}\endcsname }% \ExplSyntaxOff \unexpanded\expandafter{\@pushfilename}% @@ -466,14 +507,14 @@ {% \unexpanded\expandafter{\@popfilename}% \noexpand\if a\expandafter\noexpand\csname - \detokenize{l_expl_status_stack_tl}\endcsname a% + \detokenize{l_@@_status_stack_tl}\endcsname a% \ExplSyntaxOff \noexpand\else \noexpand\expandafter \expandafter\noexpand\csname - \detokenize{expl_status_pop:w}\endcsname + \detokenize{@@_status_pop:w}\endcsname \expandafter\noexpand\csname - \detokenize{l_expl_status_stack_tl}\endcsname + \detokenize{l_@@_status_stack_tl}\endcsname \noexpand\@nil \noexpand\fi } @@ -481,28 +522,28 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_expl_status_stack_tl} +% \begin{macro}{\l_@@_status_stack_tl} % As \pkg{expl3} itself cannot be loaded with the code environment % already active, at the end of the package \cs{ExplSyntaxOff} can % safely be called. % \begin{macrocode} %<*package> -\@namedef{\detokenize{l_expl_status_stack_tl}}{0} +\@namedef{\detokenize{l_@@_status_stack_tl}}{0} %</package> % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\expl_status_pop:w} +% \begin{macro}[aux]{\@@_status_pop:w} % The pop auxiliary function removes the first item from the stack, % saves the rest of the stack and then does the test. As % \cs{ExplSyntaxOff} is already defined as a protected macro, there % is no need for \tn{noexpand} here. % \begin{macrocode} %<*package> -\expandafter\edef\csname\detokenize{expl_status_pop:w}\endcsname#1#2\@nil +\expandafter\edef\csname\detokenize{@@_status_pop:w}\endcsname#1#2\@nil {% \def\expandafter\noexpand - \csname\detokenize{l_expl_status_stack_tl}\endcsname{#2}% + \csname\detokenize{l_@@_status_stack_tl}\endcsname{#2}% \noexpand\ifodd#1\space \noexpand\expandafter\noexpand\ExplSyntaxOn \noexpand\else @@ -513,13 +554,14 @@ % \end{macrocode} % \end{macro} % -% We want the \pkg{expl3} bundle to be loaded \enquote{as one}; -% this command is -% used to ensure that one of the |l3| packages isn't loaded on its own. +% \begin{macro}[int]{\__expl_package_check:} +% We want the \pkg{expl3} bundle to be loaded \enquote{as one}; +% this command is used to ensure that one of the |l3| packages isn't loaded +% on its own. % \begin{macrocode} %<*package> \expandafter\protected\expandafter\def - \csname\detokenize{package_check_loaded_expl:}\endcsname + \csname\detokenize{__expl_package_check:}\endcsname {% \@ifpackageloaded{expl3} {} @@ -528,90 +570,16 @@ {Cannot load the expl3 modules separately} {% The expl3 modules cannot be loaded separately;\MessageBreak - please \string\usepackage\string{expl3\string} instead. + please \string\usepackage\string{expl3\string} instead.% }% }% } %</package> % \end{macrocode} -% -% \subsection{The \tn{pdfstrcmp} primitive in \XeTeX{}} -% -% Only \pdfTeX{} has a primitive called \tn{pdfstrcmp}. The \XeTeX{} -% version is just \tn{strcmp}, so there is some shuffling to do. -% \begin{macrocode} -\begingroup\expandafter\expandafter\expandafter\endgroup - \expandafter\ifx\csname pdfstrcmp\endcsname\relax - \let\pdfstrcmp\strcmp -\fi -% \end{macrocode} -% -% \subsection{Engine requirements} -% -% The code currently requires functionality equivalent to \tn{pdfstrcmp} -% in addition to \eTeX{}. The former is therefore used as a test for -% a suitable engine. -% \begin{macrocode} -\begingroup\expandafter\expandafter\expandafter\endgroup -\expandafter\ifx\csname pdfstrcmp\endcsname\relax -%<*package> - \PackageError{l3names}{Required primitive not found: \protect\pdfstrcmp} - {% - LaTeX3 requires the e-TeX primitives and - \string\pdfstrcmp.\MessageBreak - These are available in engine versions: \MessageBreak - - pdfTeX 1.30 \MessageBreak - - XeTeX 0.9994 \MessageBreak - - LuaTeX 0.60 \MessageBreak - or later. \MessageBreak - \MessageBreak - Loading of expl3 will abort! - } -%</package> -%<*initex> - \newlinechar`\^^J\relax - \errhelp{% - LaTeX3 requires the e-TeX primitives and - \string\pdfstrcmp. ^^J - These are available in engine versions: ^^J - - pdfTeX 1.30 ^^J - - XeTeX 0.9994 ^^J - - LuaTeX 0.60 ^^J - or later. ^^J - For pdfTeX and XeTeX the '-etex' command-line switch is also - needed.^^J - ^^J - Format building will abort! - } -%</initex> - \expandafter\endinput -\fi -% \end{macrocode} +% \end{macro} % % \subsection{The \LaTeX3 code environment} % -% \begin{macro}{\ExplSyntaxNamesOn, \ExplSyntaxNamesOff} -% These can be set up early, as they are not used anywhere in the -% package or format itself. Using an \tn{edef} here makes the -% definitions that bit clearer later. -% \begin{macrocode} -\protected\edef\ExplSyntaxNamesOn - {% - \expandafter\noexpand - \csname\detokenize{char_set_catcode_letter:n}\endcsname{58}% - \expandafter\noexpand - \csname\detokenize{char_set_catcode_letter:n}\endcsname{95}% - } -\protected\edef\ExplSyntaxNamesOff - {% - \expandafter\noexpand - \csname\detokenize{char_set_catcode_other:n}\endcsname{58}% - \expandafter\noexpand - \csname\detokenize{char_set_catcode_math_subscript:n}\endcsname{95}% - } -% \end{macrocode} -% \end{macro} -% % The code environment is now set up for the format: the package deals % with this using \cs{ProvidesExplPackage}. % \begin{macrocode} @@ -636,7 +604,7 @@ %<*initex> \protected \def \ExplSyntaxOn { - \bool_if:NF \l_expl_status_bool + \bool_if:NF \l__kernel_expl_bool { \cs_set_protected_nopar:Npx \ExplSyntaxOff { @@ -651,7 +619,7 @@ \char_set_catcode:nn { 126 } { \char_value_catcode:n { 126 } } \tex_endlinechar:D = \tex_the:D \tex_endlinechar:D \scan_stop: - \bool_set_false:N \l_expl_status_bool + \bool_set_false:N \l__kernel_expl_bool \cs_set_protected_nopar:Npn \ExplSyntaxOff { } } } @@ -665,21 +633,47 @@ \char_set_catcode_other:n { 124 } % pipe \char_set_catcode_space:n { 126 } % tilde \tex_endlinechar:D = 32 \scan_stop: - \bool_set_true:N \l_expl_status_bool + \bool_set_true:N \l__kernel_expl_bool } \protected \def \ExplSyntaxOff { } %</initex> % \end{macrocode} % \end{macro} % -% \begin{variable}{\l_expl_status_bool} +% \begin{variable}{\l__kernel_expl_bool} % A flag to show the current syntax status. % \begin{macrocode} %<*initex> -\chardef \l_expl_status_bool = 0 ~ +\chardef \l__kernel_expl_bool = 0 ~ %</initex> % \end{macrocode} % \end{variable} +% +% \subsection{Deprecated functions} +% +% Deprecated 2012-06-19 for removal after 2012-12-31. +% +% \begin{macro}{\ExplSyntaxNamesOn, \ExplSyntaxNamesOff} +% These can be set up early, as they are not used anywhere in the +% package or format itself. Using an \tn{edef} here makes the +% definitions that bit clearer later. +% \begin{macrocode} +\protected\edef\ExplSyntaxNamesOn + {% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_letter:n}\endcsname{58}% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_letter:n}\endcsname{95}% + } +\protected\edef\ExplSyntaxNamesOff + {% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_other:n}\endcsname{58}% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_math_subscript:n}\endcsname{95}% + } +% \end{macrocode} +% \end{macro} % % \begin{macrocode} %</initex|package> diff --git a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx index 8ec1f62babe..b578295ac44 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx @@ -35,7 +35,7 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3box.dtx 3490 2012-03-04 01:00:53Z bruno $ +\GetIdInfo$Id: l3box.dtx 3986 2012-07-15 19:23:51Z joseph $ {L3 Experimental boxes} %</driver|package> %<*driver> @@ -106,9 +106,9 @@ % \box_gset_eq:NN, \box_gset_eq:cN, \box_gset_eq:Nc, \box_gset_eq:cc % } % \begin{syntax} -% \cs{box_set_eq:NN} \meta{box1} \meta{box2} +% \cs{box_set_eq:NN} \meta{box_1} \meta{box_2} % \end{syntax} -% Sets the content of \meta{box1} equal to that of \meta{box2}. +% Sets the content of \meta{box_1} equal to that of \meta{box_2}. % \end{function} % % \begin{function} @@ -117,10 +117,10 @@ % \box_set_eq_clear:Nc, \box_set_eq_clear:cc % } % \begin{syntax} -% \cs{box_set_eq_clear:NN} \meta{box1} \meta{box2} +% \cs{box_set_eq_clear:NN} \meta{box_1} \meta{box_2} % \end{syntax} -% Sets the content of \meta{box1} within the current \TeX{} group -% equal to that of \meta{box2}, then clears \meta{box2} globally. +% Sets the content of \meta{box_1} within the current \TeX{} group +% equal to that of \meta{box_2}, then clears \meta{box_2} globally. % \end{function} % % \begin{function} @@ -129,10 +129,10 @@ % \box_gset_eq_clear:Nc, \box_gset_eq_clear:cc % } % \begin{syntax} -% \cs{box_gset_eq_clear:NN} \meta{box1} \meta{box2} +% \cs{box_gset_eq_clear:NN} \meta{box_1} \meta{box_2} % \end{syntax} -% Sets the content of \meta{box1} equal to that of \meta{box2}, then -% clears \meta{box2}. These assignments are global. +% Sets the content of \meta{box_1} equal to that of \meta{box_2}, then +% clears \meta{box_2}. These assignments are global. % \end{function} % % \begin{function}[EXP, pTF, added=2012-03-03] @@ -255,153 +255,6 @@ % \Arg{dimension expression}. This is a global assignment. % \end{function} % -% \section{Affine transformations} -% -% Affine transformations are changes which (informally) preserve straight -% lines. Simple translations are affine transformations, but are better handled -% in \TeX{} by doing the translation first, then inserting an unmodified box. -% On the other hand, rotation and resizing of boxed material can best be -% handled by modifying boxes. These transformations are described here. -% -% \begin{function}[added = 2011-09-02]{\box_resize:Nnn, \box_resize:cnn} -% \begin{syntax} -% \cs{box_resize:Nnn} \meta{box} \Arg{x-size} \Arg{y-size} -% \end{syntax} -% Resize the \meta{box} to \meta{x-size} horizontally and \meta{y-size} -% vertically (both of the sizes are dimension expressions). -% The \meta{y-size} is the vertical size (height plus depth) of -% the box. The updated \meta{box} will be an hbox, irrespective of the nature -% of the \meta{box} before the resizing is applied. Negative sizes will -% cause the material in the \meta{box} to be reversed in direction, but the -% reference point of the \meta{box} will be unchanged. The resizing applies -% within the current \TeX{} group level. -% -% \textbf{This function is experimental} -% \end{function} -% -% \begin{function}[added = 2011-09-02, updated = 2011-10-22] -% {\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn} -% \begin{syntax} -% \cs{box_resize_to_ht_plus_dp:Nn} \meta{box} \Arg{y-size} -% \end{syntax} -% Resize the \meta{box} to \meta{y-size} vertically, scaling the horizontal -% size by the same amount (\meta{y-size} is a dimension expression). -% The \meta{y-size} is the vertical size (height plus depth) of -% the box. -% The updated \meta{box} will be an hbox, irrespective of the nature -% of the \meta{box} before the resizing is applied. A negative size will -% cause the material in the \meta{box} to be reversed in direction, but the -% reference point of the \meta{box} will be unchanged. The resizing applies -% within the current \TeX{} group level. -% -% \textbf{This function is experimental} -% \end{function} -% -% \begin{function}[added = 2011-09-02, updated = 2011-10-22] -% {\box_resize_to_wd:Nn, \box_resize_to_wd:cn} -% \begin{syntax} -% \cs{box_resize_to_wd:Nn} \meta{box} \Arg{x-size} -% \end{syntax} -% Resize the \meta{box} to \meta{x-size} horizontally, scaling the vertical -% size by the same amount (\meta{x-size} is a dimension expression). -% The updated \meta{box} will be an hbox, irrespective of the nature -% of the \meta{box} before the resizing is applied. A negative size will -% cause the material in the \meta{box} to be reversed in direction, but the -% reference point of the \meta{box} will be unchanged. The resizing applies -% within the current \TeX{} group level. -% -% \textbf{This function is experimental} -% \end{function} -% -% \begin{function}[added = 2011-09-02, updated = 2011-10-22] -% {\box_rotate:Nn, \box_rotate:cn} -% \begin{syntax} -% \cs{box_rotate:Nn} \meta{box} \Arg{angle} -% \end{syntax} -% Rotates the \meta{box} by \meta{angle} (in degrees) anti-clockwise about -% its reference point. The reference point of the updated box will be moved -% horizontally such that it is at the left side of the smallest rectangle -% enclosing the rotated material. -% The updated \meta{box} will be an hbox, irrespective of the nature -% of the \meta{box} before the rotation is applied. The rotation applies -% within the current \TeX{} group level. -% -% \textbf{This function is experimental} -% \end{function} -% -% \begin{function}[added = 2011-09-02, updated = 2011-10-22] -% {\box_scale:Nnn, \box_scale:cnn} -% \begin{syntax} -% \cs{box_scale:Nnn} \meta{box} \Arg{x-scale} \Arg{y-scale} -% \end{syntax} -% Scales the \meta{box} by factors \meta{x-scale} and \meta{y-scale} in -% the horizontal and vertical directions, respectively (both scales are -% integer expressions). The updated \meta{box} will be an hbox, irrespective -% of the nature of the \meta{box} before the scaling is applied. Negative -% scalings will cause the material in the \meta{box} to be reversed in -% direction, but the reference point of the \meta{box} will be unchanged. -% The scaling applies within the current \TeX{} group level. -% -% \textbf{This function is experimental} -% \end{function} -% -% \section{Viewing part of a box} -% -% \begin{function}[added = 2011-11-13]{\box_clip:N, \box_clip:c} -% \begin{syntax} -% \cs{box_clip:N} \meta{box} -% \end{syntax} -% Clips the \meta{box} in the output so that only material inside the -% bounding box is displayed in the output. The updated \meta{box} will be an -% hbox, irrespective of the nature of the \meta{box} before the clipping is -% applied. The clipping applies within the current \TeX{} group level. -% -% \textbf{This function is experimental} -% \begin{texnote} -% Clipping is implemented by the driver, and as such the full content of -% the box is places in the output file. Thus clipping does not remove -% any information from the raw output, and hidden material can therefore -% be viewed by direct examination of the file. -% \end{texnote} -% \end{function} -% -% \begin{function}[added = 2011-11-13] -% {\box_trim:Nnnnn, \box_trim:cnnnn} -% \begin{syntax} -% \cs{box_trim:Nnnnn} \meta{box} \Arg{left} \Arg{bottom} \Arg{right} \Arg{top} -% \end{syntax} -% Adjusts the bounding box of the \meta{box} \meta{left} is removed from -% the left-hand edge of the bounding box, \meta{right} from the right-hand -% edge and so fourth. All adjustments are \meta{dimension expressions}. -% Material output of the bounding box will still be displayed in the output -% unless \cs{box_clip:N} is subsequently applied. -% The updated \meta{box} will be an -% hbox, irrespective of the nature of the \meta{box} before the viewport -% operation is applied. The clipping applies within the current \TeX{} -% group level. -% -% \textbf{This function is experimental} -% \end{function} -% -% \begin{function}[added = 2011-11-13] -% {\box_viewport:Nnnnn, \box_viewport:cnnnn} -% \begin{syntax} -% \cs{box_viewport:Nnnnn} \meta{box} \Arg{llx} \Arg{lly} \Arg{urx} \Arg{ury} -% \end{syntax} -% Adjusts the bounding box of the \meta{box} such that it has lower-left -% co-ordinates (\meta{llx}, \meta{lly}) and upper-right co-ordinates -% (\meta{urx}, \meta{ury}). All four co-ordinate positions are -% \meta{dimension expressions}. Material output of the bounding box will -% still be displayed in the output unless \cs{box_clip:N} is -% subsequently applied. -% The updated \meta{box} will be an -% hbox, irrespective of the nature of the \meta{box} before the viewport -% operation is applied. The clipping applies within the current \TeX{} -% group level. -% -% \textbf{This function is experimental} -% \end{function} -% % \section{Box conditionals} % % \begin{function}[EXP,pTF]{\box_if_empty:N, \box_if_empty:c} @@ -460,16 +313,45 @@ % code and so should only be used for short-term storage. % \end{variable} % +% \begin{variable}{\g_tmpa_box, \g_tmpb_box} +% Scratch boxes for global assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% % \section{Viewing box contents} % -% \begin{function}{\box_show:N, \box_show:c} +% \begin{function}[updated = 2012-05-11]{\box_show:N, \box_show:c} % \begin{syntax} % \cs{box_show:N} \meta{box} % \end{syntax} -% Writes the contents of \meta{box} to the log file. -% \begin{texnote} -% This is a wrapper around the \TeX{} primitive \tn{showbox}. -% \end{texnote} +% Shows full details of the content of the \meta{box} in the terminal. +% \end{function} +% +% \begin{function}[added = 2012-05-11]{\box_show:Nnn, \box_show:cnn} +% \begin{syntax} +% \cs{box_show:Nnn} \meta{box} \meta{intexpr_1} \meta{intexpr_2} +% \end{syntax} +% Display the contents of \meta{box} in the terminal, showing the first +% \meta{intexpr_1} items of the box, and descending into \meta{intexpr_2} +% group levels. +% \end{function} +% +% \begin{function}[added = 2012-05-11]{\box_log:N, \box_log:c} +% \begin{syntax} +% \cs{box_show:N} \meta{box} +% \end{syntax} +% Writes full details of the content of the \meta{box} to the log. +% \end{function} +% +% \begin{function}[added = 2012-05-11]{\box_log:Nnn, \box_log:cnn} +% \begin{syntax} +% \cs{box_show:Nnn} \meta{box} \meta{intexpr_1} \meta{intexpr_2} +% \end{syntax} +% Writes the contents of \meta{box} to the log, showing the first +% \meta{intexpr_1} items of the box, and descending into \meta{intexpr_2} +% group levels. % \end{function} % % \section{Horizontal mode boxes} @@ -671,7 +553,7 @@ % \vbox_gset_end: % } % \begin{syntax} -% \cs{vbox_begin:Nw} \meta{box} \meta{contents} \cs{vbox_set_end:} +% \cs{vbox_set:Nw} \meta{box} \meta{contents} \cs{vbox_set_end:} % \end{syntax} % Typesets the \meta{contents} at natural height and then stores the % result inside the \meta{box}. In contrast @@ -682,10 +564,10 @@ % % \begin{function}[updated = 2011-10-22]{\vbox_set_split_to_ht:NNn} % \begin{syntax} -% \cs{vbox_set_split_to_ht:NNn} \meta{box1} \meta{box2} \Arg{dimexpr} +% \cs{vbox_set_split_to_ht:NNn} \meta{box_1} \meta{box_2} \Arg{dimexpr} % \end{syntax} -% Sets \meta{box1} to contain material to the height given by the -% \meta{dimexpr} by removing content from the top of \meta{box2} +% Sets \meta{box_1} to contain material to the height given by the +% \meta{dimexpr} by removing content from the top of \meta{box_2} % (which must be a vertical box). % \begin{texnote} % This is the \TeX{} primitive \tn{vsplit}. @@ -759,29 +641,6 @@ % \end{texnote} % \end{function} % -% \section{Experimental box functions} -% -% \begin{function}[added = 2011-11-21]{\box_show:Nnn, \box_show:cnn} -% \begin{syntax} -% \cs{box_show:Nnn} \meta{box} \meta{int 1} \meta{int 2} -% \end{syntax} -% Display the contents of \meta{box} in the terminal, -% showing the first \meta{int 1} items of the box, -% and descending into \meta{int 1} levels of nesting. -% \begin{texnote} -% This is a wrapper around the \TeX{} primitives \tn{showbox}, -% \tn{showboxbreadth} and \tn{showboxdepth}. -% \end{texnote} -% \end{function} -% -% \begin{function}[added = 2011-11-22]{\box_show_full:N, \box_show_full:c} -% \begin{syntax} -% \cs{box_show_full:N} \meta{box} -% \end{syntax} -% Display the contents of \meta{box} in the terminal, -% showing all items in the box. -% \end{function} -% % \end{documentation} % % \begin{implementation} @@ -791,12 +650,16 @@ % \begin{macrocode} %<*initex|package> % \end{macrocode} +% +% \begin{macrocode} +%<@@=box> +% \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -814,7 +677,7 @@ %<*package> \cs_new_protected:Npn \box_new:N #1 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \newbox #1 } %</package> @@ -863,8 +726,8 @@ { \tex_setbox:D #1 \tex_copy:D #2 } \cs_new_protected:Npn \box_gset_eq:NN { \tex_global:D \box_set_eq:NN } -\cs_generate_variant:Nn \box_set_eq:NN { cN , Nc , cc } -\cs_generate_variant:Nn \box_gset_eq:NN { cN , Nc , cc } +\cs_generate_variant:Nn \box_set_eq:NN { c , Nc , cc } +\cs_generate_variant:Nn \box_gset_eq:NN { c , Nc , cc } % \end{macrocode} % \end{macro} % \end{macro} @@ -888,8 +751,8 @@ { \tex_setbox:D #1 \tex_box:D #2 } \cs_new_protected:Npn \box_gset_eq_clear:NN { \tex_global:D \box_set_eq_clear:NN } -\cs_generate_variant:Nn \box_set_eq_clear:NN { cN , Nc , cc } -\cs_generate_variant:Nn \box_gset_eq_clear:NN { cN , Nc , cc } +\cs_generate_variant:Nn \box_set_eq_clear:NN { c , Nc , cc } +\cs_generate_variant:Nn \box_gset_eq_clear:NN { c , Nc , cc } % \end{macrocode} % \end{macro} % \end{macro} @@ -934,11 +797,11 @@ % expandable, so the derived functions are not either. % \begin{macrocode} \cs_new_protected:Npn \box_set_dp:Nn #1#2 - { \box_dp:N #1 \dim_eval:w #2 \dim_eval_end: } + { \box_dp:N #1 \__dim_eval:w #2 \__dim_eval_end: } \cs_new_protected:Npn \box_set_ht:Nn #1#2 - { \box_ht:N #1 \dim_eval:w #2 \dim_eval_end: } + { \box_ht:N #1 \__dim_eval:w #2 \__dim_eval_end: } \cs_new_protected:Npn \box_set_wd:Nn #1#2 - { \box_wd:N #1 \dim_eval:w #2 \dim_eval_end: } + { \box_wd:N #1 \__dim_eval:w #2 \__dim_eval_end: } \cs_generate_variant:Nn \box_set_ht:Nn { c } \cs_generate_variant:Nn \box_set_dp:Nn { c } \cs_generate_variant:Nn \box_set_wd:Nn { c } @@ -968,13 +831,13 @@ % Move box material in different directions. % \begin{macrocode} \cs_new_protected:Npn \box_move_left:nn #1#2 - { \tex_moveleft:D \dim_eval:w #1 \dim_eval_end: #2 } + { \tex_moveleft:D \__dim_eval:w #1 \__dim_eval_end: #2 } \cs_new_protected:Npn \box_move_right:nn #1#2 - { \tex_moveright:D \dim_eval:w #1 \dim_eval_end: #2 } + { \tex_moveright:D \__dim_eval:w #1 \__dim_eval_end: #2 } \cs_new_protected:Npn \box_move_up:nn #1#2 - { \tex_raise:D \dim_eval:w #1 \dim_eval_end: #2 } + { \tex_raise:D \__dim_eval:w #1 \__dim_eval_end: #2 } \cs_new_protected:Npn \box_move_down:nn #1#2 - { \tex_lower:D \dim_eval:w #1 \dim_eval_end: #2 } + { \tex_lower:D \__dim_eval:w #1 \__dim_eval_end: #2 } % \end{macrocode} % \end{macro} % \end{macro} @@ -1063,7 +926,8 @@ % % \subsection{Scratch boxes} % -% \begin{variable}{\l_tmpa_box, \l_tmpb_box} +% \begin{variable}{\l_tmpa_box, \l_tmpb_box, \g_tmpa_box, \g_tmpb_box} +% Reuse the \LaTeXe{} scratch box in package mode. % \begin{macrocode} %<*package> \cs_new_eq:NN \l_tmpa_box \@tempboxa @@ -1072,52 +936,78 @@ \box_new:N \l_tmpa_box %</initex> \box_new:N \l_tmpb_box +\box_new:N \g_tmpa_box +\box_new:N \g_tmpb_box % \end{macrocode} % \end{variable} % % \subsection{Viewing box contents} +% +% \TeX{}'s \tn{tex_showbox:D} is not really that helpful in many cases, and +% it is also inconsistent with other \LaTeX3{} \texttt{show} functions as it +% does not actually shows material in the terminal. So we provide a richer +% set of functionality. % % \begin{macro}{\box_show:N, \box_show:c} -% \testfile* -% Check that the variable exists, then show the contents of the box -% and write it into the log file. The spurious \cs{use:n} gives -% a nicer output. +% \begin{macro}{\box_show:Nnn, \box_show:cnn} +% Essentially a wrapper around the internal function. % \begin{macrocode} \cs_new_protected:Npn \box_show:N #1 + { \box_show:Nnn #1 \c_max_int \c_max_int } +\cs_generate_variant:Nn \box_show:N { c } +\cs_new_protected_nopar:Npn \box_show:Nnn + { \@@_show:NNnn \c_one } +\cs_generate_variant:Nn \box_show:Nnn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_log:N, \box_log:c} +% \begin{macro}{\box_log:Nnn, \box_log:cnn} +% Getting \TeX{} to write to the log without interruption the run is done by +% altering the interaction mode. For that, the \eTeX{} extensions are needed. +% \begin{macrocode} +\cs_new_protected:Npn \box_log:N #1 + { \box_log:Nnn #1 \c_max_int \c_max_int } +\cs_generate_variant:Nn \box_log:N { c } +\cs_new_protected:Npn \box_log:Nnn #1#2#3 { - \box_if_exist:NTF #1 - { \tex_showbox:D \use:n {#1} } + \use:x { - \msg_kernel_error:nnx { kernel } { variable-not-defined } - { \token_to_str:N #1 } + \etex_interactionmode:D \c_zero + \@@_show:NNnn \c_zero \exp_not:N #1 + { \int_eval:n {#2} } { \int_eval:n {#3} } + \etex_interactionmode:D + = \tex_the:D \etex_interactionmode:D \scan_stop: } } -\cs_generate_variant:Nn \box_show:N { c } +\cs_generate_variant:Nn \box_log:Nnn { c } % \end{macrocode} % \end{macro} -% -% \begin{macro}{\box_show:Nnn, \box_show:cnn} -% \begin{macro}{\box_show_full:N, \box_show_full:c} -% Show the contents of a box and write it into the log file, -% after setting the parameters \tn{showboxbreadth} and \tn{showboxdepth} -% to the values provided by the user. +% \end{macro} +% +% \begin{macro}[aux]{\@@_show:NNnn} +% The internal auxiliary to actually do the output uses a group to deal +% with breadth and depth values. The \cs{use:n} here gives better output +% appearance. Setting \tn{tex_tracingonline:D} is used to control what +% appears in the terminal. % \begin{macrocode} -\cs_new_protected:Npn \box_show:Nnn #1#2#3 +\cs_new_protected:Npn \@@_show:NNnn #1#2#3#4 { \group_begin: - \int_set:Nn \tex_showboxbreadth:D {#2} - \int_set:Nn \tex_showboxdepth:D {#3} - \int_set_eq:NN \tex_tracingonline:D \c_one - \box_show:N #1 + \int_set:Nn \tex_showboxbreadth:D {#3} + \int_set:Nn \tex_showboxdepth:D {#4} + \int_set_eq:NN \tex_tracingonline:D #1 + \box_if_exist:NTF #2 + { \tex_showbox:D \use:n {#2} } + { + \__msg_kernel_error:nnx { kernel } { variable-not-defined } + { \token_to_str:N #2 } + } \group_end: } -\cs_generate_variant:Nn \box_show:Nnn { c } -\cs_new_protected:Npn \box_show_full:N #1 - { \box_show:Nnn #1 { \c_max_int } { \c_max_int } } -\cs_generate_variant:Nn \box_show_full:N { c } % \end{macrocode} % \end{macro} -% \end{macro} % % \subsection{Horizontal mode boxes} % @@ -1147,7 +1037,7 @@ % Storing material in a horizontal box with a specified width. % \begin{macrocode} \cs_new_protected:Npn \hbox_set_to_wd:Nnn #1#2#3 - { \tex_setbox:D #1 \tex_hbox:D to \dim_eval:w #2 \dim_eval_end: {#3} } + { \tex_setbox:D #1 \tex_hbox:D to \__dim_eval:w #2 \__dim_eval_end: {#3} } \cs_new_protected:Npn \hbox_gset_to_wd:Nnn { \tex_global:D \hbox_set_to_wd:Nnn } \cs_generate_variant:Nn \hbox_set_to_wd:Nnn { c } @@ -1199,7 +1089,7 @@ % Put a horizontal box directly into the input stream. % \begin{macrocode} \cs_new_protected:Npn \hbox_to_wd:nn #1#2 - { \tex_hbox:D to \dim_eval:w #1 \dim_eval_end: {#2} } + { \tex_hbox:D to \__dim_eval:w #1 \__dim_eval_end: {#2} } \cs_new_protected:Npn \hbox_to_zero:n #1 { \tex_hbox:D to \c_zero_skip {#1} } % \end{macrocode} % \end{macro} @@ -1253,7 +1143,7 @@ % Put a vertical box directly into the input stream. % \begin{macrocode} \cs_new_protected:Npn \vbox_to_ht:nn #1#2 - { \tex_vbox:D to \dim_eval:w #1 \dim_eval_end: { #2 \par } } + { \tex_vbox:D to \__dim_eval:w #1 \__dim_eval_end: { #2 \par } } \cs_new_protected:Npn \vbox_to_zero:n #1 { \tex_vbox:D to \c_zero_dim { #1 \par } } % \end{macrocode} @@ -1296,7 +1186,7 @@ % Storing material in a vertical box with a specified height. % \begin{macrocode} \cs_new_protected:Npn \vbox_set_to_ht:Nnn #1#2#3 - { \tex_setbox:D #1 \tex_vbox:D to \dim_eval:w #2 \dim_eval_end: { #3 \par } } + { \tex_setbox:D #1 \tex_vbox:D to \__dim_eval:w #2 \__dim_eval_end: { #3 \par } } \cs_new_protected:Npn \vbox_gset_to_ht:Nnn { \tex_global:D \vbox_set_to_ht:Nnn } \cs_generate_variant:Nn \vbox_set_to_ht:Nnn { c } @@ -1366,614 +1256,7 @@ % Splitting a vertical box in two. % \begin{macrocode} \cs_new_protected:Npn \vbox_set_split_to_ht:NNn #1#2#3 - { \tex_setbox:D #1 \tex_vsplit:D #2 to \dim_eval:w #3 \dim_eval_end: } -% \end{macrocode} -% \end{macro} -% -% \subsection{Affine transformations} -% -% \begin{variable}{\l_box_angle_fp} -% When rotating boxes, the angle itself may be needed by the -% engine-dependent code. This is done using the \pkg{fp} module so -% that the value is tidied up properly. -% \begin{macrocode} -\fp_new:N \l_box_angle_fp -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_box_cos_fp, \l_box_sin_fp} -% These are used to hold the calculated sine and cosine values while -% carrying out a rotation. -% \begin{macrocode} -\fp_new:N \l_box_cos_fp -\fp_new:N \l_box_sin_fp -% \end{macrocode} -% \end{variable} -% -% \begin{variable} -% {\l_box_top_dim, \l_box_bottom_dim, \l_box_left_dim, \l_box_right_dim} -% These are the positions of the four edges of a box before -% manipulation. -% \begin{macrocode} -\dim_new:N \l_box_top_dim -\dim_new:N \l_box_bottom_dim -\dim_new:N \l_box_left_dim -\dim_new:N \l_box_right_dim -% \end{macrocode} -% \end{variable} -% -% \begin{variable} -% { -% \l_box_top_new_dim, \l_box_bottom_new_dim , -% \l_box_left_new_dim, \l_box_right_new_dim -% } -% These are the positions of the four edges of a box after -% manipulation. -% \begin{macrocode} -\dim_new:N \l_box_top_new_dim -\dim_new:N \l_box_bottom_new_dim -\dim_new:N \l_box_left_new_dim -\dim_new:N \l_box_right_new_dim -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_box_internal_box, \l_box_internal_fp} -% Scratch space. -% \begin{macrocode} -\box_new:N \l_box_internal_box -\fp_new:N \l_box_internal_fp -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_box_x_fp, \l_box_y_fp, \l_box_x_new_fp, \l_box_y_new_fp} -% Used as the input and output values for a point when manipulation the -% location. -% \begin{macrocode} -\fp_new:N \l_box_x_fp -\fp_new:N \l_box_y_fp -\fp_new:N \l_box_x_new_fp -\fp_new:N \l_box_y_new_fp -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\box_rotate:Nn} -% \begin{macro}[aux]{\box_rotate_aux:N} -% \begin{macro}[aux]{\box_rotate_set_sin_cos:} -% \begin{macro}[aux]{\box_rotate_x:nnN, \box_rotate_y:nnN} -% \begin{macro}[aux] -% { -% \box_rotate_quadrant_one:, \box_rotate_quadrant_two:, -% \box_rotate_quadrant_three:, \box_rotate_quadrant_four: -% } -% Rotation of a box starts with working out the relevant sine and -% cosine. There is then a check to avoid doing any real work for the -% trivial rotation. -% \begin{macrocode} -\cs_new_protected:Npn \box_rotate:Nn #1#2 - { - \hbox_set:Nn #1 - { - \group_begin: - \fp_set:Nn \l_box_angle_fp {#2} - \box_rotate_set_sin_cos: - \fp_compare:NNNTF \l_box_sin_fp = \c_zero_fp - { - \fp_compare:NNNTF \l_box_cos_fp = \c_one_fp - { \box_use:N #1 } - { \box_rotate_aux:N #1 } - } - { \box_rotate_aux:N #1 } - \group_end: - } - } -% \end{macrocode} -% The edges of the box are then recorded: the left edge will -% always be at zero. Rotation of the four edges then takes place: this is -% most efficiently done on a quadrant by quadrant basis. -% \begin{macrocode} -\cs_new_protected:Npn \box_rotate_aux:N #1 - { - \dim_set:Nn \l_box_top_dim { \box_ht:N #1 } - \dim_set:Nn \l_box_bottom_dim { -\box_dp:N #1 } - \dim_set:Nn \l_box_right_dim { \box_wd:N #1 } - \dim_zero:N \l_box_left_dim -% \end{macrocode} -% The next step is to work out the $x$ and $y$ coordinates of vertices of -% the rotated box in relation to its original coordinates. The box can be -% visualized with vertices $B$, $C$, $D$ and $E$ is illustrated -% (Figure~\ref{fig:rotation}). The vertex $O$ is the reference point on the -% baseline, and in this implementation is also the centre of rotation. -% \begin{figure} -% \centering -% \setlength{\unitlength}{3pt}^^A -% \begin{picture}(34,36)(12,44) -% \thicklines -% \put(20,52){\dashbox{1}(20,21){}} -% \put(20,80){\line(0,-1){36}} -% \put(12,58){\line(1, 0){34}} -% \put(41,59){A} -% \put(40,74){B} -% \put(21,74){C} -% \put(21,49){D} -% \put(40,49){E} -% \put(21,59){O} -% \end{picture} -% \caption{Co-ordinates of a box prior to rotation.} -% \label{fig:rotation} -% \end{figure} -% The formulae are, for a point $P$ and angle $\alpha$: -% \[ -% \begin{array}{l} -% P'_x = P_x - O_x \\ -% P'_y = P_y - O_y \\ -% P''_x = ( P'_x \cos(\alpha)) - ( P'_y \sin(\alpha) ) \\ -% P''_y = ( P'_x \sin(\alpha)) + ( P'_y \cos(\alpha) ) \\ -% P'''_x = P''_x + O_x + L_x \\ -% P'''_y = P''_y + O_y -% \end{array} -% \] -% The \enquote{extra} horizontal translation $L_x$ at the end is calculated -% so that the leftmost point of the resulting box has $x$-coordinate $0$. -% This is desirable as \TeX{} boxes must have the reference point at -% the left edge of the box. (As $O$ is always $(0,0)$, this part of the -% calculation is omitted here.) -% \begin{macrocode} - \fp_compare:NNNTF \l_box_sin_fp > \c_zero_fp - { - \fp_compare:NNNTF \l_box_cos_fp > \c_zero_fp - { \box_rotate_quadrant_one: } - { \box_rotate_quadrant_two: } - } - { - \fp_compare:NNNTF \l_box_cos_fp < \c_zero_fp - { \box_rotate_quadrant_three: } - { \box_rotate_quadrant_four: } - } -% \end{macrocode} -% The position of the box edges are now known, but the box at this -% stage be misplaced relative to the current \TeX{} reference point. So the -% content of the box is moved such that the reference point of the -% rotated box will be in the same place as the original. -% \begin{macrocode} - \hbox_set:Nn \l_box_internal_box { \box_use:N #1 } - \hbox_set:Nn \l_box_internal_box - { - \tex_kern:D -\l_box_left_new_dim - \hbox:n - { - \driver_box_rotate_begin: - \box_use:N \l_box_internal_box - \driver_box_rotate_end: - } - } -% \end{macrocode} -% Tidy up the size of the box so that the material is actually inside -% the bounding box. The result can then be used to reset the original -% box. -% \begin{macrocode} - \box_set_ht:Nn \l_box_internal_box { \l_box_top_new_dim } - \box_set_dp:Nn \l_box_internal_box { -\l_box_bottom_new_dim } - \box_set_wd:Nn \l_box_internal_box - { \l_box_right_new_dim - \l_box_left_new_dim } - \box_use:N \l_box_internal_box - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% A simple conversion from degrees to radians followed by calculation -% of the sine and cosine. -% \begin{macrocode} -\cs_new_protected:Npn \box_rotate_set_sin_cos: - { - \fp_set_eq:NN \l_box_internal_fp \l_box_angle_fp - \fp_div:Nn \l_box_internal_fp { 180 } - \fp_mul:Nn \l_box_internal_fp { \c_pi_fp } - \fp_sin:Nn \l_box_sin_fp { \l_box_internal_fp } - \fp_cos:Nn \l_box_cos_fp { \l_box_internal_fp } - } -% \end{macrocode} -% These functions take a general point $(|#1|, |#2|)$ and rotate its -% location about the origin, using the previously-set sine and cosine -% values. Each function gives only one component of the location of the -% updated point. This is because for rotation of a box each step needs -% only one value, and so performance is gained by avoiding working -% out both $x'$ and $y'$ at the same time. Contrast this with -% the equivalent function in the \pkg{l3coffins} module, where both parts -% are needed. -% \begin{macrocode} -\cs_new_protected:Npn \box_rotate_x:nnN #1#2#3 - { - \fp_set_from_dim:Nn \l_box_x_fp {#1} - \fp_set_from_dim:Nn \l_box_y_fp {#2} - \fp_set_eq:NN \l_box_x_new_fp \l_box_x_fp - \fp_set_eq:NN \l_box_internal_fp \l_box_y_fp - \fp_mul:Nn \l_box_x_new_fp { \l_box_cos_fp } - \fp_mul:Nn \l_box_internal_fp { \l_box_sin_fp } - \fp_sub:Nn \l_box_x_new_fp { \l_box_internal_fp } - \dim_set:Nn #3 { \fp_to_dim:N \l_box_x_new_fp } - } -\cs_new_protected:Npn \box_rotate_y:nnN #1#2#3 - { - \fp_set_from_dim:Nn \l_box_x_fp {#1} - \fp_set_from_dim:Nn \l_box_y_fp {#2} - \fp_set_eq:NN \l_box_y_new_fp \l_box_y_fp - \fp_set_eq:NN \l_box_internal_fp \l_box_x_fp - \fp_mul:Nn \l_box_y_new_fp { \l_box_cos_fp } - \fp_mul:Nn \l_box_internal_fp { \l_box_sin_fp } - \fp_add:Nn \l_box_y_new_fp { \l_box_internal_fp } - \dim_set:Nn #3 { \fp_to_dim:N \l_box_y_new_fp } -} -% \end{macrocode} -% Rotation of the edges is done using a different formula for each -% quadrant. In every case, the top and bottom edges only need the -% resulting $y$-values, whereas the left and right edges need the -% $x$-values. Each case is a question of picking out which corner -% ends up at with the maximum top, bottom, left and right value. Doing -% this by hand means a lot less calculating and avoids lots of -% comparisons. -% \begin{macrocode} -\cs_new_protected:Npn \box_rotate_quadrant_one: - { - \box_rotate_y:nnN \l_box_right_dim \l_box_top_dim - \l_box_top_new_dim - \box_rotate_y:nnN \l_box_left_dim \l_box_bottom_dim - \l_box_bottom_new_dim - \box_rotate_x:nnN \l_box_left_dim \l_box_top_dim - \l_box_left_new_dim - \box_rotate_x:nnN \l_box_right_dim \l_box_bottom_dim - \l_box_right_new_dim - } -\cs_new_protected:Npn \box_rotate_quadrant_two: - { - \box_rotate_y:nnN \l_box_right_dim \l_box_bottom_dim - \l_box_top_new_dim - \box_rotate_y:nnN \l_box_left_dim \l_box_top_dim - \l_box_bottom_new_dim - \box_rotate_x:nnN \l_box_right_dim \l_box_top_dim - \l_box_left_new_dim - \box_rotate_x:nnN \l_box_left_dim \l_box_bottom_dim - \l_box_right_new_dim - } -\cs_new_protected:Npn \box_rotate_quadrant_three: - { - \box_rotate_y:nnN \l_box_left_dim \l_box_bottom_dim - \l_box_top_new_dim - \box_rotate_y:nnN \l_box_right_dim \l_box_top_dim - \l_box_bottom_new_dim - \box_rotate_x:nnN \l_box_right_dim \l_box_bottom_dim - \l_box_left_new_dim - \box_rotate_x:nnN \l_box_left_dim \l_box_top_dim - \l_box_right_new_dim - } -\cs_new_protected:Npn \box_rotate_quadrant_four: - { - \box_rotate_y:nnN \l_box_left_dim \l_box_top_dim - \l_box_top_new_dim - \box_rotate_y:nnN \l_box_right_dim \l_box_bottom_dim - \l_box_bottom_new_dim - \box_rotate_x:nnN \l_box_left_dim \l_box_bottom_dim - \l_box_left_new_dim - \box_rotate_x:nnN \l_box_right_dim \l_box_top_dim - \l_box_right_new_dim - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{variable}{\l_box_scale_x_fp, \l_box_scale_y_fp} -% Scaling is potentially-different in the two axes. -% \begin{macrocode} -\fp_new:N \l_box_scale_x_fp -\fp_new:N \l_box_scale_y_fp -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\box_resize:Nnn, \box_resize:cnn} -% \begin{macro}[aux]{\box_resize_aux:Nnn} -% Resizing a box starts by working out the various dimensions of the -% existing box. -% \begin{macrocode} -\cs_new_protected:Npn \box_resize:Nnn #1#2#3 - { - \hbox_set:Nn #1 - { - \group_begin: - \dim_set:Nn \l_box_top_dim { \box_ht:N #1 } - \dim_set:Nn \l_box_bottom_dim { -\box_dp:N #1 } - \dim_set:Nn \l_box_right_dim { \box_wd:N #1 } - \dim_zero:N \l_box_left_dim -% \end{macrocode} -% The $x$-scaling and resulting box size is easy enough to work -% out: the dimension is that given as |#2|, and the scale is simply the -% new width divided by the old one. -% \begin{macrocode} - \fp_set_from_dim:Nn \l_box_scale_x_fp {#2} - \fp_set_from_dim:Nn \l_box_internal_fp { \l_box_right_dim } - \fp_div:Nn \l_box_scale_x_fp { \l_box_internal_fp } -% \end{macrocode} -% The $y$-scaling needs both the height and the depth of the current box. -% \begin{macrocode} - \fp_set_from_dim:Nn \l_box_scale_y_fp {#3} - \fp_set_from_dim:Nn \l_box_internal_fp - { \l_box_top_dim - \l_box_bottom_dim } - \fp_div:Nn \l_box_scale_y_fp { \l_box_internal_fp } -% \end{macrocode} -% At this stage, check for trivial scaling. If both scalings are unity, then -% the code does nothing. Otherwise, pass on to the auxiliary function to -% find the new dimensions. -% \begin{macrocode} - \fp_compare:NNNTF \l_box_scale_x_fp = \c_one_fp - { - \fp_compare:NNNTF \l_box_scale_y_fp = \c_one_fp - { \box_use:N #1 } - { \box_resize_aux:Nnn #1 {#2} {#3} } - } - { \box_resize_aux:Nnn #1 {#2} {#3} } - \group_end: - } - } -\cs_generate_variant:Nn \box_resize:Nnn { c } -% \end{macrocode} -% With at least one real scaling to do, the next phase is to find the new -% edge co-ordinates. In the $x$~direction this is relatively easy: just -% scale the right edge. This is done using the absolute value of the -% scale so that the new edge is in the correct place. In the $y$~direction, -% both dimensions have to be scaled, and this again needs the absolute -% scale value. Once that is all done, the common resize/rescale code can -% be employed. -% \begin{macrocode} -\cs_new_protected:Npn \box_resize_aux:Nnn #1#2#3 - { - \dim_compare:nNnTF {#2} > \c_zero_dim - { \dim_set:Nn \l_box_right_new_dim {#2} } - { \dim_set:Nn \l_box_right_new_dim { \c_zero_dim - ( #2 ) } } - \dim_compare:nNnTF {#3} > \c_zero_dim - { - \dim_set:Nn \l_box_top_new_dim - { \fp_use:N \l_box_scale_y_fp \l_box_top_dim } - \dim_set:Nn \l_box_bottom_new_dim - { \fp_use:N \l_box_scale_y_fp \l_box_bottom_dim } - } - { - \dim_set:Nn \l_box_top_new_dim - { - \fp_use:N \l_box_scale_y_fp \l_box_top_dim } - \dim_set:Nn \l_box_bottom_new_dim - { - \fp_use:N \l_box_scale_y_fp \l_box_bottom_dim } - } - \box_resize_common:N #1 - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn} -% \begin{macro}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn} -% Scaling to a total height or to a width is a simplified version of the main -% resizing operation, with the scale simply copied between the two parts. The -% internal auxiliary is called using the scaling value twice, as the sign for -% both parts is needed (as this allows the same internal code to be used as -% for the general case). -% \begin{macrocode} -\cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2 - { - \hbox_set:Nn #1 - { - \group_begin: - \dim_set:Nn \l_box_top_dim { \box_ht:N #1 } - \dim_set:Nn \l_box_bottom_dim { -\box_dp:N #1 } - \dim_set:Nn \l_box_right_dim { \box_wd:N #1 } - \dim_zero:N \l_box_left_dim - \fp_set_from_dim:Nn \l_box_scale_y_fp {#2} - \fp_set_from_dim:Nn \l_box_internal_fp - { \l_box_top_dim - \l_box_bottom_dim } - \fp_div:Nn \l_box_scale_y_fp { \l_box_internal_fp } - \fp_set_eq:NN \l_box_scale_x_fp \l_box_scale_y_fp - \fp_compare:NNNTF \l_box_scale_y_fp = \c_one_fp - { \box_use:N #1 } - { \box_resize_aux:Nnn #1 {#2} {#2} } - \group_end: - } - } -\cs_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c } -\cs_new_protected:Npn \box_resize_to_wd:Nn #1#2 - { - \hbox_set:Nn #1 - { - \group_begin: - \dim_set:Nn \l_box_top_dim { \box_ht:N #1 } - \dim_set:Nn \l_box_bottom_dim { -\box_dp:N #1 } - \dim_set:Nn \l_box_right_dim { \box_wd:N #1 } - \dim_zero:N \l_box_left_dim - \fp_set_from_dim:Nn \l_box_scale_x_fp {#2} - \fp_set_from_dim:Nn \l_box_internal_fp { \l_box_right_dim } - \fp_div:Nn \l_box_scale_x_fp { \l_box_internal_fp } - \fp_set_eq:NN \l_box_scale_y_fp \l_box_scale_x_fp - \fp_compare:NNNTF \l_box_scale_x_fp = \c_one_fp - { \box_use:N #1 } - { \box_resize_aux:Nnn #1 {#2} {#2} } - \group_end: - } - } -\cs_generate_variant:Nn \box_resize_to_wd:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\box_scale:Nnn, \box_scale:cnn} -% \begin{macro}[aux]{\box_scale_aux:Nnn} -% When scaling a box, setting the scaling itself is easy enough. The -% new dimensions are also relatively easy to find, allowing only for -% the need to keep them positive in all cases. Once that is done then -% after a check for the trivial scaling a hand-off can be made to the -% common code. The dimension scaling operations are carried out using -% the \TeX{} mechanism as it avoids needing to use \texttt{fp} -% operations. -% \begin{macrocode} -\cs_new_protected:Npn \box_scale:Nnn #1#2#3 - { - \hbox_set:Nn #1 - { - \group_begin: - \fp_set:Nn \l_box_scale_x_fp {#2} - \fp_set:Nn \l_box_scale_y_fp {#3} - \dim_set:Nn \l_box_top_dim { \box_ht:N #1 } - \dim_set:Nn \l_box_bottom_dim { -\box_dp:N #1 } - \dim_set:Nn \l_box_right_dim { \box_wd:N #1 } - \dim_zero:N \l_box_left_dim - \fp_compare:NNNTF \l_box_scale_x_fp = \c_one_fp - { - \fp_compare:NNNTF \l_box_scale_y_fp = \c_one_fp - { \box_use:N #1 } - { \box_scale_aux:Nnn #1 {#2} {#3} } - } - { \box_scale_aux:Nnn #1 {#2} {#3} } - \group_end: - } - } -\cs_generate_variant:Nn \box_scale:Nnn { c } -\cs_new_protected:Npn \box_scale_aux:Nnn #1#2#3 - { - \fp_compare:NNNTF \l_box_scale_y_fp > \c_zero_fp - { - \dim_set:Nn \l_box_top_new_dim { #3 \l_box_top_dim } - \dim_set:Nn \l_box_bottom_new_dim { #3 \l_box_bottom_dim } - } - { - \dim_set:Nn \l_box_top_new_dim { -#3 \l_box_bottom_dim } - \dim_set:Nn \l_box_bottom_new_dim { -#3 \l_box_top_dim } - } - \fp_compare:NNNTF \l_box_scale_x_fp > \c_zero_fp - { \l_box_right_new_dim #2 \l_box_right_dim } - { \l_box_right_new_dim -#2 \l_box_right_dim } - \box_resize_common:N #1 - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[int]{\box_resize_common:N} -% The main resize function places in input into a box which will start -% of with zero width, and includes the handles for engine rescaling. -% \begin{macrocode} -\cs_new_protected:Npn \box_resize_common:N #1 - { - \hbox_set:Nn \l_box_internal_box - { - \driver_box_scale_begin: - \hbox_overlap_right:n { \box_use:N #1 } - \driver_box_scale_end: - } -% \end{macrocode} -% The new height and depth can be applied directly. -% \begin{macrocode} - \box_set_ht:Nn \l_box_internal_box { \l_box_top_new_dim } - \box_set_dp:Nn \l_box_internal_box { \l_box_bottom_new_dim } -% \end{macrocode} -% Things are not quite as obvious for the width, as the reference point -% needs to remain unchanged. For positive scaling factors resizing the -% box is all that is needed. However, for case of a negative scaling -% the material must be shifted such that the reference point ends up in -% the right place. -% \begin{macrocode} - \fp_compare:NNNTF \l_box_scale_x_fp < \c_zero_fp - { - \hbox_to_wd:nn { \l_box_right_new_dim } - { - \tex_kern:D \l_box_right_new_dim - \box_use:N \l_box_internal_box - \tex_hss:D - } - } - { - \box_set_wd:Nn \l_box_internal_box { \l_box_right_new_dim } - \box_use:N \l_box_internal_box - } - } -% \end{macrocode} -% \end{macro} -% -% \subsection{Viewing part of a box} -% -% \begin{macro}{\box_clip:N, \box_clip:c} -% A wrapper around the driver-dependent code. -% \begin{macrocode} -\cs_new_protected:Npn \box_clip:N #1 - { \hbox_set:Nn #1 { \driver_box_use_clip:N #1 } } -\cs_generate_variant:Nn \box_clip:N { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\box_trim:Nnnnn, \box_trim:cnnnn} -% Trimming from the left- and right-hand edges of the box is easy. The total -% width is set to remove from the right, and a skip will shift the material -% to remove from the left. -% \begin{macrocode} -\cs_new_protected:Npn \box_trim:Nnnnn #1#2#3#4#5 - { - \box_set_wd:Nn #1 { \box_wd:N #1 - \dim_eval:n {#4} - \dim_eval:n {#2} } - \hbox_set:Nn #1 - { - \skip_horizontal:n { - \dim_eval:n {#2} } - \box_use:N #1 - } -% \end{macrocode} -% For the height and depth, there is a need to watch the baseline is -% respected. Material always has to stay on the correct side, so trimming -% has to check that there is enough material to trim. -% \begin{macrocode} - \dim_compare:nNnTF { \box_dp:N #1 } > {#3} - { \box_set_dp:Nn #1 { \box_dp:N #1 - \dim_eval:n {#3} } } - { - \hbox_set:Nn #1 - { - \box_move_down:nn { \dim_eval:n {#3} - \box_dp:N #1 } - { \box_use:N #1 } - } - \box_set_dp:Nn #1 \c_zero_dim - } - \dim_compare:nNnTF { \box_ht:N #1 } > {#5} - { \box_set_ht:Nn #1 { \box_ht:N #1 - \dim_eval:n {#5} } } - { - \hbox_set:Nn #1 - { - \box_move_up:nn { \dim_eval:n {#5} - \box_ht:N #1 } - { \box_use:N #1 } - } - \box_set_ht:Nn #1 \c_zero_dim - } - } -\cs_generate_variant:Nn \box_trim:Nnnnn { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\box_viewport:Nnnnn, \box_viewport:cnnnn} -% The same general logic as for clipping, but with absolute dimensions. -% Thus again width is easy and height is harder. -% \begin{macrocode} -\cs_new_protected:Npn \box_viewport:Nnnnn #1#2#3#4#5 - { - \box_set_wd:Nn #1 { \dim_eval:n {#4} - \dim_eval:n {#2} } - \hbox_set:Nn #1 - { - \skip_horizontal:n { - \dim_eval:n {#2} } - \box_use:N #1 - } - \dim_compare:nNnTF {#3} > \c_zero_dim - { - \hbox_set:Nn #1 { \box_move_down:nn {#3} { \box_use:N #1 } } - \box_set_dp:Nn #1 \c_zero_dim - } - { \box_set_dp:Nn #1 { - \dim_eval:n {#3} } } - \dim_compare:nNnTF {#5} > \c_zero_dim - { \box_set_ht:Nn #1 {#5} } - { - \hbox_set:Nn #1 - { \box_move_up:nn { -\dim_eval:n {#5} } { \box_use:N #1 } } - \box_set_ht:Nn #1 \c_zero_dim - } - } -\cs_generate_variant:Nn \box_viewport:Nnnnn { c } + { \tex_setbox:D #1 \tex_vsplit:D #2 to \__dim_eval:w #3 \__dim_eval_end: } % \end{macrocode} % \end{macro} % @@ -1982,7 +1265,9 @@ % \begin{variable}{\l_last_box} % Deprecated 2011-11-13, for removal by 2012-02-28. % \begin{macrocode} +%<*deprecated> \cs_new_eq:NN \l_last_box \tex_lastbox:D +%</deprecated> % \end{macrocode} % \end{variable} % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx new file mode 100644 index 00000000000..8afac7cda1f --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx @@ -0,0 +1,2828 @@ +% \iffalse meta-comment +% +%% File: l3candidates.dtx Copyright(C) 2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3candidates.dtx 3633 2012-05-12 20:11:32Z joseph $ + {L3 Experimental additions to l3kernel} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \textsf{l3candidates} package\\ Experimental additions to +% \pkg{l3kernel}^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% This module provides a space in which functions can be added to +% \pkg{l3kernel} (\pkg{expl3}) while still being experimental. As such, the +% functions here may not remain in their current form, or indeed at all, +% in \pkg{l3kernel} in the future. In contrast to the material in +% \pkg{l3experimental}, the functions here are all \emph{small} additions to +% the kernel. We encourage programmers to test them out and report back on +% the \texttt{LaTeX-L} mailing list. +% +% \section{Additions to \pkg{l3basics}} +% +% \begin{function}[EXP,TF]{\cs_if_exist_use:N, \cs_if_exist_use:c} +% \begin{syntax} +% \cs{cs_if_exist_use:NTF} \meta{control sequence} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{control sequence} exists, leave it in the input stream, +% followed by the \meta{true code} (unbraced). Otherwise, leave the +% \meta{false} code in the input stream. For example, +% \begin{verbatim} +% \cs_set:Npn \mypkg_use_character:N #1 +% { \cs_if_exist_use:cF { mypkg_#1:n } { \mypkg_default:N #1 } } +% \end{verbatim} +% calls the function |\mypkg_#1:n| if it exists, and falls back to +% a default action otherwise. This could also be done (more slowly) +% using \cs{str_case_x:nnn}. +% \begin{texnote} +% The \texttt{c} variants do not introduce the \meta{control sequence} +% in the hash table if it is not there. +% \end{texnote} +% \end{function} +% +% \section{Additions to \pkg{l3box}} +% +% \subsection{Affine transformations} +% +% Affine transformations are changes which (informally) preserve straight +% lines. Simple translations are affine transformations, but are better handled +% in \TeX{} by doing the translation first, then inserting an unmodified box. +% On the other hand, rotation and resizing of boxed material can best be +% handled by modifying boxes. These transformations are described here. +% +% \begin{function}{\box_resize:Nnn, \box_resize:cnn} +% \begin{syntax} +% \cs{box_resize:Nnn} \meta{box} \Arg{x-size} \Arg{y-size} +% \end{syntax} +% Resize the \meta{box} to \meta{x-size} horizontally and \meta{y-size} +% vertically (both of the sizes are dimension expressions). +% The \meta{y-size} is the vertical size (height plus depth) of +% the box. The updated \meta{box} will be an hbox, irrespective of the nature +% of the \meta{box} before the resizing is applied. Negative sizes will +% cause the material in the \meta{box} to be reversed in direction, but the +% reference point of the \meta{box} will be unchanged. The resizing applies +% within the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn} +% \begin{syntax} +% \cs{box_resize_to_ht_plus_dp:Nn} \meta{box} \Arg{y-size} +% \end{syntax} +% Resize the \meta{box} to \meta{y-size} vertically, scaling the horizontal +% size by the same amount (\meta{y-size} is a dimension expression). +% The \meta{y-size} is the vertical size (height plus depth) of +% the box. +% The updated \meta{box} will be an hbox, irrespective of the nature +% of the \meta{box} before the resizing is applied. A negative size will +% cause the material in the \meta{box} to be reversed in direction, but the +% reference point of the \meta{box} will be unchanged. The resizing applies +% within the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn} +% \begin{syntax} +% \cs{box_resize_to_wd:Nn} \meta{box} \Arg{x-size} +% \end{syntax} +% Resize the \meta{box} to \meta{x-size} horizontally, scaling the vertical +% size by the same amount (\meta{x-size} is a dimension expression). +% The updated \meta{box} will be an hbox, irrespective of the nature +% of the \meta{box} before the resizing is applied. A negative size will +% cause the material in the \meta{box} to be reversed in direction, but the +% reference point of the \meta{box} will be unchanged. The resizing applies +% within the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\box_rotate:Nn, \box_rotate:cn} +% \begin{syntax} +% \cs{box_rotate:Nn} \meta{box} \Arg{angle} +% \end{syntax} +% Rotates the \meta{box} by \meta{angle} (in degrees) anti-clockwise about +% its reference point. The reference point of the updated box will be moved +% horizontally such that it is at the left side of the smallest rectangle +% enclosing the rotated material. +% The updated \meta{box} will be an hbox, irrespective of the nature +% of the \meta{box} before the rotation is applied. The rotation applies +% within the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\box_scale:Nnn, \box_scale:cnn} +% \begin{syntax} +% \cs{box_scale:Nnn} \meta{box} \Arg{x-scale} \Arg{y-scale} +% \end{syntax} +% Scales the \meta{box} by factors \meta{x-scale} and \meta{y-scale} in +% the horizontal and vertical directions, respectively (both scales are +% integer expressions). The updated \meta{box} will be an hbox, irrespective +% of the nature of the \meta{box} before the scaling is applied. Negative +% scalings will cause the material in the \meta{box} to be reversed in +% direction, but the reference point of the \meta{box} will be unchanged. +% The scaling applies within the current \TeX{} group level. +% \end{function} +% +% \subsection{Viewing part of a box} +% +% \begin{function}{\box_clip:N, \box_clip:c} +% \begin{syntax} +% \cs{box_clip:N} \meta{box} +% \end{syntax} +% Clips the \meta{box} in the output so that only material inside the +% bounding box is displayed in the output. The updated \meta{box} will be an +% hbox, irrespective of the nature of the \meta{box} before the clipping is +% applied. The clipping applies within the current \TeX{} group level. +% +% \textbf{These functions require the \LaTeX3 native drivers: they will +% not work with the \LaTeXe{} \pkg{graphics} drivers!} +% +% \begin{texnote} +% Clipping is implemented by the driver, and as such the full content of +% the box is places in the output file. Thus clipping does not remove +% any information from the raw output, and hidden material can therefore +% be viewed by direct examination of the file. +% \end{texnote} +% \end{function} +% +% \begin{function}{\box_trim:Nnnnn, \box_trim:cnnnn} +% \begin{syntax} +% \cs{box_trim:Nnnnn} \meta{box} \Arg{left} \Arg{bottom} \Arg{right} \Arg{top} +% \end{syntax} +% Adjusts the bounding box of the \meta{box} \meta{left} is removed from +% the left-hand edge of the bounding box, \meta{right} from the right-hand +% edge and so fourth. All adjustments are \meta{dimension expressions}. +% Material output of the bounding box will still be displayed in the output +% unless \cs{box_clip:N} is subsequently applied. +% The updated \meta{box} will be an +% hbox, irrespective of the nature of the \meta{box} before the viewport +% operation is applied. The adjustment applies within the current \TeX{} +% group level. +% \end{function} +% +% \begin{function}{\box_viewport:Nnnnn, \box_viewport:cnnnn} +% \begin{syntax} +% \cs{box_viewport:Nnnnn} \meta{box} \Arg{llx} \Arg{lly} \Arg{urx} \Arg{ury} +% \end{syntax} +% Adjusts the bounding box of the \meta{box} such that it has lower-left +% co-ordinates (\meta{llx}, \meta{lly}) and upper-right co-ordinates +% (\meta{urx}, \meta{ury}). All four co-ordinate positions are +% \meta{dimension expressions}. Material output of the bounding box will +% still be displayed in the output unless \cs{box_clip:N} is +% subsequently applied. +% The updated \meta{box} will be an +% hbox, irrespective of the nature of the \meta{box} before the viewport +% operation is applied. The adjustment applies within the current \TeX{} +% group level. +% \end{function} +% +% \subsection{Internal variables} +% +% \begin{variable}{\l__box_angle_fp} +% The angle through which a box is rotated by \cs{box_rotate:Nn}, given in +% degrees counter-clockwise. This value is required by the underlying +% driver code in \pkg{l3driver} to carry out the driver-dependent part +% of box rotation. +% \end{variable} +% +% \begin{variable}{\l__box_cos_fp, \l__box_sin_fp} +% The sine and cosine of the angle through which a box is rotated by +% \cs{box_rotate:Nn}: the values refer to the angle counter-clockwise. These +% values are required by the underlying driver code in \pkg{l3driver} to +% carry out the driver-dependent part of box rotation. +% \end{variable} +% +% \begin{variable}{\l__box_scale_x_fp, \l__box_scale_y_fp} +% The scaling factors by which a box is scaled by \cs{box_scale:Nnn} +% or \cs{box_resize:Nnn}. These values are required by the underlying +% driver code in \pkg{l3driver} to carry out the driver-dependent part +% of box rotation. +% \end{variable} +% +% \begin{variable}{\l__box_internal_box} +% Box used for affine transformations, which is used to contain rotated +% material when applying \cs{box_rotate:Nn}. This box must be correctly +% constructed for the driver-dependent code in \pkg{l3driver} to function +% correctly. +% \end{variable} +% +% \section{Additions to \pkg{l3clist}} +% +% \begin{function}{\clist_item:Nn, \clist_item:cn, \clist_item:nn} +% \begin{syntax} +% \cs{clist_item:Nn} \meta{comma list} \Arg{integer expression} +% \end{syntax} +% Indexing items in the \meta{comma list} from~$1$ at the top (left), this +% function will evaluate the \meta{integer expression} and leave the +% appropriate item from the comma list in the input stream. If the +% \meta{integer expression} is negative, indexing occurs from the +% bottom (right) of the comma list. When the \meta{integer expression} +% is larger than the number of items in the \meta{comma list} (as +% calculated by \cs{clist_count:N}) then the function will expand to +% nothing. +% \begin{texnote} +% The result is returned within the \tn{unexpanded} +% primitive (\cs{exp_not:n}), which means that the \meta{item} +% will not expand further when appearing in an \texttt{x}-type +% argument expansion. +% \end{texnote} +% \end{function} +% +% \begin{function} +% { +% \clist_set_from_seq:NN, \clist_set_from_seq:cN, +% \clist_set_from_seq:Nc, \clist_set_from_seq:cc, +% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, +% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc +% } +% \begin{syntax} +% \cs{clist_set_from_seq:NN} \meta{comma list} \meta{sequence} +% \end{syntax} +% Sets the \meta{comma list} to be equal to the content of the +% \meta{sequence}. +% Items which contain either spaces or commas are surrounded by braces. +% \end{function} +% +% \begin{function} +% { +% \clist_const:Nn, \clist_const:Nx, +% \clist_const:cn, \clist_const:cx +% } +% \begin{syntax} +% \cs{clist_const:Nn} \meta{clist~var} \Arg{comma list} +% \end{syntax} +% Creates a new constant \meta{clist~var} or raises an error +% if the name is already taken. The value of the +% \meta{clist~var} will be set globally to the +% \meta{comma list}. +% \end{function} +% +% \begin{function}[EXP, pTF]{\clist_if_empty:n} +% \begin{syntax} +% \cs{clist_if_empty_p:n} \Arg{comma list} +% \cs{clist_if_empty:nTF} \Arg{comma list} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{comma list} is empty (containing no items). +% The rules for space trimming are as for other \texttt{n}-type +% comma-list functions, hence the comma list |{~,~,,~}| (without +% outer braces) is empty, while |{~,{},}| (without outer braces) +% contains one element, which happens to be empty: the comma-list +% is not empty. +% \end{function} +% +% \begin{function}[EXP, added = 2012-06-26]{\clist_use:Nnnn} +% \begin{syntax} +% \cs{clist_use:Nnnn} \meta{clist~var} \Arg{separator~between~two} \Arg{separator~between~more~than~two} \Arg{separator~between~final~two} +% \end{syntax} +% Places the contents of the \meta{clist~var} in the input stream, +% with the appropriate \meta{separator} between the items. Namely, if +% the comma list has more than $2$ items, the \meta{separator between +% more than two} is placed between each pair of items except the +% last, for which the \meta{separator between final two} is used. If +% the comma list has $2$ items, then they are placed in the input +% stream separated by the \meta{separator between two}. If the comma +% list has $1$ item, it is placed in the input stream, and a comma +% list with no items produces no output. An error will be raised if +% the variable does not exist or if it is invalid. +% +% For example, +% \begin{verbatim} +% \clist_set:Nn \l_tmpa_clist { a , b , , c , {de} , f } +% \clist_use:Nnnn \l_tmpa_clist { ~and~ } { ,~ } { ,~and~ } +% \end{verbatim} +% will insert \enquote{\texttt{a, b, c, de, and f}} in the input +% stream. The first separator argument is not used in this case +% because the comma list has more than $2$ items. +% \begin{texnote} +% The result is returned within the \tn{unexpanded} +% primitive (\cs{exp_not:n}), which means that the \meta{items} +% will not expand further when appearing in an \texttt{x}-type +% argument expansion. +% \end{texnote} +% \end{function} +% +% \section{Additions to \pkg{l3coffins}} +% +% \begin{function}{\coffin_resize:Nnn, \coffin_resize:cnn} +% \begin{syntax} +% \cs{coffin_resize:Nnn} \meta{coffin} \Arg{width} \Arg{total-height} +% \end{syntax} +% Resized the \meta{coffin} to \meta{width} and \meta{total-height}, +% both of which should be given as dimension expressions. These may +% include the terms \cs{TotalHeight}, \cs{Height}, \cs{Depth} and +% \cs{Width}, which will evaluate to the appropriate dimensions of +% the \meta{coffin}. +% \end{function} +% +% \begin{function}{\coffin_rotate:Nn, \coffin_rotate:cn} +% \begin{syntax} +% \cs{coffin_rotate:Nn} \meta{coffin} \Arg{angle} +% \end{syntax} +% Rotates the \meta{coffin} by the given \meta{angle} (given in +% degrees counter-clockwise). This process will rotate both the +% coffin content and poles. Multiple rotations will not result in +% the bounding box of the coffin growing unnecessarily. +% \end{function} +% +% \begin{function}{\coffin_scale:Nnn, \coffin_scale:cnn} +% \begin{syntax} +% \cs{coffin_scale:Nnn} \meta{coffin} \Arg{x-scale} \Arg{y-scale} +% \end{syntax} +% Scales the \meta{coffin} by a factors \meta{x-scale} and +% \meta{y-scale} in the horizontal and vertical directions, +% respectively. The two scale factors should be given as real numbers. +% \end{function} +% +% \section{Additions to \pkg{l3file}} +% +% \begin{function}[added = 2012-02-11]{\ior_map_inline:Nn} +% \begin{syntax} +% \cs{ior_map_inline:Nn} \meta{stream} \Arg{inline function} +% \end{syntax} +% Applies the \meta{inline function} to \meta{lines} obtained by +% reading one or more lines (until an equal number of left and right +% braces are found) from the \meta{stream}. The \meta{inline function} +% should consist of code which will receive the \meta{line} as |#1|. +% \end{function} +% +% \begin{function}[added = 2012-02-11]{\ior_str_map_inline:Nn} +% \begin{syntax} +% \cs{ior_str_map_inline:Nn} \Arg{stream} \Arg{inline function} +% \end{syntax} +% Applies the \meta{inline function} to every \meta{line} +% in the \meta{sream}. The material is read from the \meta{stream} +% as a series of tokens with category code $12$ (other), with the +% exception of space characters which are given category code $10$ +% (space). The \meta{inline function} should consist of code which +% will receive the \meta{line} as |#1|. +% \end{function} +% +% \begin{function}[added = 2012-06-29]{\ior_map_break:} +% \begin{syntax} +% \cs{ior_map_break:} +% \end{syntax} +% Used to terminate a \cs{ior_map_\ldots} function before all +% lines from the \meta{stream} have been processed. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \ior_map_inline:Nn \l_my_ior +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \ior_map_break: } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{ior_map_\ldots} scenario will lead to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{__prg_break_point:Nn} before further items are taken +% from the input stream. This will depend on the design of the mapping +% function. +% \end{texnote} +% \end{function} +% +% \begin{function}[added = 2012-06-29]{\ior_map_break:n} +% \begin{syntax} +% \cs{ior_map_break:n} \Arg{tokens} +% \end{syntax} +% Used to terminate a \cs{ior_map_\ldots} function before all +% lines in the \meta{stream} have been processed, inserting +% the \meta{tokens} after the mapping has ended. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \ior_map_inline:Nn \l_my_ior +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \ior_map_break:n { <tokens> } } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{ior_map_\ldots} scenario will lead to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{__prg_break_point:Nn} before the \meta{tokens} are +% inserted into the input stream. +% This will depend on the design of the mapping function. +% \end{texnote} +% \end{function} +% +% \section{Additions to \pkg{l3fp}} +% +% \begin{function} +% { +% \fp_set_from_dim:Nn, \fp_set_from_dim:cn, +% \fp_gset_from_dim:Nn, \fp_gset_from_dim:cn +% } +% \begin{syntax} +% \cs{fp_set_from_dim:Nn} \meta{floating point variable} \Arg{dimexpr} +% \end{syntax} +% Sets the \meta{floating point variable} to the distance represented +% by the \meta{dimension expression} in the units points. This means +% that distances given in other units are first converted to points +% before being assigned to the \meta{floating point variable}. +% \end{function} +% +% \section{Additions to \pkg{l3prop}} +% +% \begin{function}[rEXP] +% {\prop_map_tokens:Nn, \prop_map_tokens:cn} +% \begin{syntax} +% \cs{prop_map_tokens:Nn} \meta{property list} \Arg{code} +% \end{syntax} +% Analogue of \cs{prop_map_function:NN} which maps several tokens +% instead of a single function. The \meta{code} receives each +% key--value pair in the \meta{property list} as two trailing brace +% groups. For instance, +% \begin{verbatim} +% \prop_map_tokens:Nn \l_my_prop { \str_if_eq:nnT { mykey } } +% \end{verbatim} +% will expand to the value corresponding to \texttt{mykey}: for each +% pair in \cs{l_my_prop} the function \cs{str_if_eq:nnT} receives +% \texttt{mykey}, the \meta{key} and the \meta{value} as its three +% arguments. For that specific task, \cs{prop_get:Nn} is faster. +% \end{function} +% +% \begin{function}[EXP]{\prop_get:Nn, \prop_get:cn} +% \begin{syntax} +% \cs{prop_get:Nn} \meta{property list} \Arg{key} +% \end{syntax} +% Expands to the \meta{value} corresponding to the \meta{key} in +% the \meta{property list}. If the \meta{key} is missing, this has +% an empty expansion. +% \begin{texnote} +% This function is slower than the non-expandable analogue +% \cs{prop_get:NnN}. +% The result is returned within the \tn{unexpanded} +% primitive (\cs{exp_not:n}), which means that the \meta{value} +% will not expand further when appearing in an \texttt{x}-type +% argument expansion. +% \end{texnote} +% \end{function} +% +% \section{Additions to \pkg{l3seq}} +% +% \begin{function}[EXP]{\seq_item:Nn, \seq_item:cn} +% \begin{syntax} +% \cs{seq_item:Nn} \meta{sequence} \Arg{integer expression} +% \end{syntax} +% Indexing items in the \meta{sequence} from~$1$ at the top (left), this +% function will evaluate the \meta{integer expression} and leave the +% appropriate item from the sequence in the input stream. If the +% \meta{integer expression} is negative, indexing occurs from the +% bottom (right) of the sequence. When the \meta{integer expression} +% is larger than the number of items in the \meta{sequence} (as +% calculated by \cs{seq_count:N}) then the function will expand to +% nothing. +% \begin{texnote} +% The result is returned within the \tn{unexpanded} +% primitive (\cs{exp_not:n}), which means that the \meta{item} +% will not expand further when appearing in an \texttt{x}-type +% argument expansion. +% \end{texnote} +% \end{function} +% +% \begin{function}[rEXP] +% { +% \seq_mapthread_function:NNN, \seq_mapthread_function:NcN, +% \seq_mapthread_function:cNN, \seq_mapthread_function:ccN +% } +% \begin{syntax} +% \cs{seq_mapthread_function:NNN} \meta{seq_1} \meta{seq_2} \meta{function} +% \end{syntax} +% Applies \meta{function} to every pair of items +% \meta{seq_1-item}--\meta{seq_2-item} from the two sequences, returning +% items from both sequences from left to right. The \meta{function} will +% receive two \texttt{n}-type arguments for each iteration. The mapping +% will terminate when +% the end of either sequence is reached (\emph{i.e.}~whichever sequence has +% fewer items determines how many iterations +% occur). +% \end{function} +% +% \begin{function} +% { +% \seq_set_from_clist:NN, \seq_set_from_clist:cN, +% \seq_set_from_clist:Nc, \seq_set_from_clist:cc, +% \seq_set_from_clist:Nn, \seq_set_from_clist:cn, +% \seq_gset_from_clist:NN, \seq_gset_from_clist:cN, +% \seq_gset_from_clist:Nc, \seq_gset_from_clist:cc, +% \seq_gset_from_clist:Nn, \seq_gset_from_clist:cn +% } +% \begin{syntax} +% \cs{seq_set_from_clist:NN} \meta{sequence} \meta{comma-list} +% \end{syntax} +% Sets the \meta{sequence} within the current \TeX{} group to be equal +% to the content of the \meta{comma-list}. +% \end{function} +% +% \begin{function}{\seq_reverse:N, \seq_greverse:N} +% \begin{syntax} +% \cs{seq_reverse:N} \meta{sequence} +% \end{syntax} +% Reverses the order of items in the \meta{sequence}, and +% assigns the result to \meta{sequence}, locally or globally +% according to the variant chosen. +% \end{function} +% +% \begin{function}{\seq_set_filter:NNn, \seq_gset_filter:NNn} +% \begin{syntax} +% \cs{seq_set_filter:NNn} \meta{sequence_1} \meta{sequence_2} \Arg{inline boolexpr} +% \end{syntax} +% Evaluates the \meta{inline boolexpr} for every \meta{item} stored +% within the \meta{sequence_2}. The \meta{inline boolexpr} will +% receive the \meta{item} as |#1|. The sequence of all \meta{items} +% for which the \meta{inline boolexpr} evaluated to \texttt{true} +% is assigned to \meta{sequence_1}. +% \begin{texnote} +% Contrarily to other mapping functions, \cs{seq_map_break:} cannot +% be used in this function, and will lead to low-level \TeX{} errors. +% \end{texnote} +% \end{function} +% +% \begin{function}[added = 2011-12-22] +% {\seq_set_map:NNn, \seq_gset_map:NNn} +% \begin{syntax} +% \cs{seq_set_map:NNn} \meta{sequence_1} \meta{sequence_2} \Arg{inline function} +% \end{syntax} +% Applies \meta{inline function} to every \meta{item} stored +% within the \meta{sequence_2}. The \meta{inline function} should +% consist of code which will receive the \meta{item} as |#1|. +% The sequence resulting from \texttt{x}-expanding +% \meta{inline function} applied to each \meta{item} +% is assigned to \meta{sequence_1}. As such, the code +% in \meta{inline function} should be expandable. +% \begin{texnote} +% Contrarily to other mapping functions, \cs{seq_map_break:} cannot +% be used in this function, and will lead to low-level \TeX{} errors. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP, added = 2012-06-26]{\seq_use:Nnnn} +% \begin{syntax} +% \cs{seq_use:Nnnn} \meta{seq~var} \Arg{separator~between~two} \Arg{separator~between~more~than~two} \Arg{separator~between~final~two} +% \end{syntax} +% Places the contents of the \meta{seq~var} in the input stream, with +% the appropriate \meta{separator} between the items. Namely, if the +% sequence has more than $2$ items, the \meta{separator between more +% than two} is placed between each pair of items except the last, +% for which the \meta{separator between final two} is used. If the +% sequence has $2$ items, then they are placed in the input stream +% separated by the \meta{separator between two}. If the sequence has +% $1$ item, it is placed in the input stream, and an empty sequence +% produces no output. An error will be raised if the variable does +% not exist or if it is invalid. +% +% For example, +% \begin{verbatim} +% \seq_set_split:Nnn \l_tmpa_seq { | } { a | b | c | {de} | f } +% \seq_use:Nnnn \l_tmpa_seq { ~and~ } { ,~ } { ,~and~ } +% \end{verbatim} +% will insert \enquote{\texttt{a, b, c, de, and f}} in the input +% stream. The first separator argument is not used in this case +% because the sequence has more than $2$ items. +% \begin{texnote} +% The result is returned within the \tn{unexpanded} +% primitive (\cs{exp_not:n}), which means that the \meta{items} +% will not expand further when appearing in an \texttt{x}-type +% argument expansion. +% \end{texnote} +% \end{function} +% +% \section{Additions to \pkg{l3skip}} +% +% \begin{function}{\skip_split_finite_else_action:nnNN} +% \begin{syntax} +% \cs{skip_split_finite_else_action:nnNN} \Arg{skipexpr} \Arg{action} +% ~~\meta{dimen_1} \meta{dimen_2} +% \end{syntax} +% Checks if the \meta{skipexpr} contains finite glue. If it does then it +% assigns +% \meta{dimen_1} the stretch component and \meta{dimen_2} the shrink +% component. If +% it contains infinite glue set \meta{dimen_1} and \meta{dimen_2} to $0$\,pt +% and place |#2| into the input stream: this is usually an error or +% warning message of some sort. +% \end{function} +% +% \section{Additions to \pkg{l3tl}} +% +% \begin{function}[EXP,pTF]{\tl_if_single_token:n} +% \begin{syntax} +% \cs{tl_if_single_token_p:n} \Arg{token list} +% \cs{tl_if_single_token:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the token list consists of exactly one token, \emph{i.e.}~is +% either a single space character or a single \enquote{normal} token. +% Token groups (|{|\ldots|}|) are not single tokens. +% \end{function} +% +% \begin{function}[EXP]{\tl_reverse_tokens:n} +% \begin{syntax} +% \cs{tl_reverse_tokens:n} \Arg{tokens} +% \end{syntax} +% This function, which works directly on \TeX{} tokens, reverses +% the order of the \meta{tokens}: the first will be the last and +% the last will become first. Spaces are preserved. The reversal +% also operates within brace groups, but the braces themselves +% are not exchanged, as this would lead to an unbalanced token +% list. For instance, \cs{tl_reverse_tokens:n} |{a~{b()}}| +% leaves |{)(b}~a| in the input stream. This function requires +% two steps of expansion. +% \begin{texnote} +% The result is returned within the \tn{unexpanded} +% primitive (\cs{exp_not:n}), which means that the token +% list will not expand further when appearing in an \texttt{x}-type +% argument expansion. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\tl_count_tokens:n} +% \begin{syntax} +% \cs{tl_count_tokens:n} \Arg{tokens} +% \end{syntax} +% Counts the number of \TeX{} tokens in the \meta{tokens} and leaves +% this information in the input stream. Every token, including spaces and +% braces, contributes one to the total; thus for instance, the token count of +% |a~{bc}| is $6$. +% This function requires three expansions, +% giving an \meta{integer denotation}. +% \end{function} +% +% \begin{function}[EXP]{\tl_expandable_uppercase:n,\tl_expandable_lowercase:n} +% \begin{syntax} +% \cs{tl_expandable_uppercase:n} \Arg{tokens} +% \cs{tl_expandable_lowercase:n} \Arg{tokens} +% \end{syntax} +% The \cs{tl_expandable_uppercase:n} function works through all of +% the \meta{tokens}, replacing characters in the range |a|--|z| +% (with arbitrary category code) by the corresponding letter +% in the range |A|--|Z|, with category code $11$ (letter). Similarly, +% \cs{tl_expandable_lowercase:n} replaces characters in the range +% |A|--|Z| by letters in the range |a|--|z|, and leaves other tokens +% unchanged. This function requires two steps of expansion. +% \begin{texnote} +% Begin-group and end-group characters are normalized and become +% |{| and |}|, respectively. +% The result is returned within the \tn{unexpanded} +% primitive (\cs{exp_not:n}), which means that the token +% list will not expand further when appearing in an \texttt{x}-type +% argument expansion. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\tl_item:nn, \tl_item:Nn, \tl_item:cn} +% \begin{syntax} +% \cs{tl_item:nn} \Arg{token list} \Arg{integer expression} +% \end{syntax} +% Indexing items in the \meta{token list} from~$1$ on the left, this +% function will evaluate the \meta{integer expression} and leave the +% appropriate item from the \meta{token list} in the input stream. +% If the \meta{integer expression} is negative, indexing occurs from +% the right of the token list, starting at $-1$ for the right-most item. +% If the index is out of bounds, then thr function expands to nothing. +% \begin{texnote} +% The result is returned within the \tn{unexpanded} +% primitive (\cs{exp_not:n}), which means that the \meta{item} +% will not expand further when appearing in an \texttt{x}-type +% argument expansion. +% \end{texnote} +% \end{function} +% +% \section{Additions to \pkg{l3tokens}} +% +% \begin{function}{\char_set_active:Npn, \char_set_active:Npx} +% \begin{syntax} +% \cs{char_set_active:Npn} \meta{char} \meta{parameters} \Arg{code} +% \end{syntax} +% Makes \meta{char} an active character to expand to \meta{code} as +% replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed. The \meta{char} is +% made active within the current \TeX{} group level, and the definition +% is also local. +% \end{function} +% +% \begin{function}{\char_gset_active:Npn, \char_gset_active:Npx} +% \begin{syntax} +% \cs{char_gset_active:Npn} \meta{char} \meta{parameters} \Arg{code} +% \end{syntax} +% Makes \meta{char} an active character to expand to \meta{code} as +% replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed. The \meta{char} is +% made active within the current \TeX{} group level, but the definition +% is global. This function is therefore suited to cases where an active +% character definition should be applied only in some context (where the +% \meta{char} is again made active). +% \end{function} +% +% \begin{function}{\char_set_active_eq:NN} +% \begin{syntax} +% \cs{char_set_active_eq:NN} \meta{char} \meta{function} +% \end{syntax} +% Makes \meta{char} an active character equivalent in meaning to the +% \meta{function} (which may itself be an active character). The \meta{char} +% is made active within the current \TeX{} group level, and the definition +% is also local. +% \end{function} +% +% \begin{function}{\char_gset_active_eq:NN} +% \begin{syntax} +% \cs{char_gset_active_eq:NN} \meta{char} \meta{function} +% \end{syntax} +% Makes \meta{char} an active character equivalent in meaning to the +% \meta{function} (which may itself be an active character). The \meta{char} +% is made active within the current \TeX{} group level, but the definition +% is global. This function is therefore suited to cases where an active +% character definition should be applied only in some context (where the +% \meta{char} is again made active). +% \end{function} +% +% \begin{function}[TF]{\peek_N_type:} +% \begin{syntax} +% \cs{peek_N_type:TF} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream can be safely +% grabbed as an \texttt{N}-type argument. The test will be \meta{false} +% if the next \meta{token} is either an explicit or implicit +% begin-group or end-group token (with any character code), or +% an explicit or implicit space character (with character code $32$ +% and category code $10$), and \meta{true} in all other cases. +% Note that a \meta{true} result ensures that the next \meta{token} is +% a valid \texttt{N}-type argument. However, if the next \meta{token} +% is for instance \cs{c_space_token}, the test will take the +% \meta{false} branch, even though the next \meta{token} is in fact +% a valid \texttt{N}-type argument. The \meta{token} will be left +% in the input stream after the \meta{true code} or \meta{false code} +% (as appropriate to the result of the test). +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3candidates} Implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\__expl_package_check: +%</package> +% \end{macrocode} +% +% \subsection{Additions to \pkg{l3box}} +% +% \begin{macrocode} +%<@@=box> +% \end{macrocode} +% +% \subsection{Affine transformations} +% +% \begin{variable}{\l_@@_angle_fp} +% When rotating boxes, the angle itself may be needed by the +% engine-dependent code. This is done using the \pkg{fp} module so +% that the value is tidied up properly. +% \begin{macrocode} +\fp_new:N \l_@@_angle_fp +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp} +% These are used to hold the calculated sine and cosine values while +% carrying out a rotation. +% \begin{macrocode} +\fp_new:N \l_@@_cos_fp +\fp_new:N \l_@@_sin_fp +% \end{macrocode} +% \end{variable} +% +% \begin{variable} +% {\l_@@_top_dim, \l_@@_bottom_dim, \l_@@_left_dim, \l_@@_right_dim} +% These are the positions of the four edges of a box before +% manipulation. +% \begin{macrocode} +\dim_new:N \l_@@_top_dim +\dim_new:N \l_@@_bottom_dim +\dim_new:N \l_@@_left_dim +\dim_new:N \l_@@_right_dim +% \end{macrocode} +% \end{variable} +% +% \begin{variable} +% { +% \l_@@_top_new_dim, \l_@@_bottom_new_dim , +% \l_@@_left_new_dim, \l_@@_right_new_dim +% } +% These are the positions of the four edges of a box after +% manipulation. +% \begin{macrocode} +\dim_new:N \l_@@_top_new_dim +\dim_new:N \l_@@_bottom_new_dim +\dim_new:N \l_@@_left_new_dim +\dim_new:N \l_@@_right_new_dim +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_internal_box} +% Scratch space, but also needed by some parts of the driver. +% \begin{macrocode} +\box_new:N \l_@@_internal_box +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\box_rotate:Nn} +% \begin{macro}[aux]{\@@_rotate:N} +% \begin{macro}[aux]{\@@_rotate_x:nnN, \@@_rotate_y:nnN} +% \begin{macro}[aux] +% { +% \@@_rotate_quadrant_one:, \@@_rotate_quadrant_two:, +% \@@_rotate_quadrant_three:, \@@_rotate_quadrant_four: +% } +% Rotation of a box starts with working out the relevant sine and +% cosine. The actual rotation is in an auxiliary to keep the flow slightly +% clearer +% \begin{macrocode} +\cs_new_protected:Npn \box_rotate:Nn #1#2 + { + \hbox_set:Nn #1 + { + \group_begin: + \fp_set:Nn \l_@@_angle_fp {#2} + \fp_set:Nn \l_@@_sin_fp { sin ( \l_@@_angle_fp * deg ) } + \fp_set:Nn \l_@@_cos_fp { cos ( \l_@@_angle_fp * deg ) } + \@@_rotate:N #1 + \group_end: + } + } +% \end{macrocode} +% The edges of the box are then recorded: the left edge will +% always be at zero. Rotation of the four edges then takes place: this is +% most efficiently done on a quadrant by quadrant basis. +% \begin{macrocode} +\cs_new_protected:Npn \@@_rotate:N #1 + { + \dim_set:Nn \l_@@_top_dim { \box_ht:N #1 } + \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 } + \dim_set:Nn \l_@@_right_dim { \box_wd:N #1 } + \dim_zero:N \l_@@_left_dim +% \end{macrocode} +% The next step is to work out the $x$ and $y$ coordinates of vertices of +% the rotated box in relation to its original coordinates. The box can be +% visualized with vertices $B$, $C$, $D$ and $E$ is illustrated +% (Figure~\ref{fig:rotation}). The vertex $O$ is the reference point on the +% baseline, and in this implementation is also the centre of rotation. +% \begin{figure} +% \centering +% \setlength{\unitlength}{3pt}^^A +% \begin{picture}(34,36)(12,44) +% \thicklines +% \put(20,52){\dashbox{1}(20,21){}} +% \put(20,80){\line(0,-1){36}} +% \put(12,58){\line(1, 0){34}} +% \put(41,59){A} +% \put(40,74){B} +% \put(21,74){C} +% \put(21,49){D} +% \put(40,49){E} +% \put(21,59){O} +% \end{picture} +% \caption{Co-ordinates of a box prior to rotation.} +% \label{fig:rotation} +% \end{figure} +% The formulae are, for a point $P$ and angle $\alpha$: +% \[ +% \begin{array}{l} +% P'_x = P_x - O_x \\ +% P'_y = P_y - O_y \\ +% P''_x = ( P'_x \cos(\alpha)) - ( P'_y \sin(\alpha) ) \\ +% P''_y = ( P'_x \sin(\alpha)) + ( P'_y \cos(\alpha) ) \\ +% P'''_x = P''_x + O_x + L_x \\ +% P'''_y = P''_y + O_y +% \end{array} +% \] +% The \enquote{extra} horizontal translation $L_x$ at the end is calculated +% so that the leftmost point of the resulting box has $x$-coordinate $0$. +% This is desirable as \TeX{} boxes must have the reference point at +% the left edge of the box. (As $O$ is always $(0,0)$, this part of the +% calculation is omitted here.) +% \begin{macrocode} + \fp_compare:nNnTF \l_@@_sin_fp > \c_zero_fp + { + \fp_compare:nNnTF \l_@@_cos_fp > \c_zero_fp + { \@@_rotate_quadrant_one: } + { \@@_rotate_quadrant_two: } + } + { + \fp_compare:nNnTF \l_@@_cos_fp < \c_zero_fp + { \@@_rotate_quadrant_three: } + { \@@_rotate_quadrant_four: } + } +% \end{macrocode} +% The position of the box edges are now known, but the box at this +% stage be misplaced relative to the current \TeX{} reference point. So the +% content of the box is moved such that the reference point of the +% rotated box will be in the same place as the original. +% \begin{macrocode} + \hbox_set:Nn \l_@@_internal_box { \box_use:N #1 } + \hbox_set:Nn \l_@@_internal_box + { + \tex_kern:D -\l_@@_left_new_dim + \hbox:n + { + \__driver_box_rotate_begin: + \box_use:N \l_@@_internal_box + \__driver_box_rotate_end: + } + } +% \end{macrocode} +% Tidy up the size of the box so that the material is actually inside +% the bounding box. The result can then be used to reset the original +% box. +% \begin{macrocode} + \box_set_ht:Nn \l_@@_internal_box { \l_@@_top_new_dim } + \box_set_dp:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim } + \box_set_wd:Nn \l_@@_internal_box + { \l_@@_right_new_dim - \l_@@_left_new_dim } + \box_use:N \l_@@_internal_box + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% These functions take a general point $(|#1|, |#2|)$ and rotate its +% location about the origin, using the previously-set sine and cosine +% values. Each function gives only one component of the location of the +% updated point. This is because for rotation of a box each step needs +% only one value, and so performance is gained by avoiding working +% out both $x'$ and $y'$ at the same time. Contrast this with +% the equivalent function in the \pkg{l3coffins} module, where both parts +% are needed. +% \begin{macrocode} +\cs_new_protected:Npn \@@_rotate_x:nnN #1#2#3 + { + \dim_set:Nn #3 + { + \fp_to_dim:n + { + \l_@@_cos_fp * \dim_to_fp:n {#1} + - ( \l_@@_sin_fp * \dim_to_fp:n {#2} ) + } + } + } +\cs_new_protected:Npn \@@_rotate_y:nnN #1#2#3 + { + \dim_set:Nn #3 + { + \fp_to_dim:n + { + \l_@@_sin_fp * \dim_to_fp:n {#1} + + \l_@@_cos_fp * \dim_to_fp:n {#2} + } + } + } +% \end{macrocode} +% Rotation of the edges is done using a different formula for each +% quadrant. In every case, the top and bottom edges only need the +% resulting $y$-values, whereas the left and right edges need the +% $x$-values. Each case is a question of picking out which corner +% ends up at with the maximum top, bottom, left and right value. Doing +% this by hand means a lot less calculating and avoids lots of +% comparisons. +% \begin{macrocode} +\cs_new_protected:Npn \@@_rotate_quadrant_one: + { + \@@_rotate_y:nnN \l_@@_right_dim \l_@@_top_dim + \l_@@_top_new_dim + \@@_rotate_y:nnN \l_@@_left_dim \l_@@_bottom_dim + \l_@@_bottom_new_dim + \@@_rotate_x:nnN \l_@@_left_dim \l_@@_top_dim + \l_@@_left_new_dim + \@@_rotate_x:nnN \l_@@_right_dim \l_@@_bottom_dim + \l_@@_right_new_dim + } +\cs_new_protected:Npn \@@_rotate_quadrant_two: + { + \@@_rotate_y:nnN \l_@@_right_dim \l_@@_bottom_dim + \l_@@_top_new_dim + \@@_rotate_y:nnN \l_@@_left_dim \l_@@_top_dim + \l_@@_bottom_new_dim + \@@_rotate_x:nnN \l_@@_right_dim \l_@@_top_dim + \l_@@_left_new_dim + \@@_rotate_x:nnN \l_@@_left_dim \l_@@_bottom_dim + \l_@@_right_new_dim + } +\cs_new_protected:Npn \@@_rotate_quadrant_three: + { + \@@_rotate_y:nnN \l_@@_left_dim \l_@@_bottom_dim + \l_@@_top_new_dim + \@@_rotate_y:nnN \l_@@_right_dim \l_@@_top_dim + \l_@@_bottom_new_dim + \@@_rotate_x:nnN \l_@@_right_dim \l_@@_bottom_dim + \l_@@_left_new_dim + \@@_rotate_x:nnN \l_@@_left_dim \l_@@_top_dim + \l_@@_right_new_dim + } +\cs_new_protected:Npn \@@_rotate_quadrant_four: + { + \@@_rotate_y:nnN \l_@@_left_dim \l_@@_top_dim + \l_@@_top_new_dim + \@@_rotate_y:nnN \l_@@_right_dim \l_@@_bottom_dim + \l_@@_bottom_new_dim + \@@_rotate_x:nnN \l_@@_left_dim \l_@@_bottom_dim + \l_@@_left_new_dim + \@@_rotate_x:nnN \l_@@_right_dim \l_@@_top_dim + \l_@@_right_new_dim + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{variable}{\l_@@_scale_x_fp, \l_@@_scale_y_fp} +% Scaling is potentially-different in the two axes. +% \begin{macrocode} +\fp_new:N \l_@@_scale_x_fp +\fp_new:N \l_@@_scale_y_fp +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\box_resize:Nnn, \box_resize:cnn} +% \begin{macro}[aux]{\@@_resize:Nnn} +% Resizing a box starts by working out the various dimensions of the +% existing box. +% \begin{macrocode} +\cs_new_protected:Npn \box_resize:Nnn #1#2#3 + { + \hbox_set:Nn #1 + { + \group_begin: + \dim_set:Nn \l_@@_top_dim { \box_ht:N #1 } + \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 } + \dim_set:Nn \l_@@_right_dim { \box_wd:N #1 } + \dim_zero:N \l_@@_left_dim +% \end{macrocode} +% The $x$-scaling and resulting box size is easy enough to work +% out: the dimension is that given as |#2|, and the scale is simply the +% new width divided by the old one. +% \begin{macrocode} + \fp_set:Nn \l_@@_scale_x_fp + { \dim_to_fp:n {#2} / ( \dim_to_fp:n \l_@@_right_dim ) } +% \end{macrocode} +% The $y$-scaling needs both the height and the depth of the current box. +% \begin{macrocode} + \fp_set:Nn \l_@@_scale_y_fp + { + \dim_to_fp:n {#3} / + ( \dim_to_fp:n { \l_@@_top_dim - \l_@@_bottom_dim } ) + } +% \end{macrocode} +% Hand off to the auxiliary which does the work. +% \begin{macrocode} + \@@_resize:Nnn #1 {#2} {#3} + \group_end: + } + } +\cs_generate_variant:Nn \box_resize:Nnn { c } +% \end{macrocode} +% With at least one real scaling to do, the next phase is to find the new +% edge co-ordinates. In the $x$~direction this is relatively easy: just +% scale the right edge. This is done using the absolute value of the +% scale so that the new edge is in the correct place. In the $y$~direction, +% both dimensions have to be scaled, and this again needs the absolute +% scale value. Once that is all done, the common resize/rescale code can +% be employed. +% \begin{macrocode} +\cs_new_protected:Npn \@@_resize:Nnn #1#2#3 + { + \dim_compare:nNnTF {#2} > \c_zero_dim + { \dim_set:Nn \l_@@_right_new_dim {#2} } + { \dim_set:Nn \l_@@_right_new_dim { \c_zero_dim - ( #2 ) } } + \dim_compare:nNnTF {#3} > \c_zero_dim + { + \dim_set:Nn \l_@@_top_new_dim + { \fp_use:N \l_@@_scale_y_fp \l_@@_top_dim } + \dim_set:Nn \l_@@_bottom_new_dim + { \fp_use:N \l_@@_scale_y_fp \l_@@_bottom_dim } + } + { + \dim_set:Nn \l_@@_top_new_dim + { - \fp_use:N \l_@@_scale_y_fp \l_@@_top_dim } + \dim_set:Nn \l_@@_bottom_new_dim + { - \fp_use:N \l_@@_scale_y_fp \l_@@_bottom_dim } + } + \@@_resize_common:N #1 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn} +% \begin{macro}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn} +% Scaling to a total height or to a width is a simplified version of the main +% resizing operation, with the scale simply copied between the two parts. The +% internal auxiliary is called using the scaling value twice, as the sign for +% both parts is needed (as this allows the same internal code to be used as +% for the general case). +% \begin{macrocode} +\cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2 + { + \hbox_set:Nn #1 + { + \group_begin: + \dim_set:Nn \l_@@_top_dim { \box_ht:N #1 } + \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 } + \dim_set:Nn \l_@@_right_dim { \box_wd:N #1 } + \dim_zero:N \l_@@_left_dim + \fp_set:Nn \l_@@_scale_y_fp + { + \dim_to_fp:n {#2} / + ( \dim_to_fp:n { \l_@@_top_dim - \l_@@_bottom_dim } ) + } + \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp + \@@_resize:Nnn #1 {#2} {#2} + \group_end: + } + } +\cs_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c } +\cs_new_protected:Npn \box_resize_to_wd:Nn #1#2 + { + \hbox_set:Nn #1 + { + \group_begin: + \dim_set:Nn \l_@@_top_dim { \box_ht:N #1 } + \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 } + \dim_set:Nn \l_@@_right_dim { \box_wd:N #1 } + \dim_zero:N \l_@@_left_dim + \fp_set:Nn \l_@@_scale_x_fp + { \dim_to_fp:n {#2} / ( \dim_to_fp:n \l_@@_right_dim ) } + \fp_set_eq:NN \l_@@_scale_y_fp \l_@@_scale_x_fp + \@@_resize:Nnn #1 {#2} {#2} + \group_end: + } + } +\cs_generate_variant:Nn \box_resize_to_wd:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_scale:Nnn, \box_scale:cnn} +% \begin{macro}[aux]{\@@_scale:Nnn} +% When scaling a box, setting the scaling itself is easy enough. The +% new dimensions are also relatively easy to find, allowing only for +% the need to keep them positive in all cases. Once that is done then +% after a check for the trivial scaling a hand-off can be made to the +% common code. The dimension scaling operations are carried out using +% the \TeX{} mechanism as it avoids needing to use \texttt{fp} +% operations. +% \begin{macrocode} +\cs_new_protected:Npn \box_scale:Nnn #1#2#3 + { + \hbox_set:Nn #1 + { + \group_begin: + \fp_set:Nn \l_@@_scale_x_fp {#2} + \fp_set:Nn \l_@@_scale_y_fp {#3} + \dim_set:Nn \l_@@_top_dim { \box_ht:N #1 } + \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 } + \dim_set:Nn \l_@@_right_dim { \box_wd:N #1 } + \dim_zero:N \l_@@_left_dim + \@@_scale:Nnn #1 {#2} {#3} + \group_end: + } + } +\cs_generate_variant:Nn \box_scale:Nnn { c } +\cs_new_protected:Npn \@@_scale:Nnn #1#2#3 + { + \fp_compare:nNnTF \l_@@_scale_y_fp > \c_zero_fp + { + \dim_set:Nn \l_@@_top_new_dim { #3 \l_@@_top_dim } + \dim_set:Nn \l_@@_bottom_new_dim { #3 \l_@@_bottom_dim } + } + { + \dim_set:Nn \l_@@_top_new_dim { -#3 \l_@@_bottom_dim } + \dim_set:Nn \l_@@_bottom_new_dim { -#3 \l_@@_top_dim } + } + \fp_compare:nNnTF \l_@@_scale_x_fp > \c_zero_fp + { \l_@@_right_new_dim #2 \l_@@_right_dim } + { \l_@@_right_new_dim -#2 \l_@@_right_dim } + \@@_resize_common:N #1 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\@@_resize_common:N} +% The main resize function places in input into a box which will start +% of with zero width, and includes the handles for engine rescaling. +% \begin{macrocode} +\cs_new_protected:Npn \@@_resize_common:N #1 + { + \hbox_set:Nn \l_@@_internal_box + { + \__driver_box_scale_begin: + \hbox_overlap_right:n { \box_use:N #1 } + \__driver_box_scale_end: + } +% \end{macrocode} +% The new height and depth can be applied directly. +% \begin{macrocode} + \box_set_ht:Nn \l_@@_internal_box { \l_@@_top_new_dim } + \box_set_dp:Nn \l_@@_internal_box { \l_@@_bottom_new_dim } +% \end{macrocode} +% Things are not quite as obvious for the width, as the reference point +% needs to remain unchanged. For positive scaling factors resizing the +% box is all that is needed. However, for case of a negative scaling +% the material must be shifted such that the reference point ends up in +% the right place. +% \begin{macrocode} + \fp_compare:nNnTF \l_@@_scale_x_fp < \c_zero_fp + { + \hbox_to_wd:nn { \l_@@_right_new_dim } + { + \tex_kern:D \l_@@_right_new_dim + \box_use:N \l_@@_internal_box + \tex_hss:D + } + } + { + \box_set_wd:Nn \l_@@_internal_box { \l_@@_right_new_dim } + \box_use:N \l_@@_internal_box + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Viewing part of a box} +% +% \begin{macro}{\box_clip:N, \box_clip:c} +% A wrapper around the driver-dependent code. +% \begin{macrocode} +\cs_new_protected:Npn \box_clip:N #1 + { \hbox_set:Nn #1 { \__driver_box_use_clip:N #1 } } +\cs_generate_variant:Nn \box_clip:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\box_trim:Nnnnn, \box_trim:cnnnn} +% Trimming from the left- and right-hand edges of the box is easy. The total +% width is set to remove from the right, and a skip will shift the material +% to remove from the left. +% \begin{macrocode} +\cs_new_protected:Npn \box_trim:Nnnnn #1#2#3#4#5 + { + \box_set_wd:Nn #1 { \box_wd:N #1 - (#4) - (#2) } + \hbox_set:Nn #1 + { + \skip_horizontal:n { - \dim_eval:n {#2} } + \box_use:N #1 + } +% \end{macrocode} +% For the height and depth, there is a need to watch the baseline is +% respected. Material always has to stay on the correct side, so trimming +% has to check that there is enough material to trim. +% \begin{macrocode} + \dim_compare:nNnTF { \box_dp:N #1 } > {#3} + { \box_set_dp:Nn #1 { \box_dp:N #1 - (#3) } } + { + \hbox_set:Nn #1 + { \box_move_down:nn { #3 - \box_dp:N #1 } { \box_use:N #1 } } + \box_set_dp:Nn #1 \c_zero_dim + } + \dim_compare:nNnTF { \box_ht:N #1 } > {#5} + { \box_set_ht:Nn #1 { \box_ht:N #1 - (#5) } } + { + \hbox_set:Nn #1 + { \box_move_up:nn { #5 - \box_ht:N #1 } { \box_use:N #1 } } + \box_set_ht:Nn #1 \c_zero_dim + } + } +\cs_generate_variant:Nn \box_trim:Nnnnn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\box_viewport:Nnnnn, \box_viewport:cnnnn} +% The same general logic as for clipping, but with absolute dimensions. +% Thus again width is easy and height is harder. +% \begin{macrocode} +\cs_new_protected:Npn \box_viewport:Nnnnn #1#2#3#4#5 + { + \box_set_wd:Nn #1 { (#4) - (#2) } + \hbox_set:Nn #1 + { + \skip_horizontal:n { - \dim_eval:n {#2} } + \box_use:N #1 + } + \dim_compare:nNnTF {#3} > \c_zero_dim + { + \hbox_set:Nn #1 { \box_move_down:nn {#3} { \box_use:N #1 } } + \box_set_dp:Nn #1 \c_zero_dim + } + { \box_set_dp:Nn #1 { - \dim_eval:n {#3} } } + \dim_compare:nNnTF {#5} > \c_zero_dim + { \box_set_ht:Nn #1 {#5} } + { + \hbox_set:Nn #1 + { \box_move_up:nn { -\dim_eval:n {#5} } { \box_use:N #1 } } + \box_set_ht:Nn #1 \c_zero_dim + } + } +\cs_generate_variant:Nn \box_viewport:Nnnnn { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Additions to \pkg{l3clist}} +% +% \begin{macrocode} +%<@@=clist> +% \end{macrocode} +% +% \begin{macro}{\clist_item:Nn, \clist_item:cn} +% \begin{macro}[aux]{\@@_item:nnNn} +% \begin{macro}[aux]{\@@_item_N_loop:nw} +% To avoid needing to test the end of the list at each step, +% we first compute the \meta{length} of the list. If the item number +% is~$0$, less than $-\meta{length}$, or more than $\meta{length}$, +% the result is empty. If it is negative, but not less than $-\meta{length}$, +% add $\meta{length}+1$ to the item number before performing the loop. +% The loop itself is very simple, return the item if the counter +% reached~$1$, otherwise, decrease the counter and repeat. +% \begin{macrocode} +\cs_new:Npn \clist_item:Nn #1#2 + { + \exp_args:Nfo \@@_item:nnNn + { \clist_count:N #1 } + #1 + \@@_item_N_loop:nw + {#2} + } +\cs_new:Npn \@@_item:nnNn #1#2#3#4 + { + \int_compare:nNnTF {#4} < \c_zero + { + \int_compare:nNnTF {#4} < { - #1 } + { \use_none_delimit_by_q_stop:w } + { \exp_args:Nf #3 { \int_eval:n { #4 + \c_one + #1 } } } + } + { + \int_compare:nNnTF {#4} > {#1} + { \use_none_delimit_by_q_stop:w } + { #3 {#4} } + } + { } , #2 , \q_stop + } +\cs_new:Npn \@@_item_N_loop:nw #1 #2, + { + \int_compare:nNnTF {#1} = \c_zero + { \use_i_delimit_by_q_stop:nw { \exp_not:n {#2} } } + { \exp_args:Nf \@@_item_N_loop:nw { \int_eval:n { #1 - 1 } } } + } +\cs_generate_variant:Nn \clist_item:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_item:nn} +% \begin{macro}[aux]{ +% \@@_item_n:nw, +% \@@_item_n_loop:nw, +% \@@_item_n_end:n, +% \@@_item_n_strip:w} +% This starts in the same way as \cs{clist_item:Nn} by counting the items +% of the comma list. The final item should be space-trimmed before being +% brace-stripped, hence we insert a couple of odd-looking +% \cs{prg_do_nothing:} to avoid losing braces. Blank items are ignored. +% \begin{macrocode} +\cs_new:Npn \clist_item:nn #1#2 + { + \exp_args:Nf \@@_item:nnNn + { \clist_count:n {#1} } + {#1} + \@@_item_n:nw + {#2} + } +\cs_new:Npn \@@_item_n:nw #1 + { \@@_item_n_loop:nw {#1} \prg_do_nothing: } +\cs_new:Npn \@@_item_n_loop:nw #1 #2, + { + \exp_args:No \tl_if_blank:nTF {#2} + { \@@_item_n_loop:nw {#1} \prg_do_nothing: } + { + \int_compare:nNnTF {#1} = \c_zero + { \exp_args:No \@@_item_n_end:n {#2} } + { + \exp_args:Nf \@@_item_n_loop:nw + { \int_eval:n { #1 - 1 } } + \prg_do_nothing: + } + } + } +\cs_new:Npn \@@_item_n_end:n #1 #2 \q_stop + { + \__tl_trim_spaces:nn { \q_mark #1 } + { \exp_last_unbraced:No \@@_item_n_strip:w } , + } +\cs_new:Npn \@@_item_n_strip:w #1 , { \exp_not:n {#1} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \clist_set_from_seq:NN, \clist_set_from_seq:cN, +% \clist_set_from_seq:Nc, \clist_set_from_seq:cc +% } +% \UnitTested +% \begin{macro} +% { +% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, +% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc +% } +% \UnitTested +% \begin{macro}[aux]{\@@_set_from_seq:NNNN} +% \begin{macro}[aux]{\@@_wrap_item:n} +% \begin{macro}[aux]{\@@_set_from_seq:w} +% Setting a comma list from a comma-separated list is done using a simple +% mapping. We wrap most items with \cs{exp_not:n}, and a comma. Items which +% contain a comma or a space are surrounded by an extra set of braces. The +% first comma must be removed, except in the case of an empty comma-list. +% \begin{macrocode} +\cs_new_protected:Npn \clist_set_from_seq:NN + { \@@_set_from_seq:NNNN \clist_clear:N \tl_set:Nx } +\cs_new_protected:Npn \clist_gset_from_seq:NN + { \@@_set_from_seq:NNNN \clist_gclear:N \tl_gset:Nx } +\cs_new_protected:Npn \@@_set_from_seq:NNNN #1#2#3#4 + { + \seq_if_empty:NTF #4 + { #1 #3 } + { + #2 #3 + { + \exp_last_unbraced:Nf \use_none:n + { \seq_map_function:NN #4 \@@_wrap_item:n } + } + } + } +\cs_new:Npn \@@_wrap_item:n #1 + { + , + \tl_if_empty:oTF { \@@_set_from_seq:w #1 ~ , #1 ~ } + { \exp_not:n {#1} } + { \exp_not:n { {#1} } } + } +\cs_new:Npn \@@_set_from_seq:w #1 , #2 ~ { } +\cs_generate_variant:Nn \clist_set_from_seq:NN { Nc } +\cs_generate_variant:Nn \clist_set_from_seq:NN { c , cc } +\cs_generate_variant:Nn \clist_gset_from_seq:NN { Nc } +\cs_generate_variant:Nn \clist_gset_from_seq:NN { c , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \clist_const:Nn, \clist_const:cn, +% \clist_const:Nx, \clist_const:cx +% } +% Creating and initializing a constant comma list is done in a way +% similar to \cs{clist_set:Nn} and \cs{clist_gset:Nn}, being careful +% to strip spaces. +% \begin{macrocode} +\cs_new_protected:Npn \clist_const:Nn #1#2 + { \tl_const:Nx #1 { \@@_trim_spaces:n {#2} } } +\cs_generate_variant:Nn \clist_const:Nn { c , Nx , cx } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP, pTF]{\clist_if_empty:n} +% \begin{macro}[aux, EXP]{\@@_if_empty_n:w} +% \begin{macro}[aux, EXP]{\@@_if_empty_n:wNw} +% As usual, we insert a token (here |?|) before grabbing +% any argument: this avoids losing braces. The argument +% of \cs{tl_if_empty:oTF} is empty if |#1| is |?| followed +% by blank spaces (besides, this particular variant of +% the emptyness test is optimized). If the item of the +% comma list is blank, grab the next one. As soon as one +% item is non-blank, exit: the second auxiliary will grab +% \cs{prg_return_false:} as |#2|, unless every item in +% the comma list was blank and the loop actually got broken +% by the trailing |\q_mark \prg_return_false:| item. +% \begin{macrocode} +\prg_new_conditional:Npnn \clist_if_empty:n #1 { p , T , F , TF } + { + \@@_if_empty_n:w ? #1 + , \q_mark \prg_return_false: + , \q_mark \prg_return_true: + \q_stop + } +\cs_new:Npn \@@_if_empty_n:w #1 , + { + \tl_if_empty:oTF { \use_none:nn #1 ? } + { \@@_if_empty_n:w ? } + { \@@_if_empty_n:wNw } + } +\cs_new:Npn \@@_if_empty_n:wNw #1 \q_mark #2#3 \q_stop {#2} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\clist_use:Nnnn} +% \begin{macro}[EXP, aux] +% {\@@_use:wwn, \@@_use_ii:nwwwwnwn, \@@_use_iii:nwwn} +% First check that the variable exists. Then count the items in the +% comma list. If it has none, output nothing. If it has one item, +% output that item, brace stripped (note that space-trimming has +% already been done when the comma list was assigned). If it has two, +% place the \meta{separator~between~two} in the middle. +% +% Otherwise, \cs{@@_use_ii:nwwwwnwn} takes the following arguments; 1: +% a \meta{separator}, 2, 3, 4: three items from the comma list (or +% quarks), 5: the rest of the comma list, 6: a \meta{continuation} +% function (\texttt{use_ii} or \texttt{use_iii} with its +% \meta{separator} argument), 7: junk, and 8: the temporary result, +% which is built in a brace group following \cs{q_stop}. The +% \meta{separator} and the first of the three items are placed in the +% result, then we use the \meta{continuation}, placing the remaining +% two items after it. When we begin this loop, the three items really +% belong to the comma list, the first \cs{q_mark} is taken as a +% delimiter to the \texttt{use_ii} function, and the continuation is +% \texttt{use_ii} itself. When we reach the last two items of the +% original token list, \cs{q_mark} is taken as a third item, and now +% the seconf \cs{q_mark} serves as a delimiter to \texttt{use_ii}, +% switching to the other \meta{continuation}, \texttt{use_iii}, which +% uses the \meta{separator between final two}. +% \begin{macrocode} +\cs_new:Npn \clist_use:Nnnn #1#2#3#4 + { + \clist_if_exist:NTF #1 + { + \int_case:nnn { \clist_count:N #1 } + { + { 0 } { } + { 1 } { \exp_after:wN \@@_use:wwn #1 , , { } } + { 2 } { \exp_after:wN \@@_use:wwn #1 , {#2} } + } + { + \exp_after:wN \@@_use_ii:nwwwwnwn + \exp_after:wN { \exp_after:wN } #1 , + \q_mark , { \@@_use_ii:nwwwwnwn {#3} } + \q_mark , { \@@_use_iii:nwwn {#4} } + \q_stop { } + } + } + { \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#1} } + } +\cs_new:Npn \@@_use:wwn #1 , #2 , #3 { \exp_not:n { #1 #3 #2 } } +\cs_new:Npn \@@_use_ii:nwwwwnwn + #1#2 , #3 , #4 , #5 \q_mark , #6#7 \q_stop #8 + { #6 {#3} , {#4} , #5 \q_mark , {#6} #7 \q_stop { #8 #1 #2 } } +\cs_new:Npn \@@_use_iii:nwwn #1#2 , #3 \q_stop #4 + { \exp_not:n { #4 #1 #2 } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Additions to \pkg{l3coffins}} +% +% \begin{macrocode} +%<@@=coffin> +% \end{macrocode} +% +% \subsection{Rotating coffins} +% +% \begin{variable}{\l_@@_sin_fp} +% \begin{variable}{\l_@@_cos_fp} +% Used for rotations to get the sine and cosine values. +% \begin{macrocode} +\fp_new:N \l_@@_sin_fp +\fp_new:N \l_@@_cos_fp +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\l_@@_bounding_prop} +% A property list for the bounding box of a coffin. This is only needed +% during the rotation, so there is just the one. +% \begin{macrocode} +\prop_new:N \l_@@_bounding_prop +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_bounding_shift_dim} +% The shift of the bounding box of a coffin from the real content. +% \begin{macrocode} +\dim_new:N \l_@@_bounding_shift_dim +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_left_corner_dim} +% \begin{variable}{\l_@@_right_corner_dim} +% \begin{variable}{\l_@@_bottom_corner_dim} +% \begin{variable}{\l_@@_top_corner_dim} +% These are used to hold maxima for the various corner values: these +% thus define the minimum size of the bounding box after rotation. +% \begin{macrocode} +\dim_new:N \l_@@_left_corner_dim +\dim_new:N \l_@@_right_corner_dim +\dim_new:N \l_@@_bottom_corner_dim +\dim_new:N \l_@@_top_corner_dim +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{macro}{\coffin_rotate:Nn, \coffin_rotate:cn} +% Rotating a coffin requires several steps which can be conveniently +% run together. The first step is to convert the angle given in degrees +% to one in radians. This is then used to set \cs{l_@@_sin_fp} and +% \cs{l_@@_cos_fp}, which are carried through unchanged for the rest +% of the procedure. +% \begin{macrocode} +\cs_new_protected:Npn \coffin_rotate:Nn #1#2 + { + \fp_set:Nn \l_@@_sin_fp { sin ( ( #2 ) * deg ) } + \fp_set:Nn \l_@@_cos_fp { cos ( ( #2 ) * deg ) } +% \end{macrocode} +% The corners and poles of the coffin can now be rotated around the +% origin. This is best achieved using mapping functions. +% \begin{macrocode} + \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop } + { \@@_rotate_corner:Nnnn #1 {##1} ##2 } + \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop } + { \@@_rotate_pole:Nnnnnn #1 {##1} ##2 } +% \end{macrocode} +% The bounding box of the coffin needs to be rotated, and to do this +% the corners have to be found first. They are then rotated in the same +% way as the corners of the coffin material itself. +% \begin{macrocode} + \@@_set_bounding:N #1 + \prop_map_inline:Nn \l_@@_bounding_prop + { \@@_rotate_bounding:nnn {##1} ##2 } +% \end{macrocode} +% At this stage, there needs to be a calculation to find where the +% corners of the content and the box itself will end up. +% \begin{macrocode} + \@@_find_corner_maxima:N #1 + \@@_find_bounding_shift: + \box_rotate:Nn #1 {#2} +% \end{macrocode} +% The correction of the box position itself takes place here. The idea +% is that the bounding box for a coffin is tight up to the content, and +% has the reference point at the bottom-left. The $x$-direction is +% handled by moving the content by the difference in the positions of +% the bounding box and the content left edge. The $y$-direction is +% dealt with by moving the box down by any depth it has acquired. +% \begin{macrocode} + \hbox_set:Nn #1 + { + \tex_kern:D \l_@@_bounding_shift_dim + \tex_kern:D -\l_@@_left_corner_dim + \box_move_down:nn { \l_@@_bottom_corner_dim } + { \box_use:N #1 } + } +% \end{macrocode} +% If there have been any previous rotations then the size of the +% bounding box will be bigger than the contents. This can be corrected +% easily by setting the size of the box to the height and width of the +% content. +% \begin{macrocode} + \box_set_ht:Nn #1 + { \l_@@_top_corner_dim - \l_@@_bottom_corner_dim } + \box_set_dp:Nn #1 { 0 pt } + \box_set_wd:Nn #1 + { \l_@@_right_corner_dim - \l_@@_left_corner_dim } +% \end{macrocode} +% The final task is to move the poles and corners such that they are +% back in alignment with the box reference point. +% \begin{macrocode} + \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop } + { \@@_shift_corner:Nnnn #1 {##1} ##2 } + \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop } + { \@@_shift_pole:Nnnnnn #1 {##1} ##2 } + } +\cs_generate_variant:Nn \coffin_rotate:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_set_bounding:N} +% The bounding box corners for a coffin are easy enough to find: this +% is the same code as for the corners of the material itself, but +% using a dedicated property list. +% \begin{macrocode} +\cs_new_protected:Npn \@@_set_bounding:N #1 + { + \prop_put:Nnx \l_@@_bounding_prop { tl } + { { 0 pt } { \dim_use:N \box_ht:N #1 } } + \prop_put:Nnx \l_@@_bounding_prop { tr } + { { \dim_use:N \box_wd:N #1 } { \dim_use:N \box_ht:N #1 } } + \dim_set:Nn \l_@@_internal_dim { - \box_dp:N #1 } + \prop_put:Nnx \l_@@_bounding_prop { bl } + { { 0 pt } { \dim_use:N \l_@@_internal_dim } } + \prop_put:Nnx \l_@@_bounding_prop { br } + { { \dim_use:N \box_wd:N #1 } { \dim_use:N \l_@@_internal_dim } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_rotate_bounding:nnn} +% \begin{macro}{\@@_rotate_corner:Nnnn} +% Rotating the position of the corner of the coffin is just a case +% of treating this as a vector from the reference point. The same +% treatment is used for the corners of the material itself and the +% bounding box. +% \begin{macrocode} +\cs_new_protected:Npn \@@_rotate_bounding:nnn #1#2#3 + { + \@@_rotate_vector:nnNN {#2} {#3} \l_@@_x_dim \l_@@_y_dim + \prop_put:Nnx \l_@@_bounding_prop {#1} + { { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } } + } +\cs_new_protected:Npn \@@_rotate_corner:Nnnn #1#2#3#4 + { + \@@_rotate_vector:nnNN {#3} {#4} \l_@@_x_dim \l_@@_y_dim + \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } {#2} + { { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_rotate_pole:Nnnnnn} +% Rotating a single pole simply means shifting the co-ordinate of +% the pole and its direction. The rotation here is about the bottom-left +% corner of the coffin. +% \begin{macrocode} +\cs_new_protected:Npn \@@_rotate_pole:Nnnnnn #1#2#3#4#5#6 + { + \@@_rotate_vector:nnNN {#3} {#4} \l_@@_x_dim \l_@@_y_dim + \@@_rotate_vector:nnNN {#5} {#6} + \l_@@_x_prime_dim \l_@@_y_prime_dim + \@@_set_pole:Nnx #1 {#2} + { + { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } + { \dim_use:N \l_@@_x_prime_dim } + { \dim_use:N \l_@@_y_prime_dim } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_rotate_vector:nnNN} +% A rotation function, which needs only an input vector (as dimensions) +% and an output space. The values \cs{l_@@_cos_fp} and +% \cs{l_@@_sin_fp} should previously have been set up correctly. +% Working this way means that the floating point work is kept to a +% minimum: for any given rotation the sin and cosine values do no +% change, after all. +% \begin{macrocode} +\cs_new_protected:Npn \@@_rotate_vector:nnNN #1#2#3#4 + { + \dim_set:Nn #3 + { + \fp_to_dim:n + { + \dim_to_fp:n {#1} * \l_@@_cos_fp + - ( \dim_to_fp:n {#2} * \l_@@_sin_fp ) + } + } + \dim_set:Nn #4 + { + \fp_to_dim:n + { + \dim_to_fp:n {#1} * \l_@@_sin_fp + + ( \dim_to_fp:n {#2} * \l_@@_cos_fp ) + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_find_corner_maxima:N} +% \begin{macro}[aux]{\@@_find_corner_maxima_aux:nn} +% The idea here is to find the extremities of the content of the +% coffin. This is done by looking for the smallest values for the bottom +% and left corners, and the largest values for the top and right +% corners. The values start at the maximum dimensions so that the +% case where all are positive or all are negative works out correctly. +% \begin{macrocode} +\cs_new_protected:Npn \@@_find_corner_maxima:N #1 + { + \dim_set:Nn \l_@@_top_corner_dim { -\c_max_dim } + \dim_set:Nn \l_@@_right_corner_dim { -\c_max_dim } + \dim_set:Nn \l_@@_bottom_corner_dim { \c_max_dim } + \dim_set:Nn \l_@@_left_corner_dim { \c_max_dim } + \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop } + { \@@_find_corner_maxima_aux:nn ##2 } + } +\cs_new_protected:Npn \@@_find_corner_maxima_aux:nn #1#2 + { + \dim_set_min:Nn \l_@@_left_corner_dim {#1} + \dim_set_max:Nn \l_@@_right_corner_dim {#1} + \dim_set_min:Nn \l_@@_bottom_corner_dim {#2} + \dim_set_max:Nn \l_@@_top_corner_dim {#2} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_find_bounding_shift:} +% \begin{macro}[aux]{\@@_find_bounding_shift_aux:nn} +% The approach to finding the shift for the bounding box is similar to +% that for the corners. However, there is only one value needed here and +% a fixed input property list, so things are a bit clearer. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_find_bounding_shift: + { + \dim_set:Nn \l_@@_bounding_shift_dim { \c_max_dim } + \prop_map_inline:Nn \l_@@_bounding_prop + { \@@_find_bounding_shift_aux:nn ##2 } + } +\cs_new_protected:Npn \@@_find_bounding_shift_aux:nn #1#2 + { \dim_set_min:Nn \l_@@_bounding_shift_dim {#1} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_shift_corner:Nnnn} +% \begin{macro}{\@@_shift_pole:Nnnnnn} +% Shifting the corners and poles of a coffin means subtracting the +% appropriate values from the $x$- and $y$-components. For +% the poles, this means that the direction vector is unchanged. +% \begin{macrocode} +\cs_new_protected:Npn \@@_shift_corner:Nnnn #1#2#3#4 + { + \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _ prop } {#2} + { + { \dim_eval:n { #3 - \l_@@_left_corner_dim } } + { \dim_eval:n { #4 - \l_@@_bottom_corner_dim } } + } + } +\cs_new_protected:Npn \@@_shift_pole:Nnnnnn #1#2#3#4#5#6 + { + \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _ prop } {#2} + { + { \dim_eval:n { #3 - \l_@@_left_corner_dim } } + { \dim_eval:n { #4 - \l_@@_bottom_corner_dim } } + {#5} {#6} + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Resizing coffins} +% +% \begin{variable}{\l_@@_scale_x_fp} +% \begin{variable}{\l_@@_scale_y_fp} +% Storage for the scaling factors in $x$ and $y$, respectively. +% \begin{macrocode} +\fp_new:N \l_@@_scale_x_fp +\fp_new:N \l_@@_scale_y_fp +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\l_@@_scaled_total_height_dim} +% \begin{variable}{\l_@@_scaled_width_dim} +% When scaling, the values given have to be turned into absolute values. +% \begin{macrocode} +\dim_new:N \l_@@_scaled_total_height_dim +\dim_new:N \l_@@_scaled_width_dim +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{macro}{\coffin_resize:Nnn, \coffin_resize:cnn} +% Resizing a coffin begins by setting up the user-friendly names for +% the dimensions of the coffin box. The new sizes are then turned into +% scale factor. This is the same operation as takes place for the +% underlying box, but that operation is grouped and so the same +% calculation is done here. +% \begin{macrocode} +\cs_new_protected:Npn \coffin_resize:Nnn #1#2#3 + { + \@@_set_user_dimensions:N #1 + \box_resize:Nnn #1 {#2} {#3} + \fp_set:Nn \l_@@_scale_x_fp + { \dim_to_fp:n {#2} / \dim_to_fp:n \Width } + \fp_set:Nn \l_@@_scale_y_fp + { \dim_to_fp:n {#3} / \dim_to_fp:n \TotalHeight } + \@@_resize_common:Nnn #1 {#2} {#3} + } +\cs_generate_variant:Nn \coffin_resize:Nnn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_resize_common:Nnn} +% The poles and corners of the coffin are scaled to the appropriate +% places before actually resizing the underlying box. +% \begin{macrocode} +\cs_new_protected:Npn \@@_resize_common:Nnn #1#2#3 + { + \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop } + { \@@_scale_corner:Nnnn #1 {##1} ##2 } + \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop } + { \@@_scale_pole:Nnnnnn #1 {##1} ##2 } +% \end{macrocode} +% Negative $x$-scaling values will place the poles in the wrong +% location: this is corrected here. +% \begin{macrocode} + \fp_compare:nNnT \l_@@_scale_x_fp < \c_zero_fp + { + \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop } + { \@@_x_shift_corner:Nnnn #1 {##1} ##2 } + \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop } + { \@@_x_shift_pole:Nnnnnn #1 {##1} ##2 } + } + \@@_end_user_dimensions: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\coffin_scale:Nnn, \coffin_scale:cnn} +% For scaling, the opposite calculation is done to find the new +% dimensions for the coffin. Only the total height is needed, as this +% is the shift required for corners and poles. The scaling is done +% the \TeX{} way as this works properly with floating point values +% without needing to use the \texttt{fp} module. +% \begin{macrocode} +\cs_new_protected:Npn \coffin_scale:Nnn #1#2#3 + { + \box_scale:Nnn #1 {#2} {#3} + \@@_set_user_dimensions:N #1 + \fp_set:Nn \l_@@_scale_x_fp {#2} + \fp_set:Nn \l_@@_scale_y_fp {#3} + \fp_compare:nNnTF \l_@@_scale_y_fp > \c_zero_fp + { \l_@@_scaled_total_height_dim #3 \TotalHeight } + { \l_@@_scaled_total_height_dim -#3 \TotalHeight } + \fp_compare:nNnTF \l_@@_scale_x_fp > \c_zero_fp + { \l_@@_scaled_width_dim -#2 \Width } + { \l_@@_scaled_width_dim #2 \Width } + \@@_resize_common:Nnn #1 + { \l_@@_scaled_width_dim } { \l_@@_scaled_total_height_dim } + } +\cs_generate_variant:Nn \coffin_scale:Nnn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_scale_vector:nnNN} +% This functions scales a vector from the origin using the pre-set scale +% factors in $x$ and $y$. This is a much less complex operation +% than rotation, and as a result the code is a lot clearer. +% \begin{macrocode} +\cs_new_protected:Npn \@@_scale_vector:nnNN #1#2#3#4 + { + \dim_set:Nn #3 + { \fp_to_dim:n { \dim_to_fp:n {#1} * \l_@@_scale_x_fp } } + \dim_set:Nn #4 + { \fp_to_dim:n { \dim_to_fp:n {#2} * \l_@@_scale_y_fp } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_scale_corner:Nnnn} +% \begin{macro}{\@@_scale_pole:Nnnnnn} +% Scaling both corners and poles is a simple calculation using the +% preceding vector scaling. +% \begin{macrocode} +\cs_new_protected:Npn \@@_scale_corner:Nnnn #1#2#3#4 + { + \@@_scale_vector:nnNN {#3} {#4} \l_@@_x_dim \l_@@_y_dim + \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } {#2} + { { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } } + } +\cs_new_protected:Npn \@@_scale_pole:Nnnnnn #1#2#3#4#5#6 + { + \@@_scale_vector:nnNN {#3} {#4} \l_@@_x_dim \l_@@_y_dim + \@@_set_pole:Nnx #1 {#2} + { + { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } + {#5} {#6} + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_x_shift_corner:Nnnn} +% \begin{macro}{\@@_x_shift_pole:Nnnnnn} +% These functions correct for the $x$ displacement that takes +% place with a negative horizontal scaling. +% \begin{macrocode} +\cs_new_protected:Npn \@@_x_shift_corner:Nnnn #1#2#3#4 + { + \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } {#2} + { + { \dim_eval:n { #3 + \box_wd:N #1 } } {#4} + } + } +\cs_new_protected:Npn \@@_x_shift_pole:Nnnnnn #1#2#3#4#5#6 + { + \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } {#2} + { + { \dim_eval:n #3 + \box_wd:N #1 } {#4} + {#5} {#6} + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Additions to \pkg{l3file}} +% +% \begin{macrocode} +%<@@=ior> +% \end{macrocode} +% +% \begin{macro}[EXP]{\ior_map_break:, \ior_map_break:n} +% Usual map breaking functions. Those are not yet in \pkg{l3kernel} +% proper since the mapping below is the first of its kind. +% \begin{macrocode} +\cs_new_nopar:Npn \ior_map_break: + { \__prg_map_break:Nn \ior_map_break: { } } +\cs_new_nopar:Npn \ior_map_break:n + { \__prg_map_break:Nn \ior_map_break: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ior_map_inline:Nn, \ior_str_map_inline:Nn} +% \begin{macro}[aux]{\@@_map_inline:NNn} +% \begin{macro}[aux]{\@@_map_inline:NNNn} +% \begin{macro}[aux]{\@@_map_inline_loop:NNN} +% \begin{variable}{\l_@@_internal_tl} +% Mapping to an input stream can be done on either a token or a string +% basis, hence the set up. Within that, there is a check to avoid reading +% past the end of a file, hence the two applications of \cs{ior_if_eof:N}. +% This mapping cannot be nested as the stream has only one \enquote{current +% line}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \ior_map_inline:Nn + { \@@_map_inline:NNn \ior_get:NN } +\cs_new_protected_nopar:Npn \ior_str_map_inline:Nn + { \@@_map_inline:NNn \ior_get_str:NN } +\cs_new_protected_nopar:Npn \@@_map_inline:NNn + { + \int_gincr:N \g__prg_map_int + \exp_args:Nc \@@_map_inline:NNNn + { __prg_map_ \int_use:N \g__prg_map_int :n } + } +\cs_new_protected:Npn \@@_map_inline:NNNn #1#2#3#4 + { + \cs_set:Npn #1 ##1 {#4} + \ior_if_eof:NF #3 { \@@_map_inline_loop:NNN #1#2#3 } + \__prg_break_point:Nn \ior_map_break: + { \int_gdecr:N \g__prg_map_int } + } +\cs_new_protected:Npn \@@_map_inline_loop:NNN #1#2#3 + { + #2 #3 \l_@@_internal_tl + \ior_if_eof:NF #3 + { + \exp_args:No #1 \l_@@_internal_tl + \@@_map_inline_loop:NNN #1#2#3 + } + } +\tl_new:N \l_@@_internal_tl +% \end{macrocode} +% \end{variable} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Additions to \pkg{l3fp}} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \begin{macro} +% { +% \fp_set_from_dim:Nn, \fp_set_from_dim:cn, +% \fp_gset_from_dim:Nn, \fp_gset_from_dim:cn +% } +% Use the appropriate function from \pkg{l3fp-convert}. +% \begin{macrocode} +\cs_new_protected:Npn \fp_set_from_dim:Nn #1#2 + { \tl_set:Nx #1 { \dim_to_fp:n {#2} } } +\cs_new_protected:Npn \fp_gset_from_dim:Nn #1#2 + { \tl_gset:Nx #1 { \dim_to_fp:n {#2} } } +\cs_generate_variant:Nn \fp_set_from_dim:Nn { c } +\cs_generate_variant:Nn \fp_gset_from_dim:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Additions to \pkg{l3prop}} +% +% \begin{macrocode} +%<@@=prop> +% \end{macrocode} +% +% \begin{macro}[rEXP]{\prop_map_tokens:Nn, \prop_map_tokens:cn} +% \begin{macro}[aux]{\@@_map_tokens:nwn} +% The mapping grabs one key--value pair at a time, and stops when +% reaching the marker key \cs{q_recursion_tail}, which +% cannot appear in normal keys since those are strings. The odd +% construction |\use:n {#1}| allows |#1| to contain any token. +% \begin{macrocode} +\cs_new:Npn \prop_map_tokens:Nn #1#2 + { + \exp_last_unbraced:Nno \@@_map_tokens:nwn {#2} #1 + \q_recursion_tail \q__prop { } + \__prg_break_point:Nn \prop_map_break: { } + } +\cs_new:Npn \@@_map_tokens:nwn #1 \q__prop #2 \q__prop #3 + { + \__quark_if_recursion_tail_break:NN #2 \prop_map_break: + \use:n {#1} {#2} {#3} + \@@_map_tokens:nwn {#1} + } +\cs_generate_variant:Nn \prop_map_tokens:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\prop_get:Nn, \prop_get:cn} +% \begin{macro}[aux]{\@@_get_Nn:nwn} +% Getting the value corresponding to a key in a property list in an +% expandable fashion is a simple instance of mapping some tokens. +% Map the function \cs{prop_get:nnn} which takes as its three +% arguments the \meta{key} that we are looking for, the current +% \meta{key} and the current \meta{value}. If the \meta{keys} match, +% the \meta{value} is returned. If none of the keys match, this expands +% to nothing. +% \begin{macrocode} +\cs_new:Npn \prop_get:Nn #1#2 + { + \exp_last_unbraced:Noo \@@_get_Nn:nwn + { \tl_to_str:n {#2} } #1 + \tl_to_str:n {#2} \q__prop { } + \__prg_break_point: + } +\cs_new:Npn \@@_get_Nn:nwn #1 \q__prop #2 \q__prop #3 + { + \str_if_eq_x:nnTF {#1} {#2} + { \__prg_break:n { \exp_not:n {#3} } } + { \@@_get_Nn:nwn {#1} } + } +\cs_generate_variant:Nn \prop_get:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Additions to \pkg{l3seq}} +% +% \begin{macrocode} +%<@@=seq> +% \end{macrocode} +% +% \begin{macro}{\seq_item:Nn, \seq_item:cn} +% \begin{macro}[aux]{\@@_item:nnn} +% The idea here is to find the offset of the item from the left, then use +% a loop to grab the correct item. If the resulting offset is too large, +% then the stop code |{ ? \__prg_break: } { }| will be used by the auxiliary, +% terminating the loop and returning nothing at all. +% \begin{macrocode} +\cs_new:Npn \seq_item:Nn #1#2 + { + \exp_last_unbraced:Nfo \@@_item:nnn + { + \int_eval:n + { + \int_compare:nNnT {#2} < \c_zero + { \seq_count:N #1 + \c_one + } + #2 + } + } + #1 + { ? \__prg_break: } + { } + \__prg_break_point: + } +\cs_new:Npn \@@_item:nnn #1#2#3 + { + \use_none:n #2 + \int_compare:nNnTF {#1} = \c_one + { \__prg_break:n { \exp_not:n {#3} } } + { \exp_args:Nf \@@_item:nnn { \int_eval:n { #1 - 1 } } } + } +\cs_generate_variant:Nn \seq_item:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \seq_mapthread_function:NNN, \seq_mapthread_function:NcN, +% \seq_mapthread_function:cNN, \seq_mapthread_function:ccN +% } +% \begin{macro}[aux]{\@@_mapthread_function:NN} +% \begin{macro}[aux]{\@@_mapthread_function:Nnnwnn} +% The idea here is to first expand both of the sequences, adding the usual +% |{ ? \__prg_break: } { }| to the end of each one. This is most conveniently +% done in two steps using an auxiliary function. The mapping then throws +% away the first token of |#2| and |#5|, which for items in the sequences +% will both be \cs{@@_item:n}. The function to be mapped will then be +% applied to the two entries. When the code hits the end of one of the +% sequences, the break material will stop the entire loop and tidy up. This +% avoids needing to find the count of the two sequences, or worrying about +% which is longer. +% \begin{macrocode} +\cs_new:Npn \seq_mapthread_function:NNN #1#2#3 + { + \exp_after:wN \@@_mapthread_function:NN + \exp_after:wN #3 + \exp_after:wN #1 + #2 + { ? \__prg_break: } { } + \__prg_break_point: + } +\cs_new:Npn \@@_mapthread_function:NN #1#2 + { + \exp_after:wN \@@_mapthread_function:Nnnwnn + \exp_after:wN #1 + #2 + { ? \__prg_break: } { } + \q_stop + } +\cs_new:Npn \@@_mapthread_function:Nnnwnn #1#2#3#4 \q_stop #5#6 + { + \use_none:n #2 + \use_none:n #5 + #1 {#3} {#6} + \@@_mapthread_function:Nnnwnn #1 #4 \q_stop + } +\cs_generate_variant:Nn \seq_mapthread_function:NNN { Nc } +\cs_generate_variant:Nn \seq_mapthread_function:NNN { c , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \seq_set_from_clist:NN, \seq_set_from_clist:cN, +% \seq_set_from_clist:Nc, \seq_set_from_clist:cc, +% \seq_set_from_clist:Nn, \seq_set_from_clist:cn +% } +% \begin{macro} +% { +% \seq_gset_from_clist:NN, \seq_gset_from_clist:cN, +% \seq_gset_from_clist:Nc, \seq_gset_from_clist:cc, +% \seq_gset_from_clist:Nn, \seq_gset_from_clist:cn +% } +% Setting a sequence from a comma-separated list is done using a simple +% mapping. +% \begin{macrocode} +\cs_new_protected:Npn \seq_set_from_clist:NN #1#2 + { + \tl_set:Nx #1 + { \clist_map_function:NN #2 \@@_wrap_item:n } + } +\cs_new_protected:Npn \seq_set_from_clist:Nn #1#2 + { + \tl_set:Nx #1 + { \clist_map_function:nN {#2} \@@_wrap_item:n } + } +\cs_new_protected:Npn \seq_gset_from_clist:NN #1#2 + { + \tl_gset:Nx #1 + { \clist_map_function:NN #2 \@@_wrap_item:n } + } +\cs_new_protected:Npn \seq_gset_from_clist:Nn #1#2 + { + \tl_gset:Nx #1 + { \clist_map_function:nN {#2} \@@_wrap_item:n } + } +\cs_generate_variant:Nn \seq_set_from_clist:NN { Nc } +\cs_generate_variant:Nn \seq_set_from_clist:NN { c , cc } +\cs_generate_variant:Nn \seq_set_from_clist:Nn { c } +\cs_generate_variant:Nn \seq_gset_from_clist:NN { Nc } +\cs_generate_variant:Nn \seq_gset_from_clist:NN { c , cc } +\cs_generate_variant:Nn \seq_gset_from_clist:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\seq_reverse:N, \seq_reverse:c, \seq_greverse:N, \seq_greverse:c} +% \begin{macro}[aux]{\@@_tmp:w} +% \begin{macro}[aux]{\@@_reverse:NN} +% \begin{macro}[aux]{\@@_reverse_item:nwn} +% Previously, \cs{seq_reverse:N} was coded by collecting the items +% in reverse order after an \cs{exp_stop_f:} marker. +% \begin{verbatim} +% \cs_new_protected:Npn \seq_reverse:N #1 +% { +% \cs_set_eq:NN \@@_item:n \@@_reverse_item:nw +% \tl_set:Nf #2 { #2 \exp_stop_f: } +% } +% \cs_new:Npn \@@_reverse_item:nw #1 #2 \exp_stop_f: +% { +% #2 \exp_stop_f: +% \@@_item:n {#1} +% } +% \end{verbatim} +% At first, this seems optimal, since we can forget about each item +% as soon as it is placed after \cs{exp_stop_f:}. Unfortunately, +% \TeX{}'s usual tail recursion does not take place in this case: +% since the following \cs{@@_reverse_item:nw} only reads +% tokens until \cs{exp_stop_f:}, and never reads the +% |\@@_item:n {#1}| left by the previous call, \TeX{} cannot +% remove that previous call from the stack, and in particular +% must retain the various macro parameters in memory, until the +% end of the replacement text is reached. The stack is thus +% only flushed after all the \cs{@@_reverse_item:nw} are +% expanded. Keeping track of the arguments of all those calls +% uses up a memory quadratic in the length of the sequence. +% \TeX{} can then not cope with more than a few thousand items. +% +% Instead, we collect the items in the argument +% of \cs{exp_not:n}. The previous calls are cleanly removed +% from the stack, and the memory consumption becomes linear. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_tmp:w { } +\cs_new_protected_nopar:Npn \seq_reverse:N + { \@@_reverse:NN \tl_set:Nx } +\cs_new_protected_nopar:Npn \seq_greverse:N + { \@@_reverse:NN \tl_gset:Nx } +\cs_new_protected:Npn \@@_reverse:NN #1 #2 + { + \cs_set_eq:NN \@@_tmp:w \@@_item:n + \cs_set_eq:NN \@@_item:n \@@_reverse_item:nwn + #1 #2 { #2 \exp_not:n { } } + \cs_set_eq:NN \@@_item:n \@@_tmp:w + } +\cs_new:Npn \@@_reverse_item:nwn #1 #2 \exp_not:n #3 + { + #2 + \exp_not:n { \@@_item:n {#1} #3 } + } +\cs_generate_variant:Nn \seq_reverse:N { c } +\cs_generate_variant:Nn \seq_greverse:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_set_filter:NNn, \seq_gset_filter:NNn} +% \begin{macro}[aux]{\@@_set_filter:NNNn} +% Similar to \cs{seq_map_inline:Nn}, without a +% \cs{__prg_break_point:} because the user's code +% is performed within the evaluation of a boolean expression, +% and skipping out of that would break horribly. +% The \cs{@@_wrap_item:n} function inserts the relevant +% \cs{@@_item:n} without expansion in the input stream, +% hence in the \texttt{x}-expanding assignment. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \seq_set_filter:NNn + { \@@_set_filter:NNNn \tl_set:Nx } +\cs_new_protected_nopar:Npn \seq_gset_filter:NNn + { \@@_set_filter:NNNn \tl_gset:Nx } +\cs_new_protected:Npn \@@_set_filter:NNNn #1#2#3#4 + { + \@@_push_item_def:n { \bool_if:nT {#4} { \@@_wrap_item:n {##1} } } + #1 #2 { #3 } + \@@_pop_item_def: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_set_map:NNn,\seq_gset_map:NNn} +% \begin{macro}[aux]{\@@_set_map:NNNn} +% Very similar to \cs{seq_set_filter:NNn}. We could actually +% merge the two within a single function, but it would have weird +% semantics. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \seq_set_map:NNn + { \@@_set_map:NNNn \tl_set:Nx } +\cs_new_protected_nopar:Npn \seq_gset_map:NNn + { \@@_set_map:NNNn \tl_gset:Nx } +\cs_new_protected:Npn \@@_set_map:NNNn #1#2#3#4 + { + \@@_push_item_def:n { \exp_not:N \@@_item:n {#4} } + #1 #2 { #3 } + \@@_pop_item_def: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\seq_use:Nnnn} +% \begin{macro}[EXP, aux] +% {\@@_use:NnNnn, \@@_use_ii:nwwwwnwn, \@@_use_iii:nwwn} +% See \cs{clist_use:Nnnn} for a general explanation. The main +% difference is that we use \cs{@@_item:n} as a delimiter rather than +% commas. We also need to add \cs{@@_item:n} at various places. +% \begin{macrocode} +\cs_new:Npn \seq_use:Nnnn #1#2#3#4 + { + \seq_if_exist:NTF #1 + { + \int_case:nnn { \seq_count:N #1 } + { + { 0 } { } + { 1 } { \exp_after:wN \@@_use:NnNnn #1 \@@_item:n { } { } } + { 2 } { \exp_after:wN \@@_use:NnNnn #1 {#2} } + } + { + \exp_after:wN \@@_use_ii:nwwwwnwn + \exp_after:wN { \exp_after:wN } #1 \@@_item:n + \q_mark { \@@_use_ii:nwwwwnwn {#3} } + \q_mark { \@@_use_iii:nwwn {#4} } + \q_stop { } + } + } + { \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#1} } + } +\cs_new:Npn \@@_use:NnNnn \@@_item:n #1 \@@_item:n #2#3 + { \exp_not:n { #1 #3 #2 } } +\cs_new:Npn \@@_use_ii:nwwwwnwn + #1 \@@_item:n #2 \@@_item:n #3 \@@_item:n #4#5 + \q_mark #6#7 \q_stop #8 + { + #6 \@@_item:n {#3} \@@_item:n {#4} #5 + \q_mark {#6} #7 \q_stop { #8 #1 #2 } + } +\cs_new:Npn \@@_use_iii:nwwn #1 \@@_item:n #2 #3 \q_stop #4 + { \exp_not:n { #4 #1 #2 } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Additions to \pkg{l3skip}} +% +% \begin{macrocode} +%<@@=skip> +% \end{macrocode} +% +% \begin{macro}{\skip_split_finite_else_action:nnNN} +% This macro is useful when performing error checking in certain +% circumstances. If the \meta{skip} register holds finite glue it sets +% |#3| and |#4| to the stretch and shrink component, resp. If it holds +% infinite glue set |#3| and |#4| to zero and issue the special action +% |#2| which is probably an error message. +% Assignments are local. +% \begin{macrocode} +\cs_new:Npn \skip_split_finite_else_action:nnNN #1#2#3#4 + { + \skip_if_finite:nTF {#1} + { + #3 = \etex_gluestretch:D #1 \scan_stop: + #4 = \etex_glueshrink:D #1 \scan_stop: + } + { + #3 = \c_zero_skip + #4 = \c_zero_skip + #2 + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Additions to \pkg{l3tl}} +% +% \begin{macrocode} +%<@@=tl> +% \end{macrocode} +% +% \begin{macro}[EXP,pTF]{\tl_if_single_token:n} +% There are four cases: empty token list, token list starting with +% a normal token, with a brace group, or with a space token. +% If the token list starts with a normal token, remove it +% and check for emptyness. Otherwise, compare with a single +% space, only case where we have a single token. +% \begin{macrocode} +\prg_new_conditional:Npnn \tl_if_single_token:n #1 { p , T , F , TF } + { + \tl_if_head_is_N_type:nTF {#1} + { \__str_if_eq_x_return:nn { \exp_not:o { \use_none:n #1 } } { } } + { \__str_if_eq_x_return:nn { \exp_not:n {#1} } { ~ } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\tl_reverse_tokens:n} +% \begin{macro}[EXP,aux]{\@@_reverse_group:nn} +% The same as \cs{tl_reverse:n} but with recursion within brace groups. +% \begin{macrocode} +\cs_new:Npn \tl_reverse_tokens:n #1 + { + \etex_unexpanded:D \exp_after:wN + { + \tex_romannumeral:D + \@@_act:NNNnn + \@@_reverse_normal:nN + \@@_reverse_group:nn + \@@_reverse_space:n + { } + {#1} + } + } +\cs_new:Npn \@@_reverse_group:nn #1 + { + \@@_act_group_recurse:Nnn + \@@_act_reverse_output:n + { \tl_reverse_tokens:n } + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[EXP,aux]{\@@_act_group_recurse:Nnn} +% In many applications of \cs{@@_act:NNNnn}, we need to recursively +% apply some transformation within brace groups, then output. In this +% code, |#1| is the output function, |#2| is the transformation, +% which should expand in two steps, and |#3| is the group. +% \begin{macrocode} +\cs_new:Npn \@@_act_group_recurse:Nnn #1#2#3 + { + \exp_args:Nf #1 + { \exp_after:wN \exp_after:wN \exp_after:wN { #2 {#3} } } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\tl_count_tokens:n} +% \begin{macro}[EXP,aux]{\@@_act_count_normal:nN, +% \@@_act_count_group:nn,\@@_act_count_space:n} +% The token coung is computed through an \cs{int_eval:n} construction. +% Each \texttt{1+} is output to the \emph{left}, into the integer +% expression, and the sum is ended by the \cs{c_zero} inserted by +% \cs{@@_act_end:wn}. Somewhat a hack. +% \begin{macrocode} +\cs_new:Npn \tl_count_tokens:n #1 + { + \int_eval:n + { + \@@_act:NNNnn + \@@_act_count_normal:nN + \@@_act_count_group:nn + \@@_act_count_space:n + { } + {#1} + } + } +\cs_new:Npn \@@_act_count_normal:nN #1 #2 { 1 + } +\cs_new:Npn \@@_act_count_space:n #1 { 1 + } +\cs_new:Npn \@@_act_count_group:nn #1 #2 + { 2 + \tl_count_tokens:n {#2} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{variable}{\c_@@_act_uppercase_tl, \c_@@_act_lowercase_tl} +% These constants contain the correspondance between lowercase +% and uppercase letters, in the form |aAbBcC...| and |AaBbCc...| +% respectively. +% \begin{macrocode} +\tl_const:Nn \c_@@_act_uppercase_tl + { + aA bB cC dD eE fF gG hH iI jJ kK lL mM + nN oO pP qQ rR sS tT uU vV wW xX yY zZ + } +\tl_const:Nn \c_@@_act_lowercase_tl + { + Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm + Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz + } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[EXP]{\tl_expandable_uppercase:n,\tl_expandable_lowercase:n} +% \begin{macro}[EXP,aux]{\@@_act_case_normal:nN, +% \@@_act_case_group:nn,\@@_act_case_space:n} +% The only difference between uppercasing and lowercasing is +% the table of correspondance that is used. As for other +% token list actions, we feed \cs{@@_act:NNNnn} three +% functions, and this time, we use the \meta{parameters} +% argument to carry which case-changing we are applying. +% A space is simply output. A normal token is compared +% to each letter in the alphabet using \cs{str_if_eq:nn} +% tests, and converted if necessary to upper/lowercase, +% before being output. For a group, we must perform the +% conversion within the group (the \cs{exp_after:wN} trigger +% \tn{romannumeral}, which expands fully to give the +% converted group), then output. +% \begin{macrocode} +\cs_new:Npn \tl_expandable_uppercase:n #1 + { + \etex_unexpanded:D \exp_after:wN + { + \tex_romannumeral:D + \@@_act_case_aux:nn { \c_@@_act_uppercase_tl } {#1} + } + } +\cs_new:Npn \tl_expandable_lowercase:n #1 + { + \etex_unexpanded:D \exp_after:wN + { + \tex_romannumeral:D + \@@_act_case_aux:nn { \c_@@_act_lowercase_tl } {#1} + } + } +\cs_new:Npn \@@_act_case_aux:nn + { + \@@_act:NNNnn + \@@_act_case_normal:nN + \@@_act_case_group:nn + \@@_act_case_space:n + } +\cs_new:Npn \@@_act_case_space:n #1 { \@@_act_output:n {~} } +\cs_new:Npn \@@_act_case_normal:nN #1 #2 + { + \exp_args:Nf \@@_act_output:n + { + \exp_args:NNo \str_case:nnn #2 {#1} + { \exp_stop_f: #2 } + } + } +\cs_new:Npn \@@_act_case_group:nn #1 #2 + { + \exp_after:wN \@@_act_output:n \exp_after:wN + { \exp_after:wN { \tex_romannumeral:D \@@_act_case_aux:nn {#1} {#2} } } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_item:nn, \tl_item:Nn, \tl_item:cn} +% \begin{macro}[aux]{\@@_item:nn} +% The idea here is to find the offset of the item from the left, then use +% a loop to grab the correct item. If the resulting offset is too large, +% then \cs{quark_if_recursion_tail_stop:n} terminates the loop, and returns +% nothing at all. +% \begin{macrocode} +\cs_new:Npn \tl_item:nn #1#2 + { + \exp_args:Nf \@@_item:nn + { + \int_eval:n + { + \int_compare:nNnT {#2} < \c_zero + { \tl_count:n {#1} + \c_one + } + #2 + } + } + #1 + \q_recursion_tail + \__prg_break_point: + } +\cs_new:Npn \@@_item:nn #1#2 + { + \__quark_if_recursion_tail_break:nN {#2} \__prg_break: + \int_compare:nNnTF {#1} = \c_one + { \__prg_break:n { \exp_not:n {#2} } } + { \exp_args:Nf \@@_item:nn { \int_eval:n { #1 - 1 } } } + } +\cs_new_nopar:Npn \tl_item:Nn { \exp_args:No \tl_item:nn } +\cs_generate_variant:Nn \tl_item:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Additions to \pkg{l3tokens}} +% +% \begin{macrocode} +%<@@=char> +% \end{macrocode} +% +% \begin{macro}{\char_set_active:Npn,\char_set_active:Npx} +% \begin{macro}{\char_gset_active:Npn,\char_gset_active:Npx} +% \begin{macro}{\char_set_active_eq:NN,\char_gset_active_eq:NN} +% \begin{macrocode} +\group_begin: + \char_set_catcode_active:N \^^@ + \cs_set:Npn \char_tmp:NN #1#2 + { + \cs_new:Npn #1 ##1 + { + \char_set_catcode_active:n { `##1 } + \group_begin: + \char_set_lccode:nn { `\^^@ } { `##1 } + \tl_to_lowercase:n { \group_end: #2 ^^@ } + } + } + \char_tmp:NN \char_set_active:Npn \cs_set:Npn + \char_tmp:NN \char_set_active:Npx \cs_set:Npx + \char_tmp:NN \char_gset_active:Npn \cs_gset:Npn + \char_tmp:NN \char_gset_active:Npx \cs_gset:Npx + \char_tmp:NN \char_set_active_eq:NN \cs_set_eq:NN + \char_tmp:NN \char_gset_active_eq:NN \cs_gset_eq:NN +\group_end: +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%<@@=peek> +% \end{macrocode} +% +% \begin{macro}[TF]{\peek_N_type:} +% \begin{macro}{\@@_execute_branches_N_type:} +% The next token is normal if it is neither a begin-group token, +% nor an end-group token, nor a charcode-$32$ space token. +% Note that implicit begin-group tokens, end-group tokens, and +% spaces are also recognized as non-\texttt{N}-type. +% Here, there is no \meta{search token}, so we feed a dummy +% \cs{scan_stop:} to the \cs{peek_token_generic::NN} functions. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_execute_branches_N_type: + { + \bool_if:nTF + { + \token_if_eq_catcode_p:NN \l_peek_token \c_group_begin_token || + \token_if_eq_catcode_p:NN \l_peek_token \c_group_end_token || + \token_if_eq_meaning_p:NN \l_peek_token \c_space_token + } + { \@@_false:w } + { \@@_true:w } + } +\cs_new_protected_nopar:Npn \peek_N_type:TF + { \@@_token_generic:NNTF \@@_execute_branches_N_type: \scan_stop: } +\cs_new_protected_nopar:Npn \peek_N_type:T + { \@@_token_generic:NNT \@@_execute_branches_N_type: \scan_stop: } +\cs_new_protected_nopar:Npn \peek_N_type:F + { \@@_token_generic:NNF \@@_execute_branches_N_type: \scan_stop: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx index 31a429e61ef..5fbb63f89d9 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx @@ -37,8 +37,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3clist.dtx 3490 2012-03-04 01:00:53Z bruno $ - {L3 Experimental comma separated lists} +\GetIdInfo$Id: l3clist.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Comma separated lists} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -88,7 +88,9 @@ % \end{verbatim} % will leave \texttt{true} in the input stream. To include an item % which contains a comma, or starts or ends with a space, -% surround it with braces. +% surround it with braces. The sequence data type should be preferred +% to comma lists if items are to contain |{|, |}|, or |#| (assuming the +% usual \TeX{} category codes apply). % % \section{Creating and initialising comma lists} % @@ -118,7 +120,7 @@ % \cs{clist_clear_new:N} \meta{comma list} % \end{syntax} % Ensures that the \meta{comma list} exists globally by applying -% \cs{clsit_new:N} if necessary, then applies \cs{clist_(g)clear:N} to leave +% \cs{clist_new:N} if necessary, then applies \cs{clist_(g)clear:N} to leave % the list empty. % \end{function} % @@ -130,10 +132,10 @@ % \clist_gset_eq:Nc, \clist_gset_eq:cc % } % \begin{syntax} -% \cs{clist_set_eq:NN} \meta{comma list1} \meta{comma list2} +% \cs{clist_set_eq:NN} \meta{comma list_1} \meta{comma list_2} % \end{syntax} -% Sets the content of \meta{comma list1} equal to that of -% \meta{comma list2}. +% Sets the content of \meta{comma list_1} equal to that of +% \meta{comma list_2}. % \end{function} % % \begin{function} @@ -142,11 +144,11 @@ % \clist_gconcat:NNN, \clist_gconcat:ccc % } % \begin{syntax} -% \cs{clist_concat:NNN} \meta{comma list1} \meta{comma list2} \meta{comma list3} +% \cs{clist_concat:NNN} \meta{comma list_1} \meta{comma list_2} \meta{comma list_3} % \end{syntax} -% Concatenates the content of \meta{comma list2} and \meta{comma list3} -% together and saves the result in \meta{comma list1}. The items in -% \meta{comma list2} will be placed at the left side of the new comma list. +% Concatenates the content of \meta{comma list_2} and \meta{comma list_3} +% together and saves the result in \meta{comma list_1}. The items in +% \meta{comma list_2} will be placed at the left side of the new comma list. % \end{function} % % \begin{function}[EXP, pTF, added=2012-03-03] @@ -173,7 +175,7 @@ % \clist_gset:co, \clist_gset:cx % } % \begin{syntax} -% \cs{clist_set:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}| +% \cs{clist_set:Nn} \meta{comma list} |{|\meta{item_1},\ldots{},\meta{item_n}|}| % \end{syntax} % Sets \meta{comma list} to contain the \meta{items}, % removing any previous content from the variable. @@ -192,7 +194,7 @@ % \clist_gput_left:co, \clist_gput_left:cx % } % \begin{syntax} -% \cs{clist_put_left:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}| +% \cs{clist_put_left:Nn} \meta{comma list} |{|\meta{item_1},\ldots{},\meta{item_n}|}| % \end{syntax} % Appends the \meta{items} to the left of the \meta{comma list}. % Spaces are removed from both sides of each item. @@ -210,22 +212,12 @@ % \clist_gput_right:co, \clist_gput_right:cx % } % \begin{syntax} -% \cs{clist_put_right:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}| +% \cs{clist_put_right:Nn} \meta{comma list} |{|\meta{item_1},\ldots{},\meta{item_n}|}| % \end{syntax} % Appends the \meta{items} to the right of the \meta{comma list}. % Spaces are removed from both sides of each item. % \end{function} % -% \section{Using comma lists} -% -% \begin{function}[EXP]{\clist_use:N, \clist_use:c} -% \begin{syntax} -% \cs{clist_use:N} \meta{comma list} -% \end{syntax} -% Places the \meta{comma list} directly into the input stream, -% including the commas, thus treating it as a \meta{token list}. -% \end{function} -% % \section{Modifying comma lists} % % While comma lists are normally used as ordered lists, it may be @@ -281,17 +273,6 @@ % Tests if the \meta{comma list} is empty (containing no items). % \end{function} % -% \begin{function}[EXP,pTF] -% {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc} -% \begin{syntax} -% \cs{clist_if_eq_p:NN} \meta{clist_1} \meta{clist_2} -% \cs{clist_if_eq:NNTF} \meta{clist_1} \meta{clist_2} \Arg{true code} \Arg{false code} -% \end{syntax} -% Compares the content of two \meta{comma lists} and -% is logically \texttt{true} if the two contain the same list of -% entries in the same order. -% \end{function} -% % \begin{function}[updated = 2011-09-06, TF] % { % \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, @@ -326,16 +307,16 @@ % If the result of trimming spaces is empty, the item is ignored. % Otherwise, if the item is surrounded by braces, one set is removed, % and the result is passed to the mapped function. Thus, if your -% comma list that is being mapped is \verb*|{a , {b }, ,{}, {c},}| +% comma list that is being mapped is \verb*|{a , {{b} }, ,{}, {c},}| % then the arguments passed to the mapped function are -% `\verb*|a|', `\verb*|{b }|', an empty argument, and `\verb*|c|'. +% `\verb*|a|', `\verb*|{b} |', an empty argument, and `\verb*|c|'. % % When the comma list is given as an \texttt{N}-type argument, spaces % have already been trimmed on input, and items are simply stripped % of one set of braces if any. This case is more efficient than using % \texttt{n}-type comma lists. % -% \begin{function}[rEXP] +% \begin{function}[rEXP, updated = 2012-06-29] % {\clist_map_function:NN, \clist_map_function:cN, \clist_map_function:nN} % \begin{syntax} % \cs{clist_map_function:NN} \meta{comma list} \meta{function} @@ -348,7 +329,7 @@ % One mapping may be nested inside another. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-06-29] % {\clist_map_inline:Nn, \clist_map_inline:cn, \clist_map_inline:nn} % \begin{syntax} % \cs{clist_map_inline:Nn} \meta{comma list} \Arg{inline function} @@ -360,7 +341,7 @@ % are returned from left to right. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-06-29] % {\clist_map_variable:NNn, \clist_map_variable:cNn, \clist_map_variable:nNn} % \begin{syntax} % \cs{clist_map_variable:NNn} \meta{comma list} \meta{tl~var.} \Arg{function using tl~var.} @@ -373,7 +354,7 @@ % are returned from left to right. % \end{function} % -% \begin{function}[rEXP]{\clist_map_break:} +% \begin{function}[rEXP, updated = 2012-06-29]{\clist_map_break:} % \begin{syntax} % \cs{clist_map_break:} % \end{syntax} @@ -394,13 +375,13 @@ % level \TeX{} errors. % \begin{texnote} % When the mapping is broken, additional tokens may be inserted by the -% internal macro \cs{prg_break_point:n} before further items are taken +% internal macro \cs{__prg_break_point:Nn} before further items are taken % from the input stream. This will depend on the design of the mapping % function. % \end{texnote} % \end{function} % -% \begin{function}[rEXP]{\clist_map_break:n} +% \begin{function}[updated = 2012-06-29, rEXP]{\clist_map_break:n} % \begin{syntax} % \cs{clist_map_break:n} \Arg{tokens} % \end{syntax} @@ -422,12 +403,23 @@ % level \TeX{} errors. % \begin{texnote} % When the mapping is broken, additional tokens may be inserted by the -% internal macro \cs{prg_break_point:n} before the \meta{tokens} are +% internal macro \cs{__prg_break_point:Nn} before the \meta{tokens} are % inserted into the input stream. % This will depend on the design of the mapping function. % \end{texnote} % \end{function} % +% \begin{function}[EXP, added = 2012-07-13] +% {\clist_count:N, \clist_count:c, \clist_count:n} +% \begin{syntax} +% \cs{clist_count:N} \meta{comma list} +% \end{syntax} +% Leaves the number of items in the \meta{comma list} in the input +% stream as an \meta{integer denotation}. The total number of items +% in a \meta{comma list} will include those which are duplicates, +% \emph{i.e.}~every item in a \meta{comma list} is unique. +% \end{function} +% % \section{Comma lists as stacks} % % Comma lists can be used as stacks, where data is pushed to and popped @@ -437,22 +429,28 @@ % in the previous section: a comma list should either be used as an % ordered data type or as a stack, but not in both ways. % -% \begin{function}{\clist_get:NN, \clist_get:cN} +% \begin{function}[updated = 2012-05-14]{\clist_get:NN, \clist_get:cN} % \begin{syntax} % \cs{clist_get:NN} \meta{comma list} \meta{token list variable} % \end{syntax} % Stores the left-most item from a \meta{comma list} in the % \meta{token list variable} without removing it from the % \meta{comma list}. The \meta{token list variable} is assigned locally. +% If the \meta{comma list} is empty the \meta{token list variable} will +% contain the marker value \cs{q_no_value}. % \end{function} % -% \begin{function}{\clist_get:NN, \clist_get:cN} +% \begin{function}[TF, added = 2012-05-14]{\clist_get:NN, \clist_get:cN} % \begin{syntax} -% \cs{clist_get:NN} \meta{comma list} \meta{token list variable} +% \cs{clist_get:NNTF} \meta{comma list} \meta{token list variable} \Arg{true code} \Arg{false code} % \end{syntax} -% Stores the right-most item from a \meta{comma list} in the -% \meta{token list variable} without removing it from the -% \meta{comma list}. The \meta{token list variable} is assigned locally. +% If the \meta{comma list} is empty, leaves the \meta{false code} in the +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{comma list} is non-empty, stores the top item from the +% \meta{comma list} in the \meta{token list variable} without removing it +% from the \meta{comma list}. The \meta{token list variable} is assigned +% locally. % \end{function} % % \begin{function}[updated = 2011-09-06]{\clist_pop:NN, \clist_pop:cN} @@ -476,6 +474,32 @@ % the \meta{token list variable} is local. % \end{function} % +% \begin{function}[TF, added = 2012-05-14]{\clist_pop:NN, \clist_pop:cN} +% \begin{syntax} +% \cs{clist_pop:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{comma list} is empty, leaves the \meta{false code} in the +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{comma list} is non-empty, pops the top item from the +% \meta{comma list} in the \meta{token list variable}, \emph{i.e.}~removes +% the item from the \meta{comma list}. Both the \meta{comma list} and the +% \meta{token list variable} are assigned locally. +% \end{function} +% +% \begin{function}[TF, added = 2012-05-14]{\clist_gpop:NN, \clist_gpop:cN} +% \begin{syntax} +% \cs{clist_gpop:NNTF} \meta{comma list} \meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{comma list} is empty, leaves the \meta{false code} in the +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{comma list} is non-empty, pops the top item from the +% \meta{comma list} in the \meta{token list variable}, \emph{i.e.}~removes +% the item from the \meta{comma list}. The \meta{comma list} is modified +% globally, while the \meta{token list variable} is assigned locally. +% \end{function} +% % \begin{function} % { % \clist_push:Nn, \clist_push:NV, \clist_push:No, \clist_push:Nx, @@ -506,7 +530,11 @@ % Displays the entries in the comma list in the terminal. % \end{function} % -% \section{Scratch comma lists} +% \section{Constant and scratch comma lists} +% +% \begin{variable}[added = 2012-07-02]{\c_empty_clist} +% Constant that is always empty. +% \end{variable} % % \begin{variable}[added = 2011-09-06]{\l_tmpa_clist, \l_tmpb_clist} % Scratch comma lists for local assignment. These are never used by @@ -522,97 +550,6 @@ % code and so should only be used for short-term storage. % \end{variable} % -% \section{Experimental comma list functions} -% -% This section contains functions which may or may not be retained, depending -% on how useful they are found to be. -% -% \begin{function}[added = 2011-06-25, updated = 2011-09-06, EXP] -% {\clist_length:N, \clist_length:c, \clist_length:n} -% \begin{syntax} -% \cs{clist_length:N} \meta{comma list} -% \end{syntax} -% Leaves the number of items in the \meta{comma list} in the input -% stream as an \meta{integer denotation}. The total number of items -% in a \meta{comma list} will include those which are duplicates, -% \emph{i.e.}~every item in a \meta{comma list} is unique. -% \end{function} -% -% \begin{function}[updated = 2012-01-08, EXP] -% {\clist_item:Nn, \clist_item:cn, \clist_item:nn} -% \begin{syntax} -% \cs{clist_item:Nn} \meta{comma list} \Arg{integer expression} -% \end{syntax} -% Indexing items in the \meta{comma list} from $0$ at the top (left), this -% function will evaluate the \meta{integer expression} and leave the -% appropriate item from the comma list in the input stream. If the -% \meta{integer expression} is negative, indexing occurs from the -% bottom (right) of the comma list. When the \meta{integer expression} -% is larger than the number of items in the \meta{comma list} (as -% calculated by \cs{clist_length:N}) then the function will expand to -% nothing. -% \begin{texnote} -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the \meta{item} -% will not expand further when appearing in an x-type -% argument expansion. -% \end{texnote} -% \end{function} -% -% \begin{function}[updated = 2011-08-31] -% { -% \clist_set_from_seq:NN, \clist_set_from_seq:cN, -% \clist_set_from_seq:Nc, \clist_set_from_seq:cc, -% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, -% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc -% } -% \begin{syntax} -% \cs{clist_set_from_seq:NN} \meta{comma list} \meta{sequence} -% \end{syntax} -% Sets the \meta{comma list} to be equal to the content of the -% \meta{sequence}. -% Items which contain either spaces or commas are surrounded by braces. -% \end{function} -% -% \begin{function}[added = 2011-11-26] -% { -% \clist_const:Nn, \clist_const:Nx, -% \clist_const:cn, \clist_const:cx -% } -% \begin{syntax} -% \cs{clist_const:Nn} \meta{clist~var} \Arg{comma list} -% \end{syntax} -% Creates a new constant \meta{clist~var} or raises an error -% if the name is already taken. The value of the -% \meta{clist~var} will be set globally to the -% \meta{comma list}. -% \end{function} -% -% \begin{function}[EXP, pTF, added = 2011-12-07]{\clist_if_empty:n} -% \begin{syntax} -% \cs{clist_if_empty_p:n} \Arg{comma list} -% \cs{clist_if_empty:nTF} \Arg{comma list} \Arg{true code} \Arg{false code} -% \end{syntax} -% Tests if the \meta{comma list} is empty (containing no items). -% The rules for space trimming are as for other \texttt{n}-type -% comma-list functions, hence the comma list |{~,~,,~}| (without -% outer braces) is empty, while |{~,{},}| (without outer braces) -% contains one element, which happens to be empty: the comma-list -% is not empty. -% \end{function} -% -% \section{Internal comma-list functions} -% -% \begin{function}[added = 2011-07-09, rEXP]{\clist_trim_spaces:n} -% \begin{syntax} -% \cs{clist_trim_spaces:n} \Arg{comma list} -% \end{syntax} -% Removes leading and trailing spaces from each \meta{item} in the -% \meta{comma list}, leaving the resulting modified list in the -% input stream. This is used by the functions which add data -% into a comma list. -% \end{function} -% % \end{documentation} % % \begin{implementation} @@ -626,25 +563,36 @@ % \end{macrocode} % % \begin{macrocode} +%<@@=clist> +% \end{macrocode} +% +% \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % -% \begin{variable}{\l_clist_internal_clist} +% \begin{variable}{\c_empty_clist} +% An empty comma list is simply an empty token list. +% \begin{macrocode} +\cs_new_eq:NN \c_empty_clist \c_empty_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_internal_clist} % Scratch space for various internal uses. This comma list variable % cannot be declared as such because it comes before \cs{clist_new:N} % \begin{macrocode} -\tl_new:N \l_clist_internal_clist +\tl_new:N \l_@@_internal_clist % \end{macrocode} % \end{variable} % -% \begin{macro}[aux]{\clist_tmp:w} +% \begin{macro}[aux]{\@@_tmp:w} % A temporary function for various purposes. % \begin{macrocode} -\cs_new_protected:Npn \clist_tmp:w { } +\cs_new_protected:Npn \@@_tmp:w { } % \end{macrocode} % \end{macro} % @@ -714,16 +662,16 @@ % \UnitTested % \begin{macro}{\clist_gconcat:NNN, \clist_gconcat:ccc} % \UnitTested -% \begin{macro}[aux]{\clist_concat_aux:NNNN} -% Concatenating sequences is not quite as easy as it seems, as +% \begin{macro}[aux]{\@@_concat:NNNN} +% Concatenating comma lists is not quite as easy as it seems, as % there needs to be the correct addition of a comma to the output. So % a little work to do. % \begin{macrocode} \cs_new_protected_nopar:Npn \clist_concat:NNN - { \clist_concat_aux:NNNN \tl_set:Nx } + { \@@_concat:NNNN \tl_set:Nx } \cs_new_protected_nopar:Npn \clist_gconcat:NNN - { \clist_concat_aux:NNNN \tl_gset:Nx } -\cs_new_protected:Npn \clist_concat_aux:NNNN #1#2#3#4 + { \@@_concat:NNNN \tl_gset:Nx } +\cs_new_protected:Npn \@@_concat:NNNN #1#2#3#4 { #1 #2 { @@ -755,73 +703,58 @@ % % \subsection{Removing spaces around items} % -% \begin{macro}[int,EXP]{\clist_trim_spaces_generic:nw} -% \begin{macro}[aux]{\clist_trim_spaces_generic_aux:w} -% \begin{macro}[aux]{\clist_trim_spaces_generic_aux_ii:nn} -% Used as `\cs{clist_trim_spaces_generic:nw} \Arg{code} -% \cs{q_mark} \meta{item} |,|' (including the comma). +% \begin{macro}[int,EXP]{\@@_trim_spaces_generic:nw} +% \begin{macro}[aux]{\@@_trim_spaces_generic:nn} +% \begin{syntax} +% \cs{@@_trim_spaces_generic:nw} \Arg{code} \cs{q_mark} \meta{item} |,| +% \end{syntax} % This expands to the \meta{code}, followed by a brace group -% containing the \meta{item}, with leading and trailing spaces removed. -% The calling function is responsible for inserting \cs{q_mark} -% in front of the \meta{item}, as well as testing for the end of the list. -% See \cs{tl_trim_spaces:n} for a partial explanation of what -% is happening here. We changed \cs{tl_trim_spaces_aux_iv:w} -% into \cs{clist_trim_spaces_generic_aux:w} compared to -% \cs{tl_trim_spaces:n}, and dropped a \cs{q_mark}, which is -% already included in the argument |##2|. +% containing the \meta{item}, with leading and trailing spaces +% removed. The calling function is responsible for inserting +% \cs{q_mark} in front of the \meta{item}, as well as testing for the +% end of the list. We reuse a \pkg{l3tl} internal function, whose +% first argument must start with \cs{q_mark}. That trims the item +% |#2|, then feeds the result (after having to do an \texttt{o}-type +% expansion) to \cs{@@_trim_spaces_generic:nn} which places the +% \meta{code} in front of the \meta{trimmed item}. % \begin{macrocode} -\cs_set:Npn \clist_tmp:w #1 +\cs_new:Npn \@@_trim_spaces_generic:nw #1#2 , { - \cs_new:Npn \clist_trim_spaces_generic:nw ##1 ##2 , - { - \tl_trim_spaces_aux_i:w - ##2 - \q_nil - \q_mark #1 { } - \q_mark \tl_trim_spaces_aux_ii:w - \tl_trim_spaces_aux_iii:w - #1 \q_nil - \clist_trim_spaces_generic_aux:w - \q_stop - {##1} - } + \__tl_trim_spaces:nn {#2} + { \exp_args:No \@@_trim_spaces_generic:nn } {#1} } -\clist_tmp:w {~} -\cs_new:Npn \clist_trim_spaces_generic_aux:w #1 \q_nil #2 \q_stop - { \exp_args:No \clist_trim_spaces_generic_aux_ii:nn { \use_none:n #1 } } -\cs_new:Npn \clist_trim_spaces_generic_aux_ii:nn #1 #2 { #2 {#1} } +\cs_new:Npn \@@_trim_spaces_generic:nn #1#2 { #2 {#1} } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} % -% \begin{macro}[int,rEXP]{\clist_trim_spaces:n} -% \begin{macro}[aux]{\clist_trim_spaces_aux:nn} -% The first argument of \cs{clist_trim_spaces_aux:nn} is initially empty, +% \begin{macro}[int,rEXP]{\@@_trim_spaces:n} +% \begin{macro}[aux]{\@@_trim_spaces_ii:nn} +% The first argument of \cs{@@_trim_spaces_ii:nn} is initially empty, % and later a comma, namely, as soon as we have added an item to the % resulting list. The auxiliary tests for the end of the list, % and also prevents empty arguments from finding their way into the % output. % \begin{macrocode} -\cs_new:Npn \clist_trim_spaces:n #1 +\cs_new:Npn \@@_trim_spaces:n #1 { - \clist_trim_spaces_generic:nw - { \clist_trim_spaces_aux:nn { } } + \@@_trim_spaces_generic:nw + { \@@_trim_spaces_ii:nn { } } \q_mark #1 , \q_recursion_tail, \q_recursion_stop } -\cs_new:Npn \clist_trim_spaces_aux:nn #1 #2 +\cs_new:Npn \@@_trim_spaces_ii:nn #1 #2 { \quark_if_recursion_tail_stop:n {#2} \tl_if_empty:nTF {#2} { - \clist_trim_spaces_generic:nw - { \clist_trim_spaces_aux:nn {#1} } \q_mark + \@@_trim_spaces_generic:nw + { \@@_trim_spaces_ii:nn {#1} } \q_mark } { #1 \exp_not:n {#2} - \clist_trim_spaces_generic:nw - { \clist_trim_spaces_aux:nn { , } } \q_mark + \@@_trim_spaces_generic:nw + { \@@_trim_spaces_ii:nn { , } } \q_mark } } % \end{macrocode} @@ -846,9 +779,9 @@ % } % \begin{macrocode} \cs_new_protected:Npn \clist_set:Nn #1#2 - { \tl_set:Nx #1 { \clist_trim_spaces:n {#2} } } + { \tl_set:Nx #1 { \@@_trim_spaces:n {#2} } } \cs_new_protected:Npn \clist_gset:Nn #1#2 - { \tl_gset:Nx #1 { \clist_trim_spaces:n {#2} } } + { \tl_gset:Nx #1 { \@@_trim_spaces:n {#2} } } \cs_generate_variant:Nn \clist_set:Nn { NV , No , Nx , c , cV , co , cx } \cs_generate_variant:Nn \clist_gset:Nn { NV , No , Nx , c , cV , co , cx } % \end{macrocode} @@ -871,18 +804,18 @@ % \clist_gput_left:co, \clist_gput_left:cx % } % \UnitTested -% \begin{macro}[aux]{\clist_put_left_aux:NNNn} +% \begin{macro}[aux]{\@@_put_left:NNNn} % Comma lists cannot hold empty values: there are therefore a couple % of sanity checks to avoid accumulating commas. % \begin{macrocode} \cs_new_protected_nopar:Npn \clist_put_left:Nn - { \clist_put_left_aux:NNNn \clist_concat:NNN \clist_set:Nn } + { \@@_put_left:NNNn \clist_concat:NNN \clist_set:Nn } \cs_new_protected_nopar:Npn \clist_gput_left:Nn - { \clist_put_left_aux:NNNn \clist_gconcat:NNN \clist_set:Nn } -\cs_new_protected:Npn \clist_put_left_aux:NNNn #1#2#3#4 + { \@@_put_left:NNNn \clist_gconcat:NNN \clist_set:Nn } +\cs_new_protected:Npn \@@_put_left:NNNn #1#2#3#4 { - #2 \l_clist_internal_clist {#4} - #1 #3 \l_clist_internal_clist #3 + #2 \l_@@_internal_clist {#4} + #1 #3 \l_@@_internal_clist #3 } \cs_generate_variant:Nn \clist_put_left:Nn { NV , No , Nx } \cs_generate_variant:Nn \clist_put_left:Nn { c , cV , co , cx } @@ -909,16 +842,16 @@ % \clist_gput_right:co, \clist_gput_right:cx % } % \UnitTested -% \begin{macro}[aux]{\clist_put_right_aux:NNNn} +% \begin{macro}[aux]{\@@_put_right:NNNn} % \begin{macrocode} \cs_new_protected_nopar:Npn \clist_put_right:Nn - { \clist_put_right_aux:NNNn \clist_concat:NNN \clist_set:Nn } + { \@@_put_right:NNNn \clist_concat:NNN \clist_set:Nn } \cs_new_protected_nopar:Npn \clist_gput_right:Nn - { \clist_put_right_aux:NNNn \clist_gconcat:NNN \clist_gset:Nn } -\cs_new_protected:Npn \clist_put_right_aux:NNNn #1#2#3#4 + { \@@_put_right:NNNn \clist_gconcat:NNN \clist_gset:Nn } +\cs_new_protected:Npn \@@_put_right:NNNn #1#2#3#4 { - #2 \l_clist_internal_clist {#4} - #1 #3 #3 \l_clist_internal_clist + #2 \l_@@_internal_clist {#4} + #1 #3 #3 \l_@@_internal_clist } \cs_generate_variant:Nn \clist_put_right:Nn { NV , No , Nx } \cs_generate_variant:Nn \clist_put_right:Nn { c , cV , co , cx } @@ -933,13 +866,19 @@ % % \begin{macro}{\clist_get:NN, \clist_get:cN} % \UnitTested -% \begin{macro}[aux]{\clist_get_aux:wN} +% \begin{macro}[aux]{\@@_get:wN} % Getting an item from the left of a comma list is pretty easy: just % trim off the first item using the comma. % \begin{macrocode} \cs_new_protected:Npn \clist_get:NN #1#2 - { \exp_after:wN \clist_get_aux:wN #1 , \q_stop #2 } -\cs_new_protected:Npn \clist_get_aux:wN #1 , #2 \q_stop #3 + { + \if_meaning:w #1 \c_empty_clist + \tl_set:Nn #2 { \q_no_value } + \else: + \exp_after:wN \@@_get:wN #1 , \q_stop #2 + \fi: + } +\cs_new_protected:Npn \@@_get:wN #1 , #2 \q_stop #3 { \tl_set:Nn #3 {#1} } \cs_generate_variant:Nn \clist_get:NN { c } % \end{macrocode} @@ -951,28 +890,39 @@ % \begin{macro}{\clist_gpop:NN, \clist_gpop:cN} % \UnitTested % \begin{macro}[aux] -% {\clist_pop_aux:NNN, \clist_pop_aux:NwNNN, \clist_pop_aux:wNN} -% The aim here is to get the popped item as |#1| in the auxiliary, with -% |#2| containing either the remainder of the list \emph{or} \cs{q_nil} -% if there were insufficient items. That keeps the number of auxiliary -% functions down. +% {\@@_pop:NNN, \@@_pop:wwNNN, \@@_pop:wN} +% An empty clist leads to \cs{q_no_value}, otherwise grab until the +% first comma and assign to the variable. The second argument of +% \cs{@@_pop:wwNNN} is a comma list ending in a comma and +% \cs{q_mark}, unless the original clist contained exactly one item: +% then the argument is just \cs{q_mark}. The next auxiliary picks +% either \cs{exp_not:n} or \cs{use_none:n} as |#2|, ensuring that the +% result can safely be an empty comma list. % \begin{macrocode} \cs_new_protected_nopar:Npn \clist_pop:NN - { \clist_pop_aux:NNN \tl_set:Nf } + { \@@_pop:NNN \tl_set:Nx } \cs_new_protected_nopar:Npn \clist_gpop:NN - { \clist_pop_aux:NNN \tl_gset:Nf } -\cs_new_protected:Npn \clist_pop_aux:NNN #1#2#3 + { \@@_pop:NNN \tl_gset:Nx } +\cs_new_protected:Npn \@@_pop:NNN #1#2#3 { - \exp_after:wN \clist_pop_aux:wNNN #2 , \q_nil \q_stop #1#2#3 + \if_meaning:w #2 \c_empty_clist + \tl_set:Nn #3 { \q_no_value } + \else: + \exp_after:wN \@@_pop:wwNNN #2 , \q_mark \q_stop #1#2#3 + \fi: } -\cs_new_protected:Npn \clist_pop_aux:wNNN #1 , #2 \q_stop #3#4#5 +\cs_new_protected:Npn \@@_pop:wwNNN #1 , #2 \q_stop #3#4#5 { \tl_set:Nn #5 {#1} - \quark_if_nil:nTF {#2} - { #3 #4 { } } - { #3 #4 { \clist_pop_aux:w \exp_stop_f: #2 } } + #3 #4 + { + \@@_pop:wN \prg_do_nothing: + #2 \exp_not:o + , \q_mark \use_none:n + \q_stop + } } -\cs_new_protected:Npn \clist_pop_aux:w #1 , \q_nil {#1} +\cs_new:Npn \@@_pop:wN #1 , \q_mark #2 #3 \q_stop { #2 {#1} } \cs_generate_variant:Nn \clist_pop:NN { c } \cs_generate_variant:Nn \clist_gpop:NN { c } % \end{macrocode} @@ -980,6 +930,49 @@ % \end{macro} % \end{macro} % +% \begin{macro}[TF]{\clist_get:NN, \clist_get:cN} +% \begin{macro}[TF]{\clist_pop:NN, \clist_pop:cN} +% \begin{macro}[TF]{\clist_gpop:NN, \clist_gpop:cN} +% \begin{macro}[aux]{\@@_pop_TF:NNN} +% The same, as branching code: very similar to the above. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \clist_get:NN #1#2 { T , F , TF } + { + \if_meaning:w #1 \c_empty_clist + \prg_return_false: + \else: + \exp_after:wN \@@_get:wN #1 , \q_stop #2 + \prg_return_true: + \fi: + } +\cs_generate_variant:Nn \clist_get:NNT { c } +\cs_generate_variant:Nn \clist_get:NNF { c } +\cs_generate_variant:Nn \clist_get:NNTF { c } +\prg_new_protected_conditional:Npnn \clist_pop:NN #1#2 { T , F , TF } + { \@@_pop_TF:NNN \tl_set:Nx #1 #2 } +\prg_new_protected_conditional:Npnn \clist_gpop:NN #1#2 { T , F , TF } + { \@@_pop_TF:NNN \tl_gset:Nx #1 #2 } +\cs_new_protected:Npn \@@_pop_TF:NNN #1#2#3 + { + \if_meaning:w #2 \c_empty_clist + \prg_return_false: + \else: + \exp_after:wN \@@_pop:wwNNN #2 , \q_mark \q_stop #1#2#3 + \prg_return_true: + \fi: + } +\cs_generate_variant:Nn \clist_pop:NNT { c } +\cs_generate_variant:Nn \clist_pop:NNF { c } +\cs_generate_variant:Nn \clist_pop:NNTF { c } +\cs_generate_variant:Nn \clist_gpop:NNT { c } +\cs_generate_variant:Nn \clist_gpop:NNF { c } +\cs_generate_variant:Nn \clist_gpop:NNTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % \begin{macro}{ % \clist_push:Nn, \clist_push:NV, \clist_push:No, \clist_push:Nx, % \clist_push:cn, \clist_push:cV, \clist_push:co, \clist_push:cx @@ -990,7 +983,7 @@ % \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, \clist_gpush:cx % } % \UnitTested -% Pushing to a sequence is the same as adding on the left. +% Pushing to a comma list is the same as adding on the left. % \begin{macrocode} \cs_new_eq:NN \clist_push:Nn \clist_put_left:Nn \cs_new_eq:NN \clist_push:NV \clist_put_left:NV @@ -1012,23 +1005,12 @@ % \end{macro} % \end{macro} % -% \subsection{Using comma lists} -% -% \begin{macro}{\clist_use:N, \clist_use:c} -% \UnitTested -% The approach is the same as for \cs{tl_use:N}. -% \begin{macrocode} -\cs_new_eq:NN \clist_use:N \tl_use:N -\cs_new_eq:NN \clist_use:c \tl_use:c -% \end{macrocode} -% \end{macro} -% % \subsection{Modifying comma lists} % -% \begin{variable}{\l_clist_internal_remove_clist} +% \begin{variable}{\l_@@_internal_remove_clist} % An internal comma list for the removal routines. % \begin{macrocode} -\clist_new:N \l_clist_internal_remove_clist +\clist_new:N \l_@@_internal_remove_clist % \end{macrocode} % \end{variable} % @@ -1036,22 +1018,22 @@ % \UnitTested % \begin{macro}{\clist_gremove_duplicates:N, \clist_gremove_duplicates:c} % \UnitTested -% \begin{macro}[aux]{\clist_remove_duplicates_aux:NN} +% \begin{macro}[aux]{\@@_remove_duplicates:NN} % Removing duplicates means making a new list then copying it. % \begin{macrocode} \cs_new_protected:Npn \clist_remove_duplicates:N - { \clist_remove_duplicates_aux:NN \clist_set_eq:NN } + { \@@_remove_duplicates:NN \clist_set_eq:NN } \cs_new_protected:Npn \clist_gremove_duplicates:N - { \clist_remove_duplicates_aux:NN \clist_gset_eq:NN } -\cs_new_protected:Npn \clist_remove_duplicates_aux:NN #1#2 + { \@@_remove_duplicates:NN \clist_gset_eq:NN } +\cs_new_protected:Npn \@@_remove_duplicates:NN #1#2 { - \clist_clear:N \l_clist_internal_remove_clist + \clist_clear:N \l_@@_internal_remove_clist \clist_map_inline:Nn #2 { - \clist_if_in:NnF \l_clist_internal_remove_clist {##1} - { \clist_put_right:Nn \l_clist_internal_remove_clist {##1} } + \clist_if_in:NnF \l_@@_internal_remove_clist {##1} + { \clist_put_right:Nn \l_@@_internal_remove_clist {##1} } } - #1 #2 \l_clist_internal_remove_clist + #1 #2 \l_@@_internal_remove_clist } \cs_generate_variant:Nn \clist_remove_duplicates:N { c } \cs_generate_variant:Nn \clist_gremove_duplicates:N { c } @@ -1064,21 +1046,21 @@ % \UnitTested % \begin{macro}{\clist_gremove_all:Nn, \clist_gremove_all:cn} % \UnitTested -% \begin{macro}[aux]{\clist_remove_all_aux:NNn} -% \begin{macro}[aux]{\clist_remove_all_aux:w} -% \begin{macro}[aux]{\clist_remove_all_aux:} +% \begin{macro}[aux]{\@@_remove_all:NNn} +% \begin{macro}[aux]{\@@_remove_all:w} +% \begin{macro}[aux]{\@@_remove_all:} % The method used here is very similar to \cs{tl_replace_all:Nnn}. % Build a function delimited by the \meta{item} that should be removed, % surrounded with commas, and call that function followed by % the expanded comma list, and another copy of the \meta{item}. % The loop is controlled by the argument grabbed by -% \cs{clist_remove_all_aux:w}: when the item was found, +% \cs{@@_remove_all:w}: when the item was found, % the \cs{q_mark} delimiter used is the one inserted by -% \cs{clist_tmp:w}, and \cs{use_none_delimit_by_q_stop:w} +% \cs{@@_tmp:w}, and \cs{use_none_delimit_by_q_stop:w} % is deleted. At the end, the final \meta{item} is -% grabbed, and the argument of \cs{clist_tmp:w} contains -% \cs{q_mark}: in that case, \cs{clist_remove_all_aux:w} -% removes the second \cs{q_mark} (inserted by \cs{clist_tmp:w}), +% grabbed, and the argument of \cs{@@_tmp:w} contains +% \cs{q_mark}: in that case, \cs{@@_remove_all:w} +% removes the second \cs{q_mark} (inserted by \cs{@@_tmp:w}), % and lets \cs{use_none_delimit_by_q_stop:w} act. % % No brace is lost because items are always grabbed with a leading comma. @@ -1090,20 +1072,20 @@ % the second step removes it. % \begin{macrocode} \cs_new_protected:Npn \clist_remove_all:Nn - { \clist_remove_all_aux:NNn \tl_set:Nx } + { \@@_remove_all:NNn \tl_set:Nx } \cs_new_protected:Npn \clist_gremove_all:Nn - { \clist_remove_all_aux:NNn \tl_gset:Nx } -\cs_new_protected:Npn \clist_remove_all_aux:NNn #1#2#3 + { \@@_remove_all:NNn \tl_gset:Nx } +\cs_new_protected:Npn \@@_remove_all:NNn #1#2#3 { - \cs_set:Npn \clist_tmp:w ##1 , #3 , + \cs_set:Npn \@@_tmp:w ##1 , #3 , { ##1 , \q_mark , \use_none_delimit_by_q_stop:w , - \clist_remove_all_aux: + \@@_remove_all: } #1 #2 { - \exp_after:wN \clist_remove_all_aux: + \exp_after:wN \@@_remove_all: #2 , \q_mark , #3 , \q_stop } \clist_if_empty:NF #2 @@ -1115,9 +1097,9 @@ } } } -\cs_new:Npn \clist_remove_all_aux: - { \exp_after:wN \clist_remove_all_aux:w \clist_tmp:w , } -\cs_new:Npn \clist_remove_all_aux:w #1 , \q_mark , #2 , { \exp_not:n {#1} } +\cs_new:Npn \@@_remove_all: + { \exp_after:wN \@@_remove_all:w \@@_tmp:w , } +\cs_new:Npn \@@_remove_all:w #1 , \q_mark , #2 , { \exp_not:n {#1} } \cs_generate_variant:Nn \clist_remove_all:Nn { c } \cs_generate_variant:Nn \clist_gremove_all:Nn { c } % \end{macrocode} @@ -1138,43 +1120,31 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[pTF] -% {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc} -% \UnitTested -% Simple copies from the token list variable material. -% \begin{macrocode} -\prg_new_eq_conditional:NNn \clist_if_eq:NN \tl_if_eq:NN { p , T , F , TF } -\prg_new_eq_conditional:NNn \clist_if_eq:Nc \tl_if_eq:Nc { p , T , F , TF } -\prg_new_eq_conditional:NNn \clist_if_eq:cN \tl_if_eq:cN { p , T , F , TF } -\prg_new_eq_conditional:NNn \clist_if_eq:cc \tl_if_eq:cc { p , T , F , TF } -% \end{macrocode} -% \end{macro} -% % \begin{macro}[TF] % { % \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, % \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co, % \clist_if_in:nn, \clist_if_in:nV, \clist_if_in:no % } -% \begin{macro}[aux]{\clist_if_in_return:nn} +% \begin{macro}[aux]{\@@_if_in_return:nn} % \UnitTested % See description of the \cs{tl_if_in:Nn} function for details. % We simply surround the comma list, and the item, with commas. % \begin{macrocode} \prg_new_protected_conditional:Npnn \clist_if_in:Nn #1#2 { T , F , TF } { - \exp_args:No \clist_if_in_return:nn #1 {#2} + \exp_args:No \@@_if_in_return:nn #1 {#2} } \prg_new_protected_conditional:Npnn \clist_if_in:nn #1#2 { T , F , TF } { - \clist_set:Nn \l_clist_internal_clist {#1} - \exp_args:No \clist_if_in_return:nn \l_clist_internal_clist {#2} + \clist_set:Nn \l_@@_internal_clist {#1} + \exp_args:No \@@_if_in_return:nn \l_@@_internal_clist {#2} } -\cs_new_protected:Npn \clist_if_in_return:nn #1#2 +\cs_new_protected:Npn \@@_if_in_return:nn #1#2 { - \cs_set:Npn \clist_tmp:w ##1 ,#2, { } + \cs_set:Npn \@@_tmp:w ##1 ,#2, { } \tl_if_empty:oTF - { \clist_tmp:w ,#1, {} {} ,#2, } + { \@@_tmp:w ,#1, {} {} ,#2, } { \prg_return_false: } { \prg_return_true: } } \cs_generate_variant:Nn \clist_if_in:NnT { NV , No } @@ -1194,28 +1164,28 @@ % % \begin{macro}{\clist_map_function:NN, \clist_map_function:cN} % \UnitTested -% \begin{macro}[aux]{\clist_map_function_aux:Nw} +% \begin{macro}[aux]{\@@_map_function:Nw} % If the variable is empty, the mapping is skipped (otherwise, % that comma-list would be seen as consisting of one empty item). % Then loop over the comma-list, grabbing one comma-delimited % item at a time. The end is marked by \cs{q_recursion_tail}. -% The auxiliary function \cs{clist_map_function_aux:Nw} is used +% The auxiliary function \cs{@@_map_function:Nw} is used % directly in \cs{clist_map_inline:Nn}. Change with care. % \begin{macrocode} \cs_new:Npn \clist_map_function:NN #1#2 { \clist_if_empty:NF #1 { - \exp_last_unbraced:NNo \clist_map_function_aux:Nw #2 #1 + \exp_last_unbraced:NNo \@@_map_function:Nw #2 #1 , \q_recursion_tail , - \prg_break_point:n { } + \__prg_break_point:Nn \clist_map_break: { } } } -\cs_new:Npn \clist_map_function_aux:Nw #1#2 , +\cs_new:Npn \@@_map_function:Nw #1#2 , { - \quark_if_recursion_tail_break:n {#2} + \__quark_if_recursion_tail_break:nN {#2} \clist_map_break: #1 {#2} - \clist_map_function_aux:Nw #1 + \@@_map_function:Nw #1 } \cs_generate_variant:Nn \clist_map_function:NN { c } % \end{macrocode} @@ -1224,31 +1194,31 @@ % % \begin{macro}{\clist_map_function:nN} % \UnitTested -% \begin{macro}[aux]{\clist_map_function_n_aux:Nn} -% \begin{macro}{\clist_map_aux_unbrace:Nw} +% \begin{macro}[aux]{\@@_map_function_n:Nn} +% \begin{macro}[aux]{\@@_map_unbrace:Nw} % The \texttt{n}-type mapping function is a bit more awkward, -% since spaces mustbe trimmed from each item. -% Space trimming is again based on \cs{clist_trim_spaces_generic:nw}. -% The auxiliary \cs{clist_map_function_n_aux:Nn} receives +% since spaces must be trimmed from each item. +% Space trimming is again based on \cs{@@_trim_spaces_generic:nw}. +% The auxiliary \cs{@@_map_function_n:Nn} receives % as arguments the function, and the result of removing leading % and trailing spaces from the item which lies until the next comma. % Empty items are ignored, then one level of braces is removed -% by \cs{clist_map_aux_unbrace:Nw}. +% by \cs{@@_map_unbrace:Nw}. % \begin{macrocode} \cs_new:Npn \clist_map_function:nN #1#2 { - \clist_trim_spaces_generic:nw { \clist_map_function_n_aux:Nn #2 } + \@@_trim_spaces_generic:nw { \@@_map_function_n:Nn #2 } \q_mark #1, \q_recursion_tail, - \prg_break_point:n { } + \__prg_break_point:Nn \clist_map_break: { } } -\cs_new:Npn \clist_map_function_n_aux:Nn #1 #2 +\cs_new:Npn \@@_map_function_n:Nn #1 #2 { - \quark_if_recursion_tail_break:n {#2} - \tl_if_empty:nF {#2} { \clist_map_aux_unbrace:Nw #1 #2, } - \clist_trim_spaces_generic:nw { \clist_map_function_n_aux:Nn #1 } + \__quark_if_recursion_tail_break:nN {#2} \clist_map_break: + \tl_if_empty:nF {#2} { \@@_map_unbrace:Nw #1 #2, } + \@@_trim_spaces_generic:nw { \@@_map_function_n:Nn #1 } \q_mark } -\cs_new:Npn \clist_map_aux_unbrace:Nw #1 #2, { #1 {#2} } +\cs_new:Npn \@@_map_unbrace:Nw #1 #2, { #1 {#2} } % \end{macrocode} % \end{macro} % \end{macro} @@ -1274,18 +1244,19 @@ { \clist_if_empty:NF #1 { - \int_gincr:N \g_prg_map_int - \cs_gset:cpn { clist_map_ \int_use:N \g_prg_map_int :n } ##1 {#2} - \exp_last_unbraced:Nco \clist_map_function_aux:Nw - { clist_map_ \int_use:N \g_prg_map_int :n } + \int_gincr:N \g__prg_map_int + \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2} + \exp_last_unbraced:Nco \@@_map_function:Nw + { __prg_map_ \int_use:N \g__prg_map_int :w } #1 , \q_recursion_tail , - \prg_break_point:n { \int_gdecr:N \g_prg_map_int } + \__prg_break_point:Nn \clist_map_break: + { \int_gdecr:N \g__prg_map_int } } } \cs_new_protected:Npn \clist_map_inline:nn #1 { - \clist_set:Nn \l_clist_internal_clist {#1} - \clist_map_inline:Nn \l_clist_internal_clist + \clist_set:Nn \l_@@_internal_clist {#1} + \clist_map_inline:Nn \l_@@_internal_clist } \cs_generate_variant:Nn \clist_map_inline:Nn { c } % \end{macrocode} @@ -1295,7 +1266,7 @@ % \begin{macro}{\clist_map_variable:NNn, \clist_map_variable:cNn} % \UnitTested % \begin{macro}{\clist_map_variable:nNn} -% \begin{macro}[aux]{\clist_map_variable_aux:Nnw} +% \begin{macro}[aux]{\@@_map_variable:Nnw} % As for other comma-list mappings, filter out the case of % an empty list. Same approach as \cs{clist_map_function:Nn}, % additionally we store each item in the given variable. @@ -1307,23 +1278,23 @@ \clist_if_empty:NF #1 { \exp_args:Nno \use:nn - { \clist_map_variable_aux:Nnw #2 {#3} } + { \@@_map_variable:Nnw #2 {#3} } #1 , \q_recursion_tail , \q_recursion_stop - \prg_break_point:n { } + \__prg_break_point:Nn \clist_map_break: { } } } \cs_new_protected:Npn \clist_map_variable:nNn #1 { - \clist_set:Nn \l_clist_internal_clist {#1} - \clist_map_variable:NNn \l_clist_internal_clist + \clist_set:Nn \l_@@_internal_clist {#1} + \clist_map_variable:NNn \l_@@_internal_clist } -\cs_new_protected:Npn \clist_map_variable_aux:Nnw #1#2#3, +\cs_new_protected:Npn \@@_map_variable:Nnw #1#2#3, { \tl_set:Nn #1 {#3} \quark_if_recursion_tail_stop:N #1 \use:n {#2} - \clist_map_variable_aux:Nnw #1 {#2} + \@@_map_variable:Nnw #1 {#2} } \cs_generate_variant:Nn \clist_map_variable:NNn { c } % \end{macrocode} @@ -1331,293 +1302,99 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\clist_map_break:} -% \begin{macro}{\clist_map_break:n} -% The break statements are simply copies. +% \begin{macro}{\clist_map_break:, \clist_map_break:n} +% The break statements use the general \cs{__prg_map_break:Nn} mechanism. % \begin{macrocode} -\cs_new_eq:NN \clist_map_break: \prg_map_break: -\cs_new_eq:NN \clist_map_break:n \prg_map_break:n +\cs_new_nopar:Npn \clist_map_break: + { \__prg_map_break:Nn \clist_map_break: { } } +\cs_new_nopar:Npn \clist_map_break:n + { \__prg_map_break:Nn \clist_map_break: } % \end{macrocode} % \end{macro} -% \end{macro} -% -% \subsection{Viewing comma lists} -% -% \begin{macro}{\clist_show:N, \clist_show:c} -% \begin{macro}{\clist_show:n} -% Apply the general \cs{msg_aux_show:Nnx}. In the case -% of an \texttt{n}-type comma-list, first store it -% in a scratch variable, then show that variable, -% omitting its name from the $4$-th argument. -% \begin{macrocode} -\cs_new_protected:Npn \clist_show:N #1 - { - \msg_aux_show:Nnx - #1 - { clist } - { \clist_map_function:NN #1 \msg_aux_show:n } - } -\cs_new_protected:Npn \clist_show:n #1 - { - \clist_set:Nn \l_clist_internal_clist {#1} - \msg_aux_show:Nnx - \l_clist_internal_clist - { clist } - { \clist_map_function:NN \l_clist_internal_clist \msg_aux_show:n } - } -\cs_generate_variant:Nn \clist_show:N { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsection{Scratch comma lists} -% -% \begin{variable}{\l_tmpa_clist, \l_tmpb_clist} -% \begin{variable}{\g_tmpa_clist, \g_tmpb_clist} -% Temporary comma list variables. -% \begin{macrocode} -\clist_new:N \l_tmpa_clist -\clist_new:N \l_tmpb_clist -\clist_new:N \g_tmpa_clist -\clist_new:N \g_tmpb_clist -% \end{macrocode} -% \end{variable} -% \end{variable} -% -% \subsection{Experimental functions} -% -% \begin{macro}{\clist_length:N, \clist_length:c} -% \begin{macro}{\clist_length:n} -% \begin{macro}[aux]{\clist_length_aux:w} +% +% \begin{macro}{\clist_count:N, \clist_count:c, \clist_count:n} +% \begin{macro}[aux]{\@@_count:n} +% \begin{macro}[aux]{\@@_count:w} % Counting the items in a comma list is done using the same approach as for -% other length functions: turn each entry into a \texttt{+1} then use +% other token count functions: turn each entry into a \texttt{+1} then use % integer evaluation to actually do the mathematics. % In the case of an \texttt{n}-type comma-list, we could of course use % \cs{clist_map_function:nN}, but that is very slow, because it carefully % removes spaces. Instead, we loop manually, and skip blank items % (but not |{}|, hence the extra spaces). % \begin{macrocode} -\cs_new:Npn \clist_length:N #1 +\cs_new:Npn \clist_count:N #1 { \int_eval:n { 0 - \clist_map_function:NN #1 \clist_length_aux:n + \clist_map_function:NN #1 \@@_count:n } } -\cs_new:Npn \clist_length_aux:n #1 { +1 } -\cs_new:Npx \clist_length:n #1 +\cs_generate_variant:Nn \clist_count:N { c } +\cs_new:Npx \clist_count:n #1 { \exp_not:N \int_eval:n { 0 - \exp_not:N \clist_length_n_aux:w \c_space_tl + \exp_not:N \@@_count:w \c_space_tl #1 \exp_not:n { , \q_recursion_tail , \q_recursion_stop } } } -\cs_new:Npx \clist_length_n_aux:w #1 , +\cs_new:Npn \@@_count:n #1 { + \c_one } +\cs_new:Npx \@@_count:w #1 , { \exp_not:n { \exp_args:Nf \quark_if_recursion_tail_stop:n } {#1} \exp_not:N \tl_if_blank:nF {#1} { + \c_one } - \exp_not:N \clist_length_n_aux:w \c_space_tl + \exp_not:N \@@_count:w \c_space_tl } -\cs_generate_variant:Nn \clist_length:N { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % -% \begin{macro}{\clist_item:Nn, \clist_item:cn} -% \begin{macro}[aux]{\clist_item_aux:nnNn} -% \begin{macro}[aux]{\clist_item_N_loop:nw} -% To avoid needing to test the end of the list at each step, -% we first compute the \meta{length} of the list. If the item number -% is less than $-\meta{length}$ or more than $\meta{length}-1$, -% the result is empty. If it is negative, but not less than $-\meta{length}$, -% add the \meta{length} to the item number before performing the loop. -% The loop itself is very simple, return the item if the counter -% reached zero, otherwise, decrease the counter and repeat. -% \begin{macrocode} -\cs_new:Npn \clist_item:Nn #1#2 - { - \exp_args:Nfo \clist_item_aux:nnNn - { \clist_length:N #1 } - #1 - \clist_item_N_loop:nw - {#2} - } -\cs_new:Npn \clist_item_aux:nnNn #1#2#3#4 - { - \int_compare:nNnTF {#4} < \c_zero - { - \int_compare:nNnTF {#4} < { - #1 } - { \use_none_delimit_by_q_stop:w } - { \exp_args:Nf #3 { \int_eval:n { #4 + #1 } } } - } - { - \int_compare:nNnTF {#4} < {#1} - { #3 {#4} } - { \use_none_delimit_by_q_stop:w } - } - #2, \q_stop - } -\cs_new:Npn \clist_item_N_loop:nw #1 #2, - { - \int_compare:nNnTF {#1} = \c_zero - { \use_i_delimit_by_q_stop:nw { \exp_not:n {#2} } } - { \exp_args:Nf \clist_item_N_loop:nw { \int_eval:n { #1 - 1 } } } - } -\cs_generate_variant:Nn \clist_item:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\clist_item:nn} -% \begin{macro}[aux]{ -% \clist_item_n_aux:nw, -% \clist_item_n_loop:nw, -% \clist_item_n_end:n, -% \clist_item_n_strip:w} -% This starts in the same way as \cs{clist_item:Nn} by checking the length -% of the comma list. The final item should be space-trimmed before being -% brace-stripped, hence we insert a couple of odd-looking -% \cs{prg_do_nothing:} to avoid losing braces. Blank items are ignored. -% \begin{macrocode} -\cs_new:Npn \clist_item:nn #1#2 - { - \exp_args:Nf \clist_item_aux:nnNn - { \clist_length:n {#1} } - {#1} - \clist_item_n_aux:nw - {#2} - } -\cs_new:Npn \clist_item_n_aux:nw #1 - { \clist_item_n_loop:nw {#1} \prg_do_nothing: } -\cs_new:Npn \clist_item_n_loop:nw #1 #2, - { - \exp_args:No \tl_if_blank:nTF {#2} - { \clist_item_n_loop:nw {#1} \prg_do_nothing: } - { - \int_compare:nNnTF {#1} = \c_zero - { \exp_args:No \clist_item_n_end:n {#2} } - { - \exp_args:Nf \clist_item_n_loop:nw - { \int_eval:n { #1 - 1 } } - \prg_do_nothing: - } - } - } -\cs_new:Npn \clist_item_n_end:n #1 #2 \q_stop - { - \exp_after:wN \exp_after:wN \exp_after:wN \clist_item_n_strip:w - \tl_trim_spaces:n {#1} , - } -\cs_new:Npn \clist_item_n_strip:w #1 , { \exp_not:n {#1} } -% \end{macrocode} -% \end{macro} -% \end{macro} +% \subsection{Viewing comma lists} % -% \begin{macro} -% { -% \clist_set_from_seq:NN, \clist_set_from_seq:cN, -% \clist_set_from_seq:Nc, \clist_set_from_seq:cc -% } -% \UnitTested -% \begin{macro} -% { -% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, -% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc -% } -% \UnitTested -% \begin{macro}[aux]{\clist_set_from_seq_aux:NNNN} -% \begin{macro}[aux]{\clist_wrap_item:n} -% Setting a comma list from a comma-separated list is done using a simple -% mapping. We wrap most items with \cs{exp_not:n}, and a comma. Items which -% contain a comma or a space are surrounded by an extra set of braces. The -% first comma must be removed, except in the case of an empty comma-list. +% \begin{macro}{\clist_show:N, \clist_show:c} +% \begin{macro}{\clist_show:n} +% Apply the general \cs{__msg_show_variable:Nnn}. In the case +% of an \texttt{n}-type comma-list, first store it +% in a scratch variable, then show that variable, +% omitting its name from the $4$-th argument. % \begin{macrocode} -\cs_new_protected:Npn \clist_set_from_seq:NN - { \clist_set_from_seq_aux:NNNN \clist_clear:N \tl_set:Nx } -\cs_new_protected:Npn \clist_gset_from_seq:NN - { \clist_set_from_seq_aux:NNNN \clist_gclear:N \tl_gset:Nx } -\cs_new_protected:Npn \clist_set_from_seq_aux:NNNN #1#2#3#4 +\cs_new_protected:Npn \clist_show:N #1 { - \seq_if_empty:NTF #4 - { #1 #3 } - { - #2 #3 - { - \exp_last_unbraced:Nf \use_none:n - { \seq_map_function:NN #4 \clist_wrap_item:n } - } - } + \__msg_show_variable:Nnn + #1 + { clist } + { \clist_map_function:NN #1 \__msg_show_item:n } } -\cs_new:Npn \clist_wrap_item:n #1 +\cs_new_protected:Npn \clist_show:n #1 { - , - \tl_if_empty:oTF { \clist_set_from_seq_aux:w #1 ~ , #1 ~ } - { \exp_not:n {#1} } - { \exp_not:n { {#1} } } + \clist_set:Nn \l_@@_internal_clist {#1} + \__msg_show_variable:Nnn + \l_@@_internal_clist + { clist } + { \clist_map_function:NN \l_@@_internal_clist \__msg_show_item:n } } -\cs_new:Npn \clist_set_from_seq_aux:w #1 , #2 ~ { } -\cs_generate_variant:Nn \clist_set_from_seq:NN { Nc } -\cs_generate_variant:Nn \clist_set_from_seq:NN { c , cc } -\cs_generate_variant:Nn \clist_gset_from_seq:NN { Nc } -\cs_generate_variant:Nn \clist_gset_from_seq:NN { c , cc } +\cs_generate_variant:Nn \clist_show:N { c } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} % -% \begin{macro} -% { -% \clist_const:Nn, \clist_const:cn, -% \clist_const:Nx, \clist_const:cx -% } -% Creating and initializing a constant comma list is done in a way -% similar to \cs{clist_set:Nn} and \cs{clist_gset:Nn}, being careful -% to strip spaces. -% \begin{macrocode} -\cs_new_protected:Npn \clist_const:Nn #1#2 - { \tl_const:Nx #1 { \clist_trim_spaces:n {#2} } } -\cs_generate_variant:Nn \clist_const:Nn { c , Nx , cx } -% \end{macrocode} -% \end{macro} +% \subsection{Scratch comma lists} % -% \begin{macro}[EXP, pTF]{\clist_if_empty:n} -% \begin{macro}[aux, EXP]{\clist_if_empty_n_aux:w} -% \begin{macro}[aux, EXP]{\clist_if_empty_n_aux:wNw} -% As usual, we insert a token (here |?|) before grabbing -% any argument: this avoids losing braces. The argument -% of \cs{tl_if_empty:oTF} is empty if |#1| is |?| followed -% by blank spaces (besides, this particular variant of -% the emptyness test is optimized). If the item of the -% comma list is blank, grab the next one. As soon as one -% item is non-blank, exit: the second auxiliary will grab -% \cs{prg_return_false:} as |#2|, unless every item in -% the comma list was blank and the loop actually got broken -% by the trailing |\q_mark \prg_return_false:| item. +% \begin{variable}{\l_tmpa_clist, \l_tmpb_clist} +% \begin{variable}{\g_tmpa_clist, \g_tmpb_clist} +% Temporary comma list variables. % \begin{macrocode} -\prg_new_conditional:Npnn \clist_if_empty:n #1 { p , T , F , TF } - { - \clist_if_empty_n_aux:w ? #1 - , \q_mark \prg_return_false: - , \q_mark \prg_return_true: - \q_stop - } -\cs_new:Npn \clist_if_empty_n_aux:w #1 , - { - \tl_if_empty:oTF { \use_none:nn #1 ? } - { \clist_if_empty_n_aux:w ? } - { \clist_if_empty_n_aux:wNw } - } -\cs_new:Npn \clist_if_empty_n_aux:wNw #1 \q_mark #2#3 \q_stop {#2} +\clist_new:N \l_tmpa_clist +\clist_new:N \l_tmpb_clist +\clist_new:N \g_tmpa_clist +\clist_new:N \g_tmpb_clist % \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} +% \end{variable} +% \end{variable} % % \subsection{Deprecated interfaces} % @@ -1664,7 +1441,7 @@ % } % Since clist items are now always stripped from their surrounding % spaces, it is redundant to provide these functions. -% The \cs{clist_trim_spaces:n} function is now internal, +% The \cs{@@_trim_spaces:n} function is now internal, % deprecated for use outside the kernel. % \begin{macrocode} %<*deprecated> @@ -1676,6 +1453,38 @@ % \end{macrocode} % \end{macro} % +% Deprecated on 2012-05-10, for removal by 2012-08-31. +% +% \begin{macro}[pTF] +% {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc} +% Simple copies from the token list variable material. +% \begin{macrocode} +\prg_new_eq_conditional:NNn \clist__if_eq:NN \tl_if_eq:NN { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:Nc \tl_if_eq:Nc { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:cN \tl_if_eq:cN { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:cc \tl_if_eq:cc { p , T , F , TF } +% \end{macrocode} +% \end{macro} +% +% Deprecated 2012-05-13 for removal by 2012-11-31. +% +% \begin{macro}{\clist_length:N, \clist_length:c, \clist_length:n} +% \begin{macrocode} +\cs_new_eq:NN \clist_length:N \clist_count:N +\cs_new_eq:NN \clist_length:n \clist_count:c +\cs_new_eq:NN \clist_length:c \clist_count:n +% \end{macrocode} +% \end{macro} +% +% Deprecated 2012-05-19 for removal by 2012-11-31. +% +% \begin{macro}{\clist_use:N, \clist_use:c} +% \begin{macrocode} +\cs_new_eq:NN \clist_use:N \tl_use:N +\cs_new_eq:NN \clist_use:c \tl_use:c +% \end{macrocode} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx b/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx index 54575bde8ce..b4242b6d8ed 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx @@ -36,8 +36,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3coffins.dtx 3482 2012-03-03 18:48:06Z bruno $ - {L3 Experimental coffin code layer} +\GetIdInfo$Id: l3coffins.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Coffin code layer} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -94,10 +94,19 @@ % \begin{function}[added = 2011-08-17] % {\coffin_set_eq:NN, \coffin_set_eq:Nc, \coffin_set_eq:cN, \coffin_set_eq:cc} % \begin{syntax} -% \cs{coffin_set_eq:NN} \meta{coffin1} \meta{coffin2} +% \cs{coffin_set_eq:NN} \meta{coffin_1} \meta{coffin_2} % \end{syntax} -% Sets both the content and poles of \meta{coffin1} equal to those -% of \meta{coffin2} within the current \TeX\ group level. +% Sets both the content and poles of \meta{coffin_1} equal to those +% of \meta{coffin_2} within the current \TeX\ group level. +% \end{function} +% +% \begin{function}[EXP, pTF, added = 2012-06-20] +% {\coffin_if_exist:N, \coffin_if_exist:c} +% \begin{syntax} +% \cs{coffin_if_exist_p:N} \meta{box} +% \cs{coffin_if_exist:NTF} \meta{box} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests whether the \meta{coffin} is currently defined. % \end{function} % % \section{Setting coffin content and poles} @@ -127,7 +136,7 @@ % environment in a coffin. % \end{function} % -% \begin{function}[added = 2011-08-17, updated = 2011-09-03] +% \begin{function}[added = 2011-08-17, updated = 2012-05-22] % {\vcoffin_set:Nnn, \vcoffin_set:cnn} % \begin{syntax} % \cs{vcoffin_set:Nnn} \meta{coffin} \Arg{width} \Arg{material} @@ -138,7 +147,7 @@ % size of the typeset material. % \end{function} % -% \begin{function}[added = 2011-09-10] +% \begin{function}[added = 2011-09-10, updated = 2012-05-22] % {\vcoffin_set:Nnw, \vcoffin_set:cnw, \vcoffin_set_end:} % \begin{syntax} % \cs{vcoffin_set:Nnw} \meta{coffin} \Arg{width} \meta{material} \cs{vcoffin_set_end:} @@ -180,42 +189,6 @@ % the \meta{coffin}. % \end{function} % -% \section{Coffin transformations} -% -% \begin{function}[added = 2011-09-02]{\coffin_resize:Nnn, \coffin_resize:cnn} -% \begin{syntax} -% \cs{coffin_resize:Nnn} \meta{coffin} \Arg{width} \Arg{total-height} -% \end{syntax} -% Resized the \meta{coffin} to \meta{width} and \meta{total-height}, -% both of which should be given as dimension expressions. These may -% include the terms \cs{TotalHeight}, \cs{Height}, \cs{Depth} and -% \cs{Width}, which will evaluate to the appropriate dimensions of -% the \meta{coffin}. -% -% \textbf{This function is experimental.} -% \end{function} -% -% \begin{function}[added = 2011-09-02]{\coffin_rotate:Nn, \coffin_rotate:cn} -% \begin{syntax} -% \cs{coffin_rotate:Nn} \meta{coffin} \Arg{angle} -% \end{syntax} -% Rotates the \meta{coffin} by the given \meta{angle} (given in -% degrees counter-clockwise). This process will rotate both the -% coffin content and poles. Multiple rotations will not result in -% the bounding box of the coffin growing unnecessarily. -% \end{function} -% -% \begin{function}[added = 2011-09-02]{\coffin_scale:Nnn, \coffin_scale:cnn} -% \begin{syntax} -% \cs{coffin_scale:Nnn} \meta{coffin} \Arg{x-scale} \Arg{y-scale} -% \end{syntax} -% Scales the \meta{coffin} by a factors \meta{x-scale} and -% \meta{y-scale} in the horizontal and vertical directions, -% respectively. The two scale factors should be given as real numbers. -% -% \textbf{This function is experimental.} -% \end{function} -% % \section{Joining and using coffins} % % \begin{function} @@ -225,19 +198,19 @@ % } % \begin{syntax} % \cs{coffin_attach:NnnNnnnn} -% ~~\meta{coffin1} \Arg{coffin1-pole1} \Arg{coffin1-pole2} -% ~~\meta{coffin2} \Arg{coffin2-pole1} \Arg{coffin2-pole2} +% ~~\meta{coffin_1} \Arg{coffin_1-pole_1} \Arg{coffin_1-pole_2} +% ~~\meta{coffin_2} \Arg{coffin_2-pole_1} \Arg{coffin_2-pole_2} % ~~\Arg{x-offset} \Arg{y-offset} % \end{syntax} % This function attaches <coffin_2> to <coffin_1> such that the bounding box -% of \meta{coffin1} is not altered, \emph{i.e.}~\meta{coffin2} can +% of \meta{coffin_1} is not altered, \emph{i.e.}~\meta{coffin_2} can % protrude outside of the bounding box of the coffin. The alignment -% is carried out by first calculating \meta{handle1}, the -% point of intersection of \meta{coffin1-pole1} and -% \meta{coffin1-pole2}, and \meta{handle2}, the point of intersection -% of \meta{coffin2-pole1} and \meta{coffin2-pole2}. \meta{coffin2} is -% then attached to \meta{coffin1} such that the relationship between -% \meta{handle1} and \meta{handle2} is described by the \meta{x-offset} +% is carried out by first calculating \meta{handle_1}, the +% point of intersection of \meta{coffin_1-pole_1} and +% \meta{coffin_1-pole_2}, and \meta{handle_2}, the point of intersection +% of \meta{coffin_2-pole_1} and \meta{coffin_2-pole_2}. \meta{coffin_2} is +% then attached to \meta{coffin_1} such that the relationship between +% \meta{handle_1} and \meta{handle_2} is described by the \meta{x-offset} % and \meta{y-offset}. The two offsets should be given as dimension % expressions. % \end{function} @@ -249,19 +222,19 @@ % } % \begin{syntax} % \cs{coffin_join:NnnNnnnn} -% ~~\meta{coffin1} \Arg{coffin1-pole1} \Arg{coffin1-pole2} -% ~~\meta{coffin2} \Arg{coffin2-pole1} \Arg{coffin2-pole2} +% ~~\meta{coffin_1} \Arg{coffin_1-pole_1} \Arg{coffin_1-pole_2} +% ~~\meta{coffin_2} \Arg{coffin_2-pole_1} \Arg{coffin_2-pole_2} % ~~\Arg{x-offset} \Arg{y-offset} % \end{syntax} % This function joins <coffin_2> to <coffin_1> such that the bounding box -% of \meta{coffin1} may expand. The new bounding +% of \meta{coffin_1} may expand. The new bounding % box will cover the area containing the bounding boxes of the two % original coffins. The alignment is carried out by first calculating -% \meta{handle1}, the point of intersection of \meta{coffin1-pole1} and -% \meta{coffin1-pole2}, and \meta{handle2}, the point of intersection -% of \meta{coffin2-pole1} and \meta{coffin2-pole2}. \meta{coffin2} is -% then attached to \meta{coffin1} such that the relationship between -% \meta{handle1} and \meta{handle2} is described by the \meta{x-offset} +% \meta{handle_1}, the point of intersection of \meta{coffin_1-pole_1} and +% \meta{coffin_1-pole_2}, and \meta{handle_2}, the point of intersection +% of \meta{coffin_2-pole_1} and \meta{coffin_2-pole_2}. \meta{coffin_2} is +% then attached to \meta{coffin_1} such that the relationship between +% \meta{handle_1} and \meta{handle_2} is described by the \meta{x-offset} % and \meta{y-offset}. The two offsets should be given as dimension % expressions. % \end{function} @@ -272,7 +245,7 @@ % ~~\Arg{x-offset} \Arg{y-offset} % \end{syntax} % Typesetting is carried out by first calculating \meta{handle}, the -% point of intersection of \meta{pole1} and \meta{pole2}. The coffin +% point of intersection of \meta{pole_1} and \meta{pole_2}. The coffin % is then typeset such that the relationship between the current % reference point in the document and the \meta{handle} is described % by the \meta{x-offset} and \meta{y-offset}. The two offsets should @@ -310,7 +283,7 @@ % \section{Coffin diagnostics} % % \begin{function}[updated = 2011-09-02] -% {\coffin_display_handles:cn, \coffin_display_handles:cn} +% {\coffin_display_handles:Nn, \coffin_display_handles:cn} % \begin{syntax} % \cs{coffin_display_handles:Nn} \meta{coffin} \Arg{colour} % \end{syntax} @@ -329,8 +302,8 @@ % \cs{coffin_mark_handle:Nnnn} \meta{coffin} \Arg{pole_1} \Arg{pole_2} \Arg{colour} % \end{syntax} % This function first calculates the \meta{handle} for the -% \meta{coffin} as defined by the intersection of \meta{pole1} and -% \meta{pole2}. It then marks the position of the \meta{handle} +% \meta{coffin} as defined by the intersection of \meta{pole_1} and +% \meta{pole_2}. It then marks the position of the \meta{handle} % on the \meta{coffin}. The \meta{handle} will be labelled as part of % this process: the location of the \meta{handle} and the label are % both printed in the \meta{colour} specified. @@ -353,6 +326,19 @@ % the later, rather than the absolute values, which determines the % direction of the pole. % \end{function} +% +% \subsection{Constants and variables} +% +% \begin{variable}{\c_empty_coffin} +% A permanently empty coffin. +% \end{variable} +% +% \begin{variable}[added = 2012-06-19]{\l_tmpa_coffin, \l_tmpb_coffin} +% Scratch coffins for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} % % \end{documentation} % @@ -363,183 +349,148 @@ % \begin{macrocode} %<*initex|package> % \end{macrocode} +% +% \begin{macrocode} +%<@@=coffin> +% \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % % \subsection{Coffins: data structures and general variables} % -% \begin{variable}{\l_coffin_internal_box} -% \begin{variable}{\l_coffin_internal_dim} -% \begin{variable}{\l_coffin_internal_fp} -% \begin{variable}{\l_coffin_internal_tl} +% \begin{variable}{\l_@@_internal_box} +% \begin{variable}{\l_@@_internal_dim} +% \begin{variable}{\l_@@_internal_tl} % Scratch variables. % \begin{macrocode} -\box_new:N \l_coffin_internal_box -\dim_new:N \l_coffin_internal_dim -\fp_new:N \l_coffin_internal_fp -\tl_new:N \l_coffin_internal_tl +\box_new:N \l_@@_internal_box +\dim_new:N \l_@@_internal_dim +\tl_new:N \l_@@_internal_tl % \end{macrocode} % \end{variable} % \end{variable} % \end{variable} -% \end{variable} % -% \begin{variable}{\c_coffin_corners_prop} +% \begin{variable}{\c_@@_corners_prop} % The \enquote{corners}; of a coffin define the real content, as % opposed to the \TeX{} bounding box. They all start off in the same % place, of course. % \begin{macrocode} -\prop_new:N \c_coffin_corners_prop -\prop_put:Nnn \c_coffin_corners_prop { tl } { { 0 pt } { 0 pt } } -\prop_put:Nnn \c_coffin_corners_prop { tr } { { 0 pt } { 0 pt } } -\prop_put:Nnn \c_coffin_corners_prop { bl } { { 0 pt } { 0 pt } } -\prop_put:Nnn \c_coffin_corners_prop { br } { { 0 pt } { 0 pt } } +\prop_new:N \c_@@_corners_prop +\prop_put:Nnn \c_@@_corners_prop { tl } { { 0 pt } { 0 pt } } +\prop_put:Nnn \c_@@_corners_prop { tr } { { 0 pt } { 0 pt } } +\prop_put:Nnn \c_@@_corners_prop { bl } { { 0 pt } { 0 pt } } +\prop_put:Nnn \c_@@_corners_prop { br } { { 0 pt } { 0 pt } } % \end{macrocode} % \end{variable} % -% \begin{variable}{\c_coffin_poles_prop} +% \begin{variable}{\c_@@_poles_prop} % Pole positions are given for horizontal, vertical and reference-point % based values. % \begin{macrocode} -\prop_new:N \c_coffin_poles_prop -\tl_set:Nn \l_coffin_internal_tl { { 0 pt } { 0 pt } { 0 pt } { 1000 pt } } -\prop_put:Nno \c_coffin_poles_prop { l } { \l_coffin_internal_tl } -\prop_put:Nno \c_coffin_poles_prop { hc } { \l_coffin_internal_tl } -\prop_put:Nno \c_coffin_poles_prop { r } { \l_coffin_internal_tl } -\tl_set:Nn \l_coffin_internal_tl { { 0 pt } { 0 pt } { 1000 pt } { 0 pt } } -\prop_put:Nno \c_coffin_poles_prop { b } { \l_coffin_internal_tl } -\prop_put:Nno \c_coffin_poles_prop { vc } { \l_coffin_internal_tl } -\prop_put:Nno \c_coffin_poles_prop { t } { \l_coffin_internal_tl } -\prop_put:Nno \c_coffin_poles_prop { B } { \l_coffin_internal_tl } -\prop_put:Nno \c_coffin_poles_prop { H } { \l_coffin_internal_tl } -\prop_put:Nno \c_coffin_poles_prop { T } { \l_coffin_internal_tl } +\prop_new:N \c_@@_poles_prop +\tl_set:Nn \l_@@_internal_tl { { 0 pt } { 0 pt } { 0 pt } { 1000 pt } } +\prop_put:Nno \c_@@_poles_prop { l } { \l_@@_internal_tl } +\prop_put:Nno \c_@@_poles_prop { hc } { \l_@@_internal_tl } +\prop_put:Nno \c_@@_poles_prop { r } { \l_@@_internal_tl } +\tl_set:Nn \l_@@_internal_tl { { 0 pt } { 0 pt } { 1000 pt } { 0 pt } } +\prop_put:Nno \c_@@_poles_prop { b } { \l_@@_internal_tl } +\prop_put:Nno \c_@@_poles_prop { vc } { \l_@@_internal_tl } +\prop_put:Nno \c_@@_poles_prop { t } { \l_@@_internal_tl } +\prop_put:Nno \c_@@_poles_prop { B } { \l_@@_internal_tl } +\prop_put:Nno \c_@@_poles_prop { H } { \l_@@_internal_tl } +\prop_put:Nno \c_@@_poles_prop { T } { \l_@@_internal_tl } % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_coffin_calc_a_fp} -% \begin{variable}{\l_coffin_calc_b_fp} -% \begin{variable}{\l_coffin_calc_c_fp} -% \begin{variable}{\l_coffin_calc_d_fp} -% \begin{variable}{\l_coffin_calc_result_fp} -% Used for calculations of intersections and in other internal places. +% \begin{variable}{\l_@@_slope_x_fp} +% \begin{variable}{\l_@@_slope_y_fp} +% Used for calculations of intersections. % \begin{macrocode} -\fp_new:N \l_coffin_calc_a_fp -\fp_new:N \l_coffin_calc_b_fp -\fp_new:N \l_coffin_calc_c_fp -\fp_new:N \l_coffin_calc_d_fp -\fp_new:N \l_coffin_calc_result_fp +\fp_new:N \l_@@_slope_x_fp +\fp_new:N \l_@@_slope_y_fp % \end{macrocode} % \end{variable} % \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} % -% \begin{variable}{\l_coffin_error_bool} +% \begin{variable}{\l_@@_error_bool} % For propagating errors so that parts of the code can work around them. % \begin{macrocode} -\bool_new:N \l_coffin_error_bool +\bool_new:N \l_@@_error_bool % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_coffin_offset_x_dim} -% \begin{variable}{\l_coffin_offset_y_dim} +% \begin{variable}{\l_@@_offset_x_dim} +% \begin{variable}{\l_@@_offset_y_dim} % The offset between two sets of coffin handles when typesetting. These % values are corrected from those requested in an alignment for the % positions of the handles. % \begin{macrocode} -\dim_new:N \l_coffin_offset_x_dim -\dim_new:N \l_coffin_offset_y_dim +\dim_new:N \l_@@_offset_x_dim +\dim_new:N \l_@@_offset_y_dim % \end{macrocode} % \end{variable} % \end{variable} % -% \begin{variable}{\l_coffin_pole_a_tl} -% \begin{variable}{\l_coffin_pole_b_tl} +% \begin{variable}{\l_@@_pole_a_tl} +% \begin{variable}{\l_@@_pole_b_tl} % Needed for finding the intersection of two poles. % \begin{macrocode} -\tl_new:N \l_coffin_pole_a_tl -\tl_new:N \l_coffin_pole_b_tl -% \end{macrocode} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\l_coffin_sin_fp} -% \begin{variable}{\l_coffin_cos_fp} -% Used for rotations to get the sine and cosine values. -% \begin{macrocode} -\fp_new:N \l_coffin_sin_fp -\fp_new:N \l_coffin_cos_fp +\tl_new:N \l_@@_pole_a_tl +\tl_new:N \l_@@_pole_b_tl % \end{macrocode} % \end{variable} % \end{variable} % -% \begin{variable}{\l_coffin_x_dim} -% \begin{variable}{\l_coffin_y_dim} -% \begin{variable}{\l_coffin_x_prime_dim} -% \begin{variable}{\l_coffin_y_prime_dim} +% \begin{variable}{\l_@@_x_dim} +% \begin{variable}{\l_@@_y_dim} +% \begin{variable}{\l_@@_x_prime_dim} +% \begin{variable}{\l_@@_y_prime_dim} % For calculating intersections and so forth. % \begin{macrocode} -\dim_new:N \l_coffin_x_dim -\dim_new:N \l_coffin_y_dim -\dim_new:N \l_coffin_x_prime_dim -\dim_new:N \l_coffin_y_prime_dim -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\l_coffin_x_fp} -% \begin{variable}{\l_coffin_y_fp} -% \begin{variable}{\l_coffin_x_prime_fp} -% \begin{variable}{\l_coffin_y_prime_fp} -% Used for calculations where there are clear $x$- and -% $y$-components, for example during vector rotation. -% \begin{macrocode} -\fp_new:N \l_coffin_x_fp -\fp_new:N \l_coffin_y_fp -\fp_new:N \l_coffin_x_prime_fp -\fp_new:N \l_coffin_y_prime_fp +\dim_new:N \l_@@_x_dim +\dim_new:N \l_@@_y_dim +\dim_new:N \l_@@_x_prime_dim +\dim_new:N \l_@@_y_prime_dim % \end{macrocode} % \end{variable} % \end{variable} % \end{variable} % \end{variable} % -% \begin{variable}{\l_coffin_Depth_dim} -% \begin{variable}{\l_coffin_Height_dim} -% \begin{variable}{\l_coffin_TotalHeight_dim} -% \begin{variable}{\l_coffin_Width_dim} +% \begin{variable}{\l_@@_Depth_dim} +% \begin{variable}{\l_@@_Height_dim} +% \begin{variable}{\l_@@_TotalHeight_dim} +% \begin{variable}{\l_@@_Width_dim} % Dimensions for the various parts of a coffin. % \begin{macrocode} -\dim_new:N \l_coffin_Depth_dim -\dim_new:N \l_coffin_Height_dim -\dim_new:N \l_coffin_TotalHeight_dim -\dim_new:N \l_coffin_Width_dim +\dim_new:N \l_@@_Depth_dim +\dim_new:N \l_@@_Height_dim +\dim_new:N \l_@@_TotalHeight_dim +\dim_new:N \l_@@_Width_dim % \end{macrocode} % \end{variable} % \end{variable} % \end{variable} % \end{variable} % -% \begin{macro}{\coffin_saved_Depth:} -% \begin{macro}{\coffin_saved_Height:} -% \begin{macro}{\coffin_saved_TotalHeight:} -% \begin{macro}{\coffin_saved_Width:} +% \begin{macro}{\@@_saved_Depth:} +% \begin{macro}{\@@_saved_Height:} +% \begin{macro}{\@@_saved_TotalHeight:} +% \begin{macro}{\@@_saved_Width:} % Used to save the meaning of \cs{Depth}, \cs{Height}, \cs{TotalHeight} % and \cs{Width}. % \begin{macrocode} -\cs_new_nopar:Npn \coffin_saved_Depth: { } -\cs_new_nopar:Npn \coffin_saved_Height: { } -\cs_new_nopar:Npn \coffin_saved_TotalHeight: { } -\cs_new_nopar:Npn \coffin_saved_Width: { } +\cs_new_nopar:Npn \@@_saved_Depth: { } +\cs_new_nopar:Npn \@@_saved_Height: { } +\cs_new_nopar:Npn \@@_saved_TotalHeight: { } +\cs_new_nopar:Npn \@@_saved_Width: { } % \end{macrocode} % \end{macro} % \end{macro} @@ -552,25 +503,40 @@ % placing material in them. This all relies on the following data % structures. % -% \begin{macro}{\coffin_if_exist:NT} +% \begin{macro}[EXP, pTF]{\coffin_if_exist:N, \coffin_if_exist:c} % Several of the higher-level coffin functions will give multiple % errors if the coffin does not exist. A cleaner way to handle this % is provided here: both the box and the coffin structure are % checked. % \begin{macrocode} -\cs_new_protected:Npn \coffin_if_exist:NT #1#2 +\prg_new_conditional:Npnn \coffin_if_exist:N #1 { p , T , F , TF } { \cs_if_exist:NTF #1 { - \cs_if_exist:cTF { l_coffin_poles_ \int_value:w #1 _prop } - { #2 } - { - \msg_kernel_error:nnx { coffins } { unknown-coffin } - { \token_to_str:N #1 } - } + \cs_if_exist:cTF { l_@@_poles_ \__int_value:w #1 _prop } + { \prg_return_true: } + { \prg_return_false: } } + { \prg_return_false: } + } +\cs_generate_variant:Nn \coffin_if_exist_p:N { c } +\cs_generate_variant:Nn \coffin_if_exist:NT { c } +\cs_generate_variant:Nn \coffin_if_exist:NF { c } +\cs_generate_variant:Nn \coffin_if_exist:NTF { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_if_exist:NT} +% Several of the higher-level coffin functions will give multiple +% errors if the coffin does not exist. So a wrapper is provided to deal +% with this correctly, issuing an error on erroneous use. +% \begin{macrocode} +\cs_new_protected:Npn \@@_if_exist:NT #1#2 + { + \coffin_if_exist:NTF #1 + { #2 } { - \msg_kernel_error:nnx { coffins } { unknown-coffin } + \__msg_kernel_error:nnx { kernel } { unknown-coffin } { \token_to_str:N #1 } } } @@ -583,10 +549,10 @@ % \begin{macrocode} \cs_new_protected:Npn \coffin_clear:N #1 { - \coffin_if_exist:NT #1 + \@@_if_exist:NT #1 { \box_clear:N #1 - \coffin_reset_structure:N #1 + \@@_reset_structure:N #1 } } \cs_generate_variant:Nn \coffin_clear:N { c } @@ -603,12 +569,12 @@ \cs_new_protected:Npn \coffin_new:N #1 { \box_new:N #1 - \prop_clear_new:c { l_coffin_corners_ \int_value:w #1 _prop } - \prop_clear_new:c { l_coffin_poles_ \int_value:w #1 _prop } - \prop_gset_eq:cN { l_coffin_corners_ \int_value:w #1 _prop } - \c_coffin_corners_prop - \prop_gset_eq:cN { l_coffin_poles_ \int_value:w #1 _prop } - \c_coffin_poles_prop + \prop_clear_new:c { l_@@_corners_ \__int_value:w #1 _prop } + \prop_clear_new:c { l_@@_poles_ \__int_value:w #1 _prop } + \prop_gset_eq:cN { l_@@_corners_ \__int_value:w #1 _prop } + \c_@@_corners_prop + \prop_gset_eq:cN { l_@@_poles_ \__int_value:w #1 _prop } + \c_@@_poles_prop } \cs_generate_variant:Nn \coffin_new:N { c } % \end{macrocode} @@ -620,7 +586,7 @@ % \begin{macrocode} \cs_new_protected:Npn \hcoffin_set:Nn #1#2 { - \coffin_if_exist:NT #1 + \@@_if_exist:NT #1 { \hbox_set:Nn #1 { @@ -629,9 +595,9 @@ #2 \color_group_end: } - \coffin_reset_structure:N #1 - \coffin_update_poles:N #1 - \coffin_update_corners:N #1 + \@@_reset_structure:N #1 + \@@_update_poles:N #1 + \@@_update_corners:N #1 } } \cs_generate_variant:Nn \hcoffin_set:Nn { c } @@ -642,32 +608,38 @@ % Setting vertical coffins is more complex. First, the material is % typeset with a given width. The default handles and poles are set as % for a horizontal coffin, before finding the top baseline using a -% temporary box. +% temporary box. No \cs{color_ensure_current:} here as that would add a +% whatsit to the start of the vertical box and mess up the location of the +% \texttt{T}~pole (see \emph{\TeX{} by Topic} for discussion of the +% \tn{vtop} primitive, used to do the measuring). % \begin{macrocode} \cs_new_protected:Npn \vcoffin_set:Nnn #1#2#3 { - \coffin_if_exist:NT #1 + \@@_if_exist:NT #1 { \vbox_set:Nn #1 { \dim_set:Nn \tex_hsize:D {#2} +%<*package> + \dim_set_eq:NN \linewidth \tex_hsize:D + \dim_set_eq:NN \columnwidth \tex_hsize:D +%</package> \color_group_begin: - \color_ensure_current: #3 \color_group_end: } - \coffin_reset_structure:N #1 - \coffin_update_poles:N #1 - \coffin_update_corners:N #1 - \vbox_set_top:Nn \l_coffin_internal_box { \vbox_unpack:N #1 } - \coffin_set_pole:Nnx #1 { T } + \@@_reset_structure:N #1 + \@@_update_poles:N #1 + \@@_update_corners:N #1 + \vbox_set_top:Nn \l_@@_internal_box { \vbox_unpack:N #1 } + \@@_set_pole:Nnx #1 { T } { { 0 pt } - { \dim_eval:n { \box_ht:N #1 - \box_ht:N \l_coffin_internal_box } } + { \dim_eval:n { \box_ht:N #1 - \box_ht:N \l_@@_internal_box } } { 1000 pt } { 0 pt } } - \box_clear:N \l_coffin_internal_box + \box_clear:N \l_@@_internal_box } } \cs_generate_variant:Nn \vcoffin_set:Nnn { c } @@ -681,16 +653,16 @@ % \begin{macrocode} \cs_new_protected:Npn \hcoffin_set:Nw #1 { - \coffin_if_exist:NT #1 + \@@_if_exist:NT #1 { \hbox_set:Nw #1 \color_group_begin: \color_ensure_current: \cs_set_protected_nopar:Npn \hcoffin_set_end: { \color_group_end: \hbox_set_end: - \coffin_reset_structure:N #1 - \coffin_update_poles:N #1 - \coffin_update_corners:N #1 + \@@_reset_structure:N #1 + \@@_update_poles:N #1 + \@@_update_corners:N #1 } } } @@ -706,29 +678,33 @@ % \begin{macrocode} \cs_new_protected:Npn \vcoffin_set:Nnw #1#2 { - \coffin_if_exist:NT #1 + \@@_if_exist:NT #1 { \vbox_set:Nw #1 \dim_set:Nn \tex_hsize:D {#2} +%<*package> + \dim_set_eq:NN \linewidth \tex_hsize:D + \dim_set_eq:NN \columnwidth \tex_hsize:D +%</package> \color_group_begin: \color_ensure_current: \cs_set_protected:Npn \vcoffin_set_end: { \color_group_end: \vbox_set_end: - \coffin_reset_structure:N #1 - \coffin_update_poles:N #1 - \coffin_update_corners:N #1 - \vbox_set_top:Nn \l_coffin_internal_box { \vbox_unpack:N #1 } - \coffin_set_pole:Nnx #1 { T } + \@@_reset_structure:N #1 + \@@_update_poles:N #1 + \@@_update_corners:N #1 + \vbox_set_top:Nn \l_@@_internal_box { \vbox_unpack:N #1 } + \@@_set_pole:Nnx #1 { T } { { 0 pt } { - \dim_eval:n { \box_ht:N #1 - \box_ht:N \l_coffin_internal_box } + \dim_eval:n { \box_ht:N #1 - \box_ht:N \l_@@_internal_box } } { 1000 pt } { 0 pt } } - \box_clear:N \l_coffin_internal_box + \box_clear:N \l_@@_internal_box } } } @@ -747,10 +723,10 @@ % \begin{macrocode} \cs_new_protected:Npn \coffin_set_eq:NN #1#2 { - \coffin_if_exist:NT #1 + \@@_if_exist:NT #1 { \box_set_eq:NN #1 #2 - \coffin_set_eq_structure:NN #1 #2 + \@@_set_eq_structure:NN #1 #2 } } \cs_generate_variant:Nn \coffin_set_eq:NN { c , Nc , cc } @@ -758,20 +734,28 @@ % \end{macro} % % \begin{variable}{\c_empty_coffin} -% \begin{variable}{\l_coffin_aligned_coffin} -% \begin{variable}{\l_coffin_aligned_internal_coffin} +% \begin{variable}{\l_@@_aligned_coffin} +% \begin{variable}{\l_@@_aligned_internal_coffin} % Special coffins: these cannot be set up earlier as they need % \cs{coffin_new:N}. The empty coffin is set as a box as the full % coffin-setting system needs some material which is not yet available. % \begin{macrocode} \coffin_new:N \c_empty_coffin \hbox_set:Nn \c_empty_coffin { } -\coffin_new:N \l_coffin_aligned_coffin -\coffin_new:N \l_coffin_aligned_internal_coffin +\coffin_new:N \l_@@_aligned_coffin +\coffin_new:N \l_@@_aligned_internal_coffin % \end{macrocode} % \end{variable} % \end{variable} % \end{variable} +% +% \begin{variable}{\l_tmpa_coffin, \l_tmpb_coffin} +% The usual scratch space. +% \begin{macrocode} +\coffin_new:N \l_tmpa_coffin +\coffin_new:N \l_tmpb_coffin +% \end{macrocode} +% \end{variable} % % \subsection{Measuring coffins} % @@ -794,16 +778,16 @@ % % \subsection{Coffins: handle and pole management} % -% \begin{macro}{\coffin_get_pole:NnN} +% \begin{macro}{\@@_get_pole:NnN} % A simple wrapper around the recovery of a coffin pole, with some % error checking and recovery built-in. % \begin{macrocode} -\cs_new_protected:Npn \coffin_get_pole:NnN #1#2#3 +\cs_new_protected:Npn \@@_get_pole:NnN #1#2#3 { \prop_get:cnNF - { l_coffin_poles_ \int_value:w #1 _prop } {#2} #3 + { l_@@_poles_ \__int_value:w #1 _prop } {#2} #3 { - \msg_kernel_error:nnxx { coffins } { unknown-coffin-pole } + \__msg_kernel_error:nnxx { kernel } { unknown-coffin-pole } {#2} { \token_to_str:N #1 } \tl_set:Nn #3 { { 0 pt } { 0 pt } { 0 pt } { 0 pt } } } @@ -811,42 +795,42 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\coffin_reset_structure:N} +% \begin{macro}{\@@_reset_structure:N} % Resetting the structure is a simple copy job. % \begin{macrocode} -\cs_new_protected:Npn \coffin_reset_structure:N #1 +\cs_new_protected:Npn \@@_reset_structure:N #1 { - \prop_set_eq:cN { l_coffin_corners_ \int_value:w #1 _prop } - \c_coffin_corners_prop - \prop_set_eq:cN { l_coffin_poles_ \int_value:w #1 _prop } - \c_coffin_poles_prop + \prop_set_eq:cN { l_@@_corners_ \__int_value:w #1 _prop } + \c_@@_corners_prop + \prop_set_eq:cN { l_@@_poles_ \__int_value:w #1 _prop } + \c_@@_poles_prop } % \end{macrocode} % \end{macro} % -% \begin{macro}{\coffin_set_eq_structure:NN,\coffin_gset_eq_structure:NN} +% \begin{macro}{\@@_set_eq_structure:NN,\@@_gset_eq_structure:NN} % Setting coffin structures equal simply means copying the property % list. % \begin{macrocode} -\cs_new_protected:Npn \coffin_set_eq_structure:NN #1#2 +\cs_new_protected:Npn \@@_set_eq_structure:NN #1#2 { - \prop_set_eq:cc { l_coffin_corners_ \int_value:w #1 _prop } - { l_coffin_corners_ \int_value:w #2 _prop } - \prop_set_eq:cc { l_coffin_poles_ \int_value:w #1 _prop } - { l_coffin_poles_ \int_value:w #2 _prop } + \prop_set_eq:cc { l_@@_corners_ \__int_value:w #1 _prop } + { l_@@_corners_ \__int_value:w #2 _prop } + \prop_set_eq:cc { l_@@_poles_ \__int_value:w #1 _prop } + { l_@@_poles_ \__int_value:w #2 _prop } } -\cs_new_protected:Npn \coffin_gset_eq_structure:NN #1#2 +\cs_new_protected:Npn \@@_gset_eq_structure:NN #1#2 { - \prop_gset_eq:cc { l_coffin_corners_ \int_value:w #1 _prop } - { l_coffin_corners_ \int_value:w #2 _prop } - \prop_gset_eq:cc { l_coffin_poles_ \int_value:w #1 _prop } - { l_coffin_poles_ \int_value:w #2 _prop } + \prop_gset_eq:cc { l_@@_corners_ \__int_value:w #1 _prop } + { l_@@_corners_ \__int_value:w #2 _prop } + \prop_gset_eq:cc { l_@@_poles_ \__int_value:w #1 _prop } + { l_@@_poles_ \__int_value:w #2 _prop } } % \end{macrocode} % \end{macro} % -% \begin{macro}{\coffin_set_user_dimensions:N} -% \begin{macro}{\coffin_end_user_dimensions:} +% \begin{macro}{\@@_set_user_dimensions:N} +% \begin{macro}{\@@_end_user_dimensions:} % \begin{macro}{\Depth} % \begin{macro}{\Height} % \begin{macro}{\TotalHeight} @@ -854,27 +838,27 @@ % These make design-level names for the dimensions of a coffin easy to % get at. % \begin{macrocode} -\cs_new_protected:Npn \coffin_set_user_dimensions:N #1 +\cs_new_protected:Npn \@@_set_user_dimensions:N #1 { - \cs_set_eq:NN \coffin_saved_Height: \Height - \cs_set_eq:NN \coffin_saved_Depth: \Depth - \cs_set_eq:NN \coffin_saved_TotalHeight: \TotalHeight - \cs_set_eq:NN \coffin_saved_Width: \Width - \cs_set_eq:NN \Height \l_coffin_Height_dim - \cs_set_eq:NN \Depth \l_coffin_Depth_dim - \cs_set_eq:NN \TotalHeight \l_coffin_TotalHeight_dim - \cs_set_eq:NN \Width \l_coffin_Width_dim + \cs_set_eq:NN \@@_saved_Height: \Height + \cs_set_eq:NN \@@_saved_Depth: \Depth + \cs_set_eq:NN \@@_saved_TotalHeight: \TotalHeight + \cs_set_eq:NN \@@_saved_Width: \Width + \cs_set_eq:NN \Height \l_@@_Height_dim + \cs_set_eq:NN \Depth \l_@@_Depth_dim + \cs_set_eq:NN \TotalHeight \l_@@_TotalHeight_dim + \cs_set_eq:NN \Width \l_@@_Width_dim \dim_set:Nn \Height { \box_ht:N #1 } \dim_set:Nn \Depth { \box_dp:N #1 } \dim_set:Nn \TotalHeight { \box_ht:N #1 + \box_dp:N #1 } \dim_set:Nn \Width { \box_wd:N #1 } } -\cs_new_protected_nopar:Npn \coffin_end_user_dimensions: +\cs_new_protected_nopar:Npn \@@_end_user_dimensions: { - \cs_set_eq:NN \Height \coffin_saved_Height: - \cs_set_eq:NN \Depth \coffin_saved_Depth: - \cs_set_eq:NN \TotalHeight \coffin_saved_TotalHeight: - \cs_set_eq:NN \Width \coffin_saved_Width: + \cs_set_eq:NN \Height \@@_saved_Height: + \cs_set_eq:NN \Depth \@@_saved_Depth: + \cs_set_eq:NN \TotalHeight \@@_saved_TotalHeight: + \cs_set_eq:NN \Width \@@_saved_Width: } % \end{macrocode} % \end{macro} @@ -887,7 +871,7 @@ % \begin{macro} % {\coffin_set_horizontal_pole:Nnn, \coffin_set_horizontal_pole:cnn} % \begin{macro}{\coffin_set_vertical_pole:Nnn,\coffin_set_vertical_pole:cnn} -% \begin{macro}{\coffin_set_pole:Nnn, \coffin_set_pole:Nnx} +% \begin{macro}{\@@_set_pole:Nnn, \@@_set_pole:Nnx} % Setting the pole of a coffin at the user/designer level requires a % bit more care. The idea here is to provide a reasonable interface to % the system, then to do the setting with full expansion. The @@ -895,93 +879,93 @@ % \begin{macrocode} \cs_new_protected:Npn \coffin_set_horizontal_pole:Nnn #1#2#3 { - \coffin_if_exist:NT #1 + \@@_if_exist:NT #1 { - \coffin_set_user_dimensions:N #1 - \coffin_set_pole:Nnx #1 {#2} + \@@_set_user_dimensions:N #1 + \@@_set_pole:Nnx #1 {#2} { { 0 pt } { \dim_eval:n {#3} } { 1000 pt } { 0 pt } } - \coffin_end_user_dimensions: + \@@_end_user_dimensions: } } \cs_new_protected:Npn \coffin_set_vertical_pole:Nnn #1#2#3 { - \coffin_if_exist:NT #1 + \@@_if_exist:NT #1 { - \coffin_set_user_dimensions:N #1 - \coffin_set_pole:Nnx #1 {#2} + \@@_set_user_dimensions:N #1 + \@@_set_pole:Nnx #1 {#2} { { \dim_eval:n {#3} } { 0 pt } { 0 pt } { 1000 pt } } - \coffin_end_user_dimensions: + \@@_end_user_dimensions: } } -\cs_new_protected:Npn \coffin_set_pole:Nnn #1#2#3 - { \prop_put:cnn { l_coffin_poles_ \int_value:w #1 _prop } {#2} {#3} } +\cs_new_protected:Npn \@@_set_pole:Nnn #1#2#3 + { \prop_put:cnn { l_@@_poles_ \__int_value:w #1 _prop } {#2} {#3} } \cs_generate_variant:Nn \coffin_set_horizontal_pole:Nnn { c } \cs_generate_variant:Nn \coffin_set_vertical_pole:Nnn { c } -\cs_generate_variant:Nn \coffin_set_pole:Nnn { Nnx } +\cs_generate_variant:Nn \@@_set_pole:Nnn { Nnx } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % -% \begin{macro}{\coffin_update_corners:N} +% \begin{macro}{\@@_update_corners:N} % Updating the corners of a coffin is straight-forward as at this stage % there can be no rotation. So the corners of the content are just those % of the underlying \TeX{} box. % \begin{macrocode} -\cs_new_protected:Npn \coffin_update_corners:N #1 +\cs_new_protected:Npn \@@_update_corners:N #1 { - \prop_put:cnx { l_coffin_corners_ \int_value:w #1 _prop } { tl } + \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } { tl } { { 0 pt } { \dim_use:N \box_ht:N #1 } } - \prop_put:cnx { l_coffin_corners_ \int_value:w #1 _prop } { tr } + \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } { tr } { { \dim_use:N \box_wd:N #1 } { \dim_use:N \box_ht:N #1 } } - \prop_put:cnx { l_coffin_corners_ \int_value:w #1 _prop } { bl } + \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } { bl } { { 0 pt } { \dim_eval:n { - \box_dp:N #1 } } } - \prop_put:cnx { l_coffin_corners_ \int_value:w #1 _prop } { br } + \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } { br } { { \dim_use:N \box_wd:N #1 } { \dim_eval:n { - \box_dp:N #1 } } } } % \end{macrocode} % \end{macro} % -% \begin{macro}{\coffin_update_poles:N} +% \begin{macro}{\@@_update_poles:N} % This function is called when a coffin is set, and updates the poles to % reflect the nature of size of the box. Thus this function only alters % poles where the default position is dependent on the size of the box. % It also does not set poles which are relevant only to vertical % coffins. % \begin{macrocode} -\cs_new_protected:Npn \coffin_update_poles:N #1 +\cs_new_protected:Npn \@@_update_poles:N #1 { - \prop_put:cnx { l_coffin_poles_ \int_value:w #1 _prop } { hc } + \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } { hc } { { \dim_eval:n { 0.5 \box_wd:N #1 } } { 0 pt } { 0 pt } { 1000 pt } } - \prop_put:cnx { l_coffin_poles_ \int_value:w #1 _prop } { r } + \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } { r } { { \dim_use:N \box_wd:N #1 } { 0 pt } { 0 pt } { 1000 pt } } - \prop_put:cnx { l_coffin_poles_ \int_value:w #1 _prop } { vc } + \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } { vc } { { 0 pt } { \dim_eval:n { ( \box_ht:N #1 - \box_dp:N #1 ) / 2 } } { 1000 pt } { 0 pt } } - \prop_put:cnx { l_coffin_poles_ \int_value:w #1 _prop } { t } + \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } { t } { { 0 pt } { \dim_use:N \box_ht:N #1 } { 1000 pt } { 0 pt } } - \prop_put:cnx { l_coffin_poles_ \int_value:w #1 _prop } { b } + \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } { b } { { 0 pt } { \dim_eval:n { - \box_dp:N #1 } } @@ -994,27 +978,27 @@ % % \subsection{Coffins: calculation of pole intersections} % -% \begin{macro}{\coffin_calculate_intersection:Nnn} -% \begin{macro}[aux]{\coffin_calculate_intersection:nnnnnnnn} -% \begin{macro}[aux]{\coffin_calculate_intersection_aux:nnnnnN} +% \begin{macro}{\@@_calculate_intersection:Nnn} +% \begin{macro}[aux]{\@@_calculate_intersection:nnnnnnnn} +% \begin{macro}[aux]{\@@_calculate_intersection_aux:nnnnnN} % The lead off in finding intersections is to recover the two poles % and then hand off to the auxiliary for the actual calculation. There % may of course not be an intersection, for which an error trap is % needed. % \begin{macrocode} -\cs_new_protected:Npn \coffin_calculate_intersection:Nnn #1#2#3 +\cs_new_protected:Npn \@@_calculate_intersection:Nnn #1#2#3 { - \coffin_get_pole:NnN #1 {#2} \l_coffin_pole_a_tl - \coffin_get_pole:NnN #1 {#3} \l_coffin_pole_b_tl - \bool_set_false:N \l_coffin_error_bool + \@@_get_pole:NnN #1 {#2} \l_@@_pole_a_tl + \@@_get_pole:NnN #1 {#3} \l_@@_pole_b_tl + \bool_set_false:N \l_@@_error_bool \exp_last_two_unbraced:Noo - \coffin_calculate_intersection:nnnnnnnn - \l_coffin_pole_a_tl \l_coffin_pole_b_tl - \bool_if:NT \l_coffin_error_bool + \@@_calculate_intersection:nnnnnnnn + \l_@@_pole_a_tl \l_@@_pole_b_tl + \bool_if:NT \l_@@_error_bool { - \msg_kernel_error:nn { coffins } { no-pole-intersection } - \dim_zero:N \l_coffin_x_dim - \dim_zero:N \l_coffin_y_dim + \__msg_kernel_error:nn { kernel } { no-pole-intersection } + \dim_zero:N \l_@@_x_dim + \dim_zero:N \l_@@_y_dim } } % \end{macrocode} @@ -1029,7 +1013,7 @@ % is either horizontal or vertical then one or more of $c$, $d$, % $c'$ and $d'$ will be zero and a special case is needed. % \begin{macrocode} -\cs_new_protected:Npn \coffin_calculate_intersection:nnnnnnnn +\cs_new_protected:Npn \@@_calculate_intersection:nnnnnnnn #1#2#3#4#5#6#7#8 { \dim_compare:nNnTF {#3} = { \c_zero_dim } @@ -1039,9 +1023,9 @@ % second pole: if it is also vertical then there is an error. % \begin{macrocode} { - \dim_set:Nn \l_coffin_x_dim {#1} + \dim_set:Nn \l_@@_x_dim {#1} \dim_compare:nNnTF {#7} = \c_zero_dim - { \bool_set_true:N \l_coffin_error_bool } + { \bool_set_true:N \l_@@_error_bool } % \end{macrocode} % The second pole may still be horizontal, in which case the % $y$-component of the intersection will be $b'$. If not, @@ -1053,10 +1037,10 @@ % \begin{macrocode} { \dim_compare:nNnTF {#8} = \c_zero_dim - { \dim_set:Nn \l_coffin_y_dim {#6} } + { \dim_set:Nn \l_@@_y_dim {#6} } { - \coffin_calculate_intersection_aux:nnnnnN - {#1} {#5} {#6} {#7} {#8} \l_coffin_y_dim + \@@_calculate_intersection_aux:nnnnnN + {#1} {#5} {#6} {#7} {#8} \l_@@_y_dim } } } @@ -1068,12 +1052,12 @@ { \dim_compare:nNnTF {#4} = \c_zero_dim { - \dim_set:Nn \l_coffin_y_dim {#2} + \dim_set:Nn \l_@@_y_dim {#2} \dim_compare:nNnTF {#8} = { \c_zero_dim } - { \bool_set_true:N \l_coffin_error_bool } + { \bool_set_true:N \l_@@_error_bool } { \dim_compare:nNnTF {#7} = \c_zero_dim - { \dim_set:Nn \l_coffin_x_dim {#5} } + { \dim_set:Nn \l_@@_x_dim {#5} } % \end{macrocode} % The formula for the case where the second pole is neither horizontal % nor vertical is @@ -1083,8 +1067,8 @@ % which is again handled by the same auxiliary. % \begin{macrocode} { - \coffin_calculate_intersection_aux:nnnnnN - {#2} {#6} {#5} {#8} {#7} \l_coffin_x_dim + \@@_calculate_intersection_aux:nnnnnN + {#2} {#6} {#5} {#8} {#7} \l_@@_x_dim } } } @@ -1097,32 +1081,30 @@ { \dim_compare:nNnTF {#7} = \c_zero_dim { - \dim_set:Nn \l_coffin_x_dim {#5} - \coffin_calculate_intersection_aux:nnnnnN - {#5} {#1} {#2} {#3} {#4} \l_coffin_y_dim + \dim_set:Nn \l_@@_x_dim {#5} + \@@_calculate_intersection_aux:nnnnnN + {#5} {#1} {#2} {#3} {#4} \l_@@_y_dim } { \dim_compare:nNnTF {#8} = \c_zero_dim { - \dim_set:Nn \l_coffin_x_dim {#6} - \coffin_calculate_intersection_aux:nnnnnN - {#6} {#2} {#1} {#4} {#3} \l_coffin_x_dim + \dim_set:Nn \l_@@_x_dim {#6} + \@@_calculate_intersection_aux:nnnnnN + {#6} {#2} {#1} {#4} {#3} \l_@@_x_dim } % \end{macrocode} % If none of the special cases apply then there is still a need to % check that there is a unique intersection between the two pole. This % is the case if they have different slopes. % \begin{macrocode} - { - \fp_set_from_dim:Nn \l_coffin_calc_a_fp {#3} - \fp_set_from_dim:Nn \l_coffin_calc_b_fp {#4} - \fp_set_from_dim:Nn \l_coffin_calc_c_fp {#7} - \fp_set_from_dim:Nn \l_coffin_calc_d_fp {#8} - \fp_div:Nn \l_coffin_calc_b_fp \l_coffin_calc_a_fp - \fp_div:Nn \l_coffin_calc_d_fp \l_coffin_calc_c_fp + { + \fp_set:Nn \l_@@_slope_x_fp + { \dim_to_fp:n {#4} / \dim_to_fp:n {#3} } + \fp_set:Nn \l_@@_slope_y_fp + { \dim_to_fp:n {#8} / \dim_to_fp:n {#7} } \fp_compare:nNnTF - \l_coffin_calc_b_fp = \l_coffin_calc_d_fp - { \bool_set_true:N \l_coffin_error_bool } + \l_@@_slope_x_fp = \l_@@_slope_y_fp + { \bool_set_true:N \l_@@_error_bool } % \end{macrocode} % All of the tests pass, so there is the full complexity of the % calculation: @@ -1137,29 +1119,23 @@ % $x$-position. % \begin{macrocode} { - \fp_set_from_dim:Nn \l_coffin_calc_result_fp {#6} - \fp_set_from_dim:Nn \l_coffin_calc_a_fp {#2} - \fp_sub:Nn \l_coffin_calc_result_fp - { \l_coffin_calc_a_fp } - \fp_set_from_dim:Nn \l_coffin_calc_a_fp {#1} - \fp_mul:Nn \l_coffin_calc_a_fp - { \l_coffin_calc_b_fp } - \fp_add:Nn \l_coffin_calc_result_fp - { \l_coffin_calc_a_fp } - \fp_set_from_dim:Nn \l_coffin_calc_a_fp {#5} - \fp_mul:Nn \l_coffin_calc_a_fp - { \l_coffin_calc_d_fp } - \fp_sub:Nn \l_coffin_calc_result_fp - { \l_coffin_calc_a_fp } - \fp_sub:Nn \l_coffin_calc_b_fp - { \l_coffin_calc_d_fp } - \fp_div:Nn \l_coffin_calc_result_fp - { \l_coffin_calc_b_fp } - \dim_set:Nn \l_coffin_x_dim - { \fp_to_dim:N \l_coffin_calc_result_fp } - \coffin_calculate_intersection_aux:nnnnnN - { \l_coffin_x_dim } - {#5} {#6} {#8} {#7} \l_coffin_y_dim + \dim_set:Nn \l_@@_x_dim + { + \fp_to_dim:n + { + ( + \dim_to_fp:n {#1} * \l_@@_slope_x_fp + - ( \dim_to_fp:n {#5} * \l_@@_slope_y_fp ) + - \dim_to_fp:n {#2} + + \dim_to_fp:n {#6} + ) + / + ( \l_@@_slope_x_fp - \l_@@_slope_y_fp ) + } + } + \@@_calculate_intersection_aux:nnnnnN + { \l_@@_x_dim } + {#5} {#6} {#8} {#7} \l_@@_y_dim } } } @@ -1170,24 +1146,23 @@ % The formula for finding the intersection point is in most cases the % same. The formula here is % \[ -% \#6 = \frac{\#5}{\#4} \left ( \#1 - \#2 \right ) + \#3 +% \#6 = \#4 \cdot \left( \frac { \#1 - \#2 } { \#5 } \right)\#3 % \] % Thus |#4| and |#5| should be the directions of the pole while % |#2| and |#3| are co-ordinates. % \begin{macrocode} -\cs_new_protected:Npn \coffin_calculate_intersection_aux:nnnnnN - #1#2#3#4#5#6 +\cs_new_protected:Npn \@@_calculate_intersection_aux:nnnnnN #1#2#3#4#5#6 { - \fp_set_from_dim:Nn \l_coffin_calc_result_fp {#1} - \fp_set_from_dim:Nn \l_coffin_calc_a_fp {#2} - \fp_set_from_dim:Nn \l_coffin_calc_b_fp {#3} - \fp_set_from_dim:Nn \l_coffin_calc_c_fp {#4} - \fp_set_from_dim:Nn \l_coffin_calc_d_fp {#5} - \fp_sub:Nn \l_coffin_calc_result_fp { \l_coffin_calc_a_fp } - \fp_div:Nn \l_coffin_calc_result_fp { \l_coffin_calc_d_fp } - \fp_mul:Nn \l_coffin_calc_result_fp { \l_coffin_calc_c_fp } - \fp_add:Nn \l_coffin_calc_result_fp { \l_coffin_calc_b_fp } - \dim_set:Nn #6 { \fp_to_dim:N \l_coffin_calc_result_fp } + \dim_set:Nn #6 + { + \fp_to_dim:n + { + \dim_to_fp:n {#4} * + ( \dim_to_fp:n {#1} - \dim_to_fp:n {#2} ) / + \dim_to_fp:n {#5} + + \dim_to_fp:n {#3} + } + } } % \end{macrocode} % \end{macro} @@ -1209,8 +1184,8 @@ % \begin{macrocode} \cs_new_protected:Npn \coffin_join:NnnNnnnn #1#2#3#4#5#6#7#8 { - \coffin_align:NnnNnnnnN - #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} \l_coffin_aligned_coffin + \@@_align:NnnNnnnnN + #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} \l_@@_aligned_coffin % \end{macrocode} % Correct the placement of the reference point. If the $x$-offset % is negative then the reference point of the second box is to the left @@ -1219,46 +1194,46 @@ % than the sum of the $x$-offset and the width of the second box. % So a second kern may be needed. % \begin{macrocode} - \hbox_set:Nn \l_coffin_aligned_coffin + \hbox_set:Nn \l_@@_aligned_coffin { - \dim_compare:nNnT { \l_coffin_offset_x_dim } < \c_zero_dim - { \tex_kern:D -\l_coffin_offset_x_dim } - \hbox_unpack:N \l_coffin_aligned_coffin - \dim_set:Nn \l_coffin_internal_dim - { \l_coffin_offset_x_dim - \box_wd:N #1 + \box_wd:N #4 } - \dim_compare:nNnT \l_coffin_internal_dim < \c_zero_dim - { \tex_kern:D -\l_coffin_internal_dim } + \dim_compare:nNnT { \l_@@_offset_x_dim } < \c_zero_dim + { \tex_kern:D -\l_@@_offset_x_dim } + \hbox_unpack:N \l_@@_aligned_coffin + \dim_set:Nn \l_@@_internal_dim + { \l_@@_offset_x_dim - \box_wd:N #1 + \box_wd:N #4 } + \dim_compare:nNnT \l_@@_internal_dim < \c_zero_dim + { \tex_kern:D -\l_@@_internal_dim } } % \end{macrocode} % The coffin structure is reset, and the corners are cleared: only % those from the two parent coffins are needed. % \begin{macrocode} - \coffin_reset_structure:N \l_coffin_aligned_coffin + \@@_reset_structure:N \l_@@_aligned_coffin \prop_clear:c - { l_coffin_corners_ \int_value:w \l_coffin_aligned_coffin _ prop } - \coffin_update_poles:N \l_coffin_aligned_coffin + { l_@@_corners_ \__int_value:w \l_@@_aligned_coffin _ prop } + \@@_update_poles:N \l_@@_aligned_coffin % \end{macrocode} % The structures of the parent coffins are now transferred to the new % coffin, which requires that the appropriate offsets are applied. That % will then depend on whether any shift was needed. % \begin{macrocode} - \dim_compare:nNnTF \l_coffin_offset_x_dim < \c_zero_dim + \dim_compare:nNnTF \l_@@_offset_x_dim < \c_zero_dim { - \coffin_offset_poles:Nnn #1 { -\l_coffin_offset_x_dim } { 0 pt } - \coffin_offset_poles:Nnn #4 { 0 pt } { \l_coffin_offset_y_dim } - \coffin_offset_corners:Nnn #1 { -\l_coffin_offset_x_dim } { 0 pt } - \coffin_offset_corners:Nnn #4 { 0 pt } { \l_coffin_offset_y_dim } + \@@_offset_poles:Nnn #1 { -\l_@@_offset_x_dim } { 0 pt } + \@@_offset_poles:Nnn #4 { 0 pt } { \l_@@_offset_y_dim } + \@@_offset_corners:Nnn #1 { -\l_@@_offset_x_dim } { 0 pt } + \@@_offset_corners:Nnn #4 { 0 pt } { \l_@@_offset_y_dim } } { - \coffin_offset_poles:Nnn #1 { 0 pt } { 0 pt } - \coffin_offset_poles:Nnn #4 - { \l_coffin_offset_x_dim } { \l_coffin_offset_y_dim } - \coffin_offset_corners:Nnn #1 { 0 pt } { 0 pt } - \coffin_offset_corners:Nnn #4 - { \l_coffin_offset_x_dim } { \l_coffin_offset_y_dim } + \@@_offset_poles:Nnn #1 { 0 pt } { 0 pt } + \@@_offset_poles:Nnn #4 + { \l_@@_offset_x_dim } { \l_@@_offset_y_dim } + \@@_offset_corners:Nnn #1 { 0 pt } { 0 pt } + \@@_offset_corners:Nnn #4 + { \l_@@_offset_x_dim } { \l_@@_offset_y_dim } } - \coffin_update_vertical_poles:NNN #1 #4 \l_coffin_aligned_coffin - \coffin_set_eq:NN #1 \l_coffin_aligned_coffin + \@@_update_vertical_poles:NNN #1 #4 \l_@@_aligned_coffin + \coffin_set_eq:NN #1 \l_@@_aligned_coffin } \cs_generate_variant:Nn \coffin_join:NnnNnnnn { c , Nnnc , cnnc } % \end{macrocode} @@ -1278,37 +1253,37 @@ % \begin{macrocode} \cs_new_protected:Npn \coffin_attach:NnnNnnnn #1#2#3#4#5#6#7#8 { - \coffin_align:NnnNnnnnN - #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} \l_coffin_aligned_coffin - \box_set_ht:Nn \l_coffin_aligned_coffin { \box_ht:N #1 } - \box_set_dp:Nn \l_coffin_aligned_coffin { \box_dp:N #1 } - \box_set_wd:Nn \l_coffin_aligned_coffin { \box_wd:N #1 } - \coffin_reset_structure:N \l_coffin_aligned_coffin + \@@_align:NnnNnnnnN + #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} \l_@@_aligned_coffin + \box_set_ht:Nn \l_@@_aligned_coffin { \box_ht:N #1 } + \box_set_dp:Nn \l_@@_aligned_coffin { \box_dp:N #1 } + \box_set_wd:Nn \l_@@_aligned_coffin { \box_wd:N #1 } + \@@_reset_structure:N \l_@@_aligned_coffin \prop_set_eq:cc - { l_coffin_corners_ \int_value:w \l_coffin_aligned_coffin _prop } - { l_coffin_corners_ \int_value:w #1 _prop } - \coffin_update_poles:N \l_coffin_aligned_coffin - \coffin_offset_poles:Nnn #1 { 0 pt } { 0 pt } - \coffin_offset_poles:Nnn #4 - { \l_coffin_offset_x_dim } { \l_coffin_offset_y_dim } - \coffin_update_vertical_poles:NNN #1 #4 \l_coffin_aligned_coffin - \coffin_set_eq:NN #1 \l_coffin_aligned_coffin + { l_@@_corners_ \__int_value:w \l_@@_aligned_coffin _prop } + { l_@@_corners_ \__int_value:w #1 _prop } + \@@_update_poles:N \l_@@_aligned_coffin + \@@_offset_poles:Nnn #1 { 0 pt } { 0 pt } + \@@_offset_poles:Nnn #4 + { \l_@@_offset_x_dim } { \l_@@_offset_y_dim } + \@@_update_vertical_poles:NNN #1 #4 \l_@@_aligned_coffin + \coffin_set_eq:NN #1 \l_@@_aligned_coffin } \cs_new_protected:Npn \coffin_attach_mark:NnnNnnnn #1#2#3#4#5#6#7#8 { - \coffin_align:NnnNnnnnN - #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} \l_coffin_aligned_coffin - \box_set_ht:Nn \l_coffin_aligned_coffin { \box_ht:N #1 } - \box_set_dp:Nn \l_coffin_aligned_coffin { \box_dp:N #1 } - \box_set_wd:Nn \l_coffin_aligned_coffin { \box_wd:N #1 } - \box_set_eq:NN #1 \l_coffin_aligned_coffin + \@@_align:NnnNnnnnN + #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} \l_@@_aligned_coffin + \box_set_ht:Nn \l_@@_aligned_coffin { \box_ht:N #1 } + \box_set_dp:Nn \l_@@_aligned_coffin { \box_dp:N #1 } + \box_set_wd:Nn \l_@@_aligned_coffin { \box_wd:N #1 } + \box_set_eq:NN #1 \l_@@_aligned_coffin } \cs_generate_variant:Nn \coffin_attach:NnnNnnnn { c , Nnnc , cnnc } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}{\coffin_align:NnnNnnnnN} +% \begin{macro}{\@@_align:NnnNnnnnN} % The internal function aligns the two coffins into a third one, but % performs no corrections on the resulting coffin poles. The process % begins by finding the points of intersection for the poles for each @@ -1319,30 +1294,30 @@ % input coffins. The default poles are then set up, but the final result % will depend on how the bounding box is being handled. % \begin{macrocode} -\cs_new_protected:Npn \coffin_align:NnnNnnnnN #1#2#3#4#5#6#7#8#9 +\cs_new_protected:Npn \@@_align:NnnNnnnnN #1#2#3#4#5#6#7#8#9 { - \coffin_calculate_intersection:Nnn #4 {#5} {#6} - \dim_set:Nn \l_coffin_x_prime_dim { \l_coffin_x_dim } - \dim_set:Nn \l_coffin_y_prime_dim { \l_coffin_y_dim } - \coffin_calculate_intersection:Nnn #1 {#2} {#3} - \dim_set:Nn \l_coffin_offset_x_dim - { \l_coffin_x_dim - \l_coffin_x_prime_dim + #7 } - \dim_set:Nn \l_coffin_offset_y_dim - { \l_coffin_y_dim - \l_coffin_y_prime_dim + #8 } - \hbox_set:Nn \l_coffin_aligned_internal_coffin + \@@_calculate_intersection:Nnn #4 {#5} {#6} + \dim_set:Nn \l_@@_x_prime_dim { \l_@@_x_dim } + \dim_set:Nn \l_@@_y_prime_dim { \l_@@_y_dim } + \@@_calculate_intersection:Nnn #1 {#2} {#3} + \dim_set:Nn \l_@@_offset_x_dim + { \l_@@_x_dim - \l_@@_x_prime_dim + #7 } + \dim_set:Nn \l_@@_offset_y_dim + { \l_@@_y_dim - \l_@@_y_prime_dim + #8 } + \hbox_set:Nn \l_@@_aligned_internal_coffin { \box_use:N #1 \tex_kern:D -\box_wd:N #1 - \tex_kern:D \l_coffin_offset_x_dim - \box_move_up:nn { \l_coffin_offset_y_dim } { \box_use:N #4 } + \tex_kern:D \l_@@_offset_x_dim + \box_move_up:nn { \l_@@_offset_y_dim } { \box_use:N #4 } } - \coffin_set_eq:NN #9 \l_coffin_aligned_internal_coffin + \coffin_set_eq:NN #9 \l_@@_aligned_internal_coffin } % \end{macrocode} % \end{macro} % -% \begin{macro}{\coffin_offset_poles:Nnn} -% \begin{macro}[aux]{\coffin_offset_pole:Nnnnnnn} +% \begin{macro}{\@@_offset_poles:Nnn} +% \begin{macro}[aux]{\@@_offset_pole:Nnnnnnn} % Transferring structures from one coffin to another requires that the % positions are updated by the offset between the two coffins. This is % done by mapping to the property list of the source coffins, moving @@ -1353,22 +1328,22 @@ % or handle names, and that multiple alignments do not result in a % whole set of values. % \begin{macrocode} -\cs_new_protected:Npn \coffin_offset_poles:Nnn #1#2#3 +\cs_new_protected:Npn \@@_offset_poles:Nnn #1#2#3 { - \prop_map_inline:cn { l_coffin_poles_ \int_value:w #1 _prop } - { \coffin_offset_pole:Nnnnnnn #1 {##1} ##2 {#2} {#3} } + \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop } + { \@@_offset_pole:Nnnnnnn #1 {##1} ##2 {#2} {#3} } } -\cs_new_protected:Npn \coffin_offset_pole:Nnnnnnn #1#2#3#4#5#6#7#8 +\cs_new_protected:Npn \@@_offset_pole:Nnnnnnn #1#2#3#4#5#6#7#8 { - \dim_set:Nn \l_coffin_x_dim { #3 + #7 } - \dim_set:Nn \l_coffin_y_dim { #4 + #8 } + \dim_set:Nn \l_@@_x_dim { #3 + #7 } + \dim_set:Nn \l_@@_y_dim { #4 + #8 } \tl_if_in:nnTF {#2} { - } - { \tl_set:Nn \l_coffin_internal_tl { {#2} } } - { \tl_set:Nn \l_coffin_internal_tl { { #1 - #2 } } } - \exp_last_unbraced:NNo \coffin_set_pole:Nnx \l_coffin_aligned_coffin - { \l_coffin_internal_tl } + { \tl_set:Nn \l_@@_internal_tl { {#2} } } + { \tl_set:Nn \l_@@_internal_tl { { #1 - #2 } } } + \exp_last_unbraced:NNo \@@_set_pole:Nnx \l_@@_aligned_coffin + { \l_@@_internal_tl } { - { \dim_use:N \l_coffin_x_dim } { \dim_use:N \l_coffin_y_dim } + { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } {#5} {#6} } } @@ -1376,21 +1351,21 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\coffin_offset_corners:Nnn} -% \begin{macro}[aux]{\coffin_offset_corners:Nnnnn} +% \begin{macro}{\@@_offset_corners:Nnn} +% \begin{macro}[aux]{\@@_offset_corner:Nnnnn} % Saving the offset corners of a coffin is very similar, except that % there is no need to worry about naming: every corner can be saved % here as order is unimportant. % \begin{macrocode} -\cs_new_protected:Npn \coffin_offset_corners:Nnn #1#2#3 +\cs_new_protected:Npn \@@_offset_corners:Nnn #1#2#3 { - \prop_map_inline:cn { l_coffin_corners_ \int_value:w #1 _prop } - { \coffin_offset_corner:Nnnnn #1 {##1} ##2 {#2} {#3} } + \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop } + { \@@_offset_corner:Nnnnn #1 {##1} ##2 {#2} {#3} } } -\cs_new_protected:Npn \coffin_offset_corner:Nnnnn #1#2#3#4#5#6 +\cs_new_protected:Npn \@@_offset_corner:Nnnnn #1#2#3#4#5#6 { \prop_put:cnx - { l_coffin_corners_ \int_value:w \l_coffin_aligned_coffin _prop } + { l_@@_corners_ \__int_value:w \l_@@_aligned_coffin _prop } { #1 - #2 } { { \dim_eval:n { #3 + #5 } } @@ -1401,46 +1376,46 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\coffin_update_vertical_poles:NNN} -% \begin{macro}[aux]{\coffin_update_T:nnnnnnnnN} -% \begin{macro}[aux]{\coffin_update_B:nnnnnnnnN} +% \begin{macro}{\@@_update_vertical_poles:NNN} +% \begin{macro}[aux]{\@@_update_T:nnnnnnnnN} +% \begin{macro}[aux]{\@@_update_B:nnnnnnnnN} % The \texttt{T} and \texttt{B} poles will need to be recalculated % after alignment. These functions find the larger absolute value for % the poles, but this is of course only logical when the poles are % horizontal. % \begin{macrocode} -\cs_new_protected:Npn \coffin_update_vertical_poles:NNN #1#2#3 +\cs_new_protected:Npn \@@_update_vertical_poles:NNN #1#2#3 { - \coffin_get_pole:NnN #3 { #1 -T } \l_coffin_pole_a_tl - \coffin_get_pole:NnN #3 { #2 -T } \l_coffin_pole_b_tl - \exp_last_two_unbraced:Noo \coffin_update_T:nnnnnnnnN - \l_coffin_pole_a_tl \l_coffin_pole_b_tl #3 - \coffin_get_pole:NnN #3 { #1 -B } \l_coffin_pole_a_tl - \coffin_get_pole:NnN #3 { #2 -B } \l_coffin_pole_b_tl - \exp_last_two_unbraced:Noo \coffin_update_B:nnnnnnnnN - \l_coffin_pole_a_tl \l_coffin_pole_b_tl #3 + \@@_get_pole:NnN #3 { #1 -T } \l_@@_pole_a_tl + \@@_get_pole:NnN #3 { #2 -T } \l_@@_pole_b_tl + \exp_last_two_unbraced:Noo \@@_update_T:nnnnnnnnN + \l_@@_pole_a_tl \l_@@_pole_b_tl #3 + \@@_get_pole:NnN #3 { #1 -B } \l_@@_pole_a_tl + \@@_get_pole:NnN #3 { #2 -B } \l_@@_pole_b_tl + \exp_last_two_unbraced:Noo \@@_update_B:nnnnnnnnN + \l_@@_pole_a_tl \l_@@_pole_b_tl #3 } -\cs_new_protected:Npn \coffin_update_T:nnnnnnnnN #1#2#3#4#5#6#7#8#9 +\cs_new_protected:Npn \@@_update_T:nnnnnnnnN #1#2#3#4#5#6#7#8#9 { \dim_compare:nNnTF {#2} < {#6} { - \coffin_set_pole:Nnx #9 { T } + \@@_set_pole:Nnx #9 { T } { { 0 pt } {#6} { 1000 pt } { 0 pt } } } { - \coffin_set_pole:Nnx #9 { T } + \@@_set_pole:Nnx #9 { T } { { 0 pt } {#2} { 1000 pt } { 0 pt } } } } -\cs_new_protected:Npn \coffin_update_B:nnnnnnnnN #1#2#3#4#5#6#7#8#9 +\cs_new_protected:Npn \@@_update_B:nnnnnnnnN #1#2#3#4#5#6#7#8#9 { \dim_compare:nNnTF {#2} < {#6} { - \coffin_set_pole:Nnx #9 { B } + \@@_set_pole:Nnx #9 { B } { { 0 pt } {#2} { 1000 pt } { 0 pt } } } { - \coffin_set_pole:Nnx #9 { B } + \@@_set_pole:Nnx #9 { B } { { 0 pt } {#6} { 1000 pt } { 0 pt } } } } @@ -1456,556 +1431,120 @@ % \begin{macrocode} \cs_new_protected:Npn \coffin_typeset:Nnnnn #1#2#3#4#5 { - \coffin_align:NnnNnnnnN \c_empty_coffin { H } { l } - #1 {#2} {#3} {#4} {#5} \l_coffin_aligned_coffin + \@@_align:NnnNnnnnN \c_empty_coffin { H } { l } + #1 {#2} {#3} {#4} {#5} \l_@@_aligned_coffin \hbox_unpack:N \c_empty_box - \box_use:N \l_coffin_aligned_coffin + \box_use:N \l_@@_aligned_coffin } \cs_generate_variant:Nn \coffin_typeset:Nnnnn { c } % \end{macrocode} % \end{macro} % -% \subsection{Rotating coffins} -% -% \begin{variable}{\l_coffin_bounding_prop} -% A property list for the bounding box of a coffin. This is only needed -% during the rotation, so there is just the one. -% \begin{macrocode} -\prop_new:N \l_coffin_bounding_prop -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_coffin_bounding_shift_dim} -% The shift of the bounding box of a coffin from the real content. -% \begin{macrocode} -\dim_new:N \l_coffin_bounding_shift_dim -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_coffin_left_corner_dim} -% \begin{variable}{\l_coffin_right_corner_dim} -% \begin{variable}{\l_coffin_bottom_corner_dim} -% \begin{variable}{\l_coffin_top_corner_dim} -% These are used to hold maxima for the various corner values: these -% thus define the minimum size of the bounding box after rotation. -% \begin{macrocode} -\dim_new:N \l_coffin_left_corner_dim -\dim_new:N \l_coffin_right_corner_dim -\dim_new:N \l_coffin_bottom_corner_dim -\dim_new:N \l_coffin_top_corner_dim -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{macro}{\coffin_rotate:Nn, \coffin_rotate:cn} -% Rotating a coffin requires several steps which can be conveniently -% run together. The first step is to convert the angle given in degrees -% to one in radians. This is then used to set \cs{l_coffin_sin_fp} and -% \cs{l_coffin_cos_fp}, which are carried through unchanged for the rest -% of the procedure. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_rotate:Nn #1#2 - { - \fp_set:Nn \l_coffin_internal_fp {#2} - \fp_div:Nn \l_coffin_internal_fp { 180 } - \fp_mul:Nn \l_coffin_internal_fp { \c_pi_fp } - \fp_sin:Nn \l_coffin_sin_fp { \l_coffin_internal_fp } - \fp_cos:Nn \l_coffin_cos_fp { \l_coffin_internal_fp } -% \end{macrocode} -% The corners and poles of the coffin can now be rotated around the -% origin. This is best achieved using mapping functions. -% \begin{macrocode} - \prop_map_inline:cn { l_coffin_corners_ \int_value:w #1 _prop } - { \coffin_rotate_corner:Nnnn #1 {##1} ##2 } - \prop_map_inline:cn { l_coffin_poles_ \int_value:w #1 _prop } - { \coffin_rotate_pole:Nnnnnn #1 {##1} ##2 } -% \end{macrocode} -% The bounding box of the coffin needs to be rotated, and to do this -% the corners have to be found first. They are then rotated in the same -% way as the corners of the coffin material itself. -% \begin{macrocode} - \coffin_set_bounding:N #1 - \prop_map_inline:Nn \l_coffin_bounding_prop - { \coffin_rotate_bounding:nnn {##1} ##2 } -% \end{macrocode} -% At this stage, there needs to be a calculation to find where the -% corners of the content and the box itself will end up. -% \begin{macrocode} - \coffin_find_corner_maxima:N #1 - \coffin_find_bounding_shift: - \box_rotate:Nn #1 {#2} -% \end{macrocode} -% The correction of the box position itself takes place here. The idea -% is that the bounding box for a coffin is tight up to the content, and -% has the reference point at the bottom-left. The $x$-direction is -% handled by moving the content by the difference in the positions of -% the bounding box and the content left edge. The $y$-direction is -% dealt with by moving the box down by any depth it has acquired. -% \begin{macrocode} - \hbox_set:Nn #1 - { - \tex_kern:D \l_coffin_bounding_shift_dim - \tex_kern:D -\l_coffin_left_corner_dim - \box_move_down:nn { \l_coffin_bottom_corner_dim } - { \box_use:N #1 } - } -% \end{macrocode} -% If there have been any previous rotations then the size of the -% bounding box will be bigger than the contents. This can be corrected -% easily by setting the size of the box to the height and width of the -% content. -% \begin{macrocode} - \box_set_ht:Nn #1 - { \l_coffin_top_corner_dim - \l_coffin_bottom_corner_dim } - \box_set_dp:Nn #1 { 0 pt } - \box_set_wd:Nn #1 - { \l_coffin_right_corner_dim - \l_coffin_left_corner_dim } -% \end{macrocode} -% The final task is to move the poles and corners such that they are -% back in alignment with the box reference point. -% \begin{macrocode} - \prop_map_inline:cn { l_coffin_corners_ \int_value:w #1 _prop } - { \coffin_shift_corner:Nnnn #1 {##1} ##2 } - \prop_map_inline:cn { l_coffin_poles_ \int_value:w #1 _prop } - { \coffin_shift_pole:Nnnnnn #1 {##1} ##2 } - } -\cs_generate_variant:Nn \coffin_rotate:Nn { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\coffin_set_bounding:N} -% The bounding box corners for a coffin are easy enough to find: this -% is the same code as for the corners of the material itself, but -% using a dedicated property list. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_set_bounding:N #1 - { - \prop_put:Nnx \l_coffin_bounding_prop { tl } - { { 0 pt } { \dim_use:N \box_ht:N #1 } } - \prop_put:Nnx \l_coffin_bounding_prop { tr } - { { \dim_use:N \box_wd:N #1 } { \dim_use:N \box_ht:N #1 } } - \dim_set:Nn \l_coffin_internal_dim { - \box_dp:N #1 } - \prop_put:Nnx \l_coffin_bounding_prop { bl } - { { 0 pt } { \dim_use:N \l_coffin_internal_dim } } - \prop_put:Nnx \l_coffin_bounding_prop { br } - { { \dim_use:N \box_wd:N #1 } { \dim_use:N \l_coffin_internal_dim } } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\coffin_rotate_bounding:nnn} -% \begin{macro}{\coffin_rotate_corner:Nnnn} -% Rotating the position of the corner of the coffin is just a case -% of treating this as a vector from the reference point. The same -% treatment is used for the corners of the material itself and the -% bounding box. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_rotate_bounding:nnn #1#2#3 - { - \coffin_rotate_vector:nnNN {#2} {#3} \l_coffin_x_dim \l_coffin_y_dim - \prop_put:Nnx \l_coffin_bounding_prop {#1} - { { \dim_use:N \l_coffin_x_dim } { \dim_use:N \l_coffin_y_dim } } - } -\cs_new_protected:Npn \coffin_rotate_corner:Nnnn #1#2#3#4 - { - \coffin_rotate_vector:nnNN {#3} {#4} \l_coffin_x_dim \l_coffin_y_dim - \prop_put:cnx { l_coffin_corners_ \int_value:w #1 _prop } {#2} - { { \dim_use:N \l_coffin_x_dim } { \dim_use:N \l_coffin_y_dim } } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\coffin_rotate_pole:Nnnnnn} -% Rotating a single pole simply means shifting the co-ordinate of -% the pole and its direction. The rotation here is about the bottom-left -% corner of the coffin. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_rotate_pole:Nnnnnn #1#2#3#4#5#6 - { - \coffin_rotate_vector:nnNN {#3} {#4} \l_coffin_x_dim \l_coffin_y_dim - \coffin_rotate_vector:nnNN {#5} {#6} - \l_coffin_x_prime_dim \l_coffin_y_prime_dim - \coffin_set_pole:Nnx #1 {#2} - { - { \dim_use:N \l_coffin_x_dim } { \dim_use:N \l_coffin_y_dim } - { \dim_use:N \l_coffin_x_prime_dim } - { \dim_use:N \l_coffin_y_prime_dim } - } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\coffin_rotate_vector:nnNN} -% A rotation function, which needs only an input vector (as dimensions) -% and an output space. The values \cs{l_coffin_cos_fp} and -% \cs{l_coffin_sin_fp} should previously have been set up correctly. -% Working this way means that the floating point work is kept to a -% minimum: for any given rotation the sin and cosine values do no -% change, after all. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_rotate_vector:nnNN #1#2#3#4 - { - \fp_set_from_dim:Nn \l_coffin_x_fp {#1} - \fp_set_from_dim:Nn \l_coffin_y_fp {#2} - \fp_set_eq:NN \l_coffin_x_prime_fp \l_coffin_x_fp - \fp_set_eq:NN \l_coffin_internal_fp \l_coffin_y_fp - \fp_mul:Nn \l_coffin_x_prime_fp { \l_coffin_cos_fp } - \fp_mul:Nn \l_coffin_internal_fp { \l_coffin_sin_fp } - \fp_sub:Nn \l_coffin_x_prime_fp { \l_coffin_internal_fp } - \fp_set_eq:NN \l_coffin_y_prime_fp \l_coffin_y_fp - \fp_set_eq:NN \l_coffin_internal_fp \l_coffin_x_fp - \fp_mul:Nn \l_coffin_y_prime_fp { \l_coffin_cos_fp } - \fp_mul:Nn \l_coffin_internal_fp { \l_coffin_sin_fp } - \fp_add:Nn \l_coffin_y_prime_fp { \l_coffin_internal_fp } - \dim_set:Nn #3 { \fp_to_dim:N \l_coffin_x_prime_fp } - \dim_set:Nn #4 { \fp_to_dim:N \l_coffin_y_prime_fp } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\coffin_find_corner_maxima:N} -% \begin{macro}[aux]{\coffin_find_corner_maxima_aux:nn} -% The idea here is to find the extremities of the content of the -% coffin. This is done by looking for the smallest values for the bottom -% and left corners, and the largest values for the top and right -% corners. The values start at the maximum dimensions so that the -% case where all are positive or all are negative works out correctly. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_find_corner_maxima:N #1 - { - \dim_set:Nn \l_coffin_top_corner_dim { -\c_max_dim } - \dim_set:Nn \l_coffin_right_corner_dim { -\c_max_dim } - \dim_set:Nn \l_coffin_bottom_corner_dim { \c_max_dim } - \dim_set:Nn \l_coffin_left_corner_dim { \c_max_dim } - \prop_map_inline:cn { l_coffin_corners_ \int_value:w #1 _prop } - { \coffin_find_corner_maxima_aux:nn ##2 } - } -\cs_new_protected:Npn \coffin_find_corner_maxima_aux:nn #1#2 - { - \dim_set_min:Nn \l_coffin_left_corner_dim {#1} - \dim_set_max:Nn \l_coffin_right_corner_dim {#1} - \dim_set_min:Nn \l_coffin_bottom_corner_dim {#2} - \dim_set_max:Nn \l_coffin_top_corner_dim {#2} - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\coffin_find_bounding_shift:} -% \begin{macro}[aux]{\coffin_find_bounding_shift_aux:nn} -% The approach to finding the shift for the bounding box is similar to -% that for the corners. However, there is only one value needed here and -% a fixed input property list, so things are a bit clearer. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \coffin_find_bounding_shift: - { - \dim_set:Nn \l_coffin_bounding_shift_dim { \c_max_dim } - \prop_map_inline:Nn \l_coffin_bounding_prop - { \coffin_find_bounding_shift_aux:nn ##2 } - } -\cs_new_protected:Npn \coffin_find_bounding_shift_aux:nn #1#2 - { \dim_set_min:Nn \l_coffin_bounding_shift_dim {#1} } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\coffin_shift_corner:Nnnn} -% \begin{macro}{\coffin_shift_pole:Nnnnnn} -% Shifting the corners and poles of a coffin means subtracting the -% appropriate values from the $x$- and $y$-components. For -% the poles, this means that the direction vector is unchanged. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_shift_corner:Nnnn #1#2#3#4 - { - \prop_put:cnx { l_coffin_corners_ \int_value:w #1 _ prop } {#2} - { - { \dim_eval:n { #3 - \l_coffin_left_corner_dim } } - { \dim_eval:n { #4 - \l_coffin_bottom_corner_dim } } - } - } -\cs_new_protected:Npn \coffin_shift_pole:Nnnnnn #1#2#3#4#5#6 - { - \prop_put:cnx { l_coffin_poles_ \int_value:w #1 _ prop } {#2} - { - { \dim_eval:n { #3 - \l_coffin_left_corner_dim } } - { \dim_eval:n { #4 - \l_coffin_bottom_corner_dim } } - {#5} {#6} - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsection{Resizing coffins} -% -% \begin{variable}{\l_coffin_scale_x_fp} -% \begin{variable}{\l_coffin_scale_y_fp} -% Storage for the scaling factors in $x$ and $y$, respectively. -% \begin{macrocode} -\fp_new:N \l_coffin_scale_x_fp -\fp_new:N \l_coffin_scale_y_fp -% \end{macrocode} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\l_coffin_scaled_total_height_dim} -% \begin{variable}{\l_coffin_scaled_width_dim} -% When scaling, the values given have to be turned into absolute values. -% \begin{macrocode} -\dim_new:N \l_coffin_scaled_total_height_dim -\dim_new:N \l_coffin_scaled_width_dim -% \end{macrocode} -% \end{variable} -% \end{variable} -% -% \begin{macro}{\coffin_resize:Nnn, \coffin_resize:cnn} -% Resizing a coffin begins by setting up the user-friendly names for -% the dimensions of the coffin box. The new sizes are then turned into -% scale factor. This is the same operation as takes place for the -% underlying box, but that operation is grouped and so the same -% calculation is done here. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_resize:Nnn #1#2#3 - { - \coffin_set_user_dimensions:N #1 - \box_resize:Nnn #1 {#2} {#3} - \fp_set_from_dim:Nn \l_coffin_scale_x_fp {#2} - \fp_set_from_dim:Nn \l_coffin_internal_fp { \Width } - \fp_div:Nn \l_coffin_scale_x_fp { \l_coffin_internal_fp } - \fp_set_from_dim:Nn \l_coffin_scale_y_fp {#3} - \fp_set_from_dim:Nn \l_coffin_internal_fp { \TotalHeight } - \fp_div:Nn \l_coffin_scale_y_fp { \l_coffin_internal_fp } - \coffin_resize_common:Nnn #1 {#2} {#3} - } -\cs_generate_variant:Nn \coffin_resize:Nnn { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\coffin_resize_common:Nnn} -% The poles and corners of the coffin are scaled to the appropriate -% places before actually resizing the underlying box. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_resize_common:Nnn #1#2#3 - { - \prop_map_inline:cn { l_coffin_corners_ \int_value:w #1 _prop } - { \coffin_scale_corner:Nnnn #1 {##1} ##2 } - \prop_map_inline:cn { l_coffin_poles_ \int_value:w #1 _prop } - { \coffin_scale_pole:Nnnnnn #1 {##1} ##2 } -% \end{macrocode} -% Negative $x$-scaling values will place the poles in the wrong -% location: this is corrected here. -% \begin{macrocode} - \fp_compare:NNNT \l_coffin_scale_x_fp < \c_zero_fp - { - \prop_map_inline:cn { l_coffin_corners_ \int_value:w #1 _prop } - { \coffin_x_shift_corner:Nnnn #1 {##1} ##2 } - \prop_map_inline:cn { l_coffin_poles_ \int_value:w #1 _prop } - { \coffin_x_shift_pole:Nnnnnn #1 {##1} ##2 } - } - \coffin_end_user_dimensions: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\coffin_scale:Nnn, \coffin_scale:cnn} -% For scaling, the opposite calculation is done to find the new -% dimensions for the coffin. Only the total height is needed, as this -% is the shift required for corners and poles. The scaling is done -% the \TeX{} way as this works properly with floating point values -% without needing to use the \texttt{fp} module. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_scale:Nnn #1#2#3 - { - \box_scale:Nnn #1 {#2} {#3} - \coffin_set_user_dimensions:N #1 - \fp_set:Nn \l_coffin_scale_x_fp {#2} - \fp_set:Nn \l_coffin_scale_y_fp {#3} - \fp_compare:NNNTF \l_coffin_scale_y_fp > \c_zero_fp - { \l_coffin_scaled_total_height_dim #3 \TotalHeight } - { \l_coffin_scaled_total_height_dim -#3 \TotalHeight } - \fp_compare:NNNTF \l_coffin_scale_x_fp > \c_zero_fp - { \l_coffin_scaled_width_dim -#2 \Width } - { \l_coffin_scaled_width_dim #2 \Width } - \coffin_resize_common:Nnn #1 - { \l_coffin_scaled_width_dim } { \l_coffin_scaled_total_height_dim } - } -\cs_generate_variant:Nn \coffin_scale:Nnn { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\coffin_scale_vector:nnNN} -% This functions scales a vector from the origin using the pre-set scale -% factors in $x$ and $y$. This is a much less complex operation -% than rotation, and as a result the code is a lot clearer. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_scale_vector:nnNN #1#2#3#4 - { - \fp_set_from_dim:Nn \l_coffin_internal_fp {#1} - \fp_mul:Nn \l_coffin_internal_fp { \l_coffin_scale_x_fp } - \dim_set:Nn #3 { \fp_to_dim:N \l_coffin_internal_fp } - \fp_set_from_dim:Nn \l_coffin_internal_fp {#2} - \fp_mul:Nn \l_coffin_internal_fp { \l_coffin_scale_y_fp } - \dim_set:Nn #4 { \fp_to_dim:N \l_coffin_internal_fp } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\coffin_scale_corner:Nnnn} -% \begin{macro}{\coffin_scale_pole:Nnnnnn} -% Scaling both corners and poles is a simple calculation using the -% preceding vector scaling. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_scale_corner:Nnnn #1#2#3#4 - { - \coffin_scale_vector:nnNN {#3} {#4} \l_coffin_x_dim \l_coffin_y_dim - \prop_put:cnx { l_coffin_corners_ \int_value:w #1 _prop } {#2} - { { \dim_use:N \l_coffin_x_dim } { \dim_use:N \l_coffin_y_dim } } - } -\cs_new_protected:Npn \coffin_scale_pole:Nnnnnn #1#2#3#4#5#6 - { - \coffin_scale_vector:nnNN {#3} {#4} \l_coffin_x_dim \l_coffin_y_dim - \coffin_set_pole:Nnx #1 {#2} - { - { \dim_use:N \l_coffin_x_dim } { \dim_use:N \l_coffin_y_dim } - {#5} {#6} - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\coffin_x_shift_corner:Nnnn} -% \begin{macro}{\coffin_x_shift_pole:Nnnnnn} -% These functions correct for the $x$ displacement that takes -% place with a negative horizontal scaling. -% \begin{macrocode} -\cs_new_protected:Npn \coffin_x_shift_corner:Nnnn #1#2#3#4 - { - \prop_put:cnx { l_coffin_corners_ \int_value:w #1 _prop } {#2} - { - { \dim_eval:n { #3 + \box_wd:N #1 } } {#4} - } - } -\cs_new_protected:Npn \coffin_x_shift_pole:Nnnnnn #1#2#3#4#5#6 - { - \prop_put:cnx { l_coffin_poles_ \int_value:w #1 _prop } {#2} - { - { \dim_eval:n #3 + \box_wd:N #1 } {#4} - {#5} {#6} - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% % \subsection{Coffin diagnostics} % -% \begin{variable}{\l_coffin_display_coffin} -% \begin{variable}{\l_coffin_display_coord_coffin} -% \begin{variable}{\l_coffin_display_pole_coffin} +% \begin{variable}{\l_@@_display_coffin} +% \begin{variable}{\l_@@_display_coord_coffin} +% \begin{variable}{\l_@@_display_pole_coffin} % Used for printing coffins with data structures attached. % \begin{macrocode} -\coffin_new:N \l_coffin_display_coffin -\coffin_new:N \l_coffin_display_coord_coffin -\coffin_new:N \l_coffin_display_pole_coffin +\coffin_new:N \l_@@_display_coffin +\coffin_new:N \l_@@_display_coord_coffin +\coffin_new:N \l_@@_display_pole_coffin % \end{macrocode} % \end{variable} % \end{variable} % \end{variable} % -% \begin{variable}{\l_coffin_display_handles_prop} +% \begin{variable}{\l_@@_display_handles_prop} % This property list is used to print coffin handles at suitable % positions. The offsets are expressed as multiples of the basic offset % value, which therefore acts as a scale-factor. % \begin{macrocode} -\prop_new:N \l_coffin_display_handles_prop -\prop_put:Nnn \l_coffin_display_handles_prop { tl } +\prop_new:N \l_@@_display_handles_prop +\prop_put:Nnn \l_@@_display_handles_prop { tl } { { b } { r } { -1 } { 1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { thc } +\prop_put:Nnn \l_@@_display_handles_prop { thc } { { b } { hc } { 0 } { 1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { tr } +\prop_put:Nnn \l_@@_display_handles_prop { tr } { { b } { l } { 1 } { 1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { vcl } +\prop_put:Nnn \l_@@_display_handles_prop { vcl } { { vc } { r } { -1 } { 0 } } -\prop_put:Nnn \l_coffin_display_handles_prop { vchc } +\prop_put:Nnn \l_@@_display_handles_prop { vchc } { { vc } { hc } { 0 } { 0 } } -\prop_put:Nnn \l_coffin_display_handles_prop { vcr } +\prop_put:Nnn \l_@@_display_handles_prop { vcr } { { vc } { l } { 1 } { 0 } } -\prop_put:Nnn \l_coffin_display_handles_prop { bl } +\prop_put:Nnn \l_@@_display_handles_prop { bl } { { t } { r } { -1 } { -1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { bhc } +\prop_put:Nnn \l_@@_display_handles_prop { bhc } { { t } { hc } { 0 } { -1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { br } +\prop_put:Nnn \l_@@_display_handles_prop { br } { { t } { l } { 1 } { -1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { Tl } +\prop_put:Nnn \l_@@_display_handles_prop { Tl } { { t } { r } { -1 } { -1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { Thc } +\prop_put:Nnn \l_@@_display_handles_prop { Thc } { { t } { hc } { 0 } { -1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { Tr } +\prop_put:Nnn \l_@@_display_handles_prop { Tr } { { t } { l } { 1 } { -1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { Hl } +\prop_put:Nnn \l_@@_display_handles_prop { Hl } { { vc } { r } { -1 } { 1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { Hhc } +\prop_put:Nnn \l_@@_display_handles_prop { Hhc } { { vc } { hc } { 0 } { 1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { Hr } +\prop_put:Nnn \l_@@_display_handles_prop { Hr } { { vc } { l } { 1 } { 1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { Bl } +\prop_put:Nnn \l_@@_display_handles_prop { Bl } { { b } { r } { -1 } { -1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { Bhc } +\prop_put:Nnn \l_@@_display_handles_prop { Bhc } { { b } { hc } { 0 } { -1 } } -\prop_put:Nnn \l_coffin_display_handles_prop { Br } +\prop_put:Nnn \l_@@_display_handles_prop { Br } { { b } { l } { 1 } { -1 } } % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_coffin_display_offset_dim} +% \begin{variable}{\l_@@_display_offset_dim} % The standard offset for the label from the handle position when % displaying handles. % \begin{macrocode} -\dim_new:N \l_coffin_display_offset_dim -\dim_set:Nn \l_coffin_display_offset_dim { 2 pt } +\dim_new:N \l_@@_display_offset_dim +\dim_set:Nn \l_@@_display_offset_dim { 2 pt } % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_coffin_display_x_dim} -% \begin{variable}{\l_coffin_display_y_dim} +% \begin{variable}{\l_@@_display_x_dim} +% \begin{variable}{\l_@@_display_y_dim} % As the intersections of poles have to be calculated to find which % ones to print, there is a need to avoid repetition. This is done % by saving the intersection into two dedicated values. % \begin{macrocode} -\dim_new:N \l_coffin_display_x_dim -\dim_new:N \l_coffin_display_y_dim +\dim_new:N \l_@@_display_x_dim +\dim_new:N \l_@@_display_y_dim % \end{macrocode} % \end{variable} % \end{variable} % -% \begin{variable}{\l_coffin_display_poles_prop} +% \begin{variable}{\l_@@_display_poles_prop} % A property list for printing poles: various things need to be deleted % from this to get a \enquote{nice} output. % \begin{macrocode} -\prop_new:N \l_coffin_display_poles_prop +\prop_new:N \l_@@_display_poles_prop % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_coffin_display_font_tl} +% \begin{variable}{\l_@@_display_font_tl} % Stores the settings used to print coffin data: this keeps things % flexible. % \begin{macrocode} -\tl_new:N \l_coffin_display_font_tl +\tl_new:N \l_@@_display_font_tl %<*initex> -\tl_set:Nn \l_coffin_display_font_tl { } % TODO +\tl_set:Nn \l_@@_display_font_tl { } % TODO %</initex> %<*package> -\tl_set:Nn \l_coffin_display_font_tl { \sffamily \tiny } +\tl_set:Nn \l_@@_display_font_tl { \sffamily \tiny } %</package> % \end{macrocode} % \end{variable} % % \begin{macro}{\coffin_mark_handle:Nnnn, \coffin_mark_handle:cnnn} -% \begin{macro}[aux]{\coffin_mark_handle_aux:nnnnNnn} +% \begin{macro}[aux]{\@@_mark_handle_aux:nnnnNnn} % Marking a single handle is relatively easy. The standard attachment % function is used, meaning that there are two calculations for the % location. However, this is likely to be okay given the load expected. @@ -2014,7 +1553,7 @@ % \begin{macrocode} \cs_new_protected:Npn \coffin_mark_handle:Nnnn #1#2#3#4 { - \hcoffin_set:Nn \l_coffin_display_pole_coffin + \hcoffin_set:Nn \l_@@_display_pole_coffin { %<*initex> \hbox:n { \tex_vrule:D width 1 pt height 1 pt \scan_stop: } % TODO @@ -2025,8 +1564,8 @@ %</package> } \coffin_attach_mark:NnnNnnnn #1 {#2} {#3} - \l_coffin_display_pole_coffin { hc } { vc } { 0 pt } { 0 pt } - \hcoffin_set:Nn \l_coffin_display_coord_coffin + \l_@@_display_pole_coffin { hc } { vc } { 0 pt } { 0 pt } + \hcoffin_set:Nn \l_@@_display_coord_coffin { %<*initex> % TODO @@ -2034,37 +1573,37 @@ %<*package> \color {#4} %</package> - \l_coffin_display_font_tl + \l_@@_display_font_tl ( \tl_to_str:n { #2 , #3 } ) } - \prop_get:NnN \l_coffin_display_handles_prop - { #2 #3 } \l_coffin_internal_tl - \quark_if_no_value:NTF \l_coffin_internal_tl + \prop_get:NnN \l_@@_display_handles_prop + { #2 #3 } \l_@@_internal_tl + \quark_if_no_value:NTF \l_@@_internal_tl { - \prop_get:NnN \l_coffin_display_handles_prop - { #3 #2 } \l_coffin_internal_tl - \quark_if_no_value:NTF \l_coffin_internal_tl + \prop_get:NnN \l_@@_display_handles_prop + { #3 #2 } \l_@@_internal_tl + \quark_if_no_value:NTF \l_@@_internal_tl { \coffin_attach_mark:NnnNnnnn #1 {#2} {#3} - \l_coffin_display_coord_coffin { l } { vc } + \l_@@_display_coord_coffin { l } { vc } { 1 pt } { 0 pt } } { - \exp_last_unbraced:No \coffin_mark_handle_aux:nnnnNnn - \l_coffin_internal_tl #1 {#2} {#3} + \exp_last_unbraced:No \@@_mark_handle_aux:nnnnNnn + \l_@@_internal_tl #1 {#2} {#3} } } { - \exp_last_unbraced:No \coffin_mark_handle_aux:nnnnNnn - \l_coffin_internal_tl #1 {#2} {#3} + \exp_last_unbraced:No \@@_mark_handle_aux:nnnnNnn + \l_@@_internal_tl #1 {#2} {#3} } } -\cs_new_protected:Npn \coffin_mark_handle_aux:nnnnNnn #1#2#3#4#5#6#7 +\cs_new_protected:Npn \@@_mark_handle_aux:nnnnNnn #1#2#3#4#5#6#7 { \coffin_attach_mark:NnnNnnnn #5 {#6} {#7} - \l_coffin_display_coord_coffin {#1} {#2} - { #3 \l_coffin_display_offset_dim } - { #4 \l_coffin_display_offset_dim } + \l_@@_display_coord_coffin {#1} {#2} + { #3 \l_@@_display_offset_dim } + { #4 \l_@@_display_offset_dim } } \cs_generate_variant:Nn \coffin_mark_handle:Nnnn { c } % \end{macrocode} @@ -2072,9 +1611,9 @@ % \end{macro} % % \begin{macro}{\coffin_display_handles:Nn, \coffin_display_handles:cn} -% \begin{macro}[aux]{\coffin_display_handles_aux:nnnnnn} -% \begin{macro}[aux]{\coffin_display_handles_aux:nnnn} -% \begin{macro}[aux]{\coffin_display_attach:Nnnnn} +% \begin{macro}[aux]{\@@_display_handles_aux:nnnnnn} +% \begin{macro}[aux]{\@@_display_handles_aux:nnnn} +% \begin{macro}[aux]{\@@_display_attach:Nnnnn} % Printing the poles starts by removing any duplicates, for which the % \texttt{H} poles is used as the definitive version for the baseline % and bottom. Two loops are then used to find the combinations of @@ -2083,7 +1622,7 @@ % \begin{macrocode} \cs_new_protected:Npn \coffin_display_handles:Nn #1#2 { - \hcoffin_set:Nn \l_coffin_display_pole_coffin + \hcoffin_set:Nn \l_@@_display_pole_coffin { %<*initex> \hbox:n { \tex_vrule:D width 1 pt height 1 pt \scan_stop: } % TODO @@ -2093,22 +1632,22 @@ \rule { 1 pt } { 1 pt } %</package> } - \prop_set_eq:Nc \l_coffin_display_poles_prop - { l_coffin_poles_ \int_value:w #1 _prop } - \coffin_get_pole:NnN #1 { H } \l_coffin_pole_a_tl - \coffin_get_pole:NnN #1 { T } \l_coffin_pole_b_tl - \tl_if_eq:NNT \l_coffin_pole_a_tl \l_coffin_pole_b_tl - { \prop_del:Nn \l_coffin_display_poles_prop { T } } - \coffin_get_pole:NnN #1 { B } \l_coffin_pole_b_tl - \tl_if_eq:NNT \l_coffin_pole_a_tl \l_coffin_pole_b_tl - { \prop_del:Nn \l_coffin_display_poles_prop { B } } - \coffin_set_eq:NN \l_coffin_display_coffin #1 - \prop_map_inline:Nn \l_coffin_display_poles_prop + \prop_set_eq:Nc \l_@@_display_poles_prop + { l_@@_poles_ \__int_value:w #1 _prop } + \@@_get_pole:NnN #1 { H } \l_@@_pole_a_tl + \@@_get_pole:NnN #1 { T } \l_@@_pole_b_tl + \tl_if_eq:NNT \l_@@_pole_a_tl \l_@@_pole_b_tl + { \prop_remove:Nn \l_@@_display_poles_prop { T } } + \@@_get_pole:NnN #1 { B } \l_@@_pole_b_tl + \tl_if_eq:NNT \l_@@_pole_a_tl \l_@@_pole_b_tl + { \prop_remove:Nn \l_@@_display_poles_prop { B } } + \coffin_set_eq:NN \l_@@_display_coffin #1 + \prop_map_inline:Nn \l_@@_display_poles_prop { - \prop_del:Nn \l_coffin_display_poles_prop {##1} - \coffin_display_handles_aux:nnnnnn {##1} ##2 {#2} + \prop_remove:Nn \l_@@_display_poles_prop {##1} + \@@_display_handles_aux:nnnnnn {##1} ##2 {#2} } - \box_use:N \l_coffin_display_coffin + \box_use:N \l_@@_display_coffin } % \end{macrocode} % For each pole there is a check for an intersection, which here does @@ -2116,20 +1655,20 @@ % and used to align the pole coffin with the main coffin for output. % The positions are recovered from the preset list if available. % \begin{macrocode} -\cs_new_protected:Npn \coffin_display_handles_aux:nnnnnn #1#2#3#4#5#6 +\cs_new_protected:Npn \@@_display_handles_aux:nnnnnn #1#2#3#4#5#6 { - \prop_map_inline:Nn \l_coffin_display_poles_prop + \prop_map_inline:Nn \l_@@_display_poles_prop { - \bool_set_false:N \l_coffin_error_bool - \coffin_calculate_intersection:nnnnnnnn {#2} {#3} {#4} {#5} ##2 - \bool_if:NF \l_coffin_error_bool + \bool_set_false:N \l_@@_error_bool + \@@_calculate_intersection:nnnnnnnn {#2} {#3} {#4} {#5} ##2 + \bool_if:NF \l_@@_error_bool { - \dim_set:Nn \l_coffin_display_x_dim { \l_coffin_x_dim } - \dim_set:Nn \l_coffin_display_y_dim { \l_coffin_y_dim } - \coffin_display_attach:Nnnnn - \l_coffin_display_pole_coffin { hc } { vc } + \dim_set:Nn \l_@@_display_x_dim { \l_@@_x_dim } + \dim_set:Nn \l_@@_display_y_dim { \l_@@_y_dim } + \@@_display_attach:Nnnnn + \l_@@_display_pole_coffin { hc } { vc } { 0 pt } { 0 pt } - \hcoffin_set:Nn \l_coffin_display_coord_coffin + \hcoffin_set:Nn \l_@@_display_coord_coffin { %<*initex> % TODO @@ -2137,40 +1676,40 @@ %<*package> \color {#6} %</package> - \l_coffin_display_font_tl + \l_@@_display_font_tl ( \tl_to_str:n { #1 , ##1 } ) } - \prop_get:NnN \l_coffin_display_handles_prop - { #1 ##1 } \l_coffin_internal_tl - \quark_if_no_value:NTF \l_coffin_internal_tl + \prop_get:NnN \l_@@_display_handles_prop + { #1 ##1 } \l_@@_internal_tl + \quark_if_no_value:NTF \l_@@_internal_tl { - \prop_get:NnN \l_coffin_display_handles_prop - { ##1 #1 } \l_coffin_internal_tl - \quark_if_no_value:NTF \l_coffin_internal_tl + \prop_get:NnN \l_@@_display_handles_prop + { ##1 #1 } \l_@@_internal_tl + \quark_if_no_value:NTF \l_@@_internal_tl { - \coffin_display_attach:Nnnnn - \l_coffin_display_coord_coffin { l } { vc } + \@@_display_attach:Nnnnn + \l_@@_display_coord_coffin { l } { vc } { 1 pt } { 0 pt } } { \exp_last_unbraced:No - \coffin_display_handles_aux:nnnn - \l_coffin_internal_tl + \@@_display_handles_aux:nnnn + \l_@@_internal_tl } } { - \exp_last_unbraced:No \coffin_display_handles_aux:nnnn - \l_coffin_internal_tl + \exp_last_unbraced:No \@@_display_handles_aux:nnnn + \l_@@_internal_tl } } } } -\cs_new_protected:Npn \coffin_display_handles_aux:nnnn #1#2#3#4 +\cs_new_protected:Npn \@@_display_handles_aux:nnnn #1#2#3#4 { - \coffin_display_attach:Nnnnn - \l_coffin_display_coord_coffin {#1} {#2} - { #3 \l_coffin_display_offset_dim } - { #4 \l_coffin_display_offset_dim } + \@@_display_attach:Nnnnn + \l_@@_display_coord_coffin {#1} {#2} + { #3 \l_@@_display_offset_dim } + { #4 \l_@@_display_offset_dim } } \cs_generate_variant:Nn \coffin_display_handles:Nn { c } % \end{macrocode} @@ -2179,29 +1718,29 @@ % and stored for the display coffin the code simply uses it directly, % with no calculation. % \begin{macrocode} -\cs_new_protected:Npn \coffin_display_attach:Nnnnn #1#2#3#4#5 +\cs_new_protected:Npn \@@_display_attach:Nnnnn #1#2#3#4#5 { - \coffin_calculate_intersection:Nnn #1 {#2} {#3} - \dim_set:Nn \l_coffin_x_prime_dim { \l_coffin_x_dim } - \dim_set:Nn \l_coffin_y_prime_dim { \l_coffin_y_dim } - \dim_set:Nn \l_coffin_offset_x_dim - { \l_coffin_display_x_dim - \l_coffin_x_prime_dim + #4 } - \dim_set:Nn \l_coffin_offset_y_dim - { \l_coffin_display_y_dim - \l_coffin_y_prime_dim + #5 } - \hbox_set:Nn \l_coffin_aligned_coffin + \@@_calculate_intersection:Nnn #1 {#2} {#3} + \dim_set:Nn \l_@@_x_prime_dim { \l_@@_x_dim } + \dim_set:Nn \l_@@_y_prime_dim { \l_@@_y_dim } + \dim_set:Nn \l_@@_offset_x_dim + { \l_@@_display_x_dim - \l_@@_x_prime_dim + #4 } + \dim_set:Nn \l_@@_offset_y_dim + { \l_@@_display_y_dim - \l_@@_y_prime_dim + #5 } + \hbox_set:Nn \l_@@_aligned_coffin { - \box_use:N \l_coffin_display_coffin - \tex_kern:D -\box_wd:N \l_coffin_display_coffin - \tex_kern:D \l_coffin_offset_x_dim - \box_move_up:nn { \l_coffin_offset_y_dim } { \box_use:N #1 } + \box_use:N \l_@@_display_coffin + \tex_kern:D -\box_wd:N \l_@@_display_coffin + \tex_kern:D \l_@@_offset_x_dim + \box_move_up:nn { \l_@@_offset_y_dim } { \box_use:N #1 } } - \box_set_ht:Nn \l_coffin_aligned_coffin - { \box_ht:N \l_coffin_display_coffin } - \box_set_dp:Nn \l_coffin_aligned_coffin - { \box_dp:N \l_coffin_display_coffin } - \box_set_wd:Nn \l_coffin_aligned_coffin - { \box_wd:N \l_coffin_display_coffin } - \box_set_eq:NN \l_coffin_display_coffin \l_coffin_aligned_coffin + \box_set_ht:Nn \l_@@_aligned_coffin + { \box_ht:N \l_@@_display_coffin } + \box_set_dp:Nn \l_@@_aligned_coffin + { \box_dp:N \l_@@_display_coffin } + \box_set_wd:Nn \l_@@_aligned_coffin + { \box_wd:N \l_@@_display_coffin } + \box_set_eq:NN \l_@@_display_coffin \l_@@_aligned_coffin } % \end{macrocode} % \end{macro} @@ -2216,13 +1755,13 @@ % \begin{macrocode} \cs_new_protected:Npn \coffin_show_structure:N #1 { - \coffin_if_exist:NT #1 + \@@_if_exist:NT #1 { - \msg_aux_show:Nnx #1 { coffins } + \__msg_show_variable:Nnn #1 { coffins } { \prop_map_function:cN - { l_coffin_poles_ \int_value:w #1 _prop } - \msg_aux_show_unbraced:nn + { l_@@_poles_ \__int_value:w #1 _prop } + \__msg_show_item_unbraced:nn } } } @@ -2233,7 +1772,7 @@ % \subsection{Messages} % % \begin{macrocode} -\msg_kernel_new:nnnn { coffins } { no-pole-intersection } +\__msg_kernel_new:nnnn { kernel } { no-pole-intersection } { No~intersection~between~coffin~poles. } { \c_msg_coding_error_text_tl @@ -2241,17 +1780,17 @@ but~they~do~not~have~a~unique~meeting~point:~ the~value~(0~pt,~0~pt)~will~be~used. } -\msg_kernel_new:nnnn { coffins } { unknown-coffin } +\__msg_kernel_new:nnnn { kernel } { unknown-coffin } { Unknown~coffin~'#1'. } { The~coffin~'#1'~was~never~defined. } -\msg_kernel_new:nnnn { coffins } { unknown-coffin-pole } +\__msg_kernel_new:nnnn { kernel } { unknown-coffin-pole } { Pole~'#1'~unknown~for~coffin~'#2'. } { \c_msg_coding_error_text_tl LaTeX~was~asked~to~find~a~typesetting~pole~for~a~coffin,~ but~either~the~coffin~does~not~exist~or~the~pole~name~is~wrong. } -\msg_kernel_new:nnn { coffins } { show } +\__msg_kernel_new:nnn { kernel } { show-coffins } { Size~of~coffin~\token_to_str:N #1 : \\ > ~ ht~=~\dim_use:N \box_ht:N #1 \\ diff --git a/Master/texmf-dist/source/latex/l3kernel/l3color.dtx b/Master/texmf-dist/source/latex/l3kernel/l3color.dtx index 2089859d4e3..e8aa1f5d050 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3color.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3color.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3color.dtx Copyright(C) 2011 The LaTeX3 Project +%% File: l3color.dtx Copyright(C) 2011,2012 The LaTeX3 Project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -36,7 +36,7 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3color.dtx 2776 2011-09-07 18:33:19Z joseph $ +\GetIdInfo$Id: l3color.dtx 3986 2012-07-15 19:23:51Z joseph $ {L3 Experimental colour support} %</driver|package> %<*driver> @@ -111,7 +111,7 @@ %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -135,10 +135,27 @@ % \begin{macrocode} %<*initex> \cs_new_protected_nopar:Npn \color_ensure_current: - { \driver_color_ensure_current: } + { \__driver_color_ensure_current: } %</initex> +% \end{macrocode} +% In package mode, the driver code may not be loaded. To keep down +% dependencies, if there is no driver code available and no \cs{set@color} +% then colour is not in use and this function can be a no-op. +% \begin{macrocode} %<*package> -\cs_new_protected_nopar:Npn \color_ensure_current: { \set@color } +\cs_new_protected_nopar:Npn \color_ensure_current: { } +\AtBeginDocument + { + \cs_if_exist:NTF \__driver_color_ensure_current: + { + \cs_set_protected_nopar:Npn \color_ensure_current: + { \__driver_color_ensure_current: } + } + { + \cs_if_exist:NT \set@color + { \cs_set_protected_nopar:Npn \color_ensure_current: { \set@color } } + } + } %</package> % \end{macrocode} % \end{macro} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx index 8eec496836e..137d75f056f 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3doc.dtx Copyright (C) 1990-2011 The LaTeX3 project +%% File: l3doc.dtx Copyright (C) 1990-2012 The LaTeX3 project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -55,7 +55,7 @@ Do not distribute a modified version of this file. % stop docstrip adding \endinput \postamble \endpostamble -\generate{\file{l3doc.cls}{\from{l3doc.dtx}{class}}} +\generate{\file{l3doc.cls}{\from{l3doc.dtx}{class,cfg}}} \generate{\file{l3doc.ist}{\from{l3doc.dtx}{docist}}} \ifx\fmtname\nameofplainTeX \expandafter\endbatchfile @@ -64,10 +64,6 @@ Do not distribute a modified version of this file. \fi %</driver> % -%<*driver|class> -\RequirePackage{expl3,xparse,calc} -%</driver|class> -% % Need to protect the file metadata for any modules that load l3doc. % This is restored after "\ProvideExplClass" below. % \begin{macrocode} @@ -78,7 +74,11 @@ Do not distribute a modified version of this file. % \end{macrocode} % %<*driver|class> -\GetIdInfo$Id: l3doc.dtx 3491 2012-03-04 06:13:18Z bruno $ +\RequirePackage{expl3,xparse,calc} +%</driver|class> +% +%<*driver|class> +\GetIdInfo$Id: l3doc.dtx 3989 2012-07-16 01:15:43Z bruno $ {L3 Experimental documentation class} %</driver|class> % @@ -265,7 +265,7 @@ Do not distribute a modified version of this file. % when the DTX file is "\DocInput"; use "\DisableDocumentation"/"\DisableImplementation" % to omit the contents of those environments. % -% Note that \cmd\DocInput\ now takes comma-separated arguments, and \cmd\DocInputAgain\ +% Note that "\DocInput" now takes comma-separated arguments, and "\DocInputAgain" % can be used to re-input all DTX files previously input in this way. % % \subsection{Describing functions in the documentation} @@ -463,16 +463,6 @@ Do not distribute a modified version of this file. %<*class> % \end{macrocode} % -% The Guilty Parties. -% \begin{macrocode} -\cs_new_nopar:Npn\Team{% - The~\LaTeX3~Project\thanks{% - Frank~Mittelbach,~Denys~Duchier,~Chris~Rowley,~ - Rainer~Sch\"opf,~Johannes~Braams,~Michael~Downes,~ - David~Carlisle,~Alan~Jeffrey,~Morten~H\o{}gholm,~Thomas~Lotze,~ - Javier~Bezos,~Will~Robertson,~Joseph~Wright,~Bruno~Le~Floch}} -% \end{macrocode} -% % \subsection{Variables} % % \begin{macrocode} @@ -518,6 +508,19 @@ Do not distribute a modified version of this file. \bool_new:N \g_doc_checktest_bool % \end{macrocode} % +% Temporaries: +% \begin{macrocode} +\seq_new:N \g_doc_tmpa_seq +\tl_new:N \l_doc_tmpa_tl +\tl_new:N \l_doc_tmpb_tl +\int_new:N \l_doc_tmpa_int +% \end{macrocode} +% +% Other: +% \begin{macrocode} +\bool_new:N \l_doc_tested_bool +% \end{macrocode} +% % \subsection{expl3 extras} % % \begin{macro} @@ -526,18 +529,20 @@ Do not distribute a modified version of this file. % \coffin_gset_eq:cN, \coffin_gset_eq:cc % } % Setting two coffins equal is just a wrapper around other functions. +% Slightly naughty use of an internal coffin function here, but \ldots % \begin{macrocode} \cs_set_protected_nopar:Npn \coffin_gset_eq:NN #1#2 { \coffin_if_exist:NT #1 { \box_gset_eq:NN #1 #2 - \coffin_gset_eq_structure:NN #1 #2 + \__coffin_gset_eq_structure:NN #1 #2 } } \cs_generate_variant:Nn \coffin_gset_eq:NN { c , Nc , cc } % \end{macrocode} % \end{macro} +% % % \subsection{Options and configuration} % @@ -571,16 +576,18 @@ Do not distribute a modified version of this file. \ExecuteOptions{full,a4paper,nocheck,nochecktest,lm-default} % \end{macrocode} % -% Input a local configuration file, if it exists. +% Input a local configuration file, if it exists, with a message to the console that this has happened. Since we distribute a cfg file with the class, this should usually always be true. Therefore, check for \cs{ExplMakeTitle} (defined in `our' cfg file) and only output the informational message if it's not found. % % \begin{macrocode} -\InputIfFileExists{l3doc.cfg} +\msg_new:nnn {l3doc} {input-cfg} { - \typeout{*************************************^^J - *~Local~config~file~l3doc.cfg~used ^^J - *************************************} + Local~config~file~l3doc.cfg~loaded. + } +\file_if_exist:nT {l3doc.cfg} + { + \file_input:n {l3doc.cfg} + \msg_info:nn {l3doc} {input-cfg} } - { \@input{l3doc.ltx} } % \end{macrocode} % % \begin{macrocode} @@ -597,6 +604,7 @@ Do not distribute a modified version of this file. { array, alphalph, + amsmath, booktabs, color, colortbl, @@ -679,9 +687,9 @@ Do not distribute a modified version of this file. % \begin{macrocode} \setcounter{StandardModuleDepth}{1} \@addtoreset{CodelineNo}{part} -\cs_set_nopar:Npn \theCodelineNo { - \textcolor[gray]{0.5}{ \sffamily\tiny\arabic{CodelineNo} } -} +\tl_replace_once:Nnn \theCodelineNo + { \HDorg@theCodelineNo } + { \textcolor[gray]{0.5} { \sffamily\tiny\arabic{CodelineNo} } } % \end{macrocode} % % @@ -762,13 +770,29 @@ Do not distribute a modified version of this file. % \end{macrocode} % % \begin{macro}{\cmd,\cs} -% |\cmd{\foo}| Prints |\foo| verbatim. It may be used inside moving -% arguments. |\cs{foo}| also prints |\foo|, for those who prefer that -% syntax. -% \begin{macrocode} -\cs_set_nopar:Npn \cmd #1 { \cs{\expandafter\cmd@to@cs\string#1} } -\cs_set_nopar:Npn \cmd@to@cs #1#2 { \char\number`#2\relax } -\DeclareRobustCommand \cs [1] { \texttt { \char`\\ #1 } } +% |\cmd{\foo}| Prints |\foo| verbatim. It may be used inside moving +% arguments. |\cs{foo}| also prints |\foo|, for those who prefer that +% syntax. There is a bit of shuffling around to make sure that |_| +% has the catcode that \cs{doc_replace_at_at:N} expects, without +% rescanning the whole argument. For that we store in +% \cs{l_doc_tmpb_tl} a single underscore with the current catcode, +% then replace all such underscores by letter underscores in |#1| +% (stored in the |tmpa| token list). After calling +% \cs{doc_replace_at_at:N}, we replace the underscores back to their +% old meaning before using the token list. +% \begin{macrocode} +\cs_set_nopar:Npn \cmd #1 { \cs{\expandafter \doc_cmd_to_cs:w \string#1} } +\cs_set_nopar:Npn \doc_cmd_to_cs:w #1#2 { \char\number`#2\relax } +\DeclareRobustCommand \cs [1] + { + \tl_set_rescan:Nnn \l_doc_tmpb_tl { } { _ } + \tl_set:Nn \l_doc_tmpa_tl {#1} + \tl_replace_all:NVn \l_doc_tmpa_tl \l_doc_tmpb_tl { _ } + \doc_replace_at_at:N \l_doc_tmpa_tl + \tl_replace_all:NnV \l_doc_tmpa_tl { _ } \l_doc_tmpb_tl + \texttt { \char`\\ \tl_use:N \l_doc_tmpa_tl} + } +\cs_generate_variant:Nn \tl_replace_all:Nnn { NV , NnV } % \end{macrocode} % \end{macro} % @@ -823,7 +847,7 @@ Do not distribute a modified version of this file. % \begin{macro}{\DisableDocumentation,\DisableImplementation} % \begin{macrocode} \cs_new:Npn \doc_implementation: { - \cs_set:Npn \variable {\macro[var]} + \DeclareDocumentCommand {\variable} { O{} } { \doc_macro:n { var , ##1 } } \cs_set_eq:NN \endvariable \endmacro } \cs_new:Npn \doc_docu: { @@ -931,8 +955,9 @@ Do not distribute a modified version of this file. \char_set_catcode_ignore:N \ % space \char_set_catcode_ignore:N \^^M \char_set_catcode_ignore:N \^^I - - \function_aux:n + \exp_after:wN + \group_end: + \function_aux:n } { \vcoffin_set_end: @@ -989,8 +1014,6 @@ Do not distribute a modified version of this file. % \begin{macrocode} \cs_set_nopar:Npn \function_aux:n #1 { - \group_end: - \tl_set:Nn \l_doc_function_input_tl {#1} \dim_zero:N \l_doc_trial_width_dim @@ -1027,7 +1050,7 @@ Do not distribute a modified version of this file. % about the functions being typeset and their variants. % The property list uses a specific format: the keys contained are the function `names' (stripped of signature) with values specified by a comma-separated list containing two brace groups per item: % \begin{center} -% "> {my_function} => { {" \meta{Nargs 1} "}{" \meta{sig.\ 1} "} , {" \meta{Nargs 2} "}{" \meta{sig.\ 2} "} , ... }" +% |> {my_function} => {| \Arg{Nargs_1} \Arg{sig_1} |,| \Arg{Nargs_2} \Arg{sig_2} |, ... }| % \end{center} % This somewhat arcane syntax is chosen to distinguish between all variants of control sequence that may be being documented here. (With or without \textsf{expl3} function syntax.) % \begin{macrocode} @@ -1048,22 +1071,22 @@ Do not distribute a modified version of this file. % finally, for regular old csnames: \exp_args:NNf \prop_get:NnNTF \l_doc_functions_block_prop - { \cs_get_function_name:N #1 } \l_doc_tmp_tl + { \__cs_get_function_name:N #1 } \l_doc_tmpb_tl { \prop_put:Nxx \l_doc_functions_block_prop - { \cs_get_function_name:N #1 } + { \__cs_get_function_name:N #1 } { - \l_doc_tmp_tl , - {\cs_get_arg_count_from_signature:N #1} - {\cs_get_function_signature:N #1} + \l_doc_tmpb_tl , + {\__cs_count_signature:N #1} + {\__cs_get_function_signature:N #1} } } { \prop_put:Nxx \l_doc_functions_block_prop - { \cs_get_function_name:N #1 } + { \__cs_get_function_name:N #1 } { - {\cs_get_arg_count_from_signature:N #1} - {\cs_get_function_signature:N #1} + {\__cs_count_signature:N #1} + {\__cs_get_function_signature:N #1} } } } @@ -1072,7 +1095,7 @@ Do not distribute a modified version of this file. { % for now don't bother splitting into variants: \tl_gclear:N \l_doc_function_name_prefix_tl - \prop_put:Nxx \l_doc_functions_block_prop { #1 } { {-1} {} } + \prop_put:Nxx \l_doc_functions_block_prop { \tl_to_str:n {#1} } { {-1} {} } } } @@ -1091,13 +1114,13 @@ Do not distribute a modified version of this file. \cs_new:Nn \doc_typeset_functions:nn { \clist_gset:Nn \l_doc_variants_clist {#2} - \clist_gpop:NN \l_doc_variants_clist \l_doc_tmp_tl + \clist_gpop:NN \l_doc_variants_clist \l_doc_tmpb_tl \exp_args:Nc \doc_typeset_functions_aux:N { #1 - \int_compare:nT { \exp_after:wN \use_i:nn \l_doc_tmp_tl > -1 } {:} - \int_compare:nT { \exp_after:wN \use_i:nn \l_doc_tmp_tl > 0 } - { \exp_after:wN \use_ii:nn \l_doc_tmp_tl } + \int_compare:nT { \exp_after:wN \use_i:nn \l_doc_tmpb_tl > -1 } {:} + \int_compare:nT { \exp_after:wN \use_i:nn \l_doc_tmpb_tl > 0 } + { \exp_after:wN \use_ii:nn \l_doc_tmpb_tl } } \\ } @@ -1105,18 +1128,22 @@ Do not distribute a modified version of this file. \cs_new_nopar:Nn \doc_typeset_functions_aux:N { \bool_if:NT \l_doc_meta_pTF_bool { + \tl_set:Nx \l_doc_pTF_name_tl + { \l_doc_function_name_prefix_tl \doc_predicate_from_base:N #1 } + \doc_special_main_index:o { \l_doc_pTF_name_tl } + \seq_gput_right:Nx \g_doc_functions_seq + { \tl_to_str:N \l_doc_pTF_name_tl } \tl_set:Nx \l_doc_pTF_name_tl { \doc_predicate_from_base:N #1 } - \doc_special_main_index:o { \tl_to_str:N \l_doc_pTF_name_tl } - \seq_gput_right:Nx \g_doc_functions_seq { \l_doc_function_name_prefix_tl \l_doc_pTF_name_tl } } - \bool_if:NTF \l_doc_meta_TF_bool { - \doc_special_main_index:o { \token_to_str:N #1 TF } - \seq_gput_right:Nx \g_doc_functions_seq { \token_to_str:N #1 TF } - }{ - \doc_special_main_index:o { \token_to_str:N #1 } - \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:n {#1} } - } + \tl_set:Nx \l_doc_tmpa_tl + { + \l_doc_function_name_prefix_tl + \cs_to_str:N #1 + \bool_if:NT \l_doc_meta_TF_bool { \tl_to_str:n {TF} } + } + \doc_special_main_index:o { \l_doc_tmpa_tl } + \seq_gput_right:No \g_doc_functions_seq { \l_doc_tmpa_tl } \bool_if:NTF \l_doc_meta_pTF_bool { @@ -1139,24 +1166,19 @@ Do not distribute a modified version of this file. % \begin{macro}[internal]{\doc_typeset_function_block:N} % \begin{macrocode} \cs_set_nopar:Nn \doc_typeset_function_block:N { - \tl_gset:Nx \l_doc_function_name_tl { \cs_get_function_name:N #1 } - \tl_gset:Nx \l_doc_function_sig_tl { \cs_get_function_signature:N #1 } + \tl_gset:Nx \l_doc_function_name_tl { \__cs_get_function_name:N #1 } + \tl_gset:Nx \l_doc_function_sig_tl { \__cs_get_function_signature:N #1 } \tl_gset:Nx \g_doc_macro_tl { \l_doc_function_name_prefix_tl \l_doc_function_name_tl } \doc_typeset_function_basename:N #1 \bool_if:NT \l_doc_meta_TF_bool { \doc_typeset_TF: } \doc_typeset_expandability: \clist_if_empty:NF \l_doc_variants_clist { \doc_typeset_variants: } - \bool_if:NT \g_doc_full_bool { \doc_label_function: } + \bool_if:NT \g_doc_full_bool { \doc_label_function:N #1 } } \cs_set:Nn \doc_typeset_function_basename:N - { - \g_doc_macro_tl - \int_compare:nT { \cs_get_arg_count_from_signature:N #1 > -1 } { : } - \int_compare:nT { \cs_get_arg_count_from_signature:N #1 > 0 } - { \l_doc_function_sig_tl } - } + { \l_doc_function_name_prefix_tl \cs_to_str:N #1 } \cs_set:Nn \doc_typeset_expandability: { & @@ -1173,12 +1195,12 @@ Do not distribute a modified version of this file. { \\ \doc_typeset_aux:n \g_doc_macro_tl : - \int_compare:nTF { \clist_length:N \l_doc_variants_clist == 1 } + \int_compare:nTF { \clist_count:N \l_doc_variants_clist == 1 } { \exp_after:wN \use_ii:nn \l_doc_variants_clist } { \textrm( - \clist_pop:NN \l_doc_variants_clist \l_doc_tmp_tl - \exp_after:wN \use_ii:nn \l_doc_tmp_tl + \clist_pop:NN \l_doc_variants_clist \l_doc_tmpb_tl + \exp_after:wN \use_ii:nn \l_doc_tmpb_tl \clist_map_inline:Nn \l_doc_variants_clist {\textrm| \use_ii:nn ##1} \textrm) } @@ -1193,15 +1215,12 @@ Do not distribute a modified version of this file. \hyperlink{rexpstar} {\ding{73}} % hollow star } } -\cs_set:Nn \doc_label_function: +\cs_set:Nn \doc_label_function:N { - \exp_args:NNf \tl_replace_all:Nnn \g_doc_macro_tl {\token_to_str:N _} {/} - \exp_args:NNf \tl_replace_all:Nnn \g_doc_macro_tl {\@backslashchar} {} - \exp_args:Nx \label - { - doc/function//\g_doc_macro_tl - \tl_if_empty:NF \l_doc_function_sig_tl { : \l_doc_function_sig_tl } - } + \tl_set:Nx \l_doc_tmpa_tl { \l_doc_function_name_prefix_tl \cs_to_str:N #1 } + \exp_args:NNf \tl_replace_all:Nnn \l_doc_tmpa_tl {\token_to_str:N _} {/} + \exp_args:NNf \tl_remove_all:Nn \l_doc_tmpa_tl {\@backslashchar} + \exp_args:Nx \label {doc/function//\l_doc_tmpa_tl} } % \end{macrocode} % \end{macro} @@ -1339,11 +1358,14 @@ Do not distribute a modified version of this file. { \bool_set_true:N \l_doc_macro_TF_bool } , pTF .code:n = { \bool_set_true:N \l_doc_macro_pTF_bool } , + tested .code:n = + { } , } % \end{macrocode} % % \begin{macrocode} -\renewcommand \macro [1][] { +\RenewDocumentCommand { \macro } { O{} } { \doc_macro:n {#1} } +\cs_new_protected:Npn \doc_macro:n #1 { \int_compare:nNnTF \currentgrouplevel=2 { \int_gzero:N \g_doc_nested_macro_int } @@ -1412,7 +1434,7 @@ Do not distribute a modified version of this file. % \begin{macrocode} \cs_set:Nn \doc_predicate_from_base:N { - \cs_get_function_name:N #1 _p: \cs_get_function_signature:N #1 + \__cs_get_function_name:N #1 _p: \__cs_get_function_signature:N #1 } \cs_set:Npn \doc_predicate_from_base:w #1 : #2 \q_nil { @@ -1427,10 +1449,15 @@ Do not distribute a modified version of this file. % \begin{arguments} % \item Macro/function/whatever name; input has already been sanitised. % \end{arguments} +% \cs{l_doc_at_replaced_macro_tl} stores the macro name after +% replacement of |@@|. % \begin{macrocode} +\tl_new:N \l_doc_at_replaced_macro_tl \cs_set_nopar:Npn \doc_macro_single:n #1 { \int_incr:N \l_doc_macro_int - \tl_set:Nx \saved@macroname { \token_to_str:N #1 } + \tl_set:Nx \l_doc_at_replaced_macro_tl { \token_to_str:N #1 } + \doc_replace_at_at:N \l_doc_at_replaced_macro_tl + \tl_set_eq:NN \saved@macroname \l_doc_at_replaced_macro_tl \topsep\MacroTopsep \trivlist \cs_set_nopar:Npn \makelabel ##1 { \llap{##1} } @@ -1457,33 +1484,33 @@ Do not distribute a modified version of this file. } \bool_if:NF \l_doc_macro_aux_bool { - \tl_gset:Nx \l_doc_macro_tl { \tl_to_str:n {#1} } + \tl_gset:Nx \l_doc_macro_tl { \tl_to_str:N \l_doc_at_replaced_macro_tl } \exp_args:NNf \tl_greplace_all:Nnn \l_doc_macro_tl {\token_to_str:N _} {/} \exp_args:NNf \tl_greplace_all:Nnn \l_doc_macro_tl {\@backslashchar} {} } \use:x { \exp_not:N \item [ \exp_not:N \doc_print_macroname:n { - \tl_to_str:n {#1} + \tl_to_str:N \l_doc_at_replaced_macro_tl }] } \global\advance \c@CodelineNo \@ne \bool_if:NF \l_doc_macro_aux_bool { \bool_if:NTF \l_doc_macro_TF_bool { - \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n { #1 TF } } - \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n { #1 T } } - \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n { #1 F } } + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:N \l_doc_at_replaced_macro_tl \tl_to_str:n {TF} } + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:N \l_doc_at_replaced_macro_tl \tl_to_str:n {T } } + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:N \l_doc_at_replaced_macro_tl \tl_to_str:n { F} } }{ - \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n {#1} } + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:N \l_doc_at_replaced_macro_tl } } } \bool_if:NTF \l_doc_macro_TF_bool { - \SpecialMainIndex{#1 TF}\nobreak - \DoNotIndex{#1 TF} + \exp_args:Nx \SpecialMainIndex{ \tl_to_str:N \l_doc_at_replaced_macro_tl TF}\nobreak + \exp_args:Nx \DoNotIndex{ \tl_to_str:N \l_doc_at_replaced_macro_tl TF} }{ - \SpecialMainIndex{#1}\nobreak - \DoNotIndex{#1} + \exp_args:Nx \SpecialMainIndex{ \tl_to_str:N \l_doc_at_replaced_macro_tl }\nobreak + \exp_args:Nx \DoNotIndex{ \tl_to_str:N \l_doc_at_replaced_macro_tl } } \global\advance \c@CodelineNo \m@ne @@ -1496,7 +1523,8 @@ Do not distribute a modified version of this file. \tl_clear:N \l_doc_macro_tl \cs_set_nopar:Npn \doc_print_macroname:n #1 { \strut - \int_compare:nTF { \tl_length:n {#1} <= 28 } + \HD@target + \int_compare:nTF { \tl_count:n {#1} <= 28 } { \MacroFont } { \MacroLongFont } % INEFFICIENT: (!) @@ -1581,15 +1609,16 @@ Do not distribute a modified version of this file. % \end{macro} % % \begin{macro}{\TestMissing} +% Note: There \cs{l_doc_macro_input_clist} may contain unconverted |@@|. % \begin{macrocode} \cs_generate_variant:Nn \prop_gput:Nnn {NVx} \DeclareDocumentCommand \TestMissing {m} { \prop_if_in:NVTF \g_doc_missing_tests_prop \l_doc_macro_input_clist { - \prop_get:NVN \g_doc_missing_tests_prop \l_doc_macro_input_clist \l_tmpa_tl + \prop_get:NVN \g_doc_missing_tests_prop \l_doc_macro_input_clist \l_doc_tmpa_tl \prop_gput:NVx \g_doc_missing_tests_prop \l_doc_macro_input_clist { - *~ \l_tmpa_tl + *~ \l_doc_tmpa_tl ^^J \exp_not:n {\space\space\space\space\space\space} *~ #1 } @@ -1599,11 +1628,45 @@ Do not distribute a modified version of this file. % \end{macrocode} % \end{macro} % +% \begin{variable}{\g_doc_module_name_tl} +% \begin{macro}[int]{\doc_replace_at_at:N} +% \begin{macrocode} +\tl_new:N \g_doc_module_name_tl +\cs_new_protected:Npn \doc_replace_at_at:N #1 { + \tl_if_empty:NF \g_doc_module_name_tl + { + \tl_replace_all:Non #1 { \token_to_str:N @ } { @ } + \tl_replace_all:Non #1 { \token_to_str:N _ } { _ } + \tl_replace_all:Nox #1 { _@@ } { __ \g_doc_module_name_tl } + \tl_replace_all:Nox #1 { @@ } { __ \g_doc_module_name_tl } + } +} +\cs_generate_variant:Nn \tl_replace_all:Nnn { Non, Nox } +% \end{macrocode} +% \end{macro} +% \end{variable} +% % \begin{macro}{\endmacro} +% The \cs{doc_endmacro_wrap_each:N} puts each item of the sequence |#1| +% in \cs{texttt} font and with a trailing TF if needed. This should +% go inline in the definition of \cs{endmacro}, but somehow the |#| +% doesn't go through some \LaTeXe{} internals. % \begin{macrocode} -\cs_set:Nn \doc_macro_wrap:n +\cs_new_protected:Nn \doc_endmacro_build_seq:N + { + \seq_gclear:N #1 + \clist_map_inline:Nn \l_doc_macro_input_clist + { + \tl_set:Nn \l_doc_tmpa_tl {##1} + \doc_replace_at_at:N \l_doc_tmpa_tl + \seq_gput_right:No #1 { \l_doc_tmpa_tl } + } + } +\cs_set_protected:Nn \doc_endmacro_wrap_each:N { - #1 \bool_if:NT \l_doc_macro_TF_bool {TF} + \bool_if:NTF \l_doc_macro_TF_bool + { \seq_gset_map:NNn #1 #1 { \exp_not:N \texttt { ##1 TF } } } + { \seq_gset_map:NNn #1 #1 { \exp_not:N \texttt { ##1 } } } } \cs_set:Nn \doc_texttt_comma:n {\,,~\texttt{#1}} \cs_set:Npn \endmacro { @@ -1611,29 +1674,14 @@ Do not distribute a modified version of this file. { \par\nobreak\noindent{\footnotesize(\emph{ End~ definition~ for~ - \prg_case_int:nnn { \clist_length:N \l_doc_macro_input_clist } - { - {1} { \texttt{ \doc_macro_wrap:n { \clist_use:N \l_doc_macro_input_clist } }. } - {2} + \doc_endmacro_build_seq:N \g_doc_tmpa_seq + \doc_endmacro_wrap_each:N \g_doc_tmpa_seq + \int_compare:nTF { \seq_count:N \g_doc_tmpa_seq <= 3 } { - \tl_set:Nx \l_clist_first_tl { \clist_item:Nn \l_doc_macro_input_clist {0} } - \tl_set:Nx \l_clist_last_tl { \clist_item:Nn \l_doc_macro_input_clist {1} } - \texttt{\doc_macro_wrap:n\l_clist_first_tl}\,~ and~ \texttt{\doc_macro_wrap:n\l_clist_last_tl}\,. + \seq_use:Nnnn \g_doc_tmpa_seq + { \,~and~ } { \,,~ } { \,,~and~ } } - {3} - { - \tl_set:Nx \l_clist_first_tl { \clist_item:Nn \l_doc_macro_input_clist {0} } - \tl_set:Nx \l_clist_mid_tl { \clist_item:Nn \l_doc_macro_input_clist {1} } - \tl_set:Nx \l_clist_last_tl { \clist_item:Nn \l_doc_macro_input_clist {2} } - \texttt{\doc_macro_wrap:n\l_clist_first_tl}\,,~ - \texttt{\doc_macro_wrap:n\l_clist_mid_tl}\,,~ - and~ \texttt{\doc_macro_wrap:n\l_clist_last_tl}\,. - } - } - { - \tl_set:Nx \l_clist_first_tl { \clist_item:Nn \l_doc_macro_input_clist {0} } - \texttt{\doc_macro_wrap:n\l_clist_first_tl}\,~and~others. - } + { \seq_item:Nn \g_doc_tmpa_seq {1}\,~and~others. } \bool_if:nT { !\l_doc_macro_aux_bool && !\l_doc_macro_internal_bool && @@ -1656,7 +1704,7 @@ Do not distribute a modified version of this file. { \seq_gput_right:Nx \g_doc_not_tested_seq { - \l_doc_macro_input_clist + \seq_use:Nnnn \g_doc_tmpa_seq { , } { , } { , } \bool_if:NT \l_doc_macro_pTF_bool {~(pTF)} \bool_if:NT \l_doc_macro_TF_bool {~(TF)} } @@ -1665,6 +1713,70 @@ Do not distribute a modified version of this file. % \end{macrocode} % \end{macro} % +% \begin{environment}{macrocode} +% \begin{macro}[aux]{\doc_xmacro_code:n} +% Hook into the \texttt{macrocode} environment in a dirty way: +% \cs{xmacro@code} is responsible for grabbing (and tokenizing) the +% body of the environment. Redefine it to pass what it grabs to +% \cs{doc_xparse_code:n}. This new macro replaces all |@@| by the +% appropriate module name. One exceptional case is the +% |<@@=|\meta{module}|>| lines themselves, where |@@| should not be +% modified. Actually, we search for such lines, to set the module +% name automatically. We need to be careful: no |<@@=| should appear +% as such in the code below since \pkg{l3doc} is also typeset using +% this code. +% \begin{macrocode} +\group_begin: + \char_set_catcode_escape:N \/ + \char_set_catcode_other:N \^^A + \char_set_catcode_active:N \^^S + \char_set_catcode_active:N \^^B + \char_set_catcode_other:N \^^L + \char_set_catcode_other:N \^^R + \char_set_lccode:nn { `\^^A } { `\% } + \char_set_lccode:nn { `\^^S } { `\ } + \char_set_lccode:nn { `\^^B } { `\\ } + \char_set_lccode:nn { `\^^L } { `\{ } + \char_set_lccode:nn { `\^^R } { `\} } + \tl_to_lowercase:n + { + \group_end: + \cs_set_protected:Npn \xmacro@code + #1 ^^A ^^S^^S^^S^^S ^^Bend ^^Lmacrocode^^R + { \doc_xmacro_code:n {#1} /end{macrocode} } + } +\group_begin: + \char_set_catcode_active:N \< + \char_set_catcode_active:N \> + \cs_new_protected:Npn \doc_xmacro_code:n #1 + { + \tl_if_in:nnTF {#1} { < @ @ = } + { \doc_xmacro_code:w #1 \q_stop } + { + \tl_set:Nn \l_doc_tmpa_tl {#1} + \doc_replace_at_at:N \l_doc_tmpa_tl + \tl_use:N \l_doc_tmpa_tl + } + } + \cs_new_protected:Npn \doc_xmacro_code:w #1 < @ @ = #2 > #3 \q_stop + { + \tl_set:Nn \l_doc_tmpa_tl {#1} + \doc_replace_at_at:N \l_doc_tmpa_tl + + \tl_gset:Nn \g_doc_module_name_tl {#2} + \tl_put_right:Nn \l_doc_tmpa_tl { < @ @ = #2 > } + + \tl_set:Nn \l_doc_tmpb_tl {#3} + \doc_replace_at_at:N \l_doc_tmpb_tl + \tl_put_right:No \l_doc_tmpa_tl { \l_doc_tmpb_tl } + + \tl_use:N \l_doc_tmpa_tl + } +\group_end: +% \end{macrocode} +% \end{macro} +% \end{environment} +% % \begin{macro}{\DescribeOption} % For describing package options. Due to Joseph Wright. % Name/usage might change soon. @@ -1987,40 +2099,44 @@ Do not distribute a modified version of this file. % Print all defined and documented macros/functions. % % \begin{macrocode} -\iow_open:Nn \g_write_func_stream { \jobname.cmds } +\iow_new:N \g_doc_func_iow % \end{macrocode} % % \begin{macrocode} \cs_new_nopar:Npn \doc_show_functions_defined: { \bool_if:nT { \g_doc_implementation_bool && \g_doc_checkfunc_bool } { \typeout{ ======================================== ^^J } + \iow_open:Nn \g_doc_func_iow { \c_job_name_tl .cmds } - \tl_clear:N \l_tmpa_tl + \tl_clear:N \l_doc_tmpa_tl \seq_map_inline:Nn \g_doc_functions_seq { \seq_if_in:NnT \g_doc_macros_seq {##1} { - \tl_put_right:Nn \l_tmpa_tl { ##1 ^^J } - \iow_now:Nn \g_write_func_stream { ##1 } + \tl_put_right:Nn \l_doc_tmpa_tl { ##1 ^^J } + \iow_now:Nn \g_doc_func_iow { > ~ ##1 } } } - \iow_close:N \g_write_func_stream + \doc_functions_typeout:n { Functions~both~documented~and~defined:^^J (In~order~of~being~documented) } \seq_map_inline:Nn \g_doc_functions_seq { \seq_if_in:NnF \g_doc_macros_seq {##1} { - \tl_put_right:Nn \l_tmpa_tl { ##1 ^^J } + \tl_put_right:Nn \l_doc_tmpa_tl { ##1 ^^J } + \iow_now:Nn \g_doc_func_iow { ! ~ ##1} } } \doc_functions_typeout:n { Functions~documented~but~not~defined: } \seq_map_inline:Nn \g_doc_macros_seq { \seq_if_in:NnF \g_doc_functions_seq {##1} { - \tl_put_right:Nn \l_tmpa_tl { ##1 ^^J } + \tl_put_right:Nn \l_doc_tmpa_tl { ##1 ^^J } + \iow_now:Nn \g_doc_func_iow { ? ~ ##1} } } \doc_functions_typeout:n { Functions~defined~but~not~documented: } + \iow_close:N \g_doc_func_iow \typeout{ ======================================== } } } @@ -2029,12 +2145,12 @@ Do not distribute a modified version of this file. % % \begin{macrocode} \cs_set_nopar:Npn \doc_functions_typeout:n #1 { - \tl_if_empty:NF \l_tmpa_tl { + \tl_if_empty:NF \l_doc_tmpa_tl { \typeout{ -------------------------------------- ^^J #1 ^^J - -------------------------------------- ^^J \l_tmpa_tl + -------------------------------------- ^^J \l_doc_tmpa_tl } - \tl_clear:N \l_tmpa_tl + \tl_clear:N \l_doc_tmpa_tl } } % \end{macrocode} @@ -2046,23 +2162,23 @@ Do not distribute a modified version of this file. \bool_if:nT { !(\seq_if_empty_p:N \g_doc_not_tested_seq) || !(\prop_if_empty_p:N \g_doc_missing_tests_prop) } { - \tl_clear:N \l_tmpa_tl + \tl_clear:N \l_doc_tmpa_tl \prop_if_empty:NF \g_doc_missing_tests_prop { - \tl_put_right:Nn \l_tmpa_tl + \tl_put_right:Nn \l_doc_tmpa_tl { ^^J^^JThe~ following~ macro(s)~ have~ incomplete~ tests:^^J } \prop_map_inline:Nn \g_doc_missing_tests_prop { - \tl_put_right:Nn \l_tmpa_tl + \tl_put_right:Nn \l_doc_tmpa_tl {^^J\space\space\space\space ##1 ^^J\space\space\space\space\space\space ##2} } } \seq_if_empty:NF \g_doc_not_tested_seq { - \tl_put_right:Nn \l_tmpa_tl + \tl_put_right:Nn \l_doc_tmpa_tl { ^^J^^J The~ following~ macro(s)~ do~ not~ have~ any~ tests:^^J @@ -2071,12 +2187,12 @@ Do not distribute a modified version of this file. { \clist_map_inline:nn {##1} { - \tl_put_right:Nn \l_tmpa_tl {^^J\space\space\space\space ####1} + \tl_put_right:Nn \l_doc_tmpa_tl {^^J\space\space\space\space ####1} } } \int_set:Nn \l_tmpa_int {\etex_interactionmode:D} \errorstopmode - \ClassError{l3doc}{\l_tmpa_tl}{} + \ClassError{l3doc}{\l_doc_tmpa_tl}{} \int_set:Nn \etex_interactionmode:D {\l_tmpa_int} } } @@ -2111,39 +2227,31 @@ Do not distribute a modified version of this file. % \end{macrocode} % % -% \begin{macro}{\doc_special_main_index:n,\doc_special_main_index:o,\hdpgindex} +% \begin{macro}{\doc_special_main_index:n,\doc_special_main_index:o, \doc_special_main_index:x} % Heiko's replacement to play nicely with |hypdoc|: % \begin{macrocode} \cs_set_nopar:Npn \doc_special_main_index:n #1 { + \HD@target \index{ \@gobble#1 \actualchar \string\verb\quotechar*\verbatimchar#1\verbatimchar \encapchar - hdpgindex{\thepage}{usage} - } -} -\cs_set_nopar:Npn \doc_special_main_index:o { \exp_args:No \doc_special_main_index:n } -% \end{macrocode} -% \begin{macrocode} -\cs_set_nopar:Npn \hdpgindex #1#2#3 { - \csname\ifx\\#2\\relax\else#2\fi\endcsname{ - \hyperlink{page.#1}{#3} + hdclindex{\the\c@HD@hypercount}{usage} } } +\cs_generate_variant:Nn \doc_special_main_index:n { o , x } % \end{macrocode} % \end{macro} % % \begin{macrocode} -\g@addto@macro \PrintIndex { \AtEndDocument{ \typeout{^^J - ========================================^^J - Generate~the~index~by~executing^^J - \c_space_tl \c_space_tl \c_space_tl \c_space_tl - makeindex~-s~l3doc.ist~-o~\jobname.ind~\jobname.idx^^J - ========================================^^J - }} -} +\msg_new:nnn {l3doc} {print-index-howto} + { + Generate~the~index~by~executing\\ + \iow_indent:n { makeindex~-s~l3doc.ist~-o~\c_job_name_tl .ind~\c_job_name_tl .idx } + } +\tl_gput_right:Nn \PrintIndex { \AtEndDocument{ \msg_info:nn {l3doc} {print-index-howto} } } % \end{macrocode} % % \subsection{Change history} @@ -2160,14 +2268,12 @@ Do not distribute a modified version of this file. % \end{macrocode} % % \begin{macrocode} -\g@addto@macro \PrintChanges { \AtEndDocument{ \typeout{^^J - ========================================^^J - Generate~the~change~list~by~executing^^J - \c_space_tl \c_space_tl \c_space_tl \c_space_tl - makeindex~-s~gglo.ist~~-o~\jobname.gls~\jobname.glo^^J - ========================================^^J - }} -} +\msg_new:nnn {l3doc} {print-changes-howto} + { + Generate~the~change~list~by~executing\\ + \iow_indent:n { makeindex~-s~gglo.ist~-o~\c_job_name_tl .gls~\c_job_name_tl .glo } + } +\tl_gput_right:Nn \PrintChanges { \AtEndDocument{ \msg_info:nn {l3doc} {print-changes-howto} } } % \end{macrocode} % %^^A The standard \changes command modified slightly to better cope with @@ -2190,7 +2296,7 @@ Do not distribute a modified version of this file. %^^A :\levelchar #3}}% %^^A \@tempa\endgroup\@esphack} % -% \subsection{cfg} +% \subsection{Default configuration} % % \begin{macrocode} \bool_if:NTF \g_doc_full_bool { @@ -2210,6 +2316,79 @@ Do not distribute a modified version of this file. %</class> % \end{macrocode} % +% \subsection{Internal macros for \LaTeX3 sources} +% +% These definitions are only used by the \LaTeX3 documentation; +% they are not necessary for third-party users of l3doc. +% In time this will be broken into a separate package that is specifically +% loaded in the various expl3 modules, etc. +% +% \begin{macrocode} +%<*cfg> +% \end{macrocode} +% +% The Guilty Parties. +% \begin{macrocode} +\cs_new_nopar:Npn\Team{% + The~\LaTeX3~Project\thanks{% + Frank~Mittelbach,~Denys~Duchier,~Chris~Rowley,~ + Rainer~Sch\"opf,~Johannes~Braams,~Michael~Downes,~ + David~Carlisle,~Alan~Jeffrey,~Morten~H\o{}gholm,~Thomas~Lotze,~ + Javier~Bezos,~Will~Robertson,~Joseph~Wright,~Bruno~Le~Floch}} +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentCommand{\ExplMakeTitle}{mm} + { + \title + { + The~\pkg{#1}~package \\ #2 + \thanks{This~file~describes~v\ExplFileVersion,~ + last~revised~\ExplFileDate.} + } + \author{The~\LaTeX3~Project\thanks{E-mail:~ + \href{mailto:latex-l@listserv.uni-heidelberg.de} + {latex-l@listserv.uni-heidelberg.de}}} + \date{Released~\ExplFileDate} + \maketitle + } +% \end{macrocode} +% +% \subsection{Text extras} +% +% \begin{macrocode} +\DeclareDocumentCommand\ie{}{\emph{i.e.}} +\DeclareDocumentCommand\eg{}{\emph{e.g.}} +\DeclareDocumentCommand\Ie{}{\emph{I.e.}} +\DeclareDocumentCommand\Eg{}{\emph{E.g.}} +% \end{macrocode} +% +% \subsection{Math extras} +% +% For \pkg{l3fp}. +% +% \begin{macrocode} +\AtBeginDocument + { + \clist_map_inline:nn + { + asin, acos, atan, acot, + asinh, acosh, atanh, acoth, round, floor, ceil + } + { \exp_args:Nc \DeclareMathOperator{#1}{#1} } + } +% \end{macrocode} +% +% \begin{macro}{\nan} +% \begin{macrocode} +\NewDocumentCommand { \nan } { } { \text { \texttt { nan } } } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</cfg> +% \end{macrocode} +% % % \subsection{Makeindex configuration} % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx b/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx new file mode 100644 index 00000000000..5e2ba0a5e63 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx @@ -0,0 +1,277 @@ +% \iffalse +% +%% File l3dosctrip.dtx Copyright (C) 2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver|program> +\def\ExplFileDate{2012/06/08} +\def\ExplFileName{l3docstrip} +\def\ExplFileVersion{3787} +%</driver|program> +%<*driver> +% The same approach as used in \textsf{DocStrip}: if \cs{documentclass} +% is undefined then skip the driver, allowing the file to be used to extract +% \texttt{l3docstrip.tex} from \texttt{l3docstrip.dtx} directly. This works +% as the \cs{fi} is only seen if \LaTeX{} is not in use. The odd \cs{jobname} +% business allows the extraction to work with \LaTeX{} provided an appropriate +% \texttt{.ins} file is set up. +%<*gobble> +\ifx\jobname\relax\let\documentclass\undefined\fi +\ifx\documentclass\undefined +\else \csname fi\endcsname +%</gobble> + \def\filename{docstrip.dtx} + \documentclass[full]{l3doc} + \begin{document} + \DocInput{\jobname.dtx} + \end{document} +%<*gobble> +\fi +%</gobble> +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3docstrip} package\\ Code extraction and manipulation^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \section{Extending \textsf{DocStrip}} +% +% The \pkg{l3docstrip} module adds \LaTeX3 extensions to the \textsf{DocStrip} +% program for extracting code from \texttt{.dtx}. As such, this documentation +% should be read along with that for \textsf{DocStrip}. +% +% \section{Internal functions and variables} +% +% An important consideration for \LaTeX3 development is separating out public +% and internal functions. Functions and variables which are private to one +% module should not be used or modified by any other module. As \TeX{} does +% not have any formal namespacing system, this requires a convention for +% indicating which functions in a code-level module are public and which are +% private. +% +% Using \pkg{l3docstrip} allows internal functions to be indicated using a +% \enquote{two part} system. Within the \texttt{.dtx} file, internal functions +% may be indicated using |@@| in place of the module name, for example +% \begin{verbatim} +% \cs_new_protected:Npn \@@_some_function:nn #1#2 +% { +% % Some code here +% } +% \tl_new:N \l_@@_internal_tl +% \end{verbatim} +% +% To extract the code using \pkg{l3docstrip}, the \enquote{guard} concept +% used by \textsf{DocStrip} is extended by introduction of the syntax +% \texttt{\%<@@=\meta{module}}. The \meta{module} name will be used when the +% code is extracted to replace the |@@|, so that +% \begin{verbatim} +% %<*package> +% %<@@=foo> +% \cs_new_protected:Npn \@@_some_function:nn #1#2 +% { +% % Some code here +% } +% \tl_new:N \l_@@_internal_tl +% %</package> +% \end{verbatim} +% will be extracted as +% \begin{verbatim} +% \cs_new_protected:Npn \__foo_some_function:nn #1#2 +% { +% % Some code here +% } +% \tl_new:N \l__foo_internal_tl +% \end{verbatim} +% where the |__| indicates that the functions and variables are internal +% to the \texttt{foo} module. +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3docstrip} implementation} +% +% \begin{macrocode} +%<*program> +% \end{macrocode} +% +% We start by loading the existing \textsf{DocStrip} code using the \TeX{} +% input convention. +% \begin{macrocode} +\input docstrip % +% \end{macrocode} +% +% \begin{macro}{\checkOption} +% The \cs{checkOption} macro is defined by \textsf{DocStrip} and is redefined +% here to accommodate the new \texttt{\%<@} syntax. +% +% When the macros that process a line have found that the line starts with +% \enquote{\texttt{\%<}}, a guard line has been encountered. The first +% character of a guard can be an asterisk (\texttt{*}), a slash (\texttt{/}), +% a plus (\texttt{+}), a minus (\texttt{-}), a less-than sign (\texttt{<}) +% starting verbatim mode, a commercial at (\texttt{@}) or any other character +% that can be found in an option name. This means that we have to peek at the +% next token and decide what kind of guard we have. We reinsert |#1| as it +% may be needed by \cs{doOption}. +% \begin{macrocode} +\def\checkOption<#1{% + \ifcase + \ifx*#10\else \ifx/#11\else + \ifx+#12\else \ifx-#13\else + \ifx<#14\else \ifx @#15\else 6\fi\fi\fi\fi\fi\fi\relax + \expandafter\starOption\or + \expandafter\slashOption\or + \expandafter\plusOption\or + \expandafter\minusOption\or + \expandafter\verbOption\or + \expandafter\moduleOption\or + \expandafter\doOption\fi + #1% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\moduleOption} +% In the case where the line starts |%<@|: the defined syntax requires that +% this continues to |%<@@=|. At the moment, we assume that the syntax will +% be correct and |#1| here is the module name for substitution into any +% internal functions in the extracted material. +% \begin{macrocode} +\def\moduleOption @@=#1>#2\endLine{% + \maybeMsg{<@@=#1>}% + \prepareActiveModule{#1}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prepareActiveModule} +% \begin{macro}{\replaceModuleInLine} +% Here, we set up to do the search-and-replace when doing the extraction. +% The argument (|#1|) is the replacement text to use, or if empty an +% indicator that no replacement should be done. The search material is +% one of |__@@|, |_@@| or |@@|, done in order such that all three will end +% up the same in the output. The replacement function is initialised as a +% do-nothing for the case where |%<@@=| is never seen. +% \begin{macrocode} +\begingroup + \catcode`\_ = 12 % + \long\gdef\prepareActiveModule#1{% + \ifx\relax#1\relax + \let\replaceModuleInLine\empty + \else + \def\replaceModuleInLine{% + \replaceAllIn\inLine{__@@}{__#1}% + \replaceAllIn\inLine{_@@}{__#1}% + \replaceAllIn\inLine{@@}{__#1}% + }% + \fi + } +\endgroup +\let\replaceModuleInLine\empty +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\replaceAllIn} +% \begin{macro}{\replaceAllInAuxI} +% \begin{macro}{\replaceAllInAuxII} +% \begin{macro}{\replaceAllInAuxIII} +% The code here is a simple search-and-replace routine for a macro |#1|, +% replacing |#2| by |#3|. As set up here, there is an assumption that nothing +% is going to be expandable, which is reasonable as \pkg{l3docstrip} deals +% with \enquote{string} material. +% \begin{macrocode} +\long\def\replaceAllIn#1#2#3{% + \long\def\tempa##1##2#2{% + ##2\qMark\replaceAllInAuxIII#3##1% + }% + \edef#1{\expandafter\replaceAllInAuxI#1\qMark#2\qStop}% +} +\def\replaceAllInAuxI{% + \expandafter\replaceAllInAuxII\tempa\replaceAllInAuxI\empty +} +\long\def\replaceAllInAuxII#1\qMark#2{#1} +\long\def\replaceAllInAuxIII#1\qStop{} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\normalLine} +% The \cs{normalLine} macro is present in \textsf{DocStrip} but is modified +% here to include the search-and-replace macro \cs{replaceModuleInLine}. The +% macro \cs{normalLine} writes its argument (which has to be delimited with +% |\endLine|) on all active output files, i.e.~those with off-counters equal +% to zero. The counter \cs{codeLinesPassed} is incremented by~$1$ for +% statistics (the guards for this used in \textsf{DocStrip} are retained). +% \begin{macrocode} +\def\normalLine#1\endLine{% +%<*stats> + \advance\codeLinesPassed\@ne +%</stats> + \maybeMsg{.}% + \def\inLine{#1}% + \replaceModuleInLine + \let\do\putline@do + \activefiles +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</program> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx index 2729cad13ca..817a616897f 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx @@ -36,7 +36,7 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3drivers.dtx 3158 2012-01-09 00:47:42Z bruno $ +\GetIdInfo$Id: l3drivers.dtx 3986 2012-07-15 19:23:51Z joseph $ {L3 Experimental drivers} %</driver|package> %<*driver> @@ -89,9 +89,9 @@ % % \section{Box clipping} % -% \begin{function}[added = 2011-11-11]{\driver_box_use_clip:N} +% \begin{function}[added = 2011-11-11]{\__driver_box_use_clip:N} % \begin{syntax} -% \cs{driver_box_use_clip:N} \meta{box} +% \cs{__driver_box_use_clip:N} \meta{box} % \end{syntax} % Inserts the content of the \meta{box} at the current insertion point % such that any material outside of the bounding box will not be displayed @@ -101,32 +101,32 @@ % % \section{Box rotation and scaling} % -% \begin{function}[added = 2011-09-01] -% {\driver_box_rotate_begin:, \driver_box_rotate_end:} +% \begin{function}[added = 2011-09-01, updated = 2012-05-18] +% {\__driver_box_rotate_begin:, \__driver_box_rotate_end:} % \begin{syntax} -% \cs{driver_box_rotate_begin:} -% \cs{box_use:N} \cs{l_box_internal_box} -% \cs{driver_box_rotate_end:} +% \cs{__driver_box_rotate_begin:} +% \cs{box_use:N} \cs{l__box_internal_box} +% \cs{__driver_box_rotate_end:} % \end{syntax} % Rotates the \meta{box material} anti-clockwise around the current % insertion point. The angle of rotation (in degrees counter-clockwise) % and the sine and cosine of this angle should be stored in -% \cs{l_box_angle_fp}, \cs{l_box_sin_fp} and \cs{l_box_cos_fp}, +% \cs{l__box_angle_fp}, \cs{l__box_sin_fp} and \cs{l__box_cos_fp}, % respectively. Typically, the box material inserted between the beginning -% and end markers will be stored in \cs{l_box_internal_box}: this fact is +% and end markers will be stored in \cs{l__box_internal_box}: this fact is % required by some drivers to obtain the correct output. % \end{function} % -% \begin{function}[added = 2011-09-02] -% {\driver_box_scale_begin:, \driver_box_scale_end:} +% \begin{function}[added = 2011-09-02, updated = 2012-05-18] +% {\__driver_box_scale_begin:, \__driver_box_scale_end:} % \begin{syntax} -% \cs{driver_box_scale_begin:} +% \cs{__driver_box_scale_begin:} % \meta{box material} -% \cs{driver_box_scale_end:} +% \cs{__driver_box_scale_end:} % \end{syntax} % Scales the \meta{box material} (which should be either a \cs{box_use:N} % or \cs{hbox:n} construct). The \meta{box material} is scaled by the values -% stored in \cs{l_box_scale_x_fp} and \cs{l_box_scale_y_fp} in the +% stored in \cs{l__box_scale_x_fp} and \cs{l__box_scale_y_fp} in the % horizontal and vertical directions, respectively. This function is % also reused when resizing boxes: at a driver level, only scalings are % supported and so the higher-level code must convert the absolute sizes @@ -135,9 +135,10 @@ % % \section{Colour support} % -% \begin{function}[added = 2011-09-03]{\driver_color_ensure_current:} +% \begin{function}[added = 2011-09-03, updated = 2012-05-18] +% {\__driver_color_ensure_current:} % \begin{syntax} -% \cs{driver_color_ensure_current:} +% \cs{__driver_color_ensure_current:} % \end{syntax} % Ensures that the colour used to typeset material is that which was % set when the material was placed in a box. This function is therefore @@ -154,6 +155,7 @@ % % \begin{macrocode} %<*initex|package> +%<@@=driver> % \end{macrocode} % % \begin{macrocode} @@ -171,7 +173,7 @@ {l3pdfmode.def}{\ExplFileDate}{\ExplFileVersion} {L3~Experimental~driver:~xdvipdfmx} %</xdvipdfmx> -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -208,50 +210,62 @@ % % \subsection{Driver utility functions} % -% \begin{macro}{\driver_graphic_state_save:} -% \begin{macro}{\driver_graphic_state_restore:} +% \begin{macro}{\@@_graphic_state_save:, \@@_graphic_state_restore:} % All of the drivers have a stack for saving the graphic state. These -% have slightly different interfaces. As \texttt{dvips} does not -% automatically save the current location, this is set up here. +% have slightly different interfaces. For both \texttt{dvips} and +% \texttt{xdvipdfmx} this is done using an appropriate special. % \begin{macrocode} -\cs_new_protected:Npn \driver_graphic_state_save: +%<*dvips|xdvipdfmx> +\cs_new_protected_nopar:Npn \@@_graphic_state_save: %<*dvips> { \tex_special:D { ps:gsave } } %</dvips> -%<*pdfmode> - { \pdftex_pdfsave:D } -%</pdfmode> %<*xdvipdfmx> { \tex_special:D { pdf:bcontent } } %</xdvipdfmx> -\cs_new_protected:Npn \driver_graphic_state_restore: +\cs_new_protected_nopar:Npn \@@_graphic_state_restore: %<*dvips> { \tex_special:D { ps:grestore } } %</dvips> -%<*pdfmode> - { \pdftex_pdfrestore:D } -%</pdfmode> %<*xdvipdfmx> { \tex_special:D { pdf:econtent } } %</xdvipdfmx> +%</dvips|xdvipdfmx> +% \end{macrocode} +% For direct PDF output there is also a need to worry about the version +% of \pdfTeX{} in use: the \tn{pdfsave} primitive was only introduced +% in version~1.40.0. +% \begin{macrocode} +%<*pdfmode> +\cs_if_exist:NTF \pdftex_pdfsave:D + { + \cs_new_eq:NN \@@_graphic_state_save: \pdftex_pdfsave:D + \cs_new_eq:NN \@@_graphic_state_restore: \pdftex_pdfrestore:D + } + { + \cs_new_protected_nopar:Npn \@@_graphic_state_save: + { \pdftex_pdfliteral:D { q } } + \cs_new_protected_nopar:Npn \@@_graphic_state_restore: + { \pdftex_pdfliteral:D { Q } } + } +%</pdfmode> % \end{macrocode} -% \end{macro} % \end{macro} % -% \begin{macro}{\driver_pdf_literal:n, \driver_pdf_literal_direct:n} +% \begin{macro}{\@@_pdf_literal:n, \@@_pdf_literal_direct:n} % Both direct PDF mode and \texttt{xdvipdfmx} make use of direct PDF % special insertion. These are slightly different in the two cases. % The |direct| versions do not save the current matrix. % \begin{macrocode} %<*pdfmode|xdvipdfmx> -\cs_new_protected:Npn \driver_pdf_literal:n #1 +\cs_new_protected:Npn \@@_pdf_literal:n #1 %<*pdfmode> { \pdftex_pdfliteral:D {#1} } %</pdfmode> %<*xdvipdfmx> { \tex_special:D { pdf:content~ #1 } } %</xdvipdfmx> -\cs_new_protected:Npn \driver_pdf_literal_direct:n #1 +\cs_new_protected:Npn \@@_pdf_literal_direct:n #1 %<*pdfmode> { \pdftex_pdfliteral:D direct~{#1} } %</pdfmode> @@ -262,12 +276,12 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\driver_ps_literal:n} +% \begin{macro}{\@@_ps_literal:n} % The same concept for PostScript: these are \enquote{direct} by default, % but by keeping the same name life should be a little clearer. % \begin{macrocode} %<*dvips> -\cs_new_protected:Npn \driver_ps_literal:n #1 +\cs_new_protected:Npn \@@_ps_literal:n #1 { \tex_special:D { ps: #1 } } %</dvips> % \end{macrocode} @@ -275,7 +289,7 @@ % % \subsection{Box clipping} % -% \begin{macro}{\driver_box_use_clip:N} +% \begin{macro}{\@@_box_use_clip:N} % The overall logic to clipping a box is the same in all cases. The general % method is to save the current location, define a clipping path equivalent % to the bounding box, then insert the content at the current position @@ -285,9 +299,9 @@ % as much code as possible and uses the same conversions (and so same % rounding errors) in all three cases. % \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_clip:N #1 +\cs_new_protected:Npn \@@_box_use_clip:N #1 { - \driver_graphic_state_save: + \@@_graphic_state_save: % \end{macrocode} % The business end of the code sets up the clip box, using the higher-level % rectangle operators rather than the lower level direct line drawing. This @@ -301,21 +315,21 @@ % \TeX{} current positions). % \begin{macrocode} %<*dvips> - \driver_ps_literal:n + \@@_ps_literal:n { /savedmatrix~matrix~currentmatrix~def~ currentpoint~translate~ Resolution~72~div~VResolution~72~div~scale } - \driver_ps_literal:n + \@@_ps_literal:n { 0~ - -\dim_strip_bp:n { \box_dp:N #1 } ~neg~ - \dim_strip_bp:n { \box_wd:N #1 } ~ - \dim_strip_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~neg~ + \__dim_strip_bp:n { \box_dp:N #1 } ~ + \__dim_strip_bp:n { \box_wd:N #1 } ~ + \__dim_strip_bp:n { - \box_ht:N #1 - \box_dp:N #1 } ~ rectclip } - \driver_ps_literal:n { savedmatrix~setmatrix } + \@@_ps_literal:n { savedmatrix~setmatrix } %</dvips> % \end{macrocode} % The PDF box is easier to define as it is automatically in big points and @@ -323,12 +337,12 @@ % locations automatically. % \begin{macrocode} %<*pdfmode|xdvipdfmx> - \driver_pdf_literal_direct:n + \@@_pdf_literal_direct:n { 0 ~ - -\dim_strip_bp:n { \box_dp:N #1 } ~ - \dim_strip_bp:n { \box_wd:N #1 } ~ - \dim_strip_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~ + \__dim_strip_bp:n { - \box_dp:N #1 } ~ + \__dim_strip_bp:n { \box_wd:N #1 } ~ + \__dim_strip_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~ re~W~n } %</pdfmode|xdvipdfmx> @@ -337,7 +351,7 @@ % and then insert the necessary width. % \begin{macrocode} \hbox_overlap_right:n { \box_use:N #1 } - \driver_graphic_state_restore: + \@@_graphic_state_restore: \skip_horizontal:n { \box_wd:N #1 } } % \end{macrocode} @@ -345,16 +359,7 @@ % % \subsection{Box rotation and scaling} % -% \begin{variable}{\l_driver_internal_fp} -% Needed for a safe sign inversion in PDF mode. -% \begin{macrocode} -%<*pdfmode|xdvipdfmx> -\fp_new:N \l_driver_internal_fp -%</pdfmode|xdvipdfmx> -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\driver_box_rotate_begin:, \driver_box_rotate_end:} +% \begin{macro}{\@@_box_rotate_begin:, \@@_box_rotate_end:} % The driver for \texttt{dvips} works with a simple rotation angle. % In PDF mode, an affine matrix is used instead. The transformation for % \texttt{xdvipdfmx} can be done either way: to have some code sharing, @@ -362,137 +367,189 @@ % shared in this way). For the \texttt{dvips}, that odd-looking % |currentpoint| at the beginning is used to put this data onto the % stack for |neg exch neg exch translate| to pick up. +% +% In both cases, some rounding code is included to limit the floating +% point values to five decimal places. There is no point using any more +% as \TeX{}'s dimensions are of that precision, and the extra figures +% will simply bloat the PDF and make values harder to trace. In the +% case where the sine and cosine are used, we store the rounded values to +% avoid rounding twice. There are also a couple of comparisons to ensure +% that |-0| is not written to the output, as this avoids any issues with +% problematic display programs. % \begin{macrocode} -\cs_new_protected:Npn \driver_box_rotate_begin: +\cs_new_protected_nopar:Npn \@@_box_rotate_begin: { - \driver_graphic_state_save: + \@@_graphic_state_save: %<*dvips> - \driver_ps_literal:n + \@@_ps_literal:n { currentpoint~ currentpoint~translate~ - \fp_use:N \l_box_angle_fp \c_space_tl neg~rotate~ + \fp_compare:nTnTF \l__box_angle_fp = \c_zero_fp + { 0 } + { \fp_eval:n { round ( - \l__box_angle_fp , 5 ) } } + ~rotate~ neg~exch~neg~exch~translate } %</dvips> %<*pdfmode|xdvipdfmx> - \box_set_wd:Nn \l_box_internal_box \c_zero_dim - \fp_set_eq:NN \l_driver_internal_fp \l_box_sin_fp - \fp_neg:N \l_driver_internal_fp -%<*pdfmode> - \pdftex_pdfsetmatrix:D -%</pdfmode> -%<*xdvipdfmx> - \driver_pdf_literal_direct:n -%</xdvipdfmx> + \box_set_wd:Nn \l__box_internal_box \c_zero_dim + \fp_set:Nn \l__box_cos_fp { - \fp_use:N \l_box_cos_fp \c_space_tl - \fp_use:N \l_box_sin_fp \c_space_tl - \fp_use:N \l_driver_internal_fp \c_space_tl - \fp_use:N \l_box_cos_fp -%<*xdvipdfmx> - \c_space_tl 0~0~cm -%</xdvipdfmx> + \fp_compare:nNnTF \l__box_cos_fp = \c_zero_fp + { 0 } + { round ( \l__box_cos_fp , 5 ) } + } + \fp_set:Nn \l__box_sin_fp { round ( \l__box_sin_fp , 5 ) } + \@@_pdf_matrix:n + { + \fp_use:N \l__box_cos_fp \c_space_tl + \fp_compare:nNnTF \l__box_sin_fp = \c_zero_fp + { 0~0 } + { + \fp_use:N \l__box_sin_fp + \c_space_tl + \fp_eval:n { -\l__box_sin_fp } + } + \c_space_tl + \fp_use:N \l__box_cos_fp } %</pdfmode|xdvipdfmx> } % \end{macrocode} -% The end of a rotation means tidying up the output grouping. +% The end of a rotation means tidying up the output grouping. % \begin{macrocode} -\cs_new_eq:NN \driver_box_rotate_end: \driver_graphic_state_restore: +\cs_new_eq:NN \@@_box_rotate_end: \@@_graphic_state_restore: % \end{macrocode} % \end{macro} % -% \begin{macro}{\driver_box_scale_begin:, \driver_box_scale_end:} +% \begin{macro}{\@@_box_scale_begin:, \@@_box_scale_end:} % Scaling is not dissimilar to rotation, but the calculations are somewhat % less complex. % \begin{macrocode} -\cs_new_protected:Npn \driver_box_scale_begin: +\cs_new_protected_nopar:Npn \@@_box_scale_begin: { - \driver_graphic_state_save: + \fp_set:Nn \l__box_scale_x_fp { round ( \l__box_scale_x_fp , 5 ) } + \fp_set:Nn \l__box_scale_y_fp { round ( \l__box_scale_y_fp , 5 ) } + \@@_graphic_state_save: %<*dvips> - \driver_ps_literal:n + \@@_ps_literal:n { currentpoint~ currentpoint~translate~ - \fp_use:N \l_box_scale_x_fp \c_space_tl - \fp_use:N \l_box_scale_y_fp \c_space_tl scale~ + \fp_use:N \l__box_scale_x_fp \c_space_tl + \fp_use:N \l__box_scale_y_fp \c_space_tl scale~ neg~exch~neg~exch~translate } %</dvips> %<*pdfmode|xdvipdfmx> -%<*pdfmode> - \pdftex_pdfsetmatrix:D -%</pdfmode> -%<*xdvipdfmx> - \driver_pdf_literal_direct:n -%</xdvipdfmx> + \@@_pdf_matrix:n { - \fp_use:N \l_box_scale_x_fp \c_space_tl + \fp_use:N \l__box_scale_x_fp \c_space_tl 0~0~ - \fp_use:N \l_box_scale_y_fp -%<*xdvipdfmx> - \c_space_tl 0~0~cm -%</xdvipdfmx> + \fp_use:N \l__box_scale_y_fp } %</pdfmode|xdvipdfmx> } -\cs_new_eq:NN \driver_box_scale_end: \driver_graphic_state_restore: +\cs_new_eq:NN \@@_box_scale_end: \@@_graphic_state_restore: +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_pdf_matrix:n} +% Here the appropriate function is set up to insert an affine matrix +% into the PDF. With a new enough \pdfTeX{} (version~1.40.0 or later) +% there is a primitive for this, which only needs the rotation/scaling/skew +% part. With an older \pdfTeX{} or with \texttt{xdvipdfmx} the matrix +% also has to include a translation part: that is always zero and so is +% built in here. +% \begin{macrocode} +%<*pdfmode> +\cs_if_exist:NTF \pdftex_pdfsetmatrix:D + { + \cs_new_protected:Npn \@@_pdf_matrix:n #1 + { \pdftex_pdfsetmatrix:D {#1} } + } + { + \cs_new_protected:Npn \@@_pdf_matrix:n #1 + { \@@_pdf_literal:n { #1 \c_space_tl 0~0~cm } } + } +%</pdfmode> +%<*xdvipdfmx> +\cs_new_protected:Npn \@@_pdf_matrix:n #1 + { \@@_pdf_literal_direct:n { #1 \c_space_tl 0~0~cm } } +%</xdvipdfmx> % \end{macrocode} % \end{macro} % % \subsection{Colour support} % -% \begin{variable}{\l_driver_current_color_tl} +% \begin{variable}{\l_@@_current_color_tl} % The current colour is needed by all of the engines, but the way this % is stored varies. % \begin{macrocode} -\tl_new:N \l_driver_current_color_tl +\tl_new:N \l_@@_current_color_tl %<*dvips> -\tl_set:Nn \l_driver_current_color_tl { Black } +\tl_set:Nn \l_@@_current_color_tl { Black } %</dvips> %<*pdfmode> -\tl_set:Nn \l_driver_current_color_tl { 0~g~0~G } +\tl_set:Nn \l_@@_current_color_tl { 0~g~0~G } %</pdfmode> %<*xdvipdfmx> -\tl_set:Nn \l_driver_current_color_tl { gray~0 } +\tl_set:Nn \l_@@_current_color_tl { gray~0 } %</xdvipdfmx> % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_driver_color_stack_int} -% \pdfTeX{} and \LuaTeX{} have multiple stacks available, and the colour -% stack therefore needs a number. +% \begin{variable}{\l_@@_color_stack_int} +% \pdfTeX{} (version~1.40.0 or later) and \LuaTeX{} have multiple stacks +% available, and the colour stack therefore needs a number. % \begin{macrocode} %<*pdfmode> -\int_new:N \l_driver_color_stack_int +\int_new:N \l_@@_color_stack_int %</pdfmode> % \end{macrocode} % \end{variable} % -% \begin{macro}{\driver_color_ensure_current:} -% \begin{macro}[aux]{\driver_color_reset:} +% \begin{macro}{\@@_color_ensure_current:} +% \begin{macro}[aux]{\@@_color_reset:} % Setting the current colour depends on the nature of the colour stack % available. In all cases there is a need to reset the colour after % the current group. % \begin{macrocode} -\cs_new_protected:Npn \driver_color_ensure_current: - { %<*dvips|xdvipdfmx> - \tex_special:D { color~push~\l_driver_current_color_tl } -%</dvips|xdvipdfmx> -%<*pdfmode> - \pdftex_pdfcolorstack:D \l_driver_color_stack_int push - { \l_driver_current_color_tl } -%</pdfmode> - \group_insert_after:N \driver_color_reset: +\cs_new_protected_nopar:Npn \@@_color_ensure_current: + { + \tex_special:D { color~push~\l_@@_current_color_tl } + \group_insert_after:N \@@_color_reset: } -\cs_new_protected:Npn \driver_color_reset: -%<*dvips|xdvipdfmx> +\cs_new_protected_nopar:Npn \@@_color_reset: { \tex_special:D { color~pop } } %</dvips|xdvipdfmx> +% \end{macrocode} +% Once again there is a version switch for \pdfTeX{}, as the +% \tn{pdfcolorstack} primitive was introduced in version~1.40.0. +% \begin{macrocode} %<*pdfmode> - { \pdftex_pdfcolorstack:D \l_driver_color_stack_int pop } +\cs_if_exist:NTF \pdftex_pdfcolorstack:D + { + \cs_new_protected_nopar:Npn \@@_color_ensure_current: + { + \pdftex_pdfcolorstack:D \l_@@_color_stack_int push + { \l_@@_current_color_tl } + \group_insert_after:N \@@_color_reset: + } + \cs_new_protected_nopar:Npn \@@_color_reset: + { \pdftex_pdfcolorstack:D \l_@@_color_stack_int pop } + } + { + \cs_new_protected_nopar:Npn \@@_color_ensure_current: + { + \@@_pdf_literal:n { \l_@@_current_color_tl } + \group_insert_after:N \@@_color_reset: + } + \cs_new_protected_nopar:Npn \@@_color_reset: + { \@@_pdf_literal:n { \l_@@_current_color_tl } } + } %</pdfmode> % \end{macrocode} % \end{macro} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx index 01024ff6593..8e14807cfcf 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3expan.dtx 3460 2012-02-26 12:16:41Z will $ - {L3 Experimental argument expansion} +\GetIdInfo$Id: l3expan.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Argument expansion} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -85,17 +85,17 @@ % % Internally preprocessing of arguments is done with functions from the % |\exp_| module. They all look alike, an example would be -% |\exp_args:NNo|. This function has three arguments, the first and the +% \cs{exp_args:NNo}. This function has three arguments, the first and the % second are a single tokens, while the third argument should be given -% in braces. Applying |\exp_args:NNo| will expand the content of third +% in braces. Applying \cs{exp_args:NNo} will expand the content of third % argument once before any expansion of the first and second arguments. -% If |\seq_gpush:No| was not define it could be coded in the following way: +% If \cs{seq_gpush:No} was not defined it could be coded in the following way: % \begin{verbatim} % \exp_args:NNo \seq_gpush:Nn % \g_file_name_stack % \l_tmpa_tl % \end{verbatim} -% In other words, the first argument to |\exp_args:NNo| is the base +% In other words, the first argument to \cs{exp_args:NNo} is the base % function and the other arguments are preprocessed and then passed to % this base function. In the example the first argument to the base % function should be a single token which is left unchanged while the @@ -106,17 +106,17 @@ % |\cs_new_nopar:Npn\seq_gpush:No{\exp_args:NNo\seq_gpush:Nn}| % \end{quote} % Providing variants in this way in style files is uncritical as the -% |\cs_new_nopar:Npn| function will silently accept definitions whenever the +% \cs{cs_new_nopar:Npn} function will silently accept definitions whenever the % new definition is identical to an already given one. Therefore adding % such definition to later releases of the kernel will not make such % style files obsolete. % % The steps above may be automated by using the function -% |\cs_generate_variant:Nn|, described next. +% \cs{cs_generate_variant:Nn}, described next. % % \section{Methods for defining variants} % -% \begin{function}[updated = 2011-09-15]{\cs_generate_variant:Nn} +% \begin{function}[updated = 2012-06-21]{\cs_generate_variant:Nn} % \begin{syntax} % \cs{cs_generate_variant:Nn} \meta{parent control sequence} \Arg{variant argument specifiers} % \end{syntax} @@ -165,7 +165,7 @@ % Arguments that need full expansion (\emph{i.e.}, are denoted % with |x|) should be avoided if possible as they can not be % processed expandably, \emph{i.e.}, functions of this type will -% not work correctly in arguments that are itself subject to |x| +% not work correctly in arguments that are themselves subject to |x| % expansion. % \item % In general, unless in the last position, multi-token arguments @@ -176,6 +176,7 @@ % not expanded. % \end{itemize} % +% ^^A Bruno: We should drop part of that paragraph eventually. % The |V| type returns the value of a register, which can be one of % |tl|, |num|, |int|, |skip|, |dim|, |toks|, or built-in \TeX{} % registers. The |v| type is the same except it first creates a @@ -204,13 +205,13 @@ % Unfortunately this only puts % |\exp_args:NNc \cs_set_eq:NN \aaa {b \l_tmpa_tl b}| into |\l_tmpb_tl| % and not |\cs_set_eq:NN \aaa = \blurb| as we probably wanted. Using -% |\tl_set:Nx| is not an option as that will die horribly. Instead +% \cs{tl_set:Nx} is not an option as that will die horribly. Instead % we can do a % \begin{quote} % |\tl_set:Nf \l_tmpb_tl {\cs_set_eq:Nc \aaa { b \l_tmpa_tl b } }| % \end{quote} % which puts the desired result in |\l_tmpb_tl|. It requires -% |\toks_set:Nf| to be defined as +% \cs{tl_set:Nf} to be defined as % \begin{quote} % |\cs_set_nopar:Npn \tl_set:Nf { \exp_args:NNf \tl_set:Nn }| % \end{quote} @@ -315,7 +316,7 @@ % \exp_args:NVV % } % \begin{syntax} -% \cs{exp_args:NNc} \meta{token1} \meta{token2} \Arg{tokens} +% \cs{exp_args:NNc} \meta{token_1} \meta{token_2} \Arg{tokens} % \end{syntax} % These optimized functions absorb three arguments and expand the second and % third as detailed by their argument specifier. The first argument @@ -355,7 +356,7 @@ % \exp_args:Nxx % } % \begin{syntax} -% \cs{exp_args:NNx} \meta{token1} \meta{token2} \Arg{tokens} +% \cs{exp_args:NNx} \meta{token_1} \meta{token_2} \Arg{tokens} % \end{syntax} % These functions absorb three arguments and expand the second and % third as detailed by their argument specifier. The first argument @@ -376,7 +377,7 @@ % \exp_args:Ncco % } % \begin{syntax} -% \cs{exp_args:NNNo} \meta{token1} \meta{token2} \meta{token3} \Arg{tokens} +% \cs{exp_args:NNNo} \meta{token_1} \meta{token_2} \meta{token_3} \Arg{tokens} % \end{syntax} % These optimized functions absorb four arguments and expand the second, third % and fourth as detailed by their argument specifier. The first @@ -393,7 +394,7 @@ % \exp_args:Nooo, % } % \begin{syntax} -% \cs{exp_args:NNNo} \meta{token1} \meta{token2} \meta{token3} \Arg{tokens} +% \cs{exp_args:NNNo} \meta{token_1} \meta{token_2} \meta{token_3} \Arg{tokens} % \end{syntax} % These functions absorb four arguments and expand the second, third % and fourth as detailed by their argument specifier. The first @@ -413,7 +414,7 @@ % \exp_args:Nccx % } % \begin{syntax} -% \cs{exp_args:NNnx} \meta{token1} \meta{token2} \Arg{tokens_1} \Arg{tokens_2} +% \cs{exp_args:NNnx} \meta{token_1} \meta{token_2} \Arg{tokens_1} \Arg{tokens_2} % \end{syntax} % These functions absorb four arguments and expand the second, third % and fourth as detailed by their argument specifier. The first @@ -441,7 +442,7 @@ % \exp_last_unbraced:NnNo % } % \begin{syntax} -% \cs{exp_last_unbraced:Nno} \meta{token} \meta{tokens1} \meta{tokens2} +% \cs{exp_last_unbraced:Nno} \meta{token} \meta{tokens_1} \meta{tokens_2} % \end{syntax} % These functions absorb the number of arguments given by their % specification, carry out the expansion @@ -469,7 +470,7 @@ % % \begin{function}[EXP]{\exp_last_two_unbraced:Noo} % \begin{syntax} -% \cs{exp_last_two_unbraced:Noo} \meta{token} \meta{tokens1} \Arg{tokens_2} +% \cs{exp_last_two_unbraced:Noo} \meta{token} \meta{tokens_1} \Arg{tokens_2} % \end{syntax} % This function absorbs three arguments and expand the second and third % once. The first argument of the function is then the next item on the @@ -480,14 +481,14 @@ % % \begin{function}[EXP]{\exp_after:wN} % \begin{syntax} -% \cs{exp_after:wN} \meta{token1} \meta{token2} +% \cs{exp_after:wN} \meta{token_1} \meta{token_2} % \end{syntax} -% Carries out a single expansion of \meta{token2} (which may consume +% Carries out a single expansion of \meta{token_2} (which may consume % arguments) prior to the expansion -% of \meta{token1}. If \meta{token2} is a \TeX{} primitive, it will -% be executed rather than expanded, while if \meta{token2} has not +% of \meta{token_1}. If \meta{token_2} is a \TeX{} primitive, it will +% be executed rather than expanded, while if \meta{token_2} has not % expansion (for example, if it is a character) then it will be left -% unchanged. It is important to notice that \meta{token1} may be +% unchanged. It is important to notice that \meta{token_1} may be % \emph{any} single token, including group-opening and -closing % tokens (|{| or |}| assuming normal \TeX{} category codes). Unless % specifically required, expansion should be carried out using an @@ -529,11 +530,11 @@ % \begin{syntax} % \cs{exp_not:n} \Arg{tokens} % \end{syntax} -% Prevents expansion of the \meta{tokens} in a context where they would -% otherwise -% be expanded, for example an |x|-type argument. +% Prevents expansion of the \meta{tokens} in a context where they +% would otherwise be expanded, for example an |x|-type argument. % \begin{texnote} -% This is the \eTeX{} \tn{unexpanded} primitive. +% This is the \eTeX{} \tn{unexpanded} primitive. Hence its argument +% \emph{must} be surrounded by braces. % \end{texnote} % \end{function} % @@ -591,24 +592,12 @@ % % \section{Internal functions and variables} % -% \begin{variable}{\l_exp_internal_tl} +% \begin{variable}{\l__exp_internal_tl} % The |\exp_| module has its private variables to temporarily store % results of the argument expansion. This is done to avoid interference % with other functions using temporary variables. % \end{variable} % -% \begin{function}[EXP]{\exp_eval_register:N, \exp_eval_register:c} -% \begin{syntax} -% \cs{exp_eval_register:N} \meta{variable} -% \end{syntax} -% These functions evaluates a \meta{variable} as part of a |V| or |v| -% expansion (respectively), preceded by \cs{c_zero} which stops -% the expansion of a previous \tn{romannumeral}. -% A \meta{variable} might exist as -% one of two things: a parameter-less non-long, non-protected macro -% or a built-in \TeX{} register such as |\count|. -% \end{function} -% % \begin{function}{\::n, \::N, \::c, \::o, \::f, \::x, \::v, \::V, \:::} % \begin{syntax} % |\cs_set_nopar:Npn \exp_args:Ncof { \::c \::o \::f \::: }| @@ -618,15 +607,6 @@ % visible in the log and so forth. % \end{function} % -% \begin{function}{\cs_generate_internal_variant:n} -% \begin{syntax} -% \cs{cs_generate_internal_variant:n} \meta{arg~spec} -% \end{syntax} -% Tests if the function |\exp_args:N|\meta{arg~spec} exists, and defines it -% if it does not. The \meta{arg~spec} should be a series of one or more -% of the letters |N|, |c|, |n|, |o|, |V|, |v|, |f| and |x|. -% \end{function} -% % \end{documentation} % % \begin{implementation} @@ -636,13 +616,17 @@ % \begin{macrocode} %<*initex|package> % \end{macrocode} +% +% \begin{macrocode} +%<@@=exp> +% \end{macrocode} % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -659,23 +643,23 @@ % In this section a general mechanism for defining functions to handle % argument handling is defined. These general expansion functions are % expandable unless |x| is used. (Any version of |x| is going to have -% to use one of the \LaTeX3 names for |\cs_set_nopar:Npx| at some point, and -% so is never going to be expandable.\footnote{However, some -% primitives have certain characteristics that means that their -% arguments undergo an \texttt{x} type expansion but the primitive -% is in fact still expandable. We shall make it very clear when such -% a function is expandable.}) +% to use one of the \LaTeX3 names for \cs{cs_set_nopar:Npx} at some +% point, and so is never going to be expandable.\footnote{Some +% primitives have certain characteristics that means that their +% arguments undergo an expansion similar to an \texttt{x} type +% expansion but the primitive is in fact still expandable. We make it +% very clear when such a function is expandable.}) % % The definition of expansion functions with this technique happens % in section~\ref{sec:gendef}. % In section~\ref{sec:handtune} some common cases are coded by a more direct -% method for efficiency, typically using calls to |\exp_after:wN|. +% method for efficiency, typically using calls to \cs{exp_after:wN}. % -% \begin{variable}{\l_exp_internal_tl} +% \begin{variable}{\l_@@_internal_tl} % We need a scratch token list variable. % We don't use |tl| methods so that \pkg{l3expan} can be loaded earlier. % \begin{macrocode} -\cs_new_nopar:Npn \l_exp_internal_tl { } +\cs_new_nopar:Npn \l_@@_internal_tl { } % \end{macrocode} % \end{variable} % @@ -686,12 +670,12 @@ % % An argument manipulator |\::|\meta{Z} always has signature |#1\:::#2#3| % where |#1| holds the remaining argument manipulations to be performed, -% |\:::| serves as an end marker for the list of manipulations, |#2| +% \cs{:::} serves as an end marker for the list of manipulations, |#2| % is the carried over result of the previous expansion steps and |#3| is % the argument about to be processed. % -% \begin{macro}[aux, EXP]{\exp_arg_next:nnn} -% \begin{macro}[aux, EXP]{\exp_arg_next:Nnn} +% \begin{macro}[aux, EXP]{\@@_arg_next:nnn} +% \begin{macro}[aux, EXP]{\@@_arg_next:Nnn} % |#1| is the result of an expansion step, |#2| is the remaining % argument manipulations and |#3| is the current result of the % expansion chain. This auxiliary function moves |#1| back after @@ -702,8 +686,8 @@ % only the |c| of the final argument manipulation variants does not % require a set of braces. % \begin{macrocode} -\cs_new:Npn \exp_arg_next:nnn #1#2#3 { #2 \::: { #3 {#1} } } -\cs_new:Npn \exp_arg_next:Nnn #1#2#3 { #2 \::: { #3 #1 } } +\cs_new:Npn \@@_arg_next:nnn #1#2#3 { #2 \::: { #3 {#1} } } +\cs_new:Npn \@@_arg_next:Nnn #1#2#3 { #2 \::: { #3 #1 } } % \end{macrocode} % \end{macro} % \end{macro} @@ -736,7 +720,7 @@ % as control sequence without expansion. % \begin{macrocode} \cs_new:Npn \::c #1 \::: #2#3 - { \exp_after:wN \exp_arg_next:Nnn \cs:w #3 \cs_end: {#1} {#2} } + { \exp_after:wN \@@_arg_next:Nnn \cs:w #3 \cs_end: {#1} {#2} } % \end{macrocode} % \end{macro} % @@ -744,7 +728,7 @@ % This function is used to expand an argument once. % \begin{macrocode} \cs_new:Npn \::o #1 \::: #2#3 - { \exp_after:wN \exp_arg_next:nnn \exp_after:wN {#3} {#1} {#2} } + { \exp_after:wN \@@_arg_next:nnn \exp_after:wN {#3} {#1} {#2} } % \end{macrocode} % \end{macro} % @@ -755,13 +739,13 @@ % expands everything in its way to find something terminating the % number and thereby expands the function in front of it. This % scanning procedure is terminated once the expansion hits -% something non-expandable or a space. We introduce |\exp_stop_f:| +% something non-expandable or a space. We introduce \cs{exp_stop_f:} % to mark such an end of expansion marker; in case the scanner hits % a number, this number also terminates the scanning and is left % untouched. In the example shown earlier the scanning was stopped % once \TeX{} had fully expanded |\cs_set_eq:Nc \aaa { b \l_tmpa_tl b }| % into |\cs_set_eq:NN \aaa = \blurb| which then turned out to contain -% the non-expandable token |\cs_set_eq:NN|. Since the expansion of +% the non-expandable token \cs{cs_set_eq:NN}. Since the expansion of % \tn{romannumeral} |-`0| is \meta{null}, we wind up with a fully % expanded list, only \TeX{} has not tried to execute any of the % non-expandable tokens. This is what differentiates this function @@ -769,7 +753,7 @@ % \begin{macrocode} \cs_new:Npn \::f #1 \::: #2#3 { - \exp_after:wN \exp_arg_next:nnn + \exp_after:wN \@@_arg_next:nnn \exp_after:wN { \tex_romannumeral:D -`0 #3 } {#1} {#2} } @@ -783,8 +767,8 @@ % \begin{macrocode} \cs_new_protected:Npn \::x #1 \::: #2#3 { - \cs_set_nopar:Npx \l_exp_internal_tl { {#3} } - \exp_after:wN \exp_arg_next:nnn \l_exp_internal_tl {#1} {#2} + \cs_set_nopar:Npx \l_@@_internal_tl { {#3} } + \exp_after:wN \@@_arg_next:nnn \l_@@_internal_tl {#1} {#2} } % \end{macrocode} % \end{macro} @@ -801,22 +785,22 @@ % \begin{macrocode} \cs_new:Npn \::V #1 \::: #2#3 { - \exp_after:wN \exp_arg_next:nnn - \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #3 } + \exp_after:wN \@@_arg_next:nnn + \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #3 } {#1} {#2} } \cs_new:Npn \::v # 1\::: #2#3 { - \exp_after:wN \exp_arg_next:nnn - \exp_after:wN { \tex_romannumeral:D \exp_eval_register:c {#3} } + \exp_after:wN \@@_arg_next:nnn + \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#3} } {#1} {#2} } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[int, EXP]{\exp_eval_register:N, \exp_eval_register:c} -% \begin{macro}[aux, EXP]{\exp_eval_error_msg:w} +% \begin{macro}[int, EXP]{\@@_eval_register:N, \@@_eval_register:c} +% \begin{macro}[aux, EXP]{\@@_eval_error_msg:w} % This function evaluates a register. Now a register might exist as % one of two things: A parameter-less macro or a built-in \TeX{} % register such as |\count|. For the \TeX{} registers we have to @@ -824,19 +808,19 @@ % expand them once. The trick is to find out when to use % \tn{the} and when not to. What we do here is try to find out % whether the token will expand to something else when hit with -% |\exp_after:wN|. The technique is to compare the meaning of the -% register in question when it has been prefixed with |\exp_not:N| +% \cs{exp_after:wN}. The technique is to compare the meaning of the +% register in question when it has been prefixed with \cs{exp_not:N} % and the register itself. If it is a macro, the prefixed -% |\exp_not:N| will temporarily turn it into the primitive -% |\scan_stop:|. +% \cs{exp_not:N} will temporarily turn it into the primitive +% \cs{scan_stop:}. % \begin{macrocode} -\cs_new:Npn \exp_eval_register:N #1 +\cs_new:Npn \@@_eval_register:N #1 { \exp_after:wN \if_meaning:w \exp_not:N #1 #1 % \end{macrocode} % If the token was not a macro it may be a malformed variable from a % |c| expansion in which case it is equal to the primitive -% |\scan_stop:|. In that case we throw an error. We could let \TeX{} +% \cs{scan_stop:}. In that case we throw an error. We could let \TeX{} % do it for us but that would result in the rather obscure % \begin{quote} % |! You can't use `\relax' after \the.| @@ -845,7 +829,7 @@ % went wrong. We provide something more sensible. % \begin{macrocode} \if_meaning:w \scan_stop: #1 - \exp_eval_error_msg:w + \@@_eval_error_msg:w \fi: % \end{macrocode} % The next bit requires some explanation. The function must be @@ -856,15 +840,15 @@ % |\exp_after:wN \c_zero \tex_the:D #1| and if it is a macro we % need to execute |\exp_after:wN \c_zero #1|. We therefore issue % the longer of the two sequences and if the register is a macro, we -% remove the |\tex_the:D|. +% remove the \cs{tex_the:D}. % \begin{macrocode} \else: \exp_after:wN \use_i_ii:nnn \fi: \exp_after:wN \c_zero \tex_the:D #1 } -\cs_new:Npn \exp_eval_register:c #1 - { \exp_after:wN \exp_eval_register:N \cs:w #1 \cs_end: } +\cs_new:Npn \@@_eval_register:c #1 + { \exp_after:wN \@@_eval_register:N \cs:w #1 \cs_end: } % \end{macrocode} % Clean up nicely, then call the undefined control sequence. The % result is an error message looking like this: @@ -875,11 +859,11 @@ % l.55 \tl_set:Nv \l_tmpa_tl {undefined_tl} % \end{verbatim} % \begin{macrocode} -\cs_new:Npn \exp_eval_error_msg:w #1 \tex_the:D #2 +\cs_new:Npn \@@_eval_error_msg:w #1 \tex_the:D #2 { \fi: \fi: - \msg_expandable_kernel_error:nnn { kernel } { bad-var } {#2} + \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#2} \c_zero } % \end{macrocode} @@ -891,7 +875,7 @@ % % One of the most important features of these functions is that they % are fully expandable and therefore allow to prefix them with -% |\tex_global:D| for example. +% \cs{tex_global:D} for example. % % \begin{macro}[EXP]{\exp_args:No} % \begin{macro}[EXP]{\exp_args:NNo} @@ -940,12 +924,12 @@ \cs_new:Npn \exp_args:Nv #1#2 { \exp_after:wN #1 \exp_after:wN - { \tex_romannumeral:D \exp_eval_register:c {#2} } + { \tex_romannumeral:D \@@_eval_register:c {#2} } } \cs_new:Npn \exp_args:NV #1#2 { \exp_after:wN #1 \exp_after:wN - { \tex_romannumeral:D \exp_eval_register:N #2 } + { \tex_romannumeral:D \@@_eval_register:N #2 } } % \end{macrocode} % \end{macro} @@ -971,13 +955,13 @@ { \exp_after:wN #1 \exp_after:wN #2 - \exp_after:wN { \tex_romannumeral:D \exp_eval_register:c {#3} } + \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#3} } } \cs_new:Npn \exp_args:NNV #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 - \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #3 } + \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #3 } } \cs_new:Npn \exp_args:Nco #1#2#3 { @@ -995,8 +979,8 @@ { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D \exp_after:wN - \exp_eval_register:N \exp_after:wN #2 \exp_after:wN } - \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #3 } + \@@_eval_register:N \exp_after:wN #2 \exp_after:wN } + \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #3 } } % \end{macrocode} % \end{macro} @@ -1013,7 +997,7 @@ \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 - \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #4 } + \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #4 } } \cs_new:Npn \exp_args:NcNc #1#2#3#4 { @@ -1114,7 +1098,7 @@ % % \subsection{Last-unbraced versions} % -% \begin{macro}[aux, EXP]{\exp_arg_last_unbraced:nn} +% \begin{macro}[aux, EXP]{\@@_arg_last_unbraced:nn} % \begin{macro}[aux, EXP]{\::f_unbraced} % \begin{macro}[aux, EXP]{\::o_unbraced} % \begin{macro}[aux, EXP]{\::V_unbraced} @@ -1123,28 +1107,28 @@ % There are a few places where the last argument needs to be available % unbraced. First some helper macros. % \begin{macrocode} -\cs_new:Npn \exp_arg_last_unbraced:nn #1#2 { #2#1 } +\cs_new:Npn \@@_arg_last_unbraced:nn #1#2 { #2#1 } \cs_new:Npn \::f_unbraced \::: #1#2 { - \exp_after:wN \exp_arg_last_unbraced:nn + \exp_after:wN \@@_arg_last_unbraced:nn \exp_after:wN { \tex_romannumeral:D -`0 #2 } {#1} } \cs_new:Npn \::o_unbraced \::: #1#2 - { \exp_after:wN \exp_arg_last_unbraced:nn \exp_after:wN {#2} {#1} } + { \exp_after:wN \@@_arg_last_unbraced:nn \exp_after:wN {#2} {#1} } \cs_new:Npn \::V_unbraced \::: #1#2 { - \exp_after:wN \exp_arg_last_unbraced:nn - \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #2 } {#1} + \exp_after:wN \@@_arg_last_unbraced:nn + \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #2 } {#1} } \cs_new:Npn \::v_unbraced \::: #1#2 { - \exp_after:wN \exp_arg_last_unbraced:nn - \exp_after:wN { \tex_romannumeral:D \exp_eval_register:c {#2} } {#1} + \exp_after:wN \@@_arg_last_unbraced:nn + \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#2} } {#1} } \cs_new_protected:Npn \::x_unbraced \::: #1#2 { - \cs_set_nopar:Npx \l_exp_internal_tl { \exp_not:n {#1} #2 } - \l_exp_internal_tl + \cs_set_nopar:Npx \l_@@_internal_tl { \exp_not:n {#1} #2 } + \l_@@_internal_tl } % \end{macrocode} % \end{macro} @@ -1173,9 +1157,9 @@ % general system is in place. % \begin{macrocode} \cs_new:Npn \exp_last_unbraced:NV #1#2 - { \exp_after:wN #1 \tex_romannumeral:D \exp_eval_register:N #2 } + { \exp_after:wN #1 \tex_romannumeral:D \@@_eval_register:N #2 } \cs_new:Npn \exp_last_unbraced:Nv #1#2 - { \exp_after:wN #1 \tex_romannumeral:D \exp_eval_register:c {#2} } + { \exp_after:wN #1 \tex_romannumeral:D \@@_eval_register:c {#2} } \cs_new:Npn \exp_last_unbraced:No #1#2 { \exp_after:wN #1 #2 } \cs_new:Npn \exp_last_unbraced:Nf #1#2 { \exp_after:wN #1 \tex_romannumeral:D -`0 #2 } @@ -1185,13 +1169,13 @@ { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: - \tex_romannumeral:D \exp_eval_register:N #3 + \tex_romannumeral:D \@@_eval_register:N #3 } \cs_new:Npn \exp_last_unbraced:NNV #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 - \tex_romannumeral:D \exp_eval_register:N #3 + \tex_romannumeral:D \@@_eval_register:N #3 } \cs_new:Npn \exp_last_unbraced:NNo #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 #3 } @@ -1200,7 +1184,7 @@ \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 - \tex_romannumeral:D \exp_eval_register:N #4 + \tex_romannumeral:D \@@_eval_register:N #4 } \cs_new:Npn \exp_last_unbraced:NNNo #1#2#3#4 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 #4 } @@ -1227,6 +1211,7 @@ % \end{macro} % % \begin{macro}[EXP]{\exp_last_two_unbraced:Noo} +% \begin{macro}[EXP, aux]{\@@_last_two_unbraced:noN} % If |#2| is a single token then this can be implemented as % \begin{verbatim} % \cs_new:Npn \exp_last_two_unbraced:Noo #1 #2 #3 @@ -1236,11 +1221,12 @@ % shuffle is used to ensure that |#2| can be multiple tokens. % \begin{macrocode} \cs_new:Npn \exp_last_two_unbraced:Noo #1#2#3 - { \exp_after:wN \exp_last_two_unbraced_aux:noN \exp_after:wN {#3} {#2} #1 } -\cs_new:Npn \exp_last_two_unbraced_aux:noN #1#2#3 + { \exp_after:wN \@@_last_two_unbraced:noN \exp_after:wN {#3} {#2} #1 } +\cs_new:Npn \@@_last_two_unbraced:noN #1#2#3 { \exp_after:wN #3 #2 #1 } % \end{macrocode} % \end{macro} +% \end{macro} % % \subsection{Preventing expansion} % @@ -1257,12 +1243,12 @@ \cs_new:Npn \exp_not:V #1 { \etex_unexpanded:D \exp_after:wN - { \tex_romannumeral:D \exp_eval_register:N #1 } + { \tex_romannumeral:D \@@_eval_register:N #1 } } \cs_new:Npn \exp_not:v #1 { \etex_unexpanded:D \exp_after:wN - { \tex_romannumeral:D \exp_eval_register:c {#1} } + { \tex_romannumeral:D \@@_eval_register:c {#1} } } % \end{macrocode} % \end{macro} @@ -1273,94 +1259,197 @@ % % \subsection{Defining function variants} % +% \begin{macrocode} +%<@@=cs> +% \end{macrocode} +% % \begin{macro}{\cs_generate_variant:Nn} -% \begin{macro}[aux]{\cs_generate_variant_aux:nnNNn} -% \begin{macro}[aux]{\cs_generate_variant_aux:Nnnw} -% \begin{macro}[aux]{\cs_generate_variant_aux:NNn} % \begin{arguments} -% \item Base form of a function; \emph{e.g.},~|\tl_set:Nn| +% \item Base form of a function; \emph{e.g.},~\cs{tl_set:Nn} % \item One or more variant argument specifiers; e.g., |{Nx,c,cx}| % \end{arguments} -% Test whether the base function is protected or not -% and define \cs{cs_tmp:w} as either \cs{cs_new_nopar:Npx} or -% \cs{cs_new_protected_nopar:Npx}, then used to define all the -% variants. -% Split up the original base function to grab its name and signature -% consisting of $k$ letters. Then we wish to iterate through the list -% of variant argument specifiers, and for each one construct a new -% function name using the original base name, the variant signature -% consisting of $l$ letters and the last $k-l$ letters of the base -% signature. For example, for a base function |\tl_set:Nn| which -% needs a |c| variant form, we want the new signature to be |cn|. +% After making sure that the base form exists, test whether it is +% protected or not and define \cs{@@_tmp:w} as either +% \cs{cs_new_nopar:Npx} or \cs{cs_new_protected_nopar:Npx}, which is +% then used to define all the variants (except those involving +% \texttt{x}-expansion, always protected). Split up the original base +% function only once, to grab its name and signature. Then we wish to +% iterate through the comma list of variant argument specifiers, which +% we first convert to a string: the reason is explained later. % \begin{macrocode} -\cs_new_protected:Npn \cs_generate_variant:Nn #1 +\cs_new_protected:Npn \cs_generate_variant:Nn #1#2 { - \chk_if_exist_cs:N #1 - \cs_generate_variant_aux:N #1 - \cs_split_function:NN #1 \cs_generate_variant_aux:nnNNn - #1 + \__chk_if_exist_cs:N #1 + \@@_generate_variant:N #1 + \exp_after:wN \@@_split_function:NN + \exp_after:wN #1 + \exp_after:wN \@@_generate_variant:nnNN + \exp_after:wN #1 + \etex_detokenize:D {#2} , ? , \q_recursion_stop } % \end{macrocode} -% We discard the boolean |#3| and then set off a loop through the desired -% variant forms. The original function is retained as |#4| for efficiency. +% \end{macro} +% +% \begin{macro}[aux]{\@@_generate_variant:N} +% \begin{macro}[aux]{\@@_generate_variant:w} +% The idea here is to pick up protected parent functions, using the +% nature of the meaning string that they generate. If |\protected| +% appears in the meaning, the first \cs{q_mark} is taken as an +% argument, and |#3| is \cs{cs_new_protected_nopar:Npx}, otherwise it +% is \cs{cs_new_nopar:Npx}. % \begin{macrocode} -\cs_new_protected:Npn \cs_generate_variant_aux:nnNNn #1#2#3#4#5 - { \cs_generate_variant_aux:Nnnw #4 {#1}{#2} #5 , ? , \q_recursion_stop } +\group_begin: + \tex_lccode:D `\Z = `\d \scan_stop: + \tex_lccode:D `\? =`\\ \scan_stop: + \tex_catcode:D `\P = 12 \scan_stop: + \tex_catcode:D `\R = 12 \scan_stop: + \tex_catcode:D `\O = 12 \scan_stop: + \tex_catcode:D `\T = 12 \scan_stop: + \tex_catcode:D `\E = 12 \scan_stop: + \tex_catcode:D `\C = 12 \scan_stop: + \tex_catcode:D `\Z = 12 \scan_stop: +\tex_lowercase:D + { + \group_end: + \cs_new_protected:Npn \@@_generate_variant:N #1 + { + \exp_after:wN \@@_generate_variant:w + \token_to_meaning:N #1 + \q_mark \cs_new_protected_nopar:Npx + ? PROTECTEZ + \q_mark \cs_new_nopar:Npx + \q_stop + } + \cs_new_protected:Npn \@@_generate_variant:w + #1 ? PROTECTEZ #2 \q_mark #3 #4 \q_stop + { + \cs_set_eq:NN \@@_tmp:w #3 + } + } % \end{macrocode} -% Next is the real work to be done. We now have 1: original function, -% 2: base name, 3: base signature, 4: beginning of variant signature. -% To construct the new -% csname and the |\exp_args:Ncc| form, we need the variant signature. -% In our example, we wanted to discard the first two letters of the -% base signature because the variant form started with |cc|. This is -% the same as putting first |cc| in the signature and then -% |\use_none:nn| followed by the base signature |NNn|. Depending on -% the number of characters in |#4|, the relevant \cs{use_none:n\ldots{}n} -% is called. -% -% Firstly though, we check whether to terminate the loop. -% Then build the variant function once, to avoid repeating this -% relatively expensive operation. Then recurse. +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\@@_generate_variant:nnNN} +% \begin{arguments} +% \item Base name. +% \item Base signature. +% \item Boolean. +% \item Base function. +% \end{arguments} +% We discard the boolean and then set off a loop through the desired +% variant forms. The original function is retained as |#4| for +% efficiency. % \begin{macrocode} -\cs_new_protected:Npn \cs_generate_variant_aux:Nnnw #1#2#3#4 , +\cs_new_protected:Npn \@@_generate_variant:nnNN #1#2#3#4 + { \@@_generate_variant:Nnnw #4 {#1}{#2} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\@@_generate_variant:Nnnw} +% \begin{arguments} +% \item Base function. +% \item Base name. +% \item Base signature. +% \item Beginning of variant signature. +% \end{arguments} +% First check whether to terminate the loop over variant forms. Then +% build the variant function name once, to avoid repeating this +% relatively expensive operation. Then recurse, calling +% \cs{@@_generate_variant:Nnnw} with the three same arguments (and a +% new item from the comma list of variant forms). +% +% For each variant form, construct a new function name using the +% original base name, the variant signature consisting of $l$ letters +% and the last $k-l$ letters of the base signature (of length $k$). +% For example, for a base function \cs{prop_put:Nnn} which needs a +% |cV| variant form, we want the new signature to be |cVn|. This +% could be done by placing the variant form letters, then +% \cs{use_none:nn} followed by the signature (the choice of +% \cs{use_none:nn} would depend on the variant form). However, this +% would crash badly if the base signature is mistakenly shorter than +% the variant form (this includes cases where the base function had no +% colon). Instead, we do a loop which at each step removes a +% character from the base signature and leaves one from the variant +% form behind it in a \cs{cs:w} \ldots{} \cs{cs_end:} construction. +% This \texttt{c}-type expansion is not done using \cs{exp_args:NNc} +% because some error-reporting mechanism must escape out of this +% construction. +% \begin{macrocode} +\cs_new_protected:Npn \@@_generate_variant:Nnnw #1#2#3#4 , { \if:w ? #4 \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: - \exp_args:NNc \cs_generate_variant_aux:NNn - #1 - { - #2 : #4 - \exp_after:wN \use_i_delimit_by_q_stop:nw - \use_none:nnnnnnnnn #4 - \use_none:nnnnnnnnn - \use_none:nnnnnnnn - \use_none:nnnnnnn - \use_none:nnnnnn - \use_none:nnnnn - \use_none:nnnn - \use_none:nnn - \use_none:nn - \use_none:n - { } + \exp_after:wN \@@_generate_variant:NNn + \exp_after:wN #1 + \cs:w + #2 : + \@@_generate_variant_loop:NwN + ? #3 + \q_mark #4 \@@_generate_variant_loop_end:w + \q_mark \@@_generate_variant_loop_error:wnNNnn \q_stop - #3 - } + \cs_end: {#4} - \cs_generate_variant_aux:Nnnw #1 {#2} {#3} + \@@_generate_variant:Nnnw #1 {#2} {#3} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP]{\@@_generate_variant_loop:NwN} +% \begin{macro}[aux, EXP] +% { +% \@@_generate_variant_loop_end:w, +% \@@_generate_variant_loop_error:wnNNnn +% } +% Normally, the loop takes one character of the base signature and one +% from the variant form (after \cs{q_mark}), and leaves the latter one +% in the input stream. This stops when |#3| is the \texttt{loop_end} +% auxiliary, which, once left in the input stream, cleans up the rest +% of the csname construction. In case the base signature was in fact +% shorter, one reaches the point where |#1| is the \cs{q_mark} which +% is supposed to separate the base signature from the variant form. +% Then |#2| is delimited by the next \cs{q_mark}, and the +% \texttt{loop_error} auxiliary is taken as |#3|. This function +% fetches appropriate arguments for an error message, and places it +% outside the csname construction. +% +% Note in the definition of \cs{@@_generate_variant:Nnnw} the base +% signature is preceeded by a question mark. This shifts the base +% signature and variant form to compensate for the presence of the +% \texttt{loop_end} auxiliary at the end of the variant form. +% \begin{macrocode} +\cs_new:Npn \@@_generate_variant_loop:NwN #1 #2 \q_mark #3 + { #3 \@@_generate_variant_loop:NwN #2 \q_mark } +\cs_new:Npn \@@_generate_variant_loop_end:w #1#2 \q_mark #3 \q_stop {#2} +\cs_new:Npn \@@_generate_variant_loop_error:wnNNnn + #1 \q_stop \cs_end: #2 #3#4#5#6 + { + \cs_end: {#2} + \__msg_kernel_error:nnxx { kernel } { variant-too-long } + { \tl_to_str:n {#2} } { \token_to_str:N #4 } + #3 #4 {#5} {#6} } % \end{macrocode} -% Check if the variant form has already been defined. -% If not, then define it and then additionally check if -% the |\exp_args:N| form needed is defined. -% Otherwise tell that it was already defined. +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\@@_generate_variant:NNn} +% If the variant form has already been defined, log its existence. +% Otherwise, make sure that the |\exp_args:N #3| form is defined, and +% if it contains |x|, change \cs{@@_tmp:w} locally to +% \cs{cs_new_protected_nopar:Npx}. Then define the variant by +% combining the |\exp_args:N #3| variant and the base function. % \begin{macrocode} -\cs_new_protected:Npn \cs_generate_variant_aux:NNn #1 #2 #3 +\cs_new_protected:Npn \@@_generate_variant:NNn #1 #2 #3 { \cs_if_free:NTF #2 { - \cs_tmp:w #2 { \exp_not:c { exp_args:N #3 } \exp_not:N #1 } - \cs_generate_internal_variant:n {#3} + \group_begin: + \@@_generate_internal_variant:n {#3} + \@@_tmp:w #2 { \exp_not:c { exp_args:N #3 } \exp_not:N #1 } + \group_end: } { \iow_log:x @@ -1373,86 +1462,65 @@ } % \end{macrocode} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % -% \begin{macro}[aux]{\cs_generate_variant_aux:N} -% \begin{macro}[aux]{\cs_generate_variant_aux:w} -% The idea here is to pick up protected parent functions, using the -% nature of the meaning string that they generate. The test here is -% almost the same as \cs{tl_if_empty:nTF}, but has to be hard-coded as -% that function is not yet available and because it has to match both -% long and short macros. +% \begin{macro}[int]{\@@_generate_internal_variant:n} +% \begin{macro}[aux]{\@@_generate_internal_variant:wwnw} +% \begin{macro}[aux, rEXP]{\@@_generate_internal_variant_loop:n} +% Test if |\exp_args:N #1| is already defined and if not define it via +% the |\::| commands using the chars in |#1|. If |#1| contains an |x| +% (this is the place where having converted the original comma-list +% argument to a string is very important), the result should be +% protected, and the next variant to be defined using that internal +% variant should be protected. % \begin{macrocode} \group_begin: - \tex_lccode:D `\Z = `\d \scan_stop: - \tex_lccode:D `\? =`\\ \scan_stop: - \tex_catcode:D `\P = 12 \scan_stop: - \tex_catcode:D `\R = 12 \scan_stop: - \tex_catcode:D `\O = 12 \scan_stop: - \tex_catcode:D `\T = 12 \scan_stop: - \tex_catcode:D `\E = 12 \scan_stop: - \tex_catcode:D `\C = 12 \scan_stop: - \tex_catcode:D `\Z = 12 \scan_stop: + \tex_catcode:D `\X = 12 \scan_stop: + \tex_lccode:D `\N = `\N \scan_stop: \tex_lowercase:D { \group_end: - \cs_new_protected:Npn \cs_generate_variant_aux:N #1 - { - \exp_after:wN \cs_generate_variant_aux:w - \token_to_meaning:N #1 - \q_mark \cs_new_protected_nopar:Npx - ? PROTECTEZ - \q_mark \cs_new_nopar:Npx - \q_stop - } - \cs_new_protected:Npn \cs_generate_variant_aux:w - #1 ? PROTECTEZ #2 \q_mark #3 #4 \q_stop + \cs_new_protected:Npn \@@_generate_internal_variant:n #1 { - \cs_set_eq:NN \cs_tmp:w #3 + \@@_generate_internal_variant:wwnNwnn + #1 \q_mark + { \cs_set_eq:NN \@@_tmp:w \cs_new_protected_nopar:Npx } + \cs_new_protected_nopar:cpx + X \q_mark + { } + \cs_new_nopar:cpx + \q_stop + { exp_args:N #1 } + { \@@_generate_internal_variant_loop:n #1 { : \use_i:nn } } } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[int]{\cs_generate_internal_variant:n} -% \begin{macro}[aux, rEXP]{\cs_generate_internal_variant_aux:N} -% Test if |exp_args:N #1| is already defined -% and if not define it via the -% |\::| commands using the chars in |#1| -% \begin{macrocode} -\cs_new_protected:Npn \cs_generate_internal_variant:n #1 - { - \cs_if_free:cT { exp_args:N #1 } + \cs_new_protected:Npn \@@_generate_internal_variant:wwnNwnn + #1 X #2 \q_mark #3 #4 #5 \q_stop #6 #7 { - \cs_new:cpx { exp_args:N #1 } - { \cs_generate_internal_variant_aux:N #1 : } + #3 + \cs_if_free:cT {#6} { #4 {#6} {#7} } } } % \end{macrocode} % This command grabs char by char outputting |\::#1| (not expanded -% further) until we see a |:|. That colon is in fact also turned into -% |\:::| so that the required structure for |\exp_args...| commands -% is correctly terminated. +% further). We avoid tests by putting a trailing |: \use_i:nn|, which +% leaves \cs{cs_end:} and removes the looping macro. The colon is in +% fact also turned into \cs{:::} so that the required structure for +% |\exp_args:N...| commands is correctly terminated. % \begin{macrocode} -\cs_new:Npn \cs_generate_internal_variant_aux:N #1 +\cs_new:Npn \@@_generate_internal_variant_loop:n #1 { - \exp_not:c { :: #1 } - \if_meaning:w : #1 - \exp_after:wN \use_none:n - \fi: - \cs_generate_internal_variant_aux:N + \exp_after:wN \exp_not:N \cs:w :: #1 \cs_end: + \@@_generate_internal_variant_loop:n } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % %\subsection{Variants which cannot be created earlier} % % \begin{macro}[EXP,pTF] % {\str_if_eq:Vn, \str_if_eq:on, \str_if_eq:nV, \str_if_eq:no, \str_if_eq:VV} +% \begin{macro}[EXP]{\str_case:onn} % These cannot come earlier as they need \cs{cs_generate_variant:Nn}. % \begin{macrocode} \cs_generate_variant:Nn \str_if_eq_p:nn { V , o } @@ -1463,8 +1531,10 @@ \cs_generate_variant:Nn \str_if_eq:nnF { nV , no , VV } \cs_generate_variant:Nn \str_if_eq:nnTF { V , o } \cs_generate_variant:Nn \str_if_eq:nnTF { nV , no , VV } +\cs_generate_variant:Nn \str_case:nnn { o } % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macrocode} %</initex|package> diff --git a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx index 9b8bd6b1a0a..919281bd552 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3file.dtx 3520 2012-03-09 19:34:07Z joseph $ - {L3 Experimental file and I/O operations} +\GetIdInfo$Id: l3file.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 File and I/O operations} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -78,6 +78,13 @@ % \enquote{current path} for \TeX{} is somewhat broader than that for other % programs. % +% For functions which expect a \meta{file name} argument, this argument +% may contain both literal items and expandable content, which should on +% full expansion be the desired file name. Any active characters (as +% declared in \cs{l_char_active_seq}) will \emph{not} be expanded, +% allowing the direct use of these in file names. +% Spaces are not allowed in file names. +% % \section{File operation functions} % % \begin{variable}{\g_file_current_name_tl} @@ -95,11 +102,6 @@ % Searches for \meta{file name} using the current \TeX{} search % path and the additional paths controlled by % \cs{file_path_include:n}). -% \begin{texnote} -% The \meta{file name} may contain both literal items and expandable -% content, which should on full expansion be the desired file name. -% The expansion occurs when \TeX{} searches for the file. -% \end{texnote} % \end{function} % % \begin{function}[updated = 2012-02-10]{\file_add_path:nN} @@ -108,16 +110,9 @@ % \end{syntax} % Searches for \meta{file name} in the path as detailed for % \cs{file_if_exist:nTF}, and if found sets the \meta{tl var} the -% fully-qualified name of the file, \emph{i.e}.~the path and file name. +% fully-qualified name of the file, \emph{i.e.}~the path and file name. % If the file is not found then the \meta{tl var} will contain the % marker \cs{q_no_value}. -% \begin{texnote} -% The \meta{file name} may contain both literal items and expandable -% content, which should on full expansion be the desired file name. -% Any active characters (as declared in \cs{l_char_active_seq}) will -% \emph{not} be expanded, allowing the direct use of these in -% file names. -% \end{texnote} % \end{function} % % \begin{function}[updated = 2012-02-17]{\file_input:n} @@ -128,30 +123,29 @@ % \cs{file_if_exist:nTF}, and if found reads in the file as % additional \LaTeX{} source. All files read are recorded % for information and the file name stack is updated by this -% function. An error will be raised if the file is not found -% \begin{texnote} -% The \meta{file name} may contain both literal items and expandable -% content, which should on full expansion be the desired file name. -% Any active characters (as declared in \cs{l_char_active_seq}) will -% \emph{not} be expanded, allowing the direct use of these in -% file names. -% \end{texnote} +% function. An error will be raised if the file is not found. % \end{function} % -% \begin{function}{\file_path_include:n} +% \begin{function}[updated = 2012-07-04]{\file_path_include:n} % \begin{syntax} % \cs{file_path_include:n} \Arg{path} % \end{syntax} % Adds \meta{path} to the list of those used to search when reading % files. The assignment is local. +% The \meta{path} is processed in the same way as a \meta{file name}, +% \emph{i.e.}, with \texttt{x}-type expansion except active +% characters. Spaces are not allowed in the \meta{path}. % \end{function} % -% \begin{function}{\file_path_remove:n} +% \begin{function}[updated = 2012-07-04]{\file_path_remove:n} % \begin{syntax} % \cs{file_path_remove:n} \Arg{path} % \end{syntax} % Removes \meta{path} from the list of those used to search when reading % files. The assignment is local. +% The \meta{path} is processed in the same way as a \meta{file name}, +% \emph{i.e.}, with \texttt{x}-type expansion except active +% characters. Spaces are not allowed in the \meta{path}. % \end{function} % % \begin{function}{\file_list:} @@ -171,16 +165,20 @@ % close streams when they are no longer needed, to release them for other % processes. % +% Note that I/O operations are global: streams should all be declared +% with global names and treated accordingly. +% % \begin{function}[added = 2011-09-26, updated = 2011-12-27] % {\ior_new:N, \ior_new:c, \iow_new:N, \iow_new:c} % \begin{syntax} -% \cs{ior_new:Nn} \meta{stream} +% \cs{ior_new:N} \meta{stream} +% \cs{iow_new:N} \meta{stream} % \end{syntax} % Globally reserves the name of the \meta{stream}, either for reading -% or for writing as appropriate. The \meta{stream} is not opened until the -% appropriate \cs{\ldots_open:Nn} function is used. Attempting to use -% a \meta{stream} which has not been opened will result in a \TeX{} -% error. +% or for writing as appropriate. The \meta{stream} is not opened until +% the appropriate \cs{\ldots_open:Nn} function is used. Attempting to +% use a \meta{stream} which has not been opened is an error, and the +% \meta{stream} will behave as the corresponding \cs{c_term_\ldots}. % \end{function} % % \begin{function}[updated = 2012-02-10]{\ior_open:Nn, \ior_open:cn} @@ -192,14 +190,7 @@ % open it is closed before the new operation begins. The % \meta{stream} is available for access immediately and will remain % allocated to \meta{file name} until a \cs{ior_close:N} instruction -% is given or the file ends. -% \begin{texnote} -% The \meta{file name} may contain both literal items and expandable -% content, which should on full expansion be the desired file name. -% Any active characters (as declared in \cs{l_char_active_seq}) will -% \emph{not} be expanded, allowing the direct use of these in -% file names. -% \end{texnote} +% is given or the \TeX{} run ends. % \end{function} % % \begin{function}[updated = 2012-02-09]{\iow_open:Nn, \iow_open:cn} @@ -211,34 +202,20 @@ % open it is closed before the new operation begins. The % \meta{stream} is available for access immediately and will remain % allocated to \meta{file name} until a \cs{iow_close:N} instruction -% is given or the file ends. Opening a file for writing will clear +% is given or the \TeX{} run ends. Opening a file for writing will clear % any existing content in the file (\emph{i.e.}~writing is \emph{not} % additive). -% \begin{texnote} -% The \meta{file name} may contain both literal items and expandable -% content, which should on full expansion be the desired file name. -% Any active characters (as declared in \cs{l_char_active_seq}) will -% \emph{not} be expanded, allowing the direct use of these in -% file names. -% \end{texnote} % \end{function} % -% \begin{function}[updated = 2011-12-27]{\ior_close:N, \ior_close:c} +% \begin{function}[updated = 2012-07-03] +% {\ior_close:N, \ior_close:c, \iow_close:N, \iow_close:c} % \begin{syntax} % \cs{ior_close:N} \meta{stream} -% \end{syntax} -% Closes the \meta{stream}. Streams should always be closed when -% they are finished with as this ensures that they remain available -% to other programmer. -% \end{function} -% -% \begin{function}[updated = 2011-12-27]{\iow_close:N, \iow_close:c} -% \begin{syntax} % \cs{iow_close:N} \meta{stream} % \end{syntax} % Closes the \meta{stream}. Streams should always be closed when % they are finished with as this ensures that they remain available -% to other programmer. +% to other programmers. % \end{function} % % \begin{function}{\ior_list_streams:, \iow_list_streams:} @@ -250,38 +227,38 @@ % stream: intended for tracking down problems. % \end{function} % -% \section{Reading from files} +% \subsection{Reading from files} % -% \begin{function}{\ior_to:NN,\ior_gto:NN} +% \begin{function}[added = 2012-06-24]{\ior_get:NN} % \begin{syntax} -% \cs{ior_to:NN} \meta{stream} \meta{token list variable} +% \cs{ior_get:NN} \meta{stream} \meta{token list variable} % \end{syntax} -% Functions that reads one or more lines (until an equal number of left +% Function that reads one or more lines (until an equal number of left % and right braces are found) from the input \meta{stream} and stores -% the result in the \meta{token list} variable, locally or globally. If the +% the result locally in the \meta{token list} variable. If the % \meta{stream} is not open, input is requested from the terminal. % The material read from the \meta{stream} will be tokenized by % \TeX{} according to the category codes in force when the function % is used. % \begin{texnote} -% This protected macro expands to the \TeX{} primitives \tn{read} -% or \tn{global}\tn{read} along with the |to| keyword. +% This protected macro expands to the \TeX{} primitive \tn{read} +% along with the |to| keyword. % \end{texnote} % \end{function} % -% \begin{function}{\ior_str_to:NN,\ior_str_gto:NN} +% \begin{function}[added = 2012-06-24]{\ior_get_str:NN} % \begin{syntax} -% \cs{ior_str_to:NN} \meta{stream} \meta{token list variable} +% \cs{ior_get_str:NN} \meta{stream} \meta{token list variable} % \end{syntax} -% Functions that reads one line from the input \meta{stream} and stores -% the result in the \meta{token list} variable, locally or globally. If the +% Function that reads one line from the input \meta{stream} and stores +% the result locally in the \meta{token list} variable. If the % \meta{stream} is not open, input is requested from the terminal. -% The material read from the \meta{stream} as a series of tokens with +% The material is read from the \meta{stream} as a series of tokens with % category code $12$ (other), with the exception of space % characters which are given category code $10$ (space). % \begin{texnote} -% This protected macro expands to the \eTeX{} primitives \tn{readline} -% or \tn{global}\tn{readline} along with the |to| keyword. +% This protected macro expands to the \eTeX{} primitive \tn{readline} +% along with the |to| keyword. % \end{texnote} % \end{function} % @@ -297,17 +274,13 @@ % % \section{Writing to files} % -% \begin{function}{\iow_now:Nn, \iow_now:Nx} +% \begin{function}[updated = 2012-06-05]{\iow_now:Nn, \iow_now:Nx} % \begin{syntax} % \cs{iow_now:Nn} \meta{stream} \Arg{tokens} % \end{syntax} % This functions writes \meta{tokens} to the specified % \meta{stream} immediately (\emph{i.e.}~the write operation is called % on expansion of \cs{iow_now:Nn}). -% \begin{texnote} -% \cs{iow_now:Nx} is a protected macro which expands to -% the two \TeX{} primitives \tn{immediate}\tn{write}. -% \end{texnote} % \end{function} % % \begin{function}{\iow_log:n, \iow_log:x} @@ -355,9 +328,9 @@ % % \begin{function}[EXP]{\iow_char:N} % \begin{syntax} -% \cs{iow_char:N} \meta{token} +% \cs{iow_char:N} |\|\meta{char} % \end{syntax} -% Inserts \meta{token} into the output stream. Useful when trying to +% Inserts \meta{char} into the output stream. Useful when trying to % write difficult characters such as |%|, |{|, |}|, % \emph{etc.}~in messages, for example: % \begin{verbatim} @@ -376,47 +349,59 @@ % expansion (\emph{e.g.}~in the second argument of \cs{iow_now:Nn}). % \end{function} % -% \section{Wrapping lines in output} +% \subsection{Wrapping lines in output} % -% \begin{function}[updated = 2011-09-21]{\iow_wrap:xnnnN} +% \begin{function}[added = 2012-06-28]{\iow_wrap:nnnN} % \begin{syntax} -% \cs{iow_wrap:xnnnN} \Arg{text} \Arg{run-on text} \Arg{run-on length} \Arg{set up} \meta{function} +% \cs{iow_wrap:nnnN} \Arg{text} \Arg{run-on text} \Arg{set up} \meta{function} % \end{syntax} % This function will wrap the \meta{text} to a fixed number of % characters per line. At the start of each line which is wrapped, -% the \meta{run-on text} will be inserted. The line length targeted -% will be the value of \cs{l_iow_line_length_int} minus the -% \meta{run-on length}. The later value should be the number of -% characters in the \meta{run-on text}. Additional functions may be -% added to the wrapping by using the \meta{set up}, which is executed -% before the wrapping takes place. The result of the wrapping operation -% is passed as a braced argument to the \meta{function}, which will -% typically be a wrapper around a writing operation. Within the -% \meta{text}, +% the \meta{run-on text} will be inserted. The line character count +% targeted will be the value of \cs{l_iow_line_count_int} minus the +% number of characters in the \meta{run-on text}. The \meta{text} and +% \meta{run-on text} are exhaustively expanded by the function, with the +% following substitutions: % \begin{itemize} -% \item |\\| may be used to force a new line, -% \item \verb|\ | may be used to represent a forced space -% (for example after a control sequence), -% \item |\#|, |\%|, |\{|, |\}|, |\~| may be used to represent -% the corresponding character, -% \item \cs{iow_indent:n} may be used to indent a part of the -% message. +% \item |\\| may be used to force a new line, +% \item \verb*|\ | may be used to represent a forced space +% (for example after a control sequence), +% \item |\#|, |\%|, |\{|, |\}|, |\~| may be used to represent +% the corresponding character, +% \item \cs{iow_indent:n} may be used to indent a part of the +% message. % \end{itemize} -% Both the wrapping process and the subsequent write operation -% will perform \texttt{x}-type expansion. For this reason, material which -% is to be written \enquote{as is} should be given as the argument to -% \cs{token_to_str:N} or \cs{tl_to_str:n} (as appropriate) within -% the \meta{text}. The output of \cs{iow_wrap:xnnnN} (\emph{i.e.}~the -% argument passed to the \meta{function}) will consist of characters of -% category code $12$ (other) and $10$ (space) only. This means that the +% Additional functions may be added to the wrapping by using the +% \meta{set up}, which is executed before the wrapping takes place: this +% may include overriding the substitutions listed. +% +% Any expandable material in the \meta{text} which is not to be expanded +% on wrapping should be converted to a string using \cs{token_to_str:N}, +% \cs{tl_to_str:n}, \cs{tl_to_str:N}, \emph{etc.} +% +% The result of the wrapping operation is passed as a braced argument to the +% \meta{function}, which will typically be a wrapper around a write +% operation. The output of \cs{iow_wrap:nnnN} (\emph{i.e.}~the argument +% passed to the \meta{function}) will consist of characters of category +% \enquote{other} (category code~12), with the exception of spaces which +% will have category \enquote{space} (category code~10). This means that the % output will \emph{not} expand further when written to a file. +% +% \begin{texnote} +% Internally, \cs{iow_wrap:nnnN} carries out an \texttt{x}-type expansion +% on the \meta{text} to expand it. This is done in such a way that +% \cs{exp_not:N} or \cs{exp_not:n} \emph{could} be used to prevent +% expansion of material. However, this is less conceptually clear than +% conversion to a string, which is therefore the supported method for +% handling expandable material in the \meta{text}. +% \end{texnote} % \end{function} % % \begin{function}[added = 2011-09-21]{\iow_indent:n} % \begin{syntax} % \cs{iow_indent:n} \Arg{text} % \end{syntax} -% In the context of \cs{iow_wrap:xnnnN} (for instance in messages), +% In the context of \cs{iow_wrap:nnnN} (for instance in messages), % indents \meta{text} by four spaces. This function will not cause % a line break, and only affects lines which start within the scope % of the \meta{text}. In case the indented \meta{text} should appear @@ -424,8 +409,9 @@ % line breaks. % \end{function} % -% \begin{variable}{\l_iow_line_length_int} -% The maximum length of a line to be written by the \cs{iow_wrap:xxnnN} +% \begin{variable}[added = 2012-06-24]{\l_iow_line_count_int} +% The maximum number of characters in a line to be written +% by the \cs{iow_wrap:nnnN} % function. This value depends on the \TeX{} system in use: the standard % value is $78$, which is typically correct for unmodified \TeX{}live % and MiK\TeX{} systems. @@ -436,11 +422,11 @@ % (\enquote{other}), and character code $32$ (space). % \end{variable} % -% \section{Constant input--output streams} +% \subsection{Constant input--output streams} % % \begin{variable}{\c_term_ior} % Constant input stream for reading from the terminal. Reading from this -% stream using \cs{ior_to:NN} or similar will result in a prompt from +% stream using \cs{ior_get:NN} or similar will result in a prompt from % \TeX{} of the form % \begin{verbatim} % <tl>= @@ -452,123 +438,61 @@ % (plus the log), respectively. % \end{variable} % -% \section{Experimental functions} -% -% \begin{function}[added = 2012-02-11]{\ior_map_inline:Nn} -% \begin{syntax} -% \cs{ior_map_inline:Nn} \meta{stream} \Arg{inline function} -% \end{syntax} -% Applies the \meta{inline function} to \meta{items} obtained by -% reading one or more lines (until an equal number of left and right -% braces are found) from the \meta{stream}. The \meta{inline function} -% should consist of code which will receive the \meta{line} as |#1|. -% \end{function} +% \subsection{Primitive conditionals} % -% \begin{function}[added = 2012-02-11]{\ior_str_map_inline:nn} +% \begin{function}[EXP]{\if_eof:w} % \begin{syntax} -% \cs{ior_str_map_inline:Nn} \Arg{stream} \Arg{inline function} +% \cs{if_eof:w} \meta{stream} +% ~~\meta{true code} +% \cs{else:} +% ~~\meta{false code} +% \cs{fi:} % \end{syntax} -% Applies the \meta{inline function} to every \meta{line} -% in the \meta{file}. The material is read from the \meta{stream} -% as a series of tokens with category code $12$ (other), with the -% exception of space characters which are given category code $10$ -% (space). The \meta{inline function} should consist of code which -% will receive the \meta{line} as |#1|. +% Tests if the \meta{stream} returns \enquote{end of file}, which is true +% for non-existent files. The \cs{else:} branch is optional. +% \begin{texnote} +% This is the \TeX{} primitive \tn{ifeof}. +% \end{texnote} % \end{function} % -% \section{Internal file functions} -% -% \begin{variable}{\g_file_stack_seq} -% Stores the stack of nested files loaded using \cs{file_input:n}. This -% is needed to restore the appropriate file name to -% \cs{g_file_current_name_tl} at the end of each file. -% \end{variable} +% \subsection{Internal file functions and variables} % -% \begin{variable}{\g_file_record_seq} -% Stores the name of every file loaded using \cs{file_input:n}. In -% contrast to \cs{g_file_stack_seq}, no items are ever removed from this -% sequence. +% \begin{variable}{\l__file_internal_name_ior} +% Used to test for the existence of files when opening. % \end{variable} % -% \begin{variable}{\l_file_internal_name_tl} +% \begin{variable}{\l__file_internal_name_tl} % Used to return the full name of a file for internal use. % \end{variable} % -% \begin{variable}{\l_file_search_path_seq} -% The sequence of file paths to search when loading a file. -% \end{variable} -% -% \begin{variable}{\l_file_internal_saved_path_seq} -% When loaded on top of \LaTeXe{}, there is a need to save the search -% path so that \tn{input@path} can be used as appropriate. -% \end{variable} -% -% \begin{variable}[added = 2011-09-06]{\l_file_internal_seq} -% When loaded on top of \LaTeXe{}, there is a need to convert -% the comma lists \tn{input@path} and \tn{@filelist} to sequences. -% \end{variable} -% -% \section{Internal input--output functions} -% -% \begin{function}[added = 2012-02-09]{\file_name_sanitize:nn} +% \begin{function}[added = 2012-02-09]{\__file_name_sanitize:nn} % \begin{syntax} -% \cs{file_name_sanitize:nn} \Arg{name} \Arg{tokens} +% \cs{__file_name_sanitize:nn} \Arg{name} \Arg{tokens} % \end{syntax} % Exhaustively-expands the \meta{name} with the exception of any -% category \meta{active} (catcode~$12$) tokens, which are not expanded. +% category \meta{active} (catcode~$13$) tokens, which are not expanded. % The list of \meta{active} tokens is taken from \cs{l_char_active_seq}. % The \meta{sanitized name} is then inserted (in braces) after the % \meta{tokens}, which should further process the file name. If any % spaces are found in the name after expansion, an error is raised. % \end{function} % -% \begin{function}[EXP]{\if_eof:w} -% \begin{syntax} -% \cs{if_eof:w} \meta{stream} -% ~~\meta{true code} -% \cs{else:} -% ~~\meta{false code} -% \cs{fi:} -% \end{syntax} -% Tests if the \meta{stream} returns \enquote{end of file}, which is true -% for non-existent files. The \cs{else:} branch is optional. -% \begin{texnote} -% This is the \TeX{} primitive \tn{ifeof}. -% \end{texnote} -% \end{function} +% \subsection{Internal input--output functions} % -% \begin{function}[added = 2012-01-23] -% {\ior_open_unsafe:Nn, \ior_open_unsafe:No, \iow_open_unsafe:Nn} +% \begin{function}[added = 2012-01-23]{\__ior_open:Nn, \__ior_open:No} % \begin{syntax} -% \cs{ior_open_unsafe:Nn} \meta{stream} \Arg{file name} +% \cs{__ior_open:Nn} \meta{stream} \Arg{file name} % \end{syntax} -% These functions have identical syntax to the generally-available -% versions without the |_unsafe| suffix. However, these functions do not -% take precautions against active characters in the \meta{file name}: they -% are therefore intended to be used by higher-level functions which -% have already fully expanded the \meta{file name} and which need to -% perform multiple open or close operations. See for example the +% This function has identical syntax to the public version. However, +% is does not take precautions against active characters in the +% \meta{file name}, and it does not attempt to add a \meta{path} to +% the \meta{file name}: it is therefore intended to be used by +% higher-level +% functions which have already fully expanded the \meta{file name} and which +% need to perform multiple open or close operations. See for example the % implementation of \cs{file_add_path:Nn}, % \end{function} % -% \begin{function}{\ior_raw_new:N, \ior_raw_new:c} -% \begin{syntax} -% \cs{ior_raw_new:N} \meta{stream} -% \end{syntax} -% Directly allocates a new stream for reading, bypassing the stack -% system. This is to be used only when a new stream is required at a -% \TeX{} level, when a new stream is requested by the stack itself. -% \end{function} -% -% \begin{function}{\iow_raw_new:N, \iow_raw_new:c} -% \begin{syntax} -% \cs{iow_raw_new:N} \meta{stream} -% \end{syntax} -% Directly allocates a new stream for writing, bypassing the stack -% system. This is to be used only when a new stream is required at a -% \TeX{} level, when a new stream is requested by the stack itself. -% \end{function} -% % \end{documentation} % % \begin{implementation} @@ -582,10 +506,14 @@ % \end{macrocode} % % \begin{macrocode} +%<@@=file> +% \end{macrocode} +% +% \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -593,12 +521,10 @@ % % \begin{variable}{\g_file_current_name_tl} % The name of the current file should be available at all times. -% \begin{macrocode} -\tl_new:N \g_file_current_name_tl -% \end{macrocode} % For the format the file name needs to be picked up at the start of the % file. In package mode the current file name is collected from \LaTeXe{}. % \begin{macrocode} +\tl_new:N \g_file_current_name_tl %<*initex> \tex_everyjob:D \exp_after:wN { @@ -612,91 +538,92 @@ % \end{macrocode} % \end{variable} % -% \begin{variable}{\g_file_stack_seq} +% \begin{variable}{\g_@@_stack_seq} % The input list of files is stored as a sequence stack. % \begin{macrocode} -\seq_new:N \g_file_stack_seq +\seq_new:N \g_@@_stack_seq % \end{macrocode} % \end{variable} % -% \begin{variable}{\g_file_record_seq} -% The total list of files used is recorded separately from the current file -% stack, as nothing is ever popped from this list. -% \begin{macrocode} -\seq_new:N \g_file_record_seq -% \end{macrocode} -% The current file name should be included in the file list! +% \begin{variable}{\g_@@_record_seq} +% The total list of files used is recorded separately from the current +% file stack, as nothing is ever popped from this list. The current +% file name should be included in the file list! In format mode, this +% is done at the very start of the \TeX{} run. In package mode we +% will eventually copy the contents of \cs{@filelist}. % \begin{macrocode} +\seq_new:N \g_@@_record_seq %<*initex> \tex_everyjob:D \exp_after:wN { \tex_the:D \tex_everyjob:D - \seq_gput_right:NV \g_file_record_seq \g_file_current_name_tl + \seq_gput_right:NV \g_@@_record_seq \g_file_current_name_tl } %</initex> % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_file_internal_name_tl} +% \begin{variable}{\l_@@_internal_name_tl} % Used to return the fully-qualified name of a file. % \begin{macrocode} -\tl_new:N \l_file_internal_name_tl +\tl_new:N \l_@@_internal_name_tl % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_file_search_path_seq} +% \begin{variable}{\l_@@_search_path_seq} % The current search path. % \begin{macrocode} -\seq_new:N \l_file_search_path_seq +\seq_new:N \l_@@_search_path_seq % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_file_internal_saved_path_seq} +% \begin{variable}{\l_@@_saved_search_path_seq} % The current search path has to be saved for package use. % \begin{macrocode} %<*package> -\seq_new:N \l_file_internal_saved_path_seq +\seq_new:N \l_@@_saved_search_path_seq %</package> % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_file_internal_seq} +% \begin{variable}{\l_@@_internal_seq} % Scratch space for comma list conversion in package mode. % \begin{macrocode} %<*package> -\seq_new:N \l_file_internal_seq +\seq_new:N \l_@@_internal_seq %</package> % \end{macrocode} % \end{variable} % -% \begin{macro}[int]{\file_name_sanitize:nn} +% \begin{macro}[aux]{\@@_name_sanitize:nn} % For converting a token list to a string where active characters are treated % as strings from the start. % \begin{macrocode} -\cs_new_protected:Npn \file_name_sanitize:nn #1#2 +\cs_new_protected:Npn \@@_name_sanitize:nn #1#2 { \group_begin: \seq_map_inline:Nn \l_char_active_seq { \cs_set_nopar:Npx ##1 { \token_to_str:N ##1 } } - \tl_set:Nx \l_file_internal_name_tl {#1} - \tl_set:Nx \l_file_internal_name_tl - { \tl_to_str:N \l_file_internal_name_tl } - \tl_if_in:NnTF \l_file_internal_name_tl { ~ } + \tl_set:Nx \l_@@_internal_name_tl {#1} + \tl_set:Nx \l_@@_internal_name_tl + { \tl_to_str:N \l_@@_internal_name_tl } + \tl_if_in:NnT \l_@@_internal_name_tl { ~ } { - \msg_kernel_error:nnx { file } { space-in-file-name } - { \l_file_internal_name_tl } + \__msg_kernel_error:nnx { kernel } { space-in-file-name } + { \l_@@_internal_name_tl } + \tl_remove_all:Nn \l_@@_internal_name_tl { ~ } } \use:x { \group_end: - \exp_not:n {#2} { \l_file_internal_name_tl } + \exp_not:n {#2} { \l_@@_internal_name_tl } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\file_add_path:nN} -% \begin{macro}[aux]{\file_add_path_aux:nN, \file_add_path_search:nN} +% \begin{macro}[aux]{\@@_add_path:nN, \@@_add_path_search:nN} % The way to test if a file exists is to try to open it: if it does not % exist then \TeX{} will report end-of-file. For files which are in the % current directory, this is straight-forward. For other locations, a @@ -705,33 +632,31 @@ % |#2| is returned empty. % \begin{macrocode} \cs_new_protected:Npn \file_add_path:nN #1 - { \file_name_sanitize:nn {#1} { \file_add_path_aux:nN } } -\cs_new_protected:Npn \file_add_path_aux:nN #1#2 + { \@@_name_sanitize:nn {#1} { \@@_add_path:nN } } +\cs_new_protected:Npn \@@_add_path:nN #1#2 { - \ior_open_unsafe:Nn \g_file_internal_ior {#1} - \ior_if_eof:NTF \g_file_internal_ior - { \file_add_path_search:nN {#1} #2 } - { - \ior_close:N \g_file_internal_ior - \tl_set:Nn #2 {#1} - } + \__ior_open:Nn \g__file_internal_ior {#1} + \ior_if_eof:NTF \g__file_internal_ior + { \@@_add_path_search:nN {#1} #2 } + { \tl_set:Nn #2 {#1} } + \ior_close:N \g__file_internal_ior } -\cs_new_protected:Npn \file_add_path_search:nN #1#2 +\cs_new_protected:Npn \@@_add_path_search:nN #1#2 { - \tl_set:Nn #2 { \q_no_value } + \tl_set:Nn #2 { \q_no_value } %<*package> \cs_if_exist:NT \input@path { - \seq_set_eq:NN \l_file_internal_saved_path_seq \l_file_search_path_seq - \seq_set_from_clist:NN \l_file_internal_seq \input@path - \seq_concat:NNN \l_file_search_path_seq - \l_file_search_path_seq \l_file_internal_seq + \seq_set_eq:NN \l_@@_saved_search_path_seq \l_@@_search_path_seq + \seq_set_split:NnV \l_@@_internal_seq { , } \input@path + \seq_concat:NNN \l_@@_search_path_seq + \l_@@_search_path_seq \l_@@_internal_seq } %</package> - \seq_map_inline:Nn \l_file_search_path_seq + \seq_map_inline:Nn \l_@@_search_path_seq { - \ior_open_unsafe:Nn \g_file_internal_ior { ##1 #1 } - \ior_if_eof:NF \g_file_internal_ior + \__ior_open:Nn \g__file_internal_ior { ##1 #1 } + \ior_if_eof:NF \g__file_internal_ior { \tl_set:Nx #2 { ##1 #1 } \seq_map_break: @@ -739,9 +664,8 @@ } %<*package> \cs_if_exist:NT \input@path - { \seq_set_eq:NN \l_file_search_path_seq \l_file_internal_saved_path_seq } + { \seq_set_eq:NN \l_@@_search_path_seq \l_@@_saved_search_path_seq } %</package> - \ior_close:N \g_file_internal_ior } % \end{macrocode} % \end{macro} @@ -751,12 +675,12 @@ % The test for the existence of a file is a wrapper around the function to % add a path to a file. If the file was found, the path will contain % something, whereas if the file was not located then the return value -% will be empty. +% will be \cs{q_no_value}. % \begin{macrocode} \prg_new_protected_conditional:Npnn \file_if_exist:n #1 { T , F , TF } { - \file_add_path:nN {#1} \l_file_internal_name_tl - \quark_if_no_value:NTF \l_file_internal_name_tl + \file_add_path:nN {#1} \l_@@_internal_name_tl + \quark_if_no_value:NTF \l_@@_internal_name_tl { \prg_return_false: } { \prg_return_true: } } @@ -764,78 +688,124 @@ % \end{macro} % % \begin{macro}{\file_input:n} -% \begin{macro}[aux]{\file_input_aux:n \file_input_aux:V, \file_input_error:n} +% \begin{macro}[aux]{\@@_input:n \@@_input:V} +% \begin{macro}[aux, EXP]{\@@_input_aux:w} +% \begin{macro}[aux]{\@@_input_aux:n, \@@_input_aux:o} % Loading a file is done in a safe way, checking first that the file -% exists and loading only if it does. +% exists and loading only if it does. Push the file name on the +% \cs{g_@@_stack_seq}, and add it to the file list, either +% \cs{g_@@_record_seq}, or \cs{@filelist} in package mode. % \begin{macrocode} \cs_new_protected:Npn \file_input:n #1 { - \file_add_path:nN {#1} \l_file_internal_name_tl - \quark_if_no_value:NTF \l_file_internal_name_tl - { \file_name_sanitize:nn {#1} { \file_input_error:n } } - { \file_input_aux:V \l_file_internal_name_tl } + \file_add_path:nN {#1} \l_@@_internal_name_tl + \quark_if_no_value:NTF \l_@@_internal_name_tl + { + \@@_name_sanitize:nn {#1} + { \__msg_kernel_error:nnx { kernel } { file-not-found } } + } + { \@@_input:V \l_@@_internal_name_tl } } -\cs_new_protected:Npn \file_input_aux:n #1 +\cs_new_protected:Npn \@@_input:n #1 + { + \quark_if_nil:oTF { \@@_input_aux:w #1 . \q_nil . \q_stop } + { \@@_input_aux:o { \tl_to_str:n { #1 .tex } } } + { \@@_input_aux:n {#1} } + } +\cs_generate_variant:Nn \@@_input:n { V } +\cs_new:Npn \@@_input_aux:w #1 . #2 . #3 \q_stop { #2 } +\cs_new_protected:Npn \@@_input_aux:n #1 { %<*initex> - \seq_gput_right:Nn \g_file_record_seq {#1} + \seq_gput_right:Nn \g_@@_record_seq {#1} %</initex> %<*package> - \@addtofilelist {#1} + \clist_if_exist:NTF \@filelist + { \@addtofilelist {#1} } + { \seq_gput_right:Nn \g_@@_record_seq {#1} } %</package> - \seq_gpush:Nn \g_file_stack_seq \g_file_current_name_tl + \seq_gpush:Nn \g_@@_stack_seq \g_file_current_name_tl \tl_gset:Nn \g_file_current_name_tl {#1} \tex_input:D #1 \c_space_tl - \seq_gpop:NN \g_file_stack_seq \g_file_current_name_tl + \seq_gpop:NN \g_@@_stack_seq \g_file_current_name_tl } -\cs_generate_variant:Nn \file_input_aux:n { V } -\cs_new_protected:Npn \file_input_error:n #1 - { \msg_kernel_error:nnx { file } { file-not-found } {#1} } +\cs_generate_variant:Nn \@@_input_aux:n { o } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\file_path_include:n} % \begin{macro}{\file_path_remove:n} +% \begin{macro}[aux]{\@@_path_include:n} % Wrapper functions to manage the search path. % \begin{macrocode} \cs_new_protected:Npn \file_path_include:n #1 + { \@@_name_sanitize:nn {#1} { \@@_path_include:n } } +\cs_new_protected:Npn \@@_path_include:n #1 { - \seq_if_in:NnF \l_file_search_path_seq {#1} - { \seq_put_right:Nn \l_file_search_path_seq {#1} } + \seq_if_in:NnF \l_@@_search_path_seq {#1} + { \seq_put_right:Nn \l_@@_search_path_seq {#1} } } \cs_new_protected:Npn \file_path_remove:n #1 - { \seq_remove_all:Nn \l_file_search_path_seq {#1} } + { + \@@_name_sanitize:nn {#1} + { \seq_remove_all:Nn \l_@@_search_path_seq } + } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\file_list:} -% A function to list all files used to the log. +% A function to list all files used to the log, without duplicates. +% In package mode, if \cs{@filelist} is still defined, we need to take +% it into account (we capture it \cs{AtBeginDocument} into +% \cs{g_@@_record_seq}), turning each file name into a string. % \begin{macrocode} \cs_new_protected_nopar:Npn \file_list: { - \seq_remove_duplicates:N \g_file_record_seq + \seq_set_eq:NN \l_@@_internal_seq \g_@@_record_seq +%<*package> + \clist_if_exist:NT \@filelist + { + \clist_map_inline:Nn \@filelist + { + \seq_put_right:No \l_@@_internal_seq + { \tl_to_str:n {##1} } + } + } +%</package> + \seq_remove_duplicates:N \l_@@_internal_seq \iow_log:n { *~File~List~* } - \seq_map_inline:Nn \g_file_record_seq { \iow_log:n {##1} } + \seq_map_inline:Nn \l_@@_internal_seq { \iow_log:n {##1} } \iow_log:n { ************* } } % \end{macrocode} % \end{macro} % -% When used as a package, there is a need to hold onto the standard -% file list as well as the new one here. +% When used as a package, there is a need to hold onto the standard file +% list as well as the new one here. File names recorded in +% \cs{@filelist} must be turned to strings before being added to +% \cs{g_@@_record_seq}. % \begin{macrocode} %<*package> \AtBeginDocument { - \seq_set_from_clist:NN \l_file_internal_seq \@filelist - \seq_gconcat:NNN \g_file_record_seq \g_file_record_seq \l_file_internal_seq + \clist_map_inline:Nn \@filelist + { \seq_gput_right:No \g_@@_record_seq { \tl_to_str:n {#1} } } } %</package> % \end{macrocode} % -% \subsection{Input--output variables constants} +% \subsection{Input operations} +% +% \begin{macrocode} +%<@@=ior> +% \end{macrocode} +% +% \subsubsection{Variables and constants} % % \begin{variable}{\c_term_ior} % Reading from the terminal (with a prompt) is done using a positive @@ -846,20 +816,10 @@ % \end{macrocode} % \end{variable} % -% \begin{variable}{\c_log_iow, \c_term_iow} -% Here we allocate two output streams for writing to the transcript -% file only (\cs{c_log_iow}) and to both the terminal and -% transcript file (\cs{c_term_iow}). -% \begin{macrocode} -\cs_new_eq:NN \c_log_iow \c_minus_one -\cs_new_eq:NN \c_term_iow \c_sixteen -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_iow_streams_tl, \c_ior_streams_tl} +% \begin{variable}{\c_@@_streams_tl} % The list of streams available, by number. % \begin{macrocode} -\tl_const:Nn \c_iow_streams_tl +\tl_const:Nn \c_@@_streams_tl { \c_zero \c_one @@ -878,151 +838,118 @@ \c_fourteen \c_fifteen } -\cs_new_eq:NN \c_ior_streams_tl \c_iow_streams_tl % \end{macrocode} % \end{variable} % -% \begin{variable}{\g_iow_streams_prop, \g_ior_streams_prop} +% \begin{variable}{\g_@@_streams_prop} % The allocations for streams are stored in property lists, which % are set up to have a \enquote{full} set of allocations from the start. % In package mode, a few slots are always taken, so these are % blocked off from use. % \begin{macrocode} -\prop_new:N \g_iow_streams_prop -\prop_new:N \g_ior_streams_prop +\prop_new:N \g_@@_streams_prop %<*package> -\prop_put:Nnn \g_iow_streams_prop { 0 } { LaTeX2e~reserved } -\prop_put:Nnn \g_iow_streams_prop { 1 } { LaTeX2e~reserved } -\prop_put:Nnn \g_iow_streams_prop { 2 } { LaTeX2e~reserved } -\prop_put:Nnn \g_ior_streams_prop { 0 } { LaTeX2e~reserved } +\prop_put:Nnn \g_@@_streams_prop { 0 } { LaTeX2e~reserved } %</package> % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_iow_stream_int, \l_ior_stream_int} +% \begin{variable}{\l_@@_stream_int} % Used to track the number allocated to the stream being created: % this is taken from the property list but does alter. % \begin{macrocode} -\int_new:N \l_iow_stream_int -\cs_new_eq:NN \l_ior_stream_int \l_iow_stream_int +\int_new:N \l_@@_stream_int % \end{macrocode} % \end{variable} % -% \subsection{Stream management} +% \subsubsection{Stream management} % -% \begin{macro}[int]{\ior_raw_new:N, \ior_raw_new:c} -% \begin{macro}[int]{\iow_raw_new:N, \iow_raw_new:c} -% The lowest level for stream management is actually creating raw \TeX{} -% streams. As these are very limited (even with \eTeX{}), this should not -% be addressed directly. +% \begin{macro}[int]{\@@_new:N, \@@_new:c} +% The lowest level for stream management is actually creating raw \TeX{} +% streams. As these are very limited (even with \eTeX{}), this should not +% be addressed directly. % \begin{macrocode} %<*initex> -\alloc_setup_type:nnn { ior } \c_zero \c_sixteen -\cs_new_protected:Npn \ior_raw_new:N #1 - { \alloc_reg:nNN { ior } \tex_chardef:D #1 } -\alloc_setup_type:nnn { iow } \c_zero \c_sixteen -\cs_new_protected:Npn \iow_raw_new:N #1 - { \alloc_reg:nNN { iow } \tex_chardef:D #1 } +\__alloc_setup_type:nnn { ior } \c_zero \c_sixteen +\cs_new_protected:Npn \@@_new:N #1 + { \__alloc_reg:nNN { ior } \tex_chardef:D #1 } %</initex> %<*package> -\cs_set_eq:NN \iow_raw_new:N \newwrite -\cs_set_eq:NN \ior_raw_new:N \newread +\cs_set_eq:NN \@@_new:N \newread %</package> -\cs_generate_variant:Nn \ior_raw_new:N { c } -\cs_generate_variant:Nn \iow_raw_new:N { c } +\cs_generate_variant:Nn \@@_new:N { c } % \end{macrocode} % \end{macro} -% \end{macro} % -% \begin{macro}{\ior_new:N, \ior_new:c, \iow_new:N, \iow_new:c} +% \begin{macro}{\ior_new:N, \ior_new:c} % Reserving a new stream is done by defining the name as equal to using the % terminal. % \begin{macrocode} \cs_new_protected:Npn \ior_new:N #1 { \cs_new_eq:NN #1 \c_term_ior } \cs_generate_variant:Nn \ior_new:N { c } -\cs_new_protected:Npn \iow_new:N #1 { \cs_new_eq:NN #1 \c_term_iow } -\cs_generate_variant:Nn \iow_new:N { c } % \end{macrocode} % \end{macro} % -% \begin{variable}{\g_file_internal_ior} -% Delayed from above so that the mechanisms are in place. +% \begin{variable}{\g__file_internal_ior} +% Delayed from the \texttt{file} section so that the mechanisms are in place. % \begin{macrocode} -\ior_new:N \g_file_internal_ior +\ior_new:N \g__file_internal_ior % \end{macrocode} % \end{variable} % -% \begin{macro}{\ior_open:Nn, \ior_open:cn, \iow_open:Nn, \iow_open:cn} -% \begin{macro}[int]{\ior_open_aux:Nn} +% \begin{macro}{\ior_open:Nn, \ior_open:cn} % \begin{macro}[TF]{\ior_open:Nn} -% \begin{macro}[aux]{\ior_open_aux:NnTF} -% \begin{macro}[int] -% {\ior_open_unsafe:Nn, \ior_open_unsafe:No, \iow_open_unsafe:Nn} -% In both cases, opening a stream starts with a call to the closing -% function: this is safest. There is then a loop through the -% allocation number list to find the first free stream number. -% When one is found the allocation can take place, the information -% can be stored and finally the file can actually be opened. Before -% any actual file operations there is a precaution against special -% characters in file names. For reading files, there is an intermediate -% auxiliary to allow path addition, keeping the internal function fast -% and avoiding an infinite loop. +% \begin{macro}[aux]{\@@_open_aux:Nn} +% \begin{macro}[aux]{\@@_open_aux:NnTF} +% \begin{macro}[aux]{\@@_open:Nn, \@@_open:No} +% Opening a stream starts with a call to the closing function: this is +% safest. There is then a loop through the allocation number list to find +% the first free stream number. When one is found the allocation can take +% place, the information can be stored and finally the file can actually be +% opened. Before any actual file operations there is a precaution against +% special characters in file names. There is an intermediate auxiliary to +% allow path addition, keeping the internal function fast and avoiding an +% infinite loop. % \begin{macrocode} \cs_new_protected:Npn \ior_open:Nn #1#2 - { \file_name_sanitize:nn {#2} { \ior_open_aux:Nn #1 } } + { \__file_name_sanitize:nn {#2} { \@@_open_aux:Nn #1 } } \cs_generate_variant:Nn \ior_open:Nn { c } -\cs_new_protected:Npn \iow_open:Nn #1#2 - { \file_name_sanitize:nn {#2} { \iow_open_unsafe:Nn #1 } } -\cs_generate_variant:Nn \iow_open:Nn { c } -\cs_new_protected:Npn \ior_open_aux:Nn #1#2 +\cs_new_protected:Npn \@@_open_aux:Nn #1#2 { - \file_add_path:nN {#2} \l_file_internal_name_tl - \quark_if_no_value:NTF \l_file_internal_name_tl - { \file_input_error:n {#2} } - { \ior_open_unsafe:No #1 \l_file_internal_name_tl } + \file_add_path:nN {#2} \l__file_internal_name_tl + \quark_if_no_value:NTF \l__file_internal_name_tl + { \__msg_kernel_error:nnx { kernel } { file-not-found } {#2} } + { \@@_open:No #1 \l__file_internal_name_tl } } \prg_new_protected_conditional:Npnn \ior_open:Nn #1#2 { T , F , TF } - { \file_name_sanitize:nn {#2} { \ior_open_aux:NnTF #1 } } -\cs_new_protected:Npn \ior_open_aux:NnTF #1#2 + { \__file_name_sanitize:nn {#2} { \@@_open_aux:NnTF #1 } } +\cs_new_protected:Npn \@@_open_aux:NnTF #1#2 { - \file_add_path:nN {#2} \l_file_internal_name_tl - \quark_if_no_value:NTF \l_file_internal_name_tl + \file_add_path:nN {#2} \l__file_internal_name_tl + \quark_if_no_value:NTF \l__file_internal_name_tl { \prg_return_false: } { - \ior_open_unsafe:No #1 \l_file_internal_name_tl + \@@_open:No #1 \l__file_internal_name_tl \prg_return_true: } } \cs_generate_variant:Nn \ior_open:NnT { c } \cs_generate_variant:Nn \ior_open:NnF { c } \cs_generate_variant:Nn \ior_open:NnTF { c } -\cs_new_protected:Npn \ior_open_unsafe:Nn #1#2 +\cs_new_protected:Npn \@@_open:Nn #1#2 { \ior_close:N #1 - \int_set:Nn \l_ior_stream_int \c_sixteen - \tl_map_function:NN \c_ior_streams_tl \ior_alloc_read:n - \int_compare:nNnTF \l_ior_stream_int = \c_sixteen - { \msg_kernel_fatal:nn { ior } { streams-exhausted } } + \int_set_eq:NN \l_@@_stream_int \c_sixteen + \tl_map_function:NN \c_@@_streams_tl \@@_alloc:n + \int_compare:nNnTF \l_@@_stream_int = \c_sixteen + { \__msg_kernel_fatal:nn { kernel } { input-streams-exhausted } } { - \ior_stream_alloc:N #1 - \prop_gput:NVn \g_ior_streams_prop \l_ior_stream_int {#2} + \@@_alloc:N #1 + \prop_gput:NVn \g_@@_streams_prop \l_@@_stream_int {#2} \tex_openin:D #1#2 \scan_stop: } } -\cs_generate_variant:Nn \ior_open_unsafe:Nn { No } -\cs_new_protected:Npn \iow_open_unsafe:Nn #1#2 - { - \iow_close:N #1 - \int_set:Nn \l_iow_stream_int \c_sixteen - \tl_map_function:NN \c_iow_streams_tl \iow_alloc_write:n - \int_compare:nNnTF \l_iow_stream_int = \c_sixteen - { \msg_kernel_fatal:nn { iow } { streams-exhausted } } - { - \iow_stream_alloc:N #1 - \prop_gput:NVn \g_iow_streams_prop \l_iow_stream_int {#2} - \tex_immediate:D \tex_openout:D #1#2 \scan_stop: - } - } +\cs_generate_variant:Nn \@@_open:Nn { No } % \end{macrocode} % \end{macro} % \end{macro} @@ -1030,114 +957,321 @@ % \end{macro} % \end{macro} % -% \begin{macro}[aux]{\ior_alloc_read:n} -% \begin{macro}[aux]{\iow_alloc_write:n} -% These functions are used to see if a particular stream is available. -% The property list contains file names for streams in use, so -% any unused ones are for the taking. +% \begin{macro}[aux]{\@@_alloc:n} +% See if a particular stream is available: the property list contains file +% names for streams in use, so any unused ones are for the taking. % \begin{macrocode} -\cs_new_protected:Npn \iow_alloc_write:n #1 +\cs_new_protected:Npn \@@_alloc:n #1 { - \prop_if_in:NnF \g_iow_streams_prop {#1} + \prop_if_in:NnF \g_@@_streams_prop {#1} { - \int_set:Nn \l_iow_stream_int {#1} - \tl_map_break: - } - } -\cs_new_protected:Npn \ior_alloc_read:n #1 - { - \prop_if_in:NnF \g_iow_streams_prop {#1} - { - \int_set:Nn \l_ior_stream_int {#1} + \int_set:Nn \l_@@_stream_int {#1} \tl_map_break: } } % \end{macrocode} % \end{macro} -% \end{macro} % -% \begin{macro}[aux]{\iow_stream_alloc:N, \ior_stream_alloc:N} -% \begin{macro}[aux]{\iow_stream_alloc_aux:, \ior_stream_alloc_aux:} -% \begin{variable}{\g_iow_internal_iow, \g_ior_internal_ior} -% Allocating a raw stream is much easier in \IniTeX{} mode than for -% the package. For the format, all streams will be allocated by -% \pkg{l3file} and so there is a simple check to see if a raw -% stream is actually available. On the other hand, for the -% package there will be non-managed streams. So if the managed -% one is not open, a check is made to see if some other managed -% stream is available before deciding to open a new one. If a new -% one is needed, we get the number allocated by \LaTeXe{} to get -% \enquote{back on track} with allocation. +% \begin{macro}[aux]{\@@_alloc:N} +% \begin{macro}[aux]{\@@_alloc:} +% \begin{variable}{\g_@@_internal_ior} +% Allocating a raw stream is much easier in \IniTeX{} mode than for the +% package. For the format, all streams will be allocated by \pkg{l3file} and +% so there is a simple check to see if a raw stream is actually available. On +% the other hand, for the package there will be non-managed streams. So if +% the managed one is not open, a check is made to see if some other managed +% stream is available before deciding to open a new one. If a new one is +% needed, we get the number allocated by \LaTeXe{} to get \enquote{back on +% track} with allocation. % \begin{macrocode} -\iow_new:N \g_iow_internal_iow -\ior_new:N \g_ior_internal_ior -\cs_new_protected:Npn \iow_stream_alloc:N #1 +\ior_new:N \g_@@_internal_ior +\cs_new_protected:Npn \@@_alloc:N #1 { - \cs_if_exist:cF { g_iow_ \int_use:N \l_iow_stream_int _iow } + \cs_if_exist:cF { g_ior_ \int_use:N \l_@@_stream_int _ior } { %<*package> - \iow_stream_alloc_aux: - \int_compare:nNnT \l_iow_stream_int = \c_sixteen + \@@_alloc: + \int_compare:nNnT \l_@@_stream_int = \c_sixteen { - \iow_raw_new:N \g_iow_internal_iow - \int_set:Nn \l_iow_stream_int { \g_iow_internal_iow } + \@@_new:N \g_@@_internal_ior + \int_set:Nn \l_@@_stream_int { \g_@@_internal_ior } \cs_gset_eq:cN - { g_iow_ \int_use:N \l_iow_stream_int _iow } \g_iow_internal_iow + { g_ior_ \int_use:N \l_@@_stream_int _ior } \g_@@_internal_ior } %</package> %<*initex> - \iow_raw_new:c { g_iow_ \int_use:N \l_iow_stream_int _iow } + \@@_new:c { g_ior_ \int_use:N \l_@@_stream_int _ior } %</initex> } - \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_iow_stream_int _iow } + \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_@@_stream_int _ior } } %<*package> -\cs_new_protected_nopar:Npn \iow_stream_alloc_aux: +\cs_new_protected_nopar:Npn \@@_alloc: { - \int_incr:N \l_iow_stream_int - \int_compare:nNnT \l_iow_stream_int < \c_sixteen + \int_incr:N \l_@@_stream_int + \int_compare:nNnT \l_@@_stream_int < \c_sixteen { - \cs_if_exist:cTF { g_iow_ \int_use:N \l_iow_stream_int _iow } + \cs_if_exist:cTF { g_ior_ \int_use:N \l_@@_stream_int _ior } { - \prop_if_in:NVT \g_iow_streams_prop \l_iow_stream_int - { \iow_stream_alloc_aux: } + \prop_if_in:NVT \g_@@_streams_prop \l_@@_stream_int + { \@@_alloc: } } - { \iow_stream_alloc_aux: } + { \@@_alloc: } + } + } +%</package> +% \end{macrocode} +% \end{variable} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ior_close:N, \ior_close:c} +% Closing a stream is not quite the reverse of opening one. First, +% the close operation is easier than the open one, and second as the +% stream is actually a number we can use it directly to show that the +% slot has been freed up. +% \begin{macrocode} +\cs_new_protected:Npn \ior_close:N #1 + { + \__chk_if_exist_cs:N #1 + \int_compare:nNnF #1 < \c_zero + { + \int_compare:nNnF #1 > \c_fifteen + { + \tex_closein:D #1 + \prop_gremove:NV \g_@@_streams_prop #1 + \cs_gset_eq:NN #1 \c_term_ior + } + } + } +\cs_generate_variant:Nn \ior_close:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ior_list_streams:} +% \begin{macro}[aux]{\@@_list_streams:Nn} +% Show the property lists, but with some \enquote{pretty printing}. +% See the \pkg{l3msg} module. If there are no open read streams, +% issue the message \texttt{show-no-stream}, and show an empty +% token list. If there are open read streams, format them with +% \cs{__msg_show_item_unbraced:nn}, and with the message +% \texttt{show-open-streams}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \ior_list_streams: + { \@@_list_streams:Nn \g_@@_streams_prop { input } } +\cs_new_protected:Npn \@@_list_streams:Nn #1#2 + { + \__msg_term:nnn { LaTeX / kernel } + { \prop_if_empty:NTF #1 { show-no-stream } { show-open-streams } } + {#2} + \__msg_show_variable:x + { \prop_map_function:NN #1 \__msg_show_item_unbraced:nn } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Reading input} +% +% \begin{macro}[int]{\if_eof:w} +% The primitive conditional +% \begin{macrocode} +\cs_new_eq:NN \if_eof:w \tex_ifeof:D +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\ior_if_eof:N} +% To test if some particular input stream is exhausted the following +% conditional is provided. +% \begin{macrocode} +\prg_new_conditional:Nnn \ior_if_eof:N { p , T , F , TF } + { + \cs_if_exist:NTF #1 + { + \if_int_compare:w #1 = \c_sixteen + \prg_return_true: + \else: + \if_eof:w #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + \fi: } + { \prg_return_true: } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ior_get:NN} +% And here we read from files. +% \begin{macrocode} +\cs_new_protected:Npn \ior_get:NN #1#2 + { \tex_read:D #1 to #2 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ior_get_str:NN} +% Reading as strings is also a primitive wrapper. +% \begin{macrocode} +\cs_new_protected:Npn \ior_get_str:NN #1#2 + { \etex_readline:D #1 to #2 } +% \end{macrocode} +% \end{macro} +% +% \subsection{Output operations} +% +% \begin{macrocode} +%<@@=iow> +% \end{macrocode} +% +% There is a lot of similarity here to the input operations, at least for +% many of the basics. Thus quite a bit is copied from the earlier material. +% +% \subsubsection{Variables and constants} +% +% \begin{variable}{\c_log_iow, \c_term_iow} +% Here we allocate two output streams for writing to the transcript +% file only (\cs{c_log_iow}) and to both the terminal and +% transcript file (\cs{c_term_iow}). +% \begin{macrocode} +\cs_new_eq:NN \c_log_iow \c_minus_one +\cs_new_eq:NN \c_term_iow \c_sixteen +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_@@_streams_tl} +% The list of streams available, by number: copied from the input +% operations. +% \begin{macrocode} +\cs_new_eq:NN \c_@@_streams_tl \c__ior_streams_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_streams_prop} +% As for reads, but with more reserved as \LaTeXe{} takes up a few here. +% \begin{macrocode} +\prop_new:N \g_@@_streams_prop +%<*package> +\prop_put:Nnn \g_@@_streams_prop { 0 } { LaTeX2e~reserved } +\prop_put:Nnn \g_@@_streams_prop { 1 } { LaTeX2e~reserved } +\prop_put:Nnn \g_@@_streams_prop { 2 } { LaTeX2e~reserved } +%</package> +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_stream_int} +% Used to track the number allocated to the stream being created: +% this is taken from the property list but does alter. The two allocation +% routines only need one register, so we save one here. +% \begin{macrocode} +\cs_new_eq:NN \l_@@_stream_int \l__ior_stream_int +% \end{macrocode} +% \end{variable} +% +% \subsection{Stream management} +% +% \begin{macro}[aux]{\@@_new:N, \@@_new:c} +% The same idea as for input, but with a separate set of functions. +% \begin{macrocode} +%<*initex> +\__alloc_setup_type:nnn { iow } \c_zero \c_sixteen +\cs_new_protected:Npn \@@_new:N #1 + { \__alloc_reg:nNN { iow } \tex_chardef:D #1 } +%</initex> +%<*package> +\cs_set_eq:NN \@@_new:N \newwrite %</package> -\cs_new_protected:Npn \ior_stream_alloc:N #1 +\cs_generate_variant:Nn \@@_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\iow_new:N, \iow_new:c} +% Reserving a new stream is done by defining the name as equal to writing +% to the terminal: odd but at least consistent. +% \begin{macrocode} +\cs_new_protected:Npn \iow_new:N #1 { \cs_new_eq:NN #1 \c_term_iow } +\cs_generate_variant:Nn \iow_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\iow_open:Nn, \iow_open:cn} +% \begin{macro}[aux]{\@@_open:Nn} +% The same idea as for reading, but without the path. +% \begin{macrocode} +\cs_new_protected:Npn \iow_open:Nn #1#2 + { \__file_name_sanitize:nn {#2} { \@@_open:Nn #1 } } +\cs_generate_variant:Nn \iow_open:Nn { c } +\cs_new_protected:Npn \@@_open:Nn #1#2 { - \cs_if_exist:cF { g_ior_ \int_use:N \l_ior_stream_int _ior } + \iow_close:N #1 + \int_set_eq:NN \l_@@_stream_int \c_sixteen + \tl_map_function:NN \c_@@_streams_tl \@@_alloc:n + \int_compare:nNnTF \l_@@_stream_int = \c_sixteen + { \__msg_kernel_fatal:nn { kernel } { output-streams-exhausted } } + { + \@@_alloc:N #1 + \prop_gput:NVn \g_@@_streams_prop \l_@@_stream_int {#2} + \tex_immediate:D \tex_openout:D #1#2 \scan_stop: + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\@@_alloc:n} +% Identical to the input routine, but with the appropriate names used +% (when \pkg{l3docstrip} has done it's job!). +% \begin{macrocode} +\cs_new_protected:Npn \@@_alloc:n #1 + { + \prop_if_in:NnF \g_@@_streams_prop {#1} + { + \int_set:Nn \l_@@_stream_int {#1} + \tl_map_break: + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\@@_alloc:N} +% \begin{macro}[aux]{\@@_alloc:} +% \begin{variable}{\g_@@_internal_iow} +% Exactly the same as for reading! +% \begin{macrocode} +\iow_new:N \g_@@_internal_iow +\cs_new_protected:Npn \@@_alloc:N #1 + { + \cs_if_exist:cF { g_iow_ \int_use:N \l_@@_stream_int _iow } { %<*package> - \ior_stream_alloc_aux: - \int_compare:nNnT \l_ior_stream_int = \c_sixteen + \@@_alloc: + \int_compare:nNnT \l_@@_stream_int = \c_sixteen { - \ior_raw_new:N \g_ior_internal_ior - \int_set:Nn \l_ior_stream_int { \g_ior_internal_ior } + \@@_new:N \g_@@_internal_iow + \int_set:Nn \l_@@_stream_int { \g_@@_internal_iow } \cs_gset_eq:cN - { g_ior_ \int_use:N \l_iow_stream_int _ior } \g_ior_internal_ior + { g_iow_ \int_use:N \l_@@_stream_int _iow } \g_@@_internal_iow } %</package> %<*initex> - \ior_raw_new:c { g_ior_ \int_use:N \l_ior_stream_int _ior } + \@@_new:c { g_iow_ \int_use:N \l_@@_stream_int _iow } %</initex> } - \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_ior_stream_int _ior } + \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_@@_stream_int _iow } } %<*package> -\cs_new_protected_nopar:Npn \ior_stream_alloc_aux: +\cs_new_protected_nopar:Npn \@@_alloc: { - \int_incr:N \l_ior_stream_int - \int_compare:nNnT \l_ior_stream_int < \c_sixteen + \int_incr:N \l_@@_stream_int + \int_compare:nNnT \l_@@_stream_int < \c_sixteen { - \cs_if_exist:cTF { g_ior_ \int_use:N \l_ior_stream_int _ior } + \cs_if_exist:cTF { g_iow_ \int_use:N \l_@@_stream_int _iow } { - \prop_if_in:NVT \g_ior_streams_prop \l_ior_stream_int - { \ior_stream_alloc_aux: } + \prop_if_in:NVT \g_@@_streams_prop \l_@@_stream_int + { \@@_alloc: } } - { \ior_stream_alloc_aux: } + { \@@_alloc: } } } %</package> @@ -1146,84 +1280,41 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\ior_close:N, \ior_close:c, \iow_close:N, \iow_close:c} +% \begin{macro}{\iow_close:N, \iow_close:c} % Closing a stream is not quite the reverse of opening one. First, % the close operation is easier than the open one, and second as the % stream is actually a number we can use it directly to show that the % slot has been freed up. % \begin{macrocode} -\cs_new_protected:Npn \ior_close:N #1 - { - \cs_if_exist:NT #1 - { - \int_compare:nNnF #1 = \c_minus_one - { - \int_compare:nNnF #1 = \c_sixteen - { \tex_closein:D #1 } - \prop_gdel:NV \g_ior_streams_prop #1 - \cs_gset_eq:NN #1 \c_term_ior - } - } - } \cs_new_protected:Npn \iow_close:N #1 { - \cs_if_exist:NT #1 + \__chk_if_exist_cs:N #1 + \int_compare:nNnF #1 < \c_zero { - \int_compare:nNnF #1 = \c_minus_one + \int_compare:nNnF #1 > \c_fifteen { - \int_compare:nNnF #1 = \c_sixteen - { \tex_closein:D #1 } - \prop_gdel:NV \g_iow_streams_prop #1 + \tex_closeout:D #1 + \prop_gremove:NV \g_@@_streams_prop #1 \cs_gset_eq:NN #1 \c_term_iow } } } -\cs_generate_variant:Nn \ior_close:N { c } \cs_generate_variant:Nn \iow_close:N { c } % \end{macrocode} % \end{macro} % -% \begin{macro}{\ior_list_streams:} -% Show the property lists, but with some \enquote{pretty printing}. -% See the \pkg{l3msg} module. If there are no open read streams, -% issue the message \texttt{show-no-stream}, and show an empty -% token list. If there are open read streams, format them with -% \cs{msg_aux_show_unbraced:nn}, and with the message -% \texttt{show-open-streams}. +% \begin{macro}{\iow_list_streams:} +% \begin{macro}{\@@_list_streams:Nn} +% Done as for input, but with a copy of the auxiliary so the name is correct. % \begin{macrocode} -\cs_new_protected_nopar:Npn \ior_list_streams: - { \ior_list_streams_aux:Nn \g_ior_streams_prop { ior } } \cs_new_protected_nopar:Npn \iow_list_streams: - { \ior_list_streams_aux:Nn \g_iow_streams_prop { iow } } -\cs_new_protected:Npn \ior_list_streams_aux:Nn #1#2 - { - \msg_aux_use:nn { LaTeX / #2 } - { \prop_if_empty:NTF #1 { show-no-stream } { show-open-streams } } - \msg_aux_show:x - { \prop_map_function:NN #1 \msg_aux_show_unbraced:nn } - } + { \@@_list_streams:Nn \g_@@_streams_prop { output } } +\cs_new_eq:NN \@@_list_streams:Nn \__ior_list_streams:Nn % \end{macrocode} % \end{macro} +% \end{macro} % -% Text for the error messages. -% \begin{macrocode} -\msg_kernel_new:nnnn { iow } { streams-exhausted } - { Output~streams~exhausted } - { - TeX~can~only~open~up~to~16~output~streams~at~one~time.\\ - All~16 are currently~in~use,~and~something~wanted~to~open - another~one. - } -\msg_kernel_new:nnnn { ior } { streams-exhausted } - { Input~streams~exhausted } - { - TeX~can~only~open~up~to~16~input~streams~at~one~time.\\ - All~16 are currently~in~use,~and~something~wanted~to~open - another~one. - } -% \end{macrocode} -% -% \subsection{Deferred writing} +% \subsubsection{Deferred writing} % % \begin{macro}{\iow_shipout_x:Nn, \iow_shipout_x:Nx} % First the easy part, this is the primitive. @@ -1234,7 +1325,7 @@ % \end{macro} % % \begin{macro}{\iow_shipout:Nn, \iow_shipout:Nx} -% With \eTeX{} available deferred writing is easy. +% With \eTeX{} available deferred writing without expansion is easy. % \begin{macrocode} \cs_new_protected:Npn \iow_shipout:Nn #1#2 { \iow_shipout_x:Nn #1 { \exp_not:n {#2} } } @@ -1242,30 +1333,26 @@ % \end{macrocode} % \end{macro} % -% \subsection{Immediate writing} +% \subsubsection{Immediate writing} % -% \begin{macro}{\iow_now:Nx} -% An abbreviation for an often used operation, which immediately -% writes its second argument expanded to the output stream. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \iow_now:Nx { \tex_immediate:D \iow_shipout_x:Nn } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\iow_now:Nn} +% \begin{macro}{\iow_now:Nn, \iow_now:Nx} % This routine writes the second argument onto the output stream without % expansion. If this stream isn't open, the output goes to the terminal % instead. If the first argument is no output stream at all, we get an -% internal error. +% internal error. We don't use the expansion done by \tn{write} to +% get the |Nx| variant, because it differs in subtle ways from +% \texttt{x}-expansion, namely, macro parameter characters would not +% need to be doubled. % \begin{macrocode} \cs_new_protected:Npn \iow_now:Nn #1#2 - { \iow_now:Nx #1 { \exp_not:n {#2} } } + { \tex_immediate:D \iow_shipout_x:Nn #1 { \exp_not:n {#2} } } +\cs_generate_variant:Nn \iow_now:Nn { Nx } % \end{macrocode} % \end{macro} % % \begin{macro}{\iow_log:n, \iow_log:x} % \begin{macro}{\iow_term:n, \iow_term:x} -% Writing to the log and the terminal directly are relatively easy. +% Writing to the log and the terminal directly are relatively easy. % \begin{macrocode} \cs_set_protected_nopar:Npn \iow_log:x { \iow_now:Nx \c_log_iow } \cs_new_protected_nopar:Npn \iow_log:n { \iow_now:Nn \c_log_iow } @@ -1275,7 +1362,7 @@ %\end{macro} %\end{macro} % -% \subsection{Special characters for writing} +% \subsubsection{Special characters for writing} % % \begin{macro}{\iow_newline:} % Global variable holding the character that forces a new line when @@ -1292,83 +1379,87 @@ % \end{macrocode} % \end{macro} % -% \subsection{Hard-wrapping lines based on length} +% \subsubsection{Hard-wrapping lines to a character count} % % The code here implements a generic hard-wrapping function. This is % used by the messaging system, but is designed such that it is % available for other uses. % -% \begin{macro}{\l_iow_line_length_int} -% This is the \enquote{raw} length of a line which can be written to a -% file. The standard value is the line length typically used by +% \begin{macro}[var, added = 2012-06-24]{\l_iow_line_count_int} +% This is the \enquote{raw} number of characters in a line which +% can be written to the terminal. +% The standard value is the line length typically used by % \TeX{}Live and Mik\TeX{}. % \begin{macrocode} -\int_new:N \l_iow_line_length_int -\int_set:Nn \l_iow_line_length_int { 78 } +\int_new:N \l_iow_line_count_int +\int_set:Nn \l_iow_line_count_int { 78 } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\l_iow_target_length_int} -% This stores the target line length: the full length minus any -% part for a leader at the start of each line. +% \begin{macro}[aux]{\l_@@_target_count_int} +% This stores the target line count: the full number of characters +% in a line, minus any part for a leader at the start of each line. % \begin{macrocode} -\int_new:N \l_iow_target_length_int +\int_new:N \l_@@_target_count_int % \end{macrocode} % \end{macro} % % \begin{macro}[aux] % { -% \l_iow_current_line_int, -% \l_iow_current_word_int, -% \l_iow_current_indentation_int +% \l_@@_current_line_int, +% \l_@@_current_word_int, +% \l_@@_current_indentation_int % } % These store the number of characters in the line and word currently % being constructed, and the current indentation, respectively. % \begin{macrocode} -\int_new:N \l_iow_current_line_int -\int_new:N \l_iow_current_word_int -\int_new:N \l_iow_current_indentation_int +\int_new:N \l_@@_current_line_int +\int_new:N \l_@@_current_word_int +\int_new:N \l_@@_current_indentation_int % \end{macrocode} % \end{macro} % % \begin{macro}[aux] % { -% \l_iow_current_line_tl, -% \l_iow_current_word_tl, -% \l_iow_current_indentation_tl +% \l_@@_current_line_tl, +% \l_@@_current_word_tl, +% \l_@@_current_indentation_tl % } % These hold the current line of text and current word, % and a number of spaces for indentation, respectively. % \begin{macrocode} -\tl_new:N \l_iow_current_line_tl -\tl_new:N \l_iow_current_word_tl -\tl_new:N \l_iow_current_indentation_tl +\tl_new:N \l_@@_current_line_tl +\tl_new:N \l_@@_current_word_tl +\tl_new:N \l_@@_current_indentation_tl % \end{macrocode} %\end{macro} % -% \begin{macro}[aux]{\l_iow_wrap_tl} -% Used for the expansion step before detokenizing. +% \begin{macro}[aux]{\l_@@_wrap_tl} +% Used for the expansion step before detokenizing, and for the output +% from wrapping text: fully expanded and with lines which are not +% overly long. % \begin{macrocode} -\tl_new:N \l_iow_wrap_tl +\tl_new:N \l_@@_wrap_tl % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\l_iow_wrapped_tl} -% The output from wrapping text: fully expanded and with lines -% which are not overly long. +% \begin{macro}[aux]{\l_@@_newline_tl} +% The token list inserted to produce the new line, with the +% \meta{run-on text}. % \begin{macrocode} -\tl_new:N \l_iow_wrapped_tl +\tl_new:N \l_@@_newline_tl % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\l_iow_line_start_bool} -% Boolean to avoid adding a space at the beginning of forced newlines. +% \begin{macro}[aux]{\l_@@_line_start_bool} +% Boolean to avoid adding a space at the beginning of forced newlines, +% and to know when to add the indentation. % \begin{macrocode} -\bool_new:N \l_iow_line_start_bool +\bool_new:N \l_@@_line_start_bool % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\c_catcode_other_space_tl} +% \begin{macro}{\c_catcode_other_space_tl} % Lowercase a character with category code $12$ to produce an % \enquote{other} space. We can do everything within the group, % because \cs{tl_const:Nn} defines its argument globally. @@ -1381,49 +1472,45 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\c_iow_wrap_marker_tl} -% \begin{macro}[aux]{ -% \c_iow_wrap_end_marker_tl, -% \c_iow_wrap_newline_marker_tl, -% \c_iow_wrap_indent_marker_tl, -% \c_iow_wrap_unindent_marker_tl} -% \begin{macro}[aux]{\iow_wrap_new_marker:n} +% \begin{macro}[aux]{\c_@@_wrap_marker_tl} +% \begin{macro}[aux] +% { +% \c_@@_wrap_end_marker_tl, +% \c_@@_wrap_newline_marker_tl, +% \c_@@_wrap_indent_marker_tl, +% \c_@@_wrap_unindent_marker_tl +% } % Every special action of the wrapping code is preceeded by -% the same recognizable string, \cs{c_iow_wrap_marker_tl}. +% the same recognizable string, \cs{c_@@_wrap_marker_tl}. % Upon seeing that \enquote{word}, the wrapping code reads % one space-delimited argument to know what operation to % perform. The setting of \tn{escapechar} here is not -% very important, but makes \cs{c_iow_wrap_marker_tl} look -% nicer. Note that \cs{iow_wrap_new_marker:n} does not -% survive the group, but all constants are defined globally. +% very important, but makes \cs{c_@@_wrap_marker_tl} look +% nicer. % \begin{macrocode} \group_begin: \int_set_eq:NN \tex_escapechar:D \c_minus_one - \tl_const:Nx \c_iow_wrap_marker_tl + \tl_const:Nx \c_@@_wrap_marker_tl { \tl_to_str:n { \^^I \^^O \^^W \^^_ \^^W \^^R \^^A \^^P } } - \cs_set:Npn \iow_wrap_new_marker:n #1 - { - \tl_const:cx { c_iow_wrap_ #1 _marker_tl } - { - \c_catcode_other_space_tl - \c_iow_wrap_marker_tl - \c_catcode_other_space_tl - #1 - \c_catcode_other_space_tl - } - } - \iow_wrap_new_marker:n { end } - \iow_wrap_new_marker:n { newline } - \iow_wrap_new_marker:n { indent } - \iow_wrap_new_marker:n { unindent } \group_end: +\tl_map_inline:nn + { { end } { newline } { indent } { unindent } } + { + \tl_const:cx { c_@@_wrap_ #1 _marker_tl } + { + \c_catcode_other_space_tl + \c_@@_wrap_marker_tl + \c_catcode_other_space_tl + #1 + \c_catcode_other_space_tl + } + } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} % % \begin{macro}{\iow_indent:n} -% \begin{macro}[aux]{\iow_indent_expandable:n} +% \begin{macro}[aux]{\@@_indent:n} % We give a dummy (protected) definition to \cs{iow_indent:n} % when outside messages. Within wrapped message, it places % the instruction for increasing the indentation before its @@ -1432,23 +1519,26 @@ % only changes when the next line is started. % \begin{macrocode} \cs_new_protected:Npn \iow_indent:n #1 { } -\cs_new:Npx \iow_indent_expandable:n #1 +\cs_new:Npx \@@_indent:n #1 { - \c_iow_wrap_indent_marker_tl + \c_@@_wrap_indent_marker_tl #1 - \c_iow_wrap_unindent_marker_tl + \c_@@_wrap_unindent_marker_tl } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}{\iow_wrap:xnnnN} -% The main wrapping function works as follows. The target number of -% characters in a line is calculated, before fully-expanding the input -% such that |\\| and \verb*|\ | are converted into the appropriate -% values. There is then a loop over each word in the input, which -% will do the actual wrapping. After the loop, the resulting text is -% passed on to the function which has been given as a post-processor. +% \begin{macro}{\iow_wrap:nnnN} +% The main wrapping function works as follows. First give |\\|, +% \verb*|\ | and other formatting commands the correct definition for +% messages, before fully-expanding the input. In package mode, the +% expansion uses \LaTeXe{}'s \cs{protect} mechanism. Afterwards, set +% the newline marker (two assignments to fully expand, then convert +% to a string) and its length, and initialize some registers. +% There is then a loop over each word in the input, which will do the +% actual wrapping. After the loop, the resulting text is passed on to +% the function which has been given as a post-processor. % The argument |#4| is available for additional set up steps for % the output. The definition of |\\| and \verb*|\ | use an % \enquote{other} space rather than a normal space, because the latter @@ -1456,16 +1546,9 @@ % expansions. The \cs{tl_to_str:N} step converts the \enquote{other} % space back to a normal space. % \begin{macrocode} -\cs_new_protected:Npn \iow_wrap:xnnnN #1#2#3#4#5 +\cs_new_protected:Npn \iow_wrap:nnnN #1#2#3#4 { \group_begin: - \int_set:Nn \l_iow_target_length_int { \l_iow_line_length_int - ( #3 ) } - \int_zero:N \l_iow_current_indentation_int - \tl_clear:N \l_iow_current_indentation_tl - \int_zero:N \l_iow_current_line_int - \tl_clear:N \l_iow_current_line_tl - \tl_clear:N \l_iow_wrap_tl - \bool_set_true:N \l_iow_line_start_bool \int_set_eq:NN \tex_escapechar:D \c_minus_one \cs_set_nopar:Npx \{ { \token_to_str:N \{ } \cs_set_nopar:Npx \# { \token_to_str:N \# } @@ -1473,103 +1556,119 @@ \cs_set_nopar:Npx \% { \token_to_str:N \% } \cs_set_nopar:Npx \~ { \token_to_str:N \~ } \int_set:Nn \tex_escapechar:D { 92 } - \cs_set_eq:NN \\ \c_iow_wrap_newline_marker_tl + \cs_set_eq:NN \\ \c_@@_wrap_newline_marker_tl \cs_set_eq:NN \ \c_catcode_other_space_tl - \cs_set_eq:NN \iow_indent:n \iow_indent_expandable:n - #4 + \cs_set_eq:NN \iow_indent:n \@@_indent:n + #3 %<*initex> - \tl_set:Nx \l_iow_wrap_tl {#1} + \tl_set:Nx \l_@@_wrap_tl {#1} %</initex> %<*package> - \protected@edef \l_iow_wrap_tl {#1} + \protected@edef \l_@@_wrap_tl {#1} %</package> - \cs_set:Npn \\ { \iow_newline: #2 } +% \end{macrocode} +% This is a bit of a hack to measure the string length of the run on text +% without the \pkg{l3str} module (which is still experimental). This should +% be replaced once the string module is finalised with something a little +% cleaner. +% \begin{macrocode} + \tl_set:Nx \l_@@_newline_tl { \iow_newline: #2 } + \tl_set:Nx \l_@@_newline_tl { \tl_to_str:N \l_@@_newline_tl } + \tl_replace_all:Nnn \l_@@_newline_tl { ~ } { \c_space_tl } + \int_set:Nn \l_@@_target_count_int + { \l_iow_line_count_int - \tl_count:N \l_@@_newline_tl + \c_one } + \int_zero:N \l_@@_current_indentation_int + \tl_clear:N \l_@@_current_indentation_tl + \int_zero:N \l_@@_current_line_int + \tl_clear:N \l_@@_current_line_tl + \bool_set_true:N \l_@@_line_start_bool \use:x { - \iow_wrap_loop:w - \tl_to_str:N \l_iow_wrap_tl - \tl_to_str:N \c_iow_wrap_end_marker_tl + \exp_not:n { \tl_clear:N \l_@@_wrap_tl } + \@@_wrap_loop:w + \tl_to_str:N \l_@@_wrap_tl + \tl_to_str:N \c_@@_wrap_end_marker_tl \c_space_tl \c_space_tl \exp_not:N \q_stop } \exp_args:NNo \group_end: - #5 \l_iow_wrapped_tl + #4 \l_@@_wrap_tl } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\iow_wrap_loop:w} +% \begin{macro}[aux]{\@@_wrap_loop:w} % The loop grabs one word in the input, and checks whether it is % the special marker, or a normal word. % \begin{macrocode} -\cs_new_protected:Npn \iow_wrap_loop:w #1 ~ % +\cs_new_protected:Npn \@@_wrap_loop:w #1 ~ % { - \tl_set:Nn \l_iow_current_word_tl {#1} - \tl_if_eq:NNTF \l_iow_current_word_tl \c_iow_wrap_marker_tl - { \iow_wrap_special:w } - { \iow_wrap_word: } + \tl_set:Nn \l_@@_current_word_tl {#1} + \tl_if_eq:NNTF \l_@@_current_word_tl \c_@@_wrap_marker_tl + { \@@_wrap_special:w } + { \@@_wrap_word: } } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\iow_wrap_word:} -% \begin{macro}[aux]{\iow_wrap_word_fits:} -% \begin{macro}[aux]{\iow_wrap_word_newline:} -% For a normal word, update the line length, then test if the current +% \begin{macro}[aux]{\@@_wrap_word:} +% \begin{macro}[aux]{\@@_wrap_word_fits:} +% \begin{macro}[aux]{\@@_wrap_word_newline:} +% For a normal word, update the line count, then test if the current % word would fit in the current line, and call the appropriate function. % If the word fits in the current line, add it to the line, preceded by % a space unless it is the first word of the line. % Otherwise, the current line is added to the result, with the run-on text. -% The current word (and its length) are then put in the new line. +% The current word (and its character count) are then put in the new line. % \begin{macrocode} -\cs_new_protected_nopar:Npn \iow_wrap_word: +\cs_new_protected_nopar:Npn \@@_wrap_word: { - \int_set:Nn \l_iow_current_word_int - { \str_length_skip_spaces:N \l_iow_current_word_tl } - \int_add:Nn \l_iow_current_line_int { \l_iow_current_word_int } - \int_compare:nNnTF \l_iow_current_line_int < \l_iow_target_length_int - { \iow_wrap_word_fits: } - { \iow_wrap_word_newline: } - \iow_wrap_loop:w + \int_set:Nn \l_@@_current_word_int + { \__str_count_ignore_spaces:N \l_@@_current_word_tl } + \int_add:Nn \l_@@_current_line_int { \l_@@_current_word_int } + \int_compare:nNnTF \l_@@_current_line_int < \l_@@_target_count_int + { \@@_wrap_word_fits: } + { \@@_wrap_word_newline: } + \@@_wrap_loop:w } -\cs_new_protected_nopar:Npn \iow_wrap_word_fits: +\cs_new_protected_nopar:Npn \@@_wrap_word_fits: { - \bool_if:NTF \l_iow_line_start_bool + \bool_if:NTF \l_@@_line_start_bool { - \bool_set_false:N \l_iow_line_start_bool - \tl_put_right:Nx \l_iow_current_line_tl - { \l_iow_current_indentation_tl \l_iow_current_word_tl } - \int_add:Nn \l_iow_current_line_int - { \l_iow_current_indentation_int } + \bool_set_false:N \l_@@_line_start_bool + \tl_put_right:Nx \l_@@_current_line_tl + { \l_@@_current_indentation_tl \l_@@_current_word_tl } + \int_add:Nn \l_@@_current_line_int + { \l_@@_current_indentation_int } } { - \tl_put_right:Nx \l_iow_current_line_tl - { ~ \l_iow_current_word_tl } - \int_incr:N \l_iow_current_line_int + \tl_put_right:Nx \l_@@_current_line_tl + { ~ \l_@@_current_word_tl } + \int_incr:N \l_@@_current_line_int } } -\cs_new_protected_nopar:Npn \iow_wrap_word_newline: +\cs_new_protected_nopar:Npn \@@_wrap_word_newline: { - \tl_put_right:Nx \l_iow_wrapped_tl - { \l_iow_current_line_tl \\ } - \int_set:Nn \l_iow_current_line_int + \tl_put_right:Nx \l_@@_wrap_tl + { \l_@@_current_line_tl \l_@@_newline_tl } + \int_set:Nn \l_@@_current_line_int { - \l_iow_current_word_int - + \l_iow_current_indentation_int + \l_@@_current_word_int + + \l_@@_current_indentation_int } - \tl_set:Nx \l_iow_current_line_tl - { \l_iow_current_indentation_tl \l_iow_current_word_tl } + \tl_set:Nx \l_@@_current_line_tl + { \l_@@_current_indentation_tl \l_@@_current_word_tl } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % -% \begin{macro}[aux]{\iow_wrap_special:w} -% \begin{macro}[aux]{\iow_wrap_newline:w} -% \begin{macro}[aux]{\iow_wrap_indent:w} -% \begin{macro}[aux]{\iow_wrap_unindent:w} -% \begin{macro}[aux]{\iow_wrap_end:w} +% \begin{macro}[aux]{\@@_wrap_special:w} +% \begin{macro}[aux]{\@@_wrap_newline:w} +% \begin{macro}[aux]{\@@_wrap_indent:w} +% \begin{macro}[aux]{\@@_wrap_unindent:w} +% \begin{macro}[aux]{\@@_wrap_end:w} % When the \enquote{special} marker is encountered, % read what operation to perform, as a space-delimited % argument, perform it, and remember to loop. @@ -1584,37 +1683,37 @@ % At the end, we simply save the last line (without the run-on text), % and prevent the loop. % \begin{macrocode} -\cs_new_protected:Npn \iow_wrap_special:w #1 ~ #2 ~ #3 ~ % +\cs_new_protected:Npn \@@_wrap_special:w #1 ~ #2 ~ #3 ~ % { - \use:c { iow_wrap_#1: } - \str_if_eq:xxTF { #2~#3 } { ~ \c_iow_wrap_marker_tl } - { \iow_wrap_special:w } - { \iow_wrap_loop:w #2 ~ #3 ~ } + \use:c { @@_wrap_#1: } + \str_if_eq_x:nnTF { #2~#3 } { ~ \c_@@_wrap_marker_tl } + { \@@_wrap_special:w } + { \@@_wrap_loop:w #2 ~ #3 ~ } } -\cs_new_protected_nopar:Npn \iow_wrap_newline: +\cs_new_protected_nopar:Npn \@@_wrap_newline: { - \tl_put_right:Nx \l_iow_wrapped_tl - { \l_iow_current_line_tl \\ } - \int_zero:N \l_iow_current_line_int - \tl_clear:N \l_iow_current_line_tl - \bool_set_true:N \l_iow_line_start_bool + \tl_put_right:Nx \l_@@_wrap_tl + { \l_@@_current_line_tl \l_@@_newline_tl } + \int_zero:N \l_@@_current_line_int + \tl_clear:N \l_@@_current_line_tl + \bool_set_true:N \l_@@_line_start_bool } -\cs_new_protected_nopar:Npx \iow_wrap_indent: +\cs_new_protected_nopar:Npx \@@_wrap_indent: { - \int_add:Nn \l_iow_current_indentation_int \c_four - \tl_put_right:Nx \exp_not:N \l_iow_current_indentation_tl + \int_add:Nn \l_@@_current_indentation_int \c_four + \tl_put_right:Nx \exp_not:N \l_@@_current_indentation_tl { \c_space_tl \c_space_tl \c_space_tl \c_space_tl } } -\cs_new_protected_nopar:Npn \iow_wrap_unindent: +\cs_new_protected_nopar:Npn \@@_wrap_unindent: { - \int_sub:Nn \l_iow_current_indentation_int \c_four - \tl_set:Nx \l_iow_current_indentation_tl - { \prg_replicate:nn \l_iow_current_indentation_int { ~ } } + \int_sub:Nn \l_@@_current_indentation_int \c_four + \tl_set:Nx \l_@@_current_indentation_tl + { \prg_replicate:nn \l_@@_current_indentation_int { ~ } } } -\cs_new_protected_nopar:Npn \iow_wrap_end: +\cs_new_protected_nopar:Npn \@@_wrap_end: { - \tl_put_right:Nx \l_iow_wrapped_tl - { \l_iow_current_line_tl } + \tl_put_right:Nx \l_@@_wrap_tl + { \l_@@_current_line_tl } \use_none_delimit_by_q_stop:w } % \end{macrocode} @@ -1624,29 +1723,29 @@ % \end{macro} % \end{macro} % -% \begin{macro}[aux]{\str_length_skip_spaces:N} -% \begin{macro}[aux]{\str_length_skip_spaces:n} -% \begin{macro}[aux]{\str_length_loop:NNNNNNNNN} +% \begin{macro}[aux]{\__str_count_ignore_spaces:N} +% \begin{macro}[aux]{\__str_count_ignore_spaces:n} +% \begin{macro}[aux]{\__str_count_loop:NNNNNNNNN} % The wrapping code requires to measure the number of character -% in each word. This could be done with \cs{tl_length:n}, but +% in each word. This could be done with \cs{tl_count:n}, but % it is ten times faster (literally) to use the code below. % \begin{macrocode} -\cs_new_nopar:Npn \str_length_skip_spaces:N - { \exp_args:No \str_length_skip_spaces:n } -\cs_new:Npn \str_length_skip_spaces:n #1 +\cs_new_nopar:Npn \__str_count_ignore_spaces:N + { \exp_args:No \__str_count_ignore_spaces:n } +\cs_new:Npn \__str_count_ignore_spaces:n #1 { - \int_value:w \int_eval:w - \exp_after:wN \str_length_loop:NNNNNNNNN \tl_to_str:n {#1} + \__int_value:w \__int_eval:w + \exp_after:wN \__str_count_loop:NNNNNNNNN \tl_to_str:n {#1} { X8 } { X7 } { X6 } { X5 } { X4 } { X3 } { X2 } { X1 } { X0 } \q_stop - \int_eval_end: + \__int_eval_end: } -\cs_new:Npn \str_length_loop:NNNNNNNNN #1#2#3#4#5#6#7#8#9 +\cs_new:Npn \__str_count_loop:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { \if_catcode:w X #9 \exp_after:wN \use_none_delimit_by_q_stop:w \else: 9 + - \exp_after:wN \str_length_loop:NNNNNNNNN + \exp_after:wN \__str_count_loop:NNNNNNNNN \fi: } % \end{macrocode} @@ -1654,132 +1753,80 @@ % \end{macro} % \end{macro} % -% \subsection{Reading input} +% \subsection{Messages} % -% \begin{macro}[int]{\if_eof:w} -% The primitive conditional % \begin{macrocode} -\cs_new_eq:NN \if_eof:w \tex_ifeof:D -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[pTF]{\ior_if_eof:N} -% To test if some particular input stream is exhausted the following -% conditional is provided. -% \begin{macrocode} -\prg_new_conditional:Nnn \ior_if_eof:N { p , T , F , TF } +\__msg_kernel_new:nnnn { kernel } { file-not-found } + { File~'#1'~not~found. } { - \cs_if_exist:NTF #1 - { - \if_int_compare:w #1 = \c_sixteen - \prg_return_true: - \else: - \if_eof:w #1 - \prg_return_true: - \else: - \prg_return_false: - \fi: - \fi: - } - { \prg_return_true: } + The~requested~file~could~not~be~found~in~the~current~directory,~ + in~the~TeX~search~path~or~in~the~LaTeX~search~path. + } +\__msg_kernel_new:nnnn { kernel } { input-streams-exhausted } + { Input~streams~exhausted } + { + TeX~can~only~open~up~to~16~input~streams~at~one~time.\\ + All~16~are~currently~in~use,~and~something~wanted~to~open~ + another~one. + } +\__msg_kernel_new:nnnn { kernel } { output-streams-exhausted } + { Output~streams~exhausted } + { + TeX~can~only~open~up~to~16~output~streams~at~one~time.\\ + All~16~are~currently~in~use,~and~something~wanted~to~open~ + another~one. + } +\__msg_kernel_new:nnnn { kernel } { space-in-file-name } + { Space~in~file~name~'#1'. } + { + Spaces~are~not~permitted~in~files~loaded~by~LaTeX: \\ + Further~errors~may~follow! } % \end{macrocode} -% \end{macro} % -% \begin{macro}{\ior_to:NN, \ior_gto:NN} -% And here we read from files. -% \begin{macrocode} -\cs_new_protected:Npn \ior_to:NN #1#2 - { \tex_read:D #1 to #2 } -\cs_new_protected:Npn \ior_gto:NN #1#2 - { \tex_global:D \tex_read:D #1 to #2 } -% \end{macrocode} -% \end{macro} +% \subsection{Deprecated functions} % -% \begin{macro}{\ior_str_to:NN, \ior_str_gto:NN} -% Reading as strings is also a primitive wrapper. +% Deprecated on 2012-06-28, for removal by 2012-12-31. +% +% \begin{macro}{\iow_wrap:xnnnN} +% This was renamed and one unneed argument was removed. % \begin{macrocode} -\cs_new_protected:Npn \ior_str_to:NN #1#2 - { \etex_readline:D #1 to #2 } -\cs_new_protected:Npn \ior_str_gto:NN #1#2 - { \tex_global:D \etex_readline:D #1 to #2 } +\cs_new_protected:Npn \iow_wrap:xnnnN #1#2#3#4#5 + { \iow_wrap:nnnN {#1} {#2} {#4} #5 } % \end{macrocode} % \end{macro} % -% \subsection{Experimental functions} +% Deprecated on 2012-06-24, for removal by 2012-12-31. % -% \begin{macro}{\ior_map_inline:Nn, \ior_str_map_inline:Nn} -% \begin{macro}[aux]{\ior_str_map_inline_aux:NNn} -% \begin{macro}[aux]{\ior_str_map_inline_aux:NNNn} -% \begin{macro}[aux]{\ior_str_map_inline_loop:NNN} -% \begin{variable}{\l_ior_internal_tl} -% Mapping to an input stream can be done on either a token or a string -% basis, hence the set up. Within that, there is a check to avoid reading -% past the end of a file, hence the two applications of \cs{ior_if_eof:N}. -% This mapping cannot be nested as the stream has only one \enquote{current -% line}. +% \begin{variable}{\l_iow_line_length_int} +% Simple rename. Here we copy the \TeX{} register. % \begin{macrocode} -\cs_new_protected_nopar:Npn \ior_map_inline:Nn - { \ior_map_inline_aux:NNn \ior_to:NN } -\cs_new_protected_nopar:Npn \ior_str_map_inline:Nn - { \ior_map_inline_aux:NNn \ior_str_to:NN } -\cs_new_protected_nopar:Npn \ior_map_inline_aux:NNn - { - \exp_args:Nc \ior_map_inline_aux:NNNn - { ior_map_ \int_use:N \g_prg_map_int :n } - } -\cs_new_protected:Npn \ior_map_inline_aux:NNNn #1#2#3#4 - { - \cs_set:Npn #1 ##1 {#4} - \int_gincr:N \g_prg_map_int - \ior_if_eof:NF #3 { \ior_map_inline_loop:NNN #1#2#3 } - \prg_break_point:n { \int_gdecr:N \g_prg_map_int } - } -\cs_new_protected:Npn \ior_map_inline_loop:NNN #1#2#3 - { - #2 #3 \l_ior_internal_tl - \ior_if_eof:NF #3 - { - \exp_args:No #1 \l_ior_internal_tl - \ior_map_inline_loop:NNN #1#2#3 - } - } -\tl_new:N \l_ior_internal_tl +\cs_new_eq:NN \l_iow_line_length_int \l_iow_line_count_int % \end{macrocode} % \end{variable} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Messages} % +% \begin{macro}{\ior_to:NN, \ior_gto:NN, \ior_str_to:NN, \ior_str_gto:NN} +% The local variants are renames, while the global variants are +% deprecated and add the \TeX{} primitive \tn{global}. % \begin{macrocode} -\msg_kernel_new:nnnn { file } { file-not-found } - { File~'#1'~not~found. } - { - The~requested~file~could~not~be~found~in~the~current~directory,~ - in~the~TeX~search~path~or~in~the~LaTeX~search~path. - } -\msg_kernel_new:nnnn { file } { space-in-file-name } - { Space~in~file~name~'#1'. } - { - Spaces~are~not~permitted~in~files~loaded~by~LaTeX: \\ - Further~errors~may~follow! - } +\cs_new_eq:NN \ior_to:NN \ior_get:NN +\cs_new_protected_nopar:Npn \ior_gto:NN { \tex_global:D \ior_to:NN } +\cs_new_eq:NN \ior_str_to:NN \ior_get_str:NN +\cs_new_protected_nopar:Npn \ior_str_gto:NN { \tex_global:D \ior_str_to:NN } % \end{macrocode} -% -% \subsection{Deprecated functions} +% \end{macro} % % Deprecated on 2012-02-10, for removal by 2012-05-31. % % \begin{macro}{\iow_now_when_avail:Nn, \iow_now_when_avail:Nx} % For writing only if the stream requested is open at all. % \begin{macrocode} +%<*deprecated> \cs_new_protected:Npn \iow_now_when_avail:Nn #1 { \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nn #1 } } \cs_new_protected:Npn \iow_now_when_avail:Nx #1 { \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nx #1 } } +%</deprecated> % \end{macrocode} % \end{macro} % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3final.dtx b/Master/texmf-dist/source/latex/l3kernel/l3final.dtx index c86e9f269db..845d47814d5 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3final.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3final.dtx @@ -35,7 +35,7 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3final.dtx 3213 2012-01-20 11:03:46Z joseph $ +\GetIdInfo$Id: l3final.dtx 3986 2012-07-15 19:23:51Z joseph $ {L3 Experimental format finalisation} %</driver|package> %<*driver> diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx new file mode 100644 index 00000000000..981e642653b --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx @@ -0,0 +1,235 @@ +% \iffalse meta-comment +%% +%% File: l3fp-assign.dtx Copyright (C) 2011-2012 The LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-assign.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Floating-point assignments} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp-assign} package\thanks{This file +% has version number \ExplFileVersion, last +% revised \ExplFileDate.}\\ +% Floating point expressions} +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% \date{Released \ExplFileDate} +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-assign} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{Assigning values} +% +% \begin{macro}{\fp_new:N} +% Floating point variables are initialized to be $+0$. +% \begin{macrocode} +\cs_new_protected:Npn \fp_new:N #1 + { \cs_new_eq:NN #1 \c_zero_fp } +\cs_generate_variant:Nn \fp_new:N {c} +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \fp_set:Nn, \fp_set:cn, +% \fp_gset:Nn, \fp_gset:cn, +% \fp_const:Nn, \fp_const:cn +% } +% Simply use \cs{@@_parse:n} within various \texttt{x}-expanding +% assignments. +% \begin{macrocode} +\cs_new_protected:Npn \fp_set:Nn #1#2 + { \tl_set:Nx #1 { \@@_parse:n {#2} } } +\cs_new_protected:Npn \fp_gset:Nn #1#2 + { \tl_gset:Nx #1 { \@@_parse:n {#2} } } +\cs_new_protected:Npn \fp_const:Nn #1#2 + { \tl_const:Nx #1 { \@@_parse:n {#2} } } +\cs_generate_variant:Nn \fp_set:Nn {c} +\cs_generate_variant:Nn \fp_gset:Nn {c} +\cs_generate_variant:Nn \fp_const:Nn {c} +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \fp_set_eq:NN , \fp_set_eq:cN , \fp_set_eq:Nc , \fp_set_eq:cc, +% \fp_gset_eq:NN, \fp_gset_eq:cN, \fp_gset_eq:Nc, \fp_gset_eq:cc +% } +% Copying a floating point is the same as copying the underlying token +% list. +% \begin{macrocode} +\cs_new_eq:NN \fp_set_eq:NN \tl_set_eq:NN +\cs_new_eq:NN \fp_gset_eq:NN \tl_gset_eq:NN +\cs_generate_variant:Nn \fp_set_eq:NN { c , Nc , cc } +\cs_generate_variant:Nn \fp_gset_eq:NN { c , Nc , cc } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_zero:N, \fp_zero:c, \fp_gzero:N, \fp_gzero:c} +% Setting a floating point to zero: copy \cs{c_zero_fp}. +% \begin{macrocode} +\cs_new_protected:Npn \fp_zero:N #1 { \fp_set_eq:NN #1 \c_zero_fp } +\cs_new_protected:Npn \fp_gzero:N #1 { \fp_gset_eq:NN #1 \c_zero_fp } +\cs_generate_variant:Nn \fp_zero:N { c } +\cs_generate_variant:Nn \fp_gzero:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% {\fp_zero_new:N, \fp_zero_new:c, \fp_gzero_new:N, \fp_gzero_new:c} +% Set the floating point to zero, or define it if needed. +% \begin{macrocode} +\cs_new_protected:Npn \fp_zero_new:N #1 + { \fp_if_exist:NTF #1 { \fp_zero:N #1 } { \fp_new:N #1 } } +\cs_new_protected:Npn \fp_gzero_new:N #1 + { \fp_if_exist:NTF #1 { \fp_gzero:N #1 } { \fp_new:N #1 } } +\cs_generate_variant:Nn \fp_zero_new:N { c } +\cs_generate_variant:Nn \fp_gzero_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Updating values} +% +% These match the equivalent functions in \pkg{l3int} and \pkg{l3skip}. +% +% \begin{macro} +% { +% \fp_add:Nn, \fp_add:cn, \fp_gadd:Nn, \fp_gadd:cn, +% \fp_sub:Nn, \fp_sub:cn, \fp_gsub:Nn, \fp_gsub:cn, +% } +% \begin{macro}[aux]{\@@_add:NNNn} +% The auxiliary's arguments are 1: the assignment function, 2: the +% operation, 3: the fp variable, 4: the second operand. The +% parentheses around the second operand are needed because |+| and |-| +% are not the operations with the lowest priority. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_add:Nn { \@@_add:NNNn \fp_set:Nn + } +\cs_new_protected_nopar:Npn \fp_gadd:Nn { \@@_add:NNNn \fp_gset:Nn + } +\cs_new_protected_nopar:Npn \fp_sub:Nn { \@@_add:NNNn \fp_set:Nn - } +\cs_new_protected_nopar:Npn \fp_gsub:Nn { \@@_add:NNNn \fp_gset:Nn - } +\cs_new_protected:Npn \@@_add:NNNn #1#2#3#4 { #1 #3 { #3 #2 (#4) } } +\cs_generate_variant:Nn \fp_add:Nn { c } +\cs_generate_variant:Nn \fp_gadd:Nn { c } +\cs_generate_variant:Nn \fp_sub:Nn { c } +\cs_generate_variant:Nn \fp_gsub:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Showing values} +% +% \begin{macro}{\fp_show:N, \fp_show:c, \fp_show:n} +% This shows the result of computing its argument. The +% \cs{__msg_show_variable:x} auxiliary expects its input in a slightly odd +% form, starting with |>|, and displays the rest. +% \begin{macrocode} +\cs_new_protected:Npn \fp_show:N #1 + { \__msg_show_variable:x { > \fp_to_tl:N #1 } } +\cs_new_protected:Npn \fp_show:n #1 + { \__msg_show_variable:x { > \fp_to_tl:n {#1} } } +\cs_generate_variant:Nn \fp_show:N { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Some useful constants and scratch variables} +% +% \begin{variable}{\c_one_fp, \c_e_fp} +% Some constants. +% \begin{macrocode} +\fp_const:Nn \c_e_fp { 2.718 2818 2845 9045 } +\fp_const:Nn \c_one_fp { 1 } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_pi_fp, \c_one_degree_fp} +% We do not round $\pi$ to the closest multiple of $10^{-15}$, which +% would underestimate it by roughly $2.4\cdot 10^{-16}$, but instead +% round it up to the next nearest multiple, which is an overestimate +% by roughly $7.7\cdot 10^{-16}$. This particular choice of rounding +% has very nice properties: it is exactly divisible by $4$ and by +% $180$ as a $16$-digit precision floating point number, hence +% ensuring that $\sin(180\mathrm{deg}) = \sin(\pi) = 0$ exactly, with +% no rounding artifact. +% \begin{macrocode} +\fp_const:Nn \c_pi_fp { 3.141 5926 5358 9794 } +\fp_const:Nn \c_one_degree_fp { 0.0 1745 3292 5199 4330 } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_tmpa_fp, \l_tmpb_fp, \g_tmpa_fp, \g_tmpb_fp} +% Scratch variables are simply initialized there. +% \begin{macrocode} +\fp_new:N \l_tmpa_fp +\fp_new:N \l_tmpb_fp +\fp_new:N \g_tmpa_fp +\fp_new:N \g_tmpb_fp +% \end{macrocode} +% \end{variable} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx new file mode 100644 index 00000000000..566eec13ec5 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx @@ -0,0 +1,850 @@ +% \iffalse meta-comment +% +%% File: l3fp-aux.dtx Copyright(C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-aux.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Floating-point support functions} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \textsf{l3fp-aux} package\\ Support for floating points^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-aux} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{Using arguments and semicolons} +% +% \begin{macro}[int, EXP]{\@@_use_none_stop_f:n} +% This function removes an argument (typically a digit) and replaces +% it by \cs{exp_stop_f:}, a marker which stops \texttt{f}-type +% expansion. +% \begin{macrocode} +\cs_new:Npn \@@_use_none_stop_f:n #1 { \exp_stop_f: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_use_s:n, \@@_use_s:nn} +% Those functions place a semicolon after one or two arguments +% (typically digits). +% \begin{macrocode} +\cs_new:Npn \@@_use_s:n #1 { #1; } +\cs_new:Npn \@@_use_s:nn #1#2 { #1#2; } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP] +% {\@@_use_none_until_s:w, \@@_use_i_until_s:nw, \@@_use_ii_until_s:nnw} +% Those functions select specific arguments among a set of arguments +% delimited by a semicolon. +% \begin{macrocode} +\cs_new:Npn \@@_use_none_until_s:w #1; { } +\cs_new:Npn \@@_use_i_until_s:nw #1#2; {#1} +\cs_new:Npn \@@_use_ii_until_s:nnw #1#2#3; {#2} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_reverse_args:Nww} +% Many internal functions take arguments delimited by semicolons, and +% it is occasionally useful to swap two such arguments. +% \begin{macrocode} +\cs_new:Npn \@@_reverse_args:Nww #1 #2; #3; { #1 #3; #2; } +% \end{macrocode} +% \end{macro} +% +% \subsection{Constants, and structure of floating points} +% +% \begin{macro}[int]{\s_@@, \@@_chk:w} +% Floating points numbers all start with \cs{s_@@} \cs{@@_chk:w}, +% where \cs{s_@@} is equal to the \TeX{} primitive \tn{relax}, and +% \cs{@@_chk:w} is protected. The rest of the floating point number +% is made of characters (or \tn{relax}). This ensures that nothing +% expands under \texttt{f}-expansion, nor under \texttt{x}-expansion. +% However, when typeset, \cs{s_@@} does nothing, and \cs{@@_chk:w} is +% expanded. We define \cs{@@_chk:w} to produce an error. +% \begin{macrocode} +\__scan_new:N \s_@@ +\cs_new_protected:Npn \@@_chk:w #1 ; + { + \__msg_kernel_error:nnx { kernel } { misused-fp } + { \@@_to_tl:w \s_@@ \@@_chk:w #1 ; } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\s_@@_mark, \s_@@_stop} +% Aliases of \cs{tex_relax:D}, used to terminate expressions. +% \begin{macrocode} +\__scan_new:N \s_@@_mark +\__scan_new:N \s_@@_stop +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int] +% { +% \s_@@_invalid, \s_@@_underflow, \s_@@_overflow, +% \s_@@_division, \s_@@_exact +% } +% A couple of scan marks used to indicate where special floating point +% numbers come from. +% \begin{macrocode} +\__scan_new:N \s_@@_invalid +\__scan_new:N \s_@@_underflow +\__scan_new:N \s_@@_overflow +\__scan_new:N \s_@@_division +\__scan_new:N \s_@@_exact +% \end{macrocode} +% \end{macro} +% +% \begin{variable} +% {\c_zero_fp, \c_minus_zero_fp, \c_inf_fp, \c_minus_inf_fp, \c_nan_fp} +% The special floating points. All of them have the form +% \begin{quote} +% \cs{s_@@} \cs{@@_chk:w} \meta{case} \meta{sign} \cs{s_@@_...} |;| +% \end{quote} +% where the dots in \cs{s_@@_...} are one of \texttt{invalid}, +% \texttt{underflow}, \texttt{overflow}, \texttt{division}, +% \texttt{exact}, describing how the floating point was created. We +% define the floating points here as \enquote{exact}. +% \begin{macrocode} +\tl_const:Nn \c_zero_fp { \s_@@ \@@_chk:w 0 0 \s_@@_exact ; } +\tl_const:Nn \c_minus_zero_fp { \s_@@ \@@_chk:w 0 2 \s_@@_exact ; } +\tl_const:Nn \c_inf_fp { \s_@@ \@@_chk:w 2 0 \s_@@_exact ; } +\tl_const:Nn \c_minus_inf_fp { \s_@@ \@@_chk:w 2 2 \s_@@_exact ; } +\tl_const:Nn \c_nan_fp { \s_@@ \@@_chk:w 3 1 \s_@@_exact ; } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_@@_max_exponent_int} +% Normal floating point numbers have an exponent at most +% \texttt{max_exponent} in absolute value. Larger numbers are rounded +% to $\pm\infty$. Smaller numbers are subnormal (not implemented yet), +% and digits beyond +% $10^{-\text{\texttt{max_exponent}}}$ are rounded away, hence the +% true minimum exponent is $-\text{\texttt{max_exponent}}-16$; +% beyond this, numbers are rounded to zero. Why this choice of +% limits? When computing $(a\cdot 10^n)^(b\cdot 10^p)$, we need to +% evaluate $\log(a\cdot 10^n) = \log(a) + n \log(10)$ as a fixed point +% number, which we manipulate as blocks of $4$ digits. Multiplying +% such a fixed point number by $n<10000$ is much cheaper than larger +% $n$, because we can multiply $n$ with each block safely. +% \begin{macrocode} +\int_const:Nn \c_@@_max_exponent_int { 10000 } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[int, EXP]{\@@_zero_fp:N, \@@_inf_fp:N} +% In case of overflow or underflow, we have to output +% a zero or infinity with a given sign. +% \begin{macrocode} +\cs_new:Npn \@@_zero_fp:N #1 { \s_@@ \@@_chk:w 0 #1 \s_@@_underflow ; } +\cs_new:Npn \@@_inf_fp:N #1 { \s_@@ \@@_chk:w 2 #1 \s_@@_overflow ; } +% \end{macrocode} +% \end{macro} +% +%^^A todo: currently unused. +% \begin{macro}[int, EXP]{\@@_max_fp:N, \@@_min_fp:N} +% In some cases, we need to output the smallest or biggest positive or +% negative finite numbers. +% \begin{macrocode} +\cs_new:Npn \@@_min_fp:N #1 + { + \s_@@ \@@_chk:w 1 #1 + { \int_eval:n { - \c_@@_max_exponent_int } } + {1000} {0000} {0000} {0000} ; + } +\cs_new:Npn \@@_max_fp:N #1 + { + \s_@@ \@@_chk:w 1 #1 + { \int_use:N \c_@@_max_exponent_int } + {9999} {9999} {9999} {9999} ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_exponent:w} +% For normal numbers, the function expands to the exponent, otherwise +% to $0$. +% \begin{macrocode} +\cs_new:Npn \@@_exponent:w \s_@@ \@@_chk:w #1 + { + \if_meaning:w 1 #1 + \exp_after:wN \@@_use_ii_until_s:nnw + \else: + \exp_after:wN \@@_use_i_until_s:nw + \exp_after:wN 0 + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Overflow, underflow, and exact zero} +% +%^^A todo: the sign of exact zeros should depend on the rounding mode. +% +% \begin{macro}[int, EXP]{\@@_sanitize:Nw, \@@_sanitize:wN} +% \begin{macro}[aux, EXP]{\@@_sanitize_zero:w} +% Expects the sign and the exponent in some order, then the +% significand (which we don't touch). Outputs the corresponding +% floating point number, possibly underflowed to $\pm 0$ or overflowed +% to $\pm\infty$. The functions \cs{@@_underflow:w} and +% \cs{@@_overflow:w} are defined in \pkg{l3fp-traps}. +% \begin{macrocode} +\cs_new:Npn \@@_sanitize:Nw #1 #2; + { + \if_case:w \if_int_compare:w #2 > \c_@@_max_exponent_int \c_one \else: + \if_int_compare:w #2 < - \c_@@_max_exponent_int \c_two \else: + \if_meaning:w 1 #1 \c_three \else: \c_zero \fi: \fi: \fi: + \or: \exp_after:wN \@@_overflow:w + \or: \exp_after:wN \@@_underflow:w + \or: \exp_after:wN \@@_sanitize_zero:w + \fi: + \s_@@ \@@_chk:w 1 #1 {#2} + } +\cs_new:Npn \@@_sanitize:wN #1; #2 { \@@_sanitize:Nw #2 #1; } +\cs_new:Npn \@@_sanitize_zero:w \s_@@ \@@_chk:w #1 #2 #3; { \c_zero_fp } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Expanding after a floating point number} +% +% \begin{macro}[int, EXP]{\@@_exp_after_o:w} +% \begin{macro}[int, EXP]{\@@_exp_after_o:nw, \@@_exp_after_f:nw} +% \begin{syntax} +% \cs{@@_exp_after_o:nw} \Arg{tokens} \meta{floating point} \meta{more tokens} +% \end{syntax} +% Places \meta{tokens} (empty in the case of \cs{@@_exp_after_o:w}) +% between the \meta{floating point} and the \meta{more tokens}, then +% hits those tokens with either \texttt{o}-expansion (one +% \cs{exp_after:wN}) or \texttt{f}-expansion, and leaves the floating +% point number unchanged. +% +% We first distinguish normal floating points, which have a mantissa, +% from the much simpler special floating points. +% \begin{macrocode} +\cs_new:Npn \@@_exp_after_o:w \s_@@ \@@_chk:w #1 + { + \if_meaning:w 1 #1 + \exp_after:wN \@@_exp_after_normal:nNNw + \else: + \exp_after:wN \@@_exp_after_special:nNNw + \fi: + { } + #1 + } +\cs_new:Npn \@@_exp_after_o:nw #1 \s_@@ \@@_chk:w #2 + { + \if_meaning:w 1 #2 + \exp_after:wN \@@_exp_after_normal:nNNw + \else: + \exp_after:wN \@@_exp_after_special:nNNw + \fi: + { #1 } + #2 + } +\cs_new:Npn \@@_exp_after_f:nw #1 \s_@@ \@@_chk:w #2 + { + \if_meaning:w 1 #2 + \exp_after:wN \@@_exp_after_normal:nNNw + \else: + \exp_after:wN \@@_exp_after_special:nNNw + \fi: + { \tex_romannumeral:D -`0 #1 } + #2 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_exp_after_special:nNNw} +% \begin{syntax} +% \cs{@@_exp_after_special:nNNw} \Arg{after} \meta{case} \meta{sign} \meta{scan mark} |;| +% \end{syntax} +% Special floating point numbers are easy to jump over since they +% contain few tokens. +% \begin{macrocode} +\cs_new:Npn \@@_exp_after_special:nNNw #1#2#3#4; + { + \exp_after:wN \s_@@ + \exp_after:wN \@@_chk:w + \exp_after:wN #2 + \exp_after:wN #3 + \exp_after:wN #4 + \exp_after:wN ; + #1 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_exp_after_normal:nNNw} +% For normal floating point numbers, life is slightly harder, since we +% have many tokens to jump over. Here it would be slightly better if +% the digits were not braced but instead were delimited arguments (for +% instance delimited by |,|). That may be changed some day. +% \begin{macrocode} +\cs_new:Npn \@@_exp_after_normal:nNNw #1 1 #2 #3 #4#5#6#7; + { + \exp_after:wN \@@_exp_after_normal:Nwwwww + \exp_after:wN #2 + \__int_value:w #3 \exp_after:wN ; + \__int_value:w 1 #4 \exp_after:wN ; + \__int_value:w 1 #5 \exp_after:wN ; + \__int_value:w 1 #6 \exp_after:wN ; + \__int_value:w 1 #7 \exp_after:wN ; #1 + } +\cs_new:Npn \@@_exp_after_normal:Nwwwww + #1 #2; 1 #3 ; 1 #4 ; 1 #5 ; 1 #6 ; + { \s_@@ \@@_chk:w 1 #1 {#2} {#3} {#4} {#5} {#6} ; } +% \end{macrocode} +% \end{macro} +% +% \subsection{Packing digits} +% +% When a positive integer |#1| is known to be less than $10^8$, the +% following trick will split it into two blocks of $4$ digits, padding +% with zeros on the left. +% \begin{verbatim} +% \cs_new:Npn \pack:NNNNNw #1 #2#3#4#5 #6; { {#2#3#4#5} {#6} } +% \exp_after:wN \pack:NNNNNw +% \int_use:N \__int_eval:w 1 0000 0000 + #1 ; +% \end{verbatim} +% The idea is that adding $10^8$ to the number ensures that it has +% exactly $9$ digits, and can then easily find which digits correspond +% to what position in the number. Of course, this can be modified +% for any number of digits less or equal to~$9$ (we are limited by +% \TeX{}'s integers). This method is very heavily relied upon in +% \texttt{l3fp-basics}. +% +% More specifically, the auxiliary inserts |+ #1#2#3#4#5 ; {#6}|, which +% allows us to compute several blocks of $4$ digits in a nested manner, +% performing carries on the fly. Say we want to compute $1\,2345 \times +% 6677\,8899$. With simplified names, we would do +% \begin{verbatim} +% \exp_after:wN \post_processing:w +% \int_use:N \__int_eval:w - 5 0000 +% \exp_after:wN \pack:NNNNNw +% \int_use:N \__int_eval:w 4 9995 0000 +% + 12345 * 6677 +% \exp_after:wN \pack:NNNNNw +% \int_use:N \__int_eval:w 5 0000 0000 +% + 12345 * 8899 ; +% \end{verbatim} +% The \cs{exp_after:wN} triggers |\int_use:N \__int_eval:w|, which +% starts a first computation, whose initial value is $- 5\,0000$ (the +% \enquote{leading shift}). In that computation appears an +% \cs{exp_after:wN}, which triggers the nested computation +% |\int_use:N \__int_eval:w| with starting value $4\,9995\,0000$ (the +% \enquote{middle shift}). That, in turn, expands \cs{exp_after:wN} +% which triggers the third computation. The third computation's value +% is $5\,0000\,0000 + 12345 \times 8899$, which has $9$ digits. Adding +% $5\cdot 10^{8}$ to the product allowed us to know how many digits to +% expect as long as the numbers to multiply are not too big; it will +% also work to some extent with negative results. The \texttt{pack} +% function puts the last $4$ of those $9$ digits into a brace group, +% moves the semi-colon delimiter, and inserts a |+|, which combines the +% carry with the previous computation. The shifts nicely combine into +% $5\,0000\,0000 / 10^{4} + 4\,9995\,0000 = 5\,0000\,0000$. As long as +% the operands are in some range, the result of this second computation +% will have $9$ digits. The corresponding \texttt{pack} function, +% expanded after the result is computed, braces the last $4$ digits, and +% leaves |+| \meta{5 digits} for the initial computation. The +% \enquote{leading shift} cancels the combination of the other shifts, +% and the |\post_processing:w| takes care of packing the last few +% digits. +% +% Admittedly, this is quite intricate. It is probably the key in making +% \pkg{l3fp} as fast as other pure \TeX{} floating point units despite +% its increased precision. In fact, this is used so much that we +% provide different sets of packing functions and shifts, depending on +% ranges of input. +% +% \begin{macro}[int, EXP]{\@@_pack:NNNNNw} +% \begin{variable} +% { +% \c_@@_trailing_shift_int , +% \c_@@_middle_shift_int , +% \c_@@_leading_shift_int , +% } +% This set of shifts allows for computations involving results in the +% range $[-4\cdot 10^{8}, 5\cdot 10^{8}-1]$. Shifted values all have +% exactly $9$ digits. +% \begin{macrocode} +\int_const:Nn \c_@@_leading_shift_int { - 5 0000 } +\int_const:Nn \c_@@_middle_shift_int { 5 0000 * 9999 } +\int_const:Nn \c_@@_trailing_shift_int { 5 0000 * 10000 } +\cs_new:Npn \@@_pack:NNNNNw #1 #2#3#4#5 #6; { + #1#2#3#4#5 ; {#6} } +% \end{macrocode} +% \end{variable} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_pack_big:NNNNNNw} +% \begin{variable} +% { +% \c_@@_big_trailing_shift_int , +% \c_@@_big_middle_shift_int , +% \c_@@_big_leading_shift_int , +% } +% This set of shifts allows for computations involving results in the +% range $[-5\cdot 10^{8}, 6\cdot 10^{8}-1]$ (actually a bit more). +% Shifted values all have exactly $10$ digits. Note that the upper +% bound is due to \TeX{}'s limit of $2^{31}-1$ on integers. The +% shifts are chosen to be roughly the mid-point of $10^{9}$ and +% $2^{31}$, the two bounds on $10$-digit integers in \TeX{}. +% \begin{macrocode} +\int_const:Nn \c_@@_big_leading_shift_int { - 15 2374 } +\int_const:Nn \c_@@_big_middle_shift_int { 15 2374 * 9999 } +\int_const:Nn \c_@@_big_trailing_shift_int { 15 2374 * 10000 } +\cs_new:Npn \@@_pack_big:NNNNNNw #1#2 #3#4#5#6 #7; + { + #1#2#3#4#5#6 ; {#7} } +% \end{macrocode} +% \end{variable} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_pack_twice_four:wNNNNNNNN} +% \begin{syntax} +% \cs{@@_pack_twice_four:wNNNNNNNN} \meta{tokens} |;| \meta{$\geq 8$ digits} +% \end{syntax} +% Grabs two sets of $4$ digits and places them before the semi-colon +% delimiter. Putting several copies of this function before a +% semicolon will pack more digits since each will take the digits +% packed by the others in its first argument. +% \begin{macrocode} +\cs_new:Npn \@@_pack_twice_four:wNNNNNNNN #1; #2#3#4#5 #6#7#8#9 + { #1 {#2#3#4#5} {#6#7#8#9} ; } +% \end{macrocode} +% \end{macro} +% +% \subsection{Decimate (dividing by a power of 10)} +% +% ^^A begin[todo] +% \begin{macro}[int, EXP]{\@@_decimate:nNnnnn} +% \begin{syntax} +% \cs{@@_decimate:nNnnnn} \Arg{shift} \Arg{f_1} +% ~~\Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} +% \end{syntax} +% Each \meta{X_i} consists in $4$ digits exactly, +% and $1000\leq\meta{X_1}<9999$. The first argument determines +% by how much we shift the digits. \meta{f_1} is called as follows: +% \begin{syntax} +% \meta{f_1} \meta{rounding} \Arg{X'_1} \Arg{X'_2} \meta{extra-digits} |;| +% \end{syntax} +% where $0\leq\meta{X'_i}<10^{8}-1$ are $8$ digit numbers, +% forming the truncation of our number. In other words, +% \[ +% \left( +% \sum_{i=1}^{4} \meta{X_i} \cdot 10^{-4i} \cdot 10^{-\meta{shift}} +% - \meta{X'_1} \cdot 10^{-8} + \meta{X'_2} \cdot 10^{-16} +% \right) +% \in [0,10^{-16}). +% \] +% To round properly later, we need to remember some information +% about the difference. The \meta{rounding} digit is $0$ if and +% only if the difference is exactly $0$, and $5$ if and only if +% the difference is exactly $0.5\cdot 10^{-16}$. Otherwise, it +% is the (non-$0$, non-$5$) digit closest to $10^{17}$ times the +% difference. In particular, if the shift is $17$ or more, all +% the digits are dropped, \meta{rounding} is $1$ (not $0$), and +% \meta{X'_1} \meta{X'_2} are both zero. +% +% If the shift is $1$, the \meta{rounding} digit is simply the +% only digit that was pushed out of the brace groups (this is +% important for subtraction). It would be more natural for the +% \meta{rounding} digit to be placed after the \meta{X_i}, +% but the choice we make involves less reshuffling. +% +% Note that this function fails for negative \meta{shift}. +% \begin{macrocode} +\cs_new:Npn \@@_decimate:nNnnnn #1 + { + \cs:w + @@_decimate_ + \if_int_compare:w \__int_eval:w #1 > \c_sixteen + tiny + \else: + \tex_romannumeral:D \__int_eval:w #1 + \fi: + :Nnnnn + \cs_end: + } +% \end{macrocode} +% Each of the auxiliaries see the function \meta{f_1}, +% followed by $4$ blocks of $4$ digits. +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_decimate_:Nnnnn, \@@_decimate_tiny:Nnnnn} +% If the \meta{shift} is zero, or too big, life is very easy. +% \begin{macrocode} +\cs_new:Npn \@@_decimate_:Nnnnn #1 #2#3#4#5 + { #1 0 {#2#3} {#4#5} ; } +\cs_new:Npn \@@_decimate_tiny:Nnnnn #1 #2#3#4#5 + { #1 1 { 0000 0000 } { 0000 0000 } 0 #2#3#4#5 ; } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP] +% { +% \@@_decimate_i:Nnnnn, \@@_decimate_ii:Nnnnn, +% \@@_decimate_iii:Nnnnn, \@@_decimate_iv:Nnnnn, +% \@@_decimate_v:Nnnnn, \@@_decimate_vi:Nnnnn, +% \@@_decimate_vii:Nnnnn, \@@_decimate_viii:Nnnnn, +% \@@_decimate_ix:Nnnnn, \@@_decimate_x:Nnnnn, +% \@@_decimate_xi:Nnnnn, \@@_decimate_xii:Nnnnn, +% \@@_decimate_xiii:Nnnnn, \@@_decimate_xiv:Nnnnn, +% \@@_decimate_xv:Nnnnn, \@@_decimate_xvi:Nnnnn +% } +% \begin{syntax} +% \cs{@@_decimate_i:Nnnnn} \meta{f_1} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} +% \end{syntax} +% Shifting happens in two steps: compute the \meta{rounding} digit, +% and repack digits into two blocks of $8$. The sixteen functions +% are very similar, and defined through \cs{@@_tmp:w}. +% The arguments are as follows: |#1| indicates which function is +% being defined; after one step of expansion, |#2| yields the +% \enquote{extra digits} which are then converted by +% \cs{@@_decimate_round:Nw} to the \meta{rounding} digit. +% This triggers the \texttt{f}-expansion of +% \cs{@@_decimate_pack:nnnnnnnnnnw},\footnote{No, the argument +% spec is not a mistake: the function calls an auxiliary to +% do half of the job.} responsible for building two blocks of +% $8$ digits, and removing the rest. For this to work, |#3| +% alternates between braced and unbraced blocks of $4$ digits, +% in such a way that the $5$ first and $5$ next token groups +% yield the correct blocks of $8$ digits. +% \begin{macrocode} +\cs_new:Npn \@@_tmp:w #1 #2 #3 + { + \cs_new:cpn { @@_decimate_ #1 :Nnnnn } ##1 ##2##3##4##5 + { + \exp_after:wN ##1 + \__int_value:w + \exp_after:wN \@@_decimate_round:Nw #2 ; + \@@_decimate_pack:nnnnnnnnnnw #3 ; + } + } +\@@_tmp:w {i} {\use_none:nnn #50} { 0{#2}#3{#4}#5 } +\@@_tmp:w {ii} {\use_none:nn #5 } { 00{#2}#3{#4}#5 } +\@@_tmp:w {iii} {\use_none:n #5 } { 000{#2}#3{#4}#5 } +\@@_tmp:w {iv} { #5 } { {0000}#2{#3}#4 #5 } +\@@_tmp:w {v} {\use_none:nnn #4#5 } { 0{0000}#2{#3}#4 #5 } +\@@_tmp:w {vi} {\use_none:nn #4#5 } { 00{0000}#2{#3}#4 #5 } +\@@_tmp:w {vii} {\use_none:n #4#5 } { 000{0000}#2{#3}#4 #5 } +\@@_tmp:w {viii}{ #4#5 } { {0000}0000{#2}#3 #4 #5 } +\@@_tmp:w {ix} {\use_none:nnn #3#4+#5} { 0{0000}0000{#2}#3 #4 #5 } +\@@_tmp:w {x} {\use_none:nn #3#4+#5} { 00{0000}0000{#2}#3 #4 #5 } +\@@_tmp:w {xi} {\use_none:n #3#4+#5} { 000{0000}0000{#2}#3 #4 #5 } +\@@_tmp:w {xii} { #3#4+#5} { {0000}0000{0000}#2 #3 #4 #5 } +\@@_tmp:w {xiii}{\use_none:nnn#2#3+#4#5} { 0{0000}0000{0000}#2 #3 #4 #5 } +\@@_tmp:w {xiv} {\use_none:nn #2#3+#4#5} { 00{0000}0000{0000}#2 #3 #4 #5 } +\@@_tmp:w {xv} {\use_none:n #2#3+#4#5} { 000{0000}0000{0000}#2 #3 #4 #5 } +\@@_tmp:w {xvi} { #2#3+#4#5} {{0000}0000{0000}0000 #2 #3 #4 #5 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP, aux] +% {\@@_decimate_round:Nw, \@@_decimate_pack:nnnnnnnnnnw} +% \cs{@@_decimate_round:Nw} will receive the \enquote{extra digits} +% as its argument, and its expansion is triggered by \cs{__int_value:w}. +% If the first digit is neither $0$ nor $5$, then it is the \meta{rounding} +% digit. Otherwise, if the remaining digits are not all zero, we need +% to add $1$ to that leading digit to get the rounding digit. Some caution +% is required, though, because there may be more than $10$ +% \enquote{extra digits}, and this may overflow \TeX{}'s integers. +% Instead of feeding the digits directly to \cs{@@_decimate_round:Nw}, +% they come split into several blocks, separated by $+$. Hence the first +% \cs{__int_eval:w} here. +% \begin{macrocode} +\cs_new:Npn \@@_decimate_round:Nw #1 #2; + { + \if_int_odd:w \if_meaning:w 0 #1 \c_one \else: + \if_meaning:w 5 #1 \c_one \else: + \c_zero \fi: \fi: + \if_int_compare:w \__int_eval:w #2 > \c_zero + \__int_eval:w 1 + + \fi: + \fi: + #1 + } +% \end{macrocode} +% The computation of the \meta{rounding} digit leaves an unfinished +% \cs{__int_value:w}, which expands the following functions. This +% allows us to repack nicely the digits we keep. Those digits come +% as an alternation of unbraced and braced blocks of $4$ digits, +% such that the first $5$ groups of token consist in $4$ single digits, +% and one brace group (in some order), and the next $5$ have the same +% structure. This is followed by some digits and a semicolon. +% \begin{macrocode} +\cs_new:Npn \@@_decimate_pack:nnnnnnnnnnw #1#2#3#4#5 + { \@@_decimate_pack_ii:nnnnnnw { #1#2#3#4#5 } } +\cs_new:Npn \@@_decimate_pack_ii:nnnnnnw #1 #2#3#4#5#6 + { {#1} {#2#3#4#5#6} } +% \end{macrocode} +% \end{macro} +% ^^A end[todo] +% +% \subsection{Functions for use within primitive conditional branches} +% +% The functions described in this section are not pretty and can easily +% be misused. When correctly used, each of them removes one \cs{fi:} as +% part of its parameter text, and puts one back as part of its +% replacement text. +% +% Many computation functions in \pkg{l3fp} must perform tests on the +% type of floating points that they receive. This is often done in an +% \cs{if_case:w} statement or another conditional statement, and only a +% few cases lead to actual computations: most of the special cases are +% treated using a few standard functions which we define now. A typical +% use context for those functions would be +% \begin{syntax} +% |\if_case:w| \meta{integer} |\exp_stop_f:| +% | \@@_case_return_o:Nw| \meta{fp var} +% |\or: \@@_case_use:nw| \Arg{some computation} +% |\or: \@@_case_return_same_o:w| +% |\or: \@@_case_return:nw| \Arg{something} +% |\fi:| +% \meta{junk} +% \meta{floating point} +% \end{syntax} +% In this example, the case $0$ will return the floating point +% \meta{fp~var}, expanding once after that floating point. Case $1$ +% will do \meta{some computation} using the \meta{floating point} +% (presumably compute the operation requested by the user in that +% non-trivial case). Case $2$ will return the \meta{floating point} +% without modifying it, removing the \meta{junk} and expanding once +% after. Case $3$ will close the conditional, remove the \meta{junk} +% and the \meta{floating point}, and expand \meta{something} next. In +% other cases, the \enquote{\meta{junk}} is expanded, performing some +% other operation on the \meta{floating point}. We provide similar +% functions with two trailing \meta{floating points}. +% +% \begin{macro}[int, EXP]{\@@_case_use:nw} +% This function ends a \TeX{} conditional, removes junk until the next +% floating point, and places its first argument before that floating +% point, to perform some operation on the floating point. +% \begin{macrocode} +\cs_new:Npn \@@_case_use:nw #1#2 \fi: #3 \s_@@ { \fi: #1 \s_@@ } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_case_return:nw} +% This function ends a \TeX{} conditional, removes junk and a floating +% point, and places its first argument in the input stream. A quirk +% is that we don't define this function requiring a floating point to +% follow, simply anything ending in a semicolon. This, in turn, means +% that the \meta{junk} may not contain semicolons. +% \begin{macrocode} +\cs_new:Npn \@@_case_return:nw #1#2 \fi: #3 ; { \fi: #1 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_case_return_o:Nw} +% This function ends a \TeX{} conditional, removes junk and a floating +% point, and returns its first argument, a \meta{fp~var}, expanding +% once after it. +% \begin{macrocode} +\cs_new:Npn \@@_case_return_o:Nw #1#2 \fi: #3 \s_@@ #4 ; + { \fi: \exp_after:wN #1 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_case_return_same_o:w} +% This function ends a \TeX{} conditional, removes junk, and returns +% the following floating point, expanding once after it. +% \begin{macrocode} +\cs_new:Npn \@@_case_return_same_o:w #1 \fi: #2 \s_@@ + { \fi: \@@_exp_after_o:w \s_@@ } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_case_return_o:Nww} +% Same as \cs{@@_case_return_o:Nw} but with two trailing floating +% points. +% \begin{macrocode} +\cs_new:Npn \@@_case_return_o:Nww #1#2 \fi: #3 \s_@@ #4 ; #5 ; + { \fi: \exp_after:wN #1 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_case_return_ii_o:ww} +% Similar to \cs{@@_case_return_same_o:w}, but this returns the second +% of two trailing floating point numbers, expanding once after it. +% \begin{macrocode} +\cs_new:Npn \@@_case_return_ii_o:ww #1 \fi: #2 \s_@@ #3 ; + { \fi: \@@_exp_after_o:w } +% \end{macrocode} +% \end{macro} +% +% \subsection{Small integer floating points} +% +% \begin{macro}[int, EXP]{\@@_small_int:wTF} +% \begin{macro}[aux, EXP] +% { +% \@@_small_int_true:wTF, +% \@@_small_int_normal:NnwTF, +% \@@_small_int_test:NnnwNTF +% } +% This function tests if its floating point argument is an integer in +% the range $[-99999999,99999999]$. If it is, the result of the +% conversion is fed as a braced argument to the \meta{true code}. +% Otherwise, the \meta{false code} is performed. First filter special +% cases: neither \texttt{nan} nor infinities are integers. Normal +% numbers with a non-positive exponent are never integers. When the +% exponent is greater than $8$, the number is too large for the range. +% Otherwise, decimate, and test the digits after the decimal +% separator. The \cs{use_iii:nnn} remove a trailing |;| and the true +% branch, leaving only the false branch. The \cs{__int_value:w} +% appearing in the case where the normal floating point is an integer +% takes care of expanding all the conditionals until the trailing |;|. +% That integer is fed to \cs{@@_small_int_true:wTF} which places it as +% a braced argument of the true branch. +% \begin{macrocode} +\cs_new:Npn \@@_small_int:wTF \s_@@ \@@_chk:w #1 + { + \if_case:w #1 \exp_stop_f: + \@@_case_return:nw { \@@_small_int_true:wTF 0 ; } + \or: \exp_after:wN \@@_small_int_normal:NnwTF + \else: \@@_case_return:nw \use_ii:nn + \fi: + } +\cs_new:Npn \@@_small_int_true:wTF #1; #2#3 { #2 {#1} } +\cs_new:Npn \@@_small_int_normal:NnwTF #1#2#3; + { + \if_int_compare:w #2 > \c_zero + \if_int_compare:w #2 > \c_eight + \exp_after:wN \exp_after:wN + \exp_after:wN \use_iii:nnn + \else: + \@@_decimate:nNnnnn { \c_sixteen - #2 } + \@@_small_int_test:NnnwNTF + #3 #1 + \fi: + \else: + \exp_after:wN \use_iii:nnn + \fi: + ; + } +\cs_new:Npn \@@_small_int_test:NnnwNTF #1#2#3#4; #5 + { + \if_meaning:w 0 #1 + \exp_after:wN \@@_small_int_true:wTF + \__int_value:w \if_meaning:w 2 #5 - \fi: #3 + \else: + \exp_after:wN \use_iii:nnn + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Length of a floating point array} +% +% \begin{macro}[int, EXP]{\@@_array_count:w} +% \begin{macro}[aux, EXP]{\@@_array_count_loop:Nw} +% Count the number of items in an array of floating points. The +% technique is very similar to \cs{tl_count:n}, but with the loop +% built-in. Checking for the end of the loop is done with the +% |\use_none:n #1| construction. +% \begin{macrocode} +\cs_new:Npn \@@_array_count:w #1 @ + { + \int_use:N \__int_eval:w \c_zero + \@@_array_count_loop:Nw #1 { ? \__prg_break: } ; + \__prg_break_point: + \__int_eval_end: + } +\cs_new:Npn \@@_array_count_loop:Nw #1#2; + { \use_none:n #1 + \c_one \@@_array_count_loop:Nw } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Messages} +% +% Using a floating point directly is an error. +% \begin{macrocode} +\__msg_kernel_new:nnnn { kernel } { misused-fp } + { A~floating~point~with~value~'#1'~was~misused. } + { + To~obtain~the~value~of~a~floating~point~variable,~use~ + '\token_to_str:N \fp_to_decimal:N',~ + '\token_to_str:N \fp_to_scientific:N',~or~other~ + conversion~functions. + } +% \end{macrocode} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx new file mode 100644 index 00000000000..0b06d377232 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx @@ -0,0 +1,1634 @@ +% \iffalse meta-comment +% +%% File: l3fp-basics.dtx Copyright (C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-basics.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Floating-point arithmetic} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp-basics} package\thanks{This file +% has version number \ExplFileVersion, last +% revised \ExplFileDate.}\\ +% Floating point arithmetic} +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-basics} Implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% All operations implemented in this module yield the outcome of +% rounding the infinitely precise result of the operation to the +% nearest representable number. +% +% ^^A begin[todo]: move +% \section{Internal storage of floating points numbers} +% +% A floating point number \meta{X} is stored as +% \begin{quote} +% \cs{s_@@} \cs{@@_chk:w} \meta{case} \meta{sign} \meta{body} |;| +% \end{quote} +% Here, \meta{case} is 0 for $\pm 0$, 1 for normal numbers, 2 for $\pm +% \infty$, and 3 for \texttt{nan}, and \meta{sign} is $0$ for positive +% numbers, $1$ for \texttt{nan}s, and $2$ for negative numbers. The +% \meta{body} of normal numbers is \Arg{exponent} \Arg{X_1} \Arg{X_2} +% \Arg{X_3} \Arg{X_4}, with +% \[ +% \meta{X} = (-1)^{\meta{sign}} 10^{-\meta{exponent}} \sum_i +% \meta{X_i} 10^{-4i}. +% \] +% Calculations are done in base $10000$, \emph{i.e.} one myriad. The +% \meta{exponent} lies between $\pm\cs{c_@@_max_exponent_int} = \pm +% \the\csname\detokenize{c__fp_max_exponent_int}\endcsname$ inclusive. +% +% Additionally, positive and negative floating point numbers may only be +% stored with $1000\leq\meta{X_1}<10000$. This requirement is necessary +% in order to preserve accuracy and speed. +% +% ^^A end[todo] +% +% ^^A begin[todo] +% +% Some algorithms used below end up being quite similar to some +% described in \enquote{What Every Computer Scientist Should Know About +% Floating Point Arithmetic}, by David Goldberg, which can be found at +% \texttt{http://cr.yp.to/2005-590/goldberg.pdf}. I need to compare them +% very carefully. +% +% ^^A end[todo] +% +%^^A todo sanitize, pack. +% +% \subsection{Common to several operations} +% +% \begin{macro}[EXP] +% { +% \@@_basics_pack_low:NNNNNw , +% \@@_basics_pack_high:NNNNNw , +% \@@_basics_pack_high_carry:w +% } +% Addition and multiplication of mantissas are done in two steps: +% first compute a (more or less) exact result, +% then round and pack digits in the final (braced) form. +% These functions take care of the packing, with special attention +% given to the case where rounding has caused a carry. +% In \cs{@@_basics_pack_high_carry:w}, |#1| should +% always be $0000$. +% \begin{macrocode} +\cs_new:Npn \@@_basics_pack_low:NNNNNw #1 #2#3#4#5 #6; + { + \if_meaning:w 2 #1 + + \c_one + \fi: + ; {#2#3#4#5} {#6} ; + } +\cs_new:Npn \@@_basics_pack_high:NNNNNw #1 #2#3#4#5 #6; + { + \if_meaning:w 2 #1 + \@@_basics_pack_high_carry:w + \fi: + ; {#2#3#4#5} {#6} + } +\cs_new:Npn \@@_basics_pack_high_carry:w \fi: ; #1 + { \fi: + \c_one ; {1000} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \@@_basics_return_nan_nan:NNww , +% \@@_basics_return_zero:NNww , +% \@@_basics_return_inf:NNww , +% \@@_basics_return_i:NNNNww , +% \@@_basics_return_ii:NNNNww , +% \@@_basics_return_nan:NNNNww +% } +% \begin{syntax} +% \cs{@@_basics_return_...:NNww} +% ~~\meta{sign_1} \meta{sign_2} \meta{body_1} |;| \meta{body_2} |;| +% \end{syntax} +% Used for binary operations, to return a value for some special +% cases (common to several operations). All functions expand once +% after their arguments. +% +% ^^A todo: redoc, changed. +% The \texttt{nan_nan} function combines the \texttt{info} fields +% of the two \texttt{nan}.\footnote{Bruno: check that messages are +% kept.} +% The \texttt{zero} and \texttt{inf} functions return $\pm 0$ or +% $\pm\infty$ with a sign equal to the product of the two signs: +% three \cs{exp_after:wN} are needed to escape out of the +% conditional, and expand once after. +% The \texttt{i} and \texttt{ii} functions return one of their +% operands and expand after using \cs{@@_exp_after_o:w}. +% In some cases, this could be optimized, since we know in advance +% what case of number we have. However, it seems better to keep the +% number of control sequences low: these functions are called only +% in special cases anyways, so performance is not an issue. +% \begin{macrocode} +\cs_new:Npn \@@_basics_return_nan_nan:NNww #1#2 #3; #4; + { \@@_exp_after_o:w \s_@@ \@@_chk:w 3 1 #3 ; } +\cs_new:Npn \@@_basics_return_zero:NNww #1#2 #3; #4; + { + \if_meaning:w #1 #2 + \exp_after:wN \exp_after:wN \exp_after:wN \c_zero_fp + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \c_minus_zero_fp + \fi: + } +\cs_new:Npn \@@_basics_return_inf:NNww #1#2 #3; #4; + { + \if_meaning:w #1 #2 + \exp_after:wN \exp_after:wN \exp_after:wN \c_inf_fp + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \c_minus_inf_fp + \fi: + } +\cs_new:Npn \@@_basics_return_i:NNNNww #1#2 #3#4 #5; #6; + { \@@_exp_after_o:w \s_@@ \@@_chk:w #1 #3 #5; } +\cs_new:Npn \@@_basics_return_ii:NNNNww #1#2 #3#4 #5; #6; + { \@@_exp_after_o:w \s_@@ \@@_chk:w #2 #4 #6; } +\cs_new:Npn \@@_basics_return_nan:NNww #1#2 + { + \if_meaning:w 1 #1 + \exp_after:wN \@@_basics_return_i:NNNNww + \else: + \exp_after:wN \@@_basics_return_ii:NNNNww + \fi: + 3 3 #1 #2 + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Addition and subtraction} +% +% \begin{macro}[int, EXP]{\@@_+_o:ww} +% For addition, everything is easy. No need to grab the +% \meta{body_2}. +% \begin{macrocode} +\cs_new:cpn { @@_+_o:ww } + \s_@@ \@@_chk:w #1 #2 #3 ; \s_@@ \@@_chk:w #4 #5 + { \@@_add_cases:NN #1 #4 #2 #5 #3 ; } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_-_o:ww} +% Change the sign of the second argument. +% \begin{macrocode} +\cs_new:cpn { @@_-_o:ww } + \s_@@ \@@_chk:w #1 #2 #3 ; \s_@@ \@@_chk:w #4 #5 + { + \exp_after:wN \@@_add_cases:NN + \exp_after:wN #1 + \exp_after:wN #4 + \exp_after:wN #2 + \int_use:N \__int_eval:w \c_two - #5 \__int_eval_end: + #3 ; + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Sign, exponent, and special numbers} +% +% \begin{macro}[EXP,aux]{\@@_add_cases:NN} +% \begin{syntax} +% \cs{@@_add_cases:NN} \meta{case_1} \meta{case_2} +% ~~\meta{sign_1} \meta{sign_2} \meta{body_1} |;| \meta{body_2} |;| +% \end{syntax} +% This performs the addition. it also expands the following tokens +% on the input stream once. +% +% Whenever \meta{case_1} is different from \meta{case_2}, the result +% is simply the floating point number with the highest \meta{case}. +% For instance, adding a normal number to a zero gives the normal +% number, and adding a \texttt{nan} to any non-\texttt{nan} gives +% that \texttt{nan}. Optimizing for addition of normal numbers, +% we test for equality and then separate the \enquote{greater than} +% and \enquote{less than} branches. +% \begin{macrocode} +\cs_new:Npn \@@_add_cases:NN #1 #2 + { + \if_int_compare:w #1 = #2 \exp_stop_f: + \exp_after:wN \@@_add_cases_eq:N + \else: + \if_int_compare:w #1 < #2 \exp_stop_f: + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_basics_return_ii:NNNNww + \else: + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_basics_return_i:NNNNww + \fi: + \exp_after:wN #1 + \fi: + #2 + } +% \end{macrocode} +% If the first \meta{case} is larger, then the first number remains +% untouched, while the second number is ignored. On the other hand, +% if the second \meta{case} is larger, the opposite happens: we retain +% the second number. In both cases, there needs to be one step of +% expansion after. +% \begin{macrocode} +% \end{macrocode} +% We are then ready for the equality case: we split according +% to the \meta{case}. +% \begin{macrocode} +\cs_new:Npn \@@_add_cases_eq:N #1 + { + \if_case:w #1 \exp_stop_f: + \exp_after:wN \@@_add_zeros:NNww + \or: \exp_after:wN \@@_add_normal:NNww + \or: \exp_after:wN \@@_add_inf:NNww + \or: \exp_after:wN \@@_basics_return_nan_nan:NNww + \fi: + } +% \end{macrocode} +% Adding two zeros yields \cs{c_zero_fp}, except if both +% zeros were $-0$.\footnote{Bruno: this should depend on the +% rounding mode.} +% \begin{macrocode} +\cs_new:Npn \@@_add_zeros:NNww #1#2 #3; + { + \if_int_compare:w #1 #2 = 02 \exp_stop_f: + \@@_case_return_o:Nw \c_zero_fp + \else: + \@@_case_return_same_o:w + \fi: + \s_@@ \@@_chk:w 0 #2 + } +% \end{macrocode} +% If both infinities have the same sign, just return that infinity, +% otherwise, it is an invalid operation. +% \begin{macrocode} +\cs_new:Npn \@@_add_inf:NNww #1#2 #3; + { + \if_meaning:w #1 #2 + \@@_case_return_same_o:w + \else: + \@@_case_use:nw + { + \@@_invalid_operation:Nnww \c_nan_fp { + } + \s_@@ \@@_chk:w 2 #1 #3 ; + } + \fi: + \s_@@ \@@_chk:w 2 #2 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_add_normal:NNww} +% \begin{syntax} +% \cs{@@_add_normal:NNww} \meta{sign_1} \meta{sign_2} +% ~~\Arg{exp_1} \meta{body_1} |;| \Arg{exp_2} \meta{body_2} |;| +% \end{syntax} +% We now have two normal numbers to add, and we have to check signs +% and exponents more carefully before performing the addition. +% \begin{macrocode} +\cs_new:Npn \@@_add_normal:NNww #1#2 + { + \if_meaning:w #1#2 + \exp_after:wN \@@_add_npos:Nnwnw + \else: + \exp_after:wN \@@_sub_npos:Nnwnw + \fi: + #1 + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Absolute addition} +% +% In this subsection, we perform the addition +% of two positive normal numbers. +% +% \begin{macro}[EXP]{\@@_add_npos:Nnwnw} +% \begin{syntax} +% \cs{@@_add_npos:Nnwnw} \meta{sign} +% ~~\Arg{exp_1} \meta{body_1} |;| \Arg{exp_2} \meta{body_2} |;| +% \end{syntax} +% Since we are doing an addition, \meta{sign} will be the final sign. +% The only special case which may arise is the case of an overflow. +% This will be checked by \cs{@@_sanitize:Nw} at the end of +% the calculation. We start an \cs{__int_eval:w}, responsible for +% computing the exponent, which may receive a contribution of |+1| +% in case of carry. The exponent should be stopped by |;| followed by +% the overall \meta{sign} for the sanitizing to work properly. +% +% Grab and compare the exponents. The smaller number is decimated until +% its exponent reaches that of the bigger number. We need to bring the +% final sign down in the midst of the calculation to do the rounding +% correctly. +% \begin{macrocode} +\cs_new:Npn \@@_add_npos:Nnwnw #1 #2#3; #4 + { + \exp_after:wN \@@_sanitize:Nw + \exp_after:wN #1 + \int_use:N \__int_eval:w + \if_int_compare:w #2 > #4 \exp_stop_f: + #2 + \exp_after:wN \@@_add_big_i:wNww \__int_value:w - + \else: + #4 + \exp_after:wN \@@_add_big_ii:wNww \__int_value:w + \fi: + \__int_eval:w #4 - #2 ; #1 #3; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_add_big_i:wNww, +% \@@_add_big_ii:wNww} +% \begin{syntax} +% \cs{@@_add_big_i:wNww} \meta{shift} |;| \meta{sign} +% ~~\meta{body_1} |;| \meta{body_2} |;| +% \end{syntax} +% Shift the mantissa of the small number, and then add with +% \cs{@@_add_mantissa:NnnwnnnnN}. +% \begin{macrocode} +\cs_new:Npn \@@_add_big_i:wNww #1; #2 #3; #4; + { + \@@_decimate:nNnnnn {#1} + \@@_add_mantissa:NnnwnnnnN + #4 + #3 + #2 + } +\cs_new:Npn \@@_add_big_ii:wNww #1; #2 #3; #4; + { + \@@_decimate:nNnnnn {#1} + \@@_add_mantissa:NnnwnnnnN + #3 + #4 + #2 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_add_mantissa:NnnwnnnnN} +% \begin{syntax} +% \cs{@@_add_mantissa:NnnwnnnnN} +% ~~\meta{rounding} +% ~~\Arg{Y'_1} \Arg{Y'_2} \meta{extra-digits} |;| +% ~~\Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} +% ~~\meta{final sign} +% \end{syntax} +% To round properly, we must know at which digit the rounding +% should occur. This requires to know whether the addition +% produces an overall carry or not. Thus, we do the computation +% now and check for a carry, then go back and do the rounding. +% The rounding may cause a carry in very rare cases such as +% $0.99\cdots 95 \to 1.00\cdots 0$, but this situation always +% give an exact power of $10$, for which it is easy to correct +% the result at the end. +% \begin{macrocode} +\cs_new:Npn \@@_add_mantissa:NnnwnnnnN #1 #2#3 #4; #5#6#7#8 + { + \exp_after:wN \@@_add_mantissa_test:N + \int_use:N \__int_eval:w 1#5#6 + #2 + \exp_after:wN \@@_add_mantissa_pack:NNNNNNN + \int_use:N \__int_eval:w 1#7#8 + #3 ; #1 + } +% \end{macrocode} +% +% \begin{macrocode} +\cs_new:Npn \@@_add_mantissa_pack:NNNNNNN #1 #2#3#4#5#6#7 + { + \if:w 2 #1 + + \c_one + \fi: + ; #2 #3 #4 #5 #6 #7 ; + } +\cs_new:Npn \@@_add_mantissa_test:N #1 + { + \if:w 2 #1 + \exp_after:wN \@@_add_mantissa_carry:wwNNNN + \else: + \exp_after:wN \@@_add_mantissa_no_carry:wwNNNN + \fi: + } +% \end{macrocode} +% +% \begin{quote} +% \cs{@@_add_mantissa_no_carry:wwNNNN} +% ~~\meta{8d} |;| \meta{6d} |;| \meta{2d} |;| +% ~~\meta{rounding} \meta{sign} +% \end{quote} +% If there's no carry, grab all the digits again, and just +% set the rounding correctly.\footnote{Bruno: an optimization +% would be to compute whether we need rounding or not, +% and only grab digits if there is rounding.} +% +% \begin{macrocode} +\cs_new:Npn \@@_add_mantissa_no_carry:wwNNNN + #1; #2; #3#4 ; #5#6 + { + \exp_after:wN \@@_basics_pack_high:NNNNNw + \int_use:N \__int_eval:w 1 #1 + \exp_after:wN \@@_basics_pack_low:NNNNNw + \int_use:N \__int_eval:w 1 #2 #3#4 + + \@@_round:NNN #6 #4 #5 + \exp_after:wN ; + } +% \end{macrocode} +% +% The case where there is a carry is very similar: rounding can even +% raise the first digit from $1$ to $2$ (but we don't need to check that). +% \begin{quote} +% \cs{@@_add_mantissa_carry:wwNNNN} +% ~~\meta{8d} |;| \meta{6d} |;| \meta{2d} |;| +% ~~\meta{rounding} \meta{sign} +% \end{quote} +% \begin{macrocode} +\cs_new:Npn \@@_add_mantissa_carry:wwNNNN + #1; #2; #3#4; #5#6 + { + + \c_one + \exp_after:wN \@@_add_mantissa_carry_pack:NNNNNNNNw + \int_use:N \__int_eval:w 1 #1 + \exp_after:wN \@@_add_mantissa_carry_pack_ii:NNNNw + \int_use:N \__int_eval:w 1 #2#3 + + \@@_round:NNNN #6 #3 #4 #5 + \exp_after:wN ; + } +\cs_new:Npn \@@_add_mantissa_carry_pack_ii:NNNNw #1 #2#3#4 #5; + { + \if:w 2 #1 + + \c_one + \fi: + \__int_eval_end: + #2#3#4; {#5} ; + } +\cs_new:Npn \@@_add_mantissa_carry_pack:NNNNNNNNw + #1#2#3#4 #5#6#7#8 #9; { ; {#1#2#3#4} {#5#6#7#8} {#9} } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Absolute subtraction} +% +% \begin{macro}[EXP]{\@@_sub_npos:Nnwnw} +% \begin{syntax} +% \cs{@@_sub_npos:Nnwnw} \meta{sign} +% ~~\Arg{exp_1} \meta{body_1} |;| \Arg{exp_2} \meta{body_2} |;| +% \end{syntax} +% Rounding properly in some modes requires to know what the sign +% of the result will be. For addition, this was easy. Here, besides +% comparing the exponents to know how to decimate, we need to +% check carefully which number is bigger when they have the same +% exponent. +% \begin{macrocode} +\cs_new:Npn \@@_sub_npos:Nnwnw #1 #2#3; #4 #5; + { + \exp_after:wN \@@_sanitize:wN + \int_use:N \__int_eval:w + \if_int_compare:w #2 > #4 \exp_stop_f: + #2 + \exp_after:wN \@@_sub_big_i:wNww \__int_value:w - + \else: + #4 + \if_int_compare:w #2 = #4 \exp_stop_f: + \@@_sub_exponent_eq:nnnnnnnn #3 #5 + \else: + \exp_after:wN \@@_sub_big_ii:wNww \__int_value:w + \fi: + \fi: + \__int_eval:w #4 - #2 ; #1 #3; #5; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_sub_exponent_eq:nnnnnnnn} +% \begin{macrocode} +\cs_new:Npn \@@_sub_exponent_eq:nnnnnnnn #1#2#3#4 #5#6#7#8 + { + \if_int_compare:w #1#2 > #5#6 \exp_stop_f: + \exp_after:wN \@@_sub_big_i:wNww \__int_value:w + \else: + \if_int_compare:w #1#2 < #5#6 \exp_stop_f: + \exp_after:wN \@@_sub_big_ii:wNww \__int_value:w + \else: + \if_int_compare:w #3#4 > #7#8 \exp_stop_f: + \exp_after:wN \@@_sub_big_i:wNww \__int_value:w + \else: + \if_int_compare:w #3#4 < #7#8 \exp_stop_f: + \exp_after:wN \@@_sub_big_ii:wNww \__int_value:w + \else: + \exp_after:wN \@@_sub_eq:wNww \__int_value:w + \fi: + \fi: + \fi: + \fi: + } +\cs_new:Npn \@@_sub_eq:wNww #1; #2 #3; #4; + { \exp_after:wN ; \exp_after:wN 1 \exp_after:wN ; } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_sub_big_i:wNww,\@@_sub_big_ii:wNww} +% \begin{syntax} +% \cs{@@_sub_big_i:wNww} \meta{shift} |;| \meta{sign} +% ~~\meta{body_1} |;| \meta{body_2} |;| +% \end{syntax} +% Shift the mantissa of the small number, and then subtract with +% \cs{@@_sub_back_mantissa:NnnwNnnnn}. +% \begin{macrocode} +\cs_new:Npn \@@_sub_big_i:wNww #1; #2 #3; #4; + { + \@@_decimate:nNnnnn {#1} + \@@_sub_back_mantissa:NnnwNnnnn + #4 + #2 + #3 + } +\cs_new:Npn \@@_sub_big_ii:wNww #1; #2 #3; #4; + { + \exp_after:wN \@@_sub_big_i:wNww + \__int_value:w #1 \exp_after:wN ; + \int_use:N \__int_eval:w 2 - #2 \__int_eval_end: + #4; #3; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_sub_back_mantissa:NnnwNnnnn} +% \begin{syntax} +% \cs{@@_sub_back_mantissa:NnnwNnnnn} +% ~~\meta{rounding} \Arg{Y'_1} \Arg{Y'_2} \meta{extra-digits} +% ~~\meta{final sign} +% ~~\Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} +% \end{syntax} +% At this stage, we know that \meta{Y} is less than \meta{X}, +% and we know the final sign. +% \begin{macrocode} +\cs_new:Npn \@@_sub_back_mantissa:NnnwNnnnn #1 #2#3 #4; #5 #6#7#8#9 + { + \exp_after:wN \@@_sub_back_mantissa_i:NNwNNNNwN + \exp_after:wN #1 + \exp_after:wN #5 + \int_use:N \__int_eval:w 2#6#7 - #2 - \c_two + + \exp_after:wN \@@_sub_back_mantissa_round:wNN + \int_use:N \__int_eval:w 2#8#9 - #3 ; #1 #5 + } +% \end{macrocode} +% After the computation, we need to check whether the first digit of +% the result is zero. This can only happen if the two numbers had the +% same exponent, or exponents differing by $1$. In the latter case, +% the \meta{rounding} digit is not quite enough to let us retrieve +% the exact result (consider $\cdots25$ and $\cdots15$, both rounded +% to $\cdots2$ in the usual mode), so we also move the result of +% \cs{@@_round_neg:NNN} upstream as the digit $0$ or $1$. +% \begin{macrocode} +\cs_new:Npn \@@_sub_back_mantissa_round:wNN #1; #2 #3 + { + \exp_after:wN \@@_sub_back_mantissa_iii:N + \__int_value:w + \exp_after:wN \@@_round_neg:NNN + \exp_after:wN #3 + \use_none:nnnnnnnn #1 #2 + + #1 + \exp_after:wN ; + } +\cs_new:Npn \@@_sub_back_mantissa_iii:N #1 + { + \exp_after:wN \@@_sub_back_mantissa_ii:NNNNNNw + \exp_after:wN #1 + \int_use:N \__int_eval:w + - #1 + } +\cs_new:Npn \@@_sub_back_mantissa_ii:NNNNNNw #1 #2 #3#4#5#6 #7; + { #2 ; #1 {#3#4#5#6} {#7} ; } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_sub_back_mantissa_i:NNwNNNNwN} +% Here, |#3| should always be $2$, but we have to take is +% as a normal undelimited argument since that would break +% if |#2| is $2$. +% \begin{macrocode} +\cs_new:Npn \@@_sub_back_mantissa_i:NNwNNNNwN #1#2 #3 #4#5#6#7 #8; #9 + { + \if:w 0 #4 + \exp_after:wN \@@_sub_back_carry:NNwNnnnn + \exp_after:wN #1 + \exp_after:wN #9 + \fi: + ; #2 + {#4#5#6#7} {#8} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_sub_back_carry:NNwNnnnn} +% \begin{syntax} +% \cs{@@_sub_back_carry:NNwNnnnn} +% ~~\meta{rounding} \meta{0 or 1} |;| \meta{final sign} +% ~~\Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} |;| +% \end{syntax} +% This function is called when $\meta{Z_1}\leq 999$. We revert +% the carry, which is given by \meta{0 or 1}, and subtract the +% \meta{rounding} digit as appropriate, then feed the result, +% of the form \meta{$\leq$ 7d} |;| \meta{9d} |;| to +% \cs{@@_sub_back_carry_i:wwN}. The result is always exact. +% \begin{macrocode} +\cs_new:Npn \@@_sub_back_carry:NNwNnnnn #1#2 ; #3 #4#5#6#7 ; + { + \exp_after:wN \@@_sub_back_carry_i:wwN + \int_use:N \__int_eval:w #4 #5 - 1 + \exp_after:wN \@@_use_s:n + \int_use:N \__int_eval:w 1 #6 #7 0 + #2 0 - #1 ; #3 + } +% \end{macrocode} +% Unless the first block is zero, check how many digits is has, +% and shift the exponent down by the corresponding amount. Then +% pack digits into blocks of $4$ (there are between $10$ and $16$ +% digits in front of \cs{@@_sub_back_carry_large:NNNNNNNNw}). +% \begin{macrocode} +\cs_new:Npn \@@_sub_back_carry_i:wwN #1 ; + { + \if:w 0 #1 + - 8 + \exp_after:wN \@@_sub_back_carry_small:wN \__int_value:w + \else: + - \@@_sub_back_carry_ii:NNNNNNNNw #1 1234567; + \exp_after:wN \@@_sub_back_carry_large:NNNNNNNNw + \fi: + #1 + } +% \end{macrocode} +% The case where the number is non-zero is slightly easier. +% \begin{macrocode} +\cs_new:Npn \@@_sub_back_carry_ii:NNNNNNNNw #1#2#3#4#5#6#7#8#9; {#8} +\cs_new:Npn \@@_sub_back_carry_large:NNNNNNNNw #1#2#3#4 #5#6#7#8 #9; + { + \@@_sub_back_carry_large_ii:NNNNNNNNw + #9 000000 ; {#1#2#3#4} {#5#6#7#8} + } +\cs_new:Npn \@@_sub_back_carry_large_ii:NNNNNNNNw #1#2#3#4 #5#6#7#8 #9; + { \@@_sub_back_carry_large_iii:nnnnN {#1#2#3#4} {#5#6#7#8} } +\cs_new:Npn \@@_sub_back_carry_large_iii:nnnnN #1#2 #3#4 #5 + { ; #5 {#3}{#4} {#1}{#2} ; } +% \end{macrocode} +% In the case of a \enquote{small} result, what comes after +% \cs{@@_sub_back_carry_small:wN} has between $1$ +% and $9$ digits, and is not zero. +% \begin{macrocode} +\cs_new:Npn \@@_sub_back_carry_small:wN #1; + { + - \exp_after:wN \@@_use_i_until_s:nw + \use_none:nnnnnnnnn #1 012345678; + \@@_sub_back_carry_small_ii:NNNNNNNN #1 00000000 ; + } +\cs_new:Npn \@@_sub_back_carry_small_ii:NNNNNNNN #1#2#3#4 #5#6#7#8 + { \@@_sub_back_carry_small_iii:nnNwN {#1#2#3#4} {#5#6#7#8} } +\cs_new:Npn \@@_sub_back_carry_small_iii:nnNwN #1 #2 #3 #4; #5 + { ; #5 {#1} {#2} {#3000} {0000} ; } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Multiplication} +% +% \begin{macro}[int, EXP]{\@@_*_o:ww} +% For multiplication, everything is easy. No need to grab the +% \meta{body_2}. +% \begin{macrocode} +\cs_new:cpn { @@_*_o:ww } + \s_@@ \@@_chk:w #1 #2 #3 ; \s_@@ \@@_chk:w #4 #5 + { \@@_mul_cases:NN #1 #4 #2 #5 #3 ; } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Signs, and special numbers} +% +% \begin{macro}[EXP,aux]{\@@_mul_cases:NN} +% \begin{syntax} +% \cs{@@_mul_cases:NN} \meta{case_1} \meta{case_2} +% ~~\meta{sign_1} \meta{sign_2} \meta{body_1} |;| \meta{body_2} |;| +% \end{syntax} +% Expands the following tokens on the input stream once. +% The special cases are coded at the start of this module, +% and identical to the ones for division.\footnote{Bruno: \texttt{nan} +% are not treated properly: $\infty\times 0$ should signal.} +%^^A todo: use the faster \if_meaning:w. +% \begin{macrocode} +\cs_new:Npn \@@_mul_cases:NN #1 #2 + { + \if_case:w \if_meaning:w 1 #1 #2 \else: + \if_meaning:w 1 #2 #1 \else: + \if_meaning:w #1#2 #1 \else: + \if_int_compare:w \__int_eval:w #1 + #2 > \c_two + 3 \else: 4 \fi: \fi: \fi: \fi: + \exp_stop_f: + \exp_after:wN \@@_basics_return_zero:NNww + \or: \exp_after:wN \@@_mul_normal:NNww + \or: \exp_after:wN \@@_basics_return_inf:NNww + \or: \exp_after:wN \@@_basics_return_nan:NNww + \or: + \exp_after:wN \@@_mul_invalid:NNNNww + \exp_after:wN #1 + \exp_after:wN #2 + \fi: + } +\cs_new:Npn \@@_mul_invalid:NNNNww #1#2#3#4#5; #6; + { + \@@_invalid_operation:Nnww \c_nan_fp { * } + \s_@@ \@@_chk:w #1 #3 #5 ; + \s_@@ \@@_chk:w #2 #4 #6 ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_mul_normal:NNww} +% \begin{syntax} +% \cs{@@_mul_normal:NNww} \meta{sign_1} \meta{sign_2} +% ~~\Arg{exp_1} \meta{body_1} |;| \Arg{exp_2} \meta{body_2} |;| +% \end{syntax} +% We now have two normal numbers to multiply. Combine the signs. +% \begin{macrocode} +\cs_new:Npn \@@_mul_normal:NNww #1#2 + { + \if:w #1#2 + \exp_after:wN \@@_mul_npos:Nnwnw + \exp_after:wN 0 + \else: + \exp_after:wN \@@_mul_npos:Nnwnw + \exp_after:wN 2 + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Absolute multiplication} +% +% In this subsection, we perform the multiplication +% of two positive normal numbers. +% +% \begin{macro}[EXP]{\@@_mul_npos:Nnwnw} +% \begin{syntax} +% \cs{@@_mul_npos:Nnwnw} \meta{sign} +% ~~\Arg{exp_1} \meta{body_1} |;| \Arg{exp_2} \meta{body_2} |;| +% \end{syntax} +% As for addition, \meta{sign} is the final sign. After the computation, +% \cs{@@_sanitize:Nw} checks for overflow or underflow. +% As before, \cs{__int_eval:w} computes the exponent, catching any +% shift coming from the computation in the mantissa. Again, the +% \meta{sign} is needed for rounding to be done properly, so we move +% it around with us. We setup the post-expansion here, triggered by +% \cs{@@_mul_mantissa:nnnnNnnnn}. +% \begin{macrocode} +\cs_new:Npn \@@_mul_npos:Nnwnw #1 #2#3; #4 #5; + { + \exp_after:wN \@@_sanitize:Nw + \exp_after:wN #1 + \int_use:N \__int_eval:w + #2 + #4 + \@@_mul_mantissa:nnnnNnnnn #3 #1 #5 + \exp_after:wN ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_mul_mantissa:nnnnNnnnn} +% \begin{syntax} +% \cs{@@_mul_mantissa:nnnnNnnnn} +% ~~\Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \meta{sign} +% ~~\Arg{Y_1} \Arg{Y_2} \Arg{Y_3} \Arg{Y_4} \meta{;} +% \end{syntax} +% After one expansion, the token following \meta{Y_4} must be a semicolon +% (represented by \meta{;}). +% +% The product of two $16$ digit integers has $31$ or $32$ digits, +% but it is impossible to know which one before computing. The place +% where we round depends on that number of digits, and may depend +% on all digits until the last in some rare cases. The approach is +% thus to compute the $5$ first blocks of $4$ digits (the first one +% is between $100$ and $9999$ inclusive), and a compact version of +% the remaining $3$ blocks. Afterwards, the number of digits is +% known, and we can do the rounding within yet another set of +% \cs{__int_eval:w}. +% \begin{macrocode} +\cs_new:Npn \@@_mul_mantissa:nnnnNnnnn #1#2#3#4 #5 #6#7#8#9 + { + \exp_after:wN \@@_mul_mantissa_after:NNN + \exp_after:wN #5 + \int_use:N \__int_eval:w 99990000 + #1*#6 + + \exp_after:wN \@@_mul_mantissa_keep:NNNNNw + \int_use:N \__int_eval:w 99990000 + #1*#7 + #2*#6 + + \exp_after:wN \@@_mul_mantissa_keep:NNNNNw + \int_use:N \__int_eval:w 99990000 + #1*#8 + #2*#7 + #3*#6 + + \exp_after:wN \@@_mul_mantissa_drop:NNNNNw + \int_use:N \__int_eval:w 99990000 + #1*#9 + #2*#8 + #3*#7 + #4*#6 + + \exp_after:wN \@@_mul_mantissa_drop:NNNNNw + \int_use:N \__int_eval:w 99990000 + #2*#9 + #3*#8 + #4*#7 + + \exp_after:wN \@@_mul_mantissa_drop:NNNNNw + \int_use:N \__int_eval:w 99990000 + #3*#9 + #4*#8 + + \exp_after:wN \@@_mul_mantissa_drop:NNNNNw + \int_use:N \__int_eval:w 100000000 + #4*#9 \exp_after:wN ; + } +\cs_new:Npn \@@_mul_mantissa_drop:NNNNNw #1#2#3#4#5 #6; + { #1#2#3#4#5 ; + #6 } +\cs_new:Npn \@@_mul_mantissa_keep:NNNNNw #1#2#3#4#5 #6; + { #1#2#3#4#5 ; #6 ; } +% \end{macrocode} +% Once the first \cs{int_use:N} \cs{__int_eval:w}, and all the +% \cs{@@_mul_mantissa_...:NNNNNw} have been expanded, +% we get +% \begin{quote} +% \cs{@@_mul_mantissa_after:NNN} \meta{sign} |1| +% ~~\meta{digits 1--8} |;| \meta{digits 9--12} |;| \meta{digits 13--16} |;| +% ~~|+| \meta{digits 17--20} |+| \meta{digits 21--24} +% ~~|+| \meta{digits 25--28} |+| \meta{digits 29--32} |;| +% \end{quote} +% If the \meta{digit 1} is non-zero, then for rounding we only care +% about the digits $16$ and $17$, and whether all other digits are zero +% or not (check for exact ties). On the other hand, if \meta{digit 1} +% is zero, we care about digits $17$ and $18$, and whether all others are +% zero. +% \begin{macrocode} +\cs_new:Npn \@@_mul_mantissa_after:NNN #1 #2 #3 + { + \if:w 0 #3 + \exp_after:wN \@@_mul_mantissa_small:NNwwwN + \else: + \exp_after:wN \@@_mul_mantissa_large:NwwNNNN + \fi: + #1 #3 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_mul_mantissa_large:NwwNNNN} +% In this branch, \meta{digit 1} is non-zero. The result is thus +% \meta{digits 1--16}, plus some rounding which depends on the digits +% $16$, $17$, and whether all subsequent digits are zero or not. +% Here, \cs{@@_round_s:NNNw} takes the \meta{sign}, followed by +% digits $16$, $17$, and an integer expression which is zero if and +% only if all further digits are zero. +% \begin{macrocode} +\cs_new:Npn \@@_mul_mantissa_large:NwwNNNN #1 #2; #3; #4#5#6#7; + + { + \exp_after:wN \@@_basics_pack_high:NNNNNw + \int_use:N \__int_eval:w 1#2 + \exp_after:wN \@@_basics_pack_low:NNNNNw + \int_use:N \__int_eval:w 1#3#4#5#6#7 + \@@_round_s:NNNw #1 #7 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_mul_mantissa_small:NNwwwN} +% In this branch, \meta{digit 1} is zero. Our result will thus be +% \meta{digits 2--17}, plus some rounding which depends on the digits +% $17$, $18$, and whether all subsequent digits are zero or not. +% The $8$ digits |1#3| are followed, after expansion of the +% \texttt{small_pack} auxiliary, by the next digit, to form a $9$ +% digit number. Also, rounding may have caused a carry, which is +% then converted to \cs{c_ten} rather than the usual \cs{c_one}, +% because of the shift. +% \begin{macrocode} +\cs_new:Npn \@@_mul_mantissa_small:NNwwwN #1 #2#3; #4; #5; + #6 + { + - \c_one + \exp_after:wN \@@_basics_pack_high:NNNNNw + \int_use:N \__int_eval:w 1#3 + \exp_after:wN \@@_mul_mantissa_small_pack:NNNNNNw + \int_use:N \__int_eval:w 1#4#5#6 + \@@_round_s:NNNw #1 #6 + } +\cs_new:Npn \@@_mul_mantissa_small_pack:NNNNNNw #1#2 #3#4#5#6 #7; + { + #2 + \if:w 2 #1 + + \c_ten + \fi: + ; {#3#4#5#6} {#7} ; + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Division} +% +% Time is now ripe to tackle the hardest of the four elementary +% operations: division. +% +% \begin{macro}[EXP]{\@@_/_o:ww} +% For division we swap the two floating point numbers. +% \begin{macrocode} +\cs_new:cpn { @@_/_o:ww } + \s_@@ \@@_chk:w #1 #2 #3 ; \s_@@ \@@_chk:w #4 #5 #6 ; + { \@@_div_back_cases:NN #4 #1 #5 #2 #6 ; #3 ; } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Signs, and special numbers} +% +% In the case of division, the order of the operands matters, +% and it turns out to be slightly simpler if we internally +% compute the \enquote{backwards} division. +% +% \begin{macro}[EXP,aux]{\@@_div_back_cases:NN} +% \begin{syntax} +% \cs{@@_div_back_cases:NN} \meta{case_2} \meta{case_1} +% ~~\meta{sign_2} \meta{sign_1} \meta{body_2} |;| \meta{body_1} |;| +% \end{syntax} +% Expands the following tokens on the input stream once. +% \begin{macrocode} +\cs_new:Npn \@@_div_back_cases:NN #1 #2 + { + \if_case:w \if_int_compare:w #1 = #2 \exp_stop_f: + #1 \exp_stop_f: + \else: + \if_int_compare:w #1 < #2 \exp_stop_f: + \if:w 3 #2 \c_four \else: \c_five \fi: + \else: + \if:w 3 #1 \c_six \else: \c_seven \fi: + \fi: + \fi: + \exp_after:wN \@@_div_back_invalid:NNNww \exp_after:wN 0 + \or: \exp_after:wN \@@_div_back_normal:NNww + \or: \exp_after:wN \@@_div_back_invalid:NNNww \exp_after:wN 2 + \or: \exp_after:wN \@@_basics_return_nan_nan:NNww + \or: + \exp_after:wN \@@_basics_return_ii:NNNNww + \exp_after:wN #1 + \exp_after:wN #2 + \or: \exp_after:wN \@@_basics_return_inf:NNww + \or: + \exp_after:wN \@@_basics_return_i:NNNNww + \exp_after:wN #1 + \exp_after:wN #2 + \or: \exp_after:wN \@@_basics_return_zero:NNww + \fi: + } +% \end{macrocode} +% Most of the special cases are common with some +% previous operations. We only need to write the cases of +% $0/0$ and $\infty/\infty$. +% \begin{macrocode} +\cs_new:Npn \@@_div_back_invalid:NNNww #1#2#3 #4; #5; + { + \@@_invalid_operation:Nnww \c_nan_fp { / } + \s_@@ \@@_chk:w #1 #3 #5 ; + \s_@@ \@@_chk:w #1 #2 #4 ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_div_back_normal:NNww} +% \begin{syntax} +% \cs{@@_div_back_normal:NNww} \meta{sign_1} \meta{sign_2} +% ~~\Arg{exp_1} \meta{body_1} |;| \Arg{exp_2} \meta{body_2} |;| +% \end{syntax} +% We now have two normal numbers to divide. Combine the signs. +% \begin{macrocode} +\cs_new:Npn \@@_div_back_normal:NNww #1#2 + { + \if:w #1#2 + \exp_after:wN \@@_div_back_npos:Nnwnw + \exp_after:wN 0 + \else: + \exp_after:wN \@@_div_back_npos:Nnwnw + \exp_after:wN 2 + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Absolute (backwards) division} +% +% In this subsection, we perform the division +% of two positive normal numbers. +% +% \begin{macro}[EXP]{\@@_div_back_npos:Nnwnw} +% \begin{syntax} +% \cs{@@_div_back_npos:Nnwnw} \meta{sign} +% ~~\Arg{exp Z} \Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} |;| +% ~~\Arg{exp A} \Arg{A_1} \Arg{A_2} \Arg{A_3} \Arg{A_4} |;| +% \end{syntax} +% We want to compute $A/Z$. As for addition and multiplication, +% \meta{sign} is the final sign. Checking for underflow and +% overflow is done using the same auxiliary as for multiplication. +% As explained just below, we first compute $y$, which is +% the $5$ first digits of $Z$, plus $1$, and then compute pieces +% of the quotient roughly $4$ digits at a time. Here, |#1| is +% a single digit, |#2| and |#7| are the exponents (integers), +% |#8| is three brace groups, and all others are each $4$ digits. +% \begin{macrocode} +\cs_new:Npn \@@_div_back_npos:Nnwnw #1 #2 #3#4#5#6; #7 #8; + { + \exp_after:wN \@@_sanitize:Nw + \exp_after:wN #1 + \int_use:N \__int_eval:w + #7 - #2 + \@@_div_mantissa_i:wNwnn #3; #4; + #8 {#3}{#4}{#5}{#6} #1 + } +% \end{macrocode} +% \end{macro} +% +% We are given two numbers, $A=0.A_{1}A_{2}A_{3}A_{4}$ +% and $Z=0.Z_{1}Z_{2}Z_{3}Z_{4}$, in blocks of $4$ digits, +% and we know that the first digits of $A_{1}$ and of $Z_{1}$ +% are non-zero. To compute $A/Z$, we proceed as follows. +% \begin{itemize} +% \item Find an integer $Q_{1} \simeq 10^4 A / Z$. +% \item Replace $A$ by $B = 10^4 A - Q_{1} Z$. +% \item Find an integer $Q_{2} \simeq 10^4 B / Z$. +% \item Replace $B$ by $C = 10^4 B - Q_{2} Z$. +% \item Find an integer $Q_{3} \simeq 10^4 C / Z$. +% \item Replace $C$ by $D = 10^4 C - Q_{3} Z$. +% \item Find an integer $Q_{4} \simeq 10^4 D / Z$. +% \item Consider $E = 10^4 D - Q_{4} Z$, and ensure +% correct rounding. +% \end{itemize} +% The calculations of $B$, $C$, $D$, and $E$ can be done +% exactly with only $16$ (or $17$) digits. +% +% Unfortunately, things are not as easy as they seem. +% Firstly, we make sure that all intermediate steps are positive, +% since negative results would require extra calculations at the end. +% This requires that $Q_{1} \leq 10^4 A / Z$ etc. A reasonable +% attempt would be to define $Q_{1}$ as +% \[ +% \cs{int_eval:n} \left\{ +% \frac{ A_{1} A_{2} }{ Z_{1} + 1 } - 1 \right\}. +% \] +% Subtracting $1$ at the end takes care of the fact that e\TeX{}'s +% \cs{__int_eval:w} rounds instead of truncating. We add $1$ to $Z_{1}$ +% because $ Z_{1} \leq 10^4 Z < Z_{1}+1$ and we need $Q_{1}$ +% to be an underestimate. However, we are now underestimating +% $Q_{1}$ too much: it can be wrong by up to $100$, for instance +% when $Z = 0.1$ and $A \simeq 1$. Then $B$ could take values up to +% $10$ (maybe more), and a few steps down the line, we would run into +% arithmetic overflow, since \TeX{} can only handle integers less than +% roughly $2\cdot 10^9$. +% +% A better formula is to take +% \[ +% Q_{1} = \cs{int_eval:n} \left\{ +% \frac{ 10 \cdot A_{1} A_{2} } +% { \left\lfloor 10^{-3} \cdot Z_{1} Z_{2} \right\rfloor + 1 } +% - 1 \right\}. +% \] +% This is always less than $10^9 A / (10^5 Z)$, as we wanted. +% In words, we take the $5$ first digits of $Z$ into account, +% and the $8$ first digits of $A$, using $0$ as a $9$-th digit +% rather than the true digit for efficiency reasons. We shall +% prove that using this formula to define all the $Q_{i}$ +% leads to no overflow. For convenience, let us denote +% \[ +% y = \left\lfloor 10^{-3} \cdot Z_{1} Z_{2} \right\rfloor + 1, +% \] +% so that, taking into account the fact that e\TeX{} rounds ties +% away from zero, +% \[ +% Q_{1} = \left\lfloor A_{1}A_{2}0/y - 1/2 \right\rfloor. +% \] +% Note that $10^4<y\leq 10^5$, and $999 \leq Q_{1} \leq 99989$. +% Also note that this formula does not cause an overflow as long as +% $A<2.147\cdots$, since the numerator involves an integer slightly +% smaller than $10^9A$. +% +% Let us bound $B$: +% \begin{align*} +% 10^5 B +% &= +% A_{1}A_{2}0 + 10 \cdot 0.A_{3}A_{4} +% - 10 \cdot Z_{1}.Z_{2}Z_{3}Z_{4} +% \cdot \left\lfloor A_{1}A_{2}0/y - 1/2 \right\rfloor +% \\ +% &< +% A_{1}A_{2}0 +% \cdot \left( 1 - 10 \frac{Z_{1}.Z_{2}Z_{3}Z_{4}}{y} \right) +% + \frac{3}{2} \cdot 10 \cdot Z_{1}.Z_{2}Z_{3}Z_{4} + 10 +% \\ +% &\leq +% \frac{A_{1}A_{2}0 \cdot (y - 10 Z_{1}.Z_{2}Z_{3}Z_{4})}{y} +% + \frac{3}{2} y + 10 +% \\ +% &\leq +% \frac{A_{1}A_{2}0}{y} + \frac{3}{2} y + 10 +% \leq +% \frac{10^9 A}{y} + 1.6 y +% \end{align*} +% At the last step, we hide $10$ into the second term +% for later convenience. The same reasoning yields\footnote{Bruno: +% I need to find much better notations. These are not great.} +% \begin{align*} +% 10^5 B &< 10^9 A/y + 1.6 y, \\ +% 10^5 C &< 10^9 B/y + 1.6 y, \\ +% 10^5 D &< 10^9 C/y + 1.6 y, \\ +% 10^5 E &< 10^9 D/y + 1.6 y. \\ +% \end{align*} +% The goal is now to prove that none of $B$, $C$, $D$, and $E$ +% can go beyond $2.147\cdots$. Simply bounding each term on the +% right-hand side separately will not be tight enough: for instance, +% we would get $10^5 B < 10^5 + 1.6\cdot 10^5 = 2.6 \cdot 10^5$, +% which is too large. +% +% Combining the various inequalities together with $A<1$, we get +% \begin{align*} +% 10^5 B &< 10^9/y + 1.6 y, \\ +% 10^5 C &< 10^{13}/y^2 + 1.6 (y + 10^4), \\ +% 10^5 D &< 10^{17}/y^3 + 1.6 (y + 10^4 + 10^8/y), \\ +% 10^5 E &< 10^{21}/y^4 + 1.6 (y + 10^4 + 10^8/y + 10^{12}/y^2). \\ +% \end{align*} +% All of those bounds are convex functions of $y$ (since every power +% of $y$ involved is convex, and hte coefficients are positive), and +% thus maximal at one of the end-points of the allowed range +% $10^4<y\leq 10^5$. Thus, +% \begin{align*} +% 10^5 B &< \mathrm{max} ( 1.16\cdot 10^5, 1.7 \cdot 10^5), \\ +% 10^5 C &< \mathrm{max} ( 1.32\cdot 10^5, 1.77 \cdot 10^5), \\ +% 10^5 D &< \mathrm{max} ( 1.48\cdot 10^5, 1.777 \cdot 10^5), \\ +% 10^5 E &< \mathrm{max} ( 1.64\cdot 10^5, 1.7777 \cdot 10^5). \\ +% \end{align*} +% All of those bounds are less than $2.147\cdot 10^5$, and +% we are thus within \TeX{}'s bounds in all cases!\footnote{Bruno: +% but I need to check this very carefully again.} +% +% We will later need to have a bound on the $Q_{i}$. Their +% definitions imply that $Q_{1} < 10^9 A/y - 1/2 < 10^5 A$ and +% similarly for the other $Q_{i}$. Thus each of them is at most +% $177770$. +% +% The last step is to ensure correct rounding. We have +% \[ +% A/Z = \sum_{i=1}^4 \left(10^{-4i} Q_{i}\right) + 10^{-16} E/Z +% \] +% exactly. Furthermore, we know that the result will be between +% $0.1$ (inclusive) and $10$, so we only need to know the integer +% part of $E/Z$, and a \enquote{rounding} digit encoding the rest +% (see maybe addition for an explanation of why). Equivalently, +% we need to find the integer part of $2E/Z$, and determine whether +% it was an exact integer or not (this serves to detect ties). Since +% \[ +% \frac{2E}{Z} = 2\frac{10^5 E}{10^5 Z} +% \leq 2\frac{10^5 E}{10^4} < 36, +% \] +% this integer part is between $0$ and $35$ inclusive. We let +% e\TeX{} round +% \[ +% P = \cs{int_eval:n} \left\{ +% 2 \frac{E_{1}E_{2}}{Z_{1}Z_{2}} \right\}, +% \] +% which differs from $2E/Z$ by at most +% \[ +% \frac{1}{2} +% + 2 \left\lvert \frac{E}{Z} - \frac{E}{10^{-8} Z_{1}Z_{2}}\right\rvert +% + 2 \left\lvert \frac{10^8 E - E_{1}E_{2}}{Z_{1}Z_{2}}\right\rvert +% < 1, +% \] +% ($1/2$ comes from e\TeX{}'s rounding) because each absolute value +% is less than $10^{-7}$. Thus $P$ is either the correct integer part, +% or an overestimate by $1$ (impossible if $2E/Z$ is an integer). It +% then suffices to compare $PZ$ with $2E$ to get the integer part of +% $2E/Z$ and the information of whether it was an exact quotient or not. +% +% \begin{macro}[EXP]{\@@_div_mantissa_i:wNwnn} +% \begin{syntax} +% \cs{@@_div_mantissa_i:wNwnn} +% ~~\meta{Z_1} |;| \meta{Z_2} |;| +% ~~\Arg{A_1} \Arg{A_2} \Arg{A_3} \Arg{A_4} +% ~~\Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} \meta{sign} +% \end{syntax} +% First compute $y$ from the first $5$ digits of $Z$, and +% unbrace \meta{A_1} and \meta{A_2}. +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_i:wNwnn #1; #2 #3; #4 #5 + { + \exp_after:wN \@@_div_mantissa_ii:ww + \int_use:N \__int_eval:w #1#2 + \c_one ; + #4 #5 ; + } +% \end{macrocode} +% \begin{quote} +% \cs{@@_div_mantissa_ii:ww} +% ~~\meta{y} |;| \meta{A_1} \meta{A_2} |;| \Arg{A_3} \Arg{A_4} +% ~~\Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} \meta{sign} +% \end{quote} +% Compute $Q_{1}$ by evaluating $\meta{A_1}\meta{A_2}0/y - 1$. +% The result will be output to the left, in an \cs{__int_eval:w} +% which we start now. +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_ii:ww #1; #2; + { + \exp_after:wN \@@_div_mantissa_iii:www + \__int_value:w #1 \exp_after:wN ; + \__int_value:w + \exp_after:wN \@@_div_mantissa_calc:Nwwnnnnnn + \int_use:N \__int_eval:w #20/#1 + 999999 ; #2 ; + } +% \end{macrocode} +% \begin{quote} +% \cs{@@_div_mantissa_calc:Nwwnnnnnn} \meta{$10^6+{}$Q_1} |;| +% ~~\meta{A_1} \meta{A_2} |;| \Arg{A_3} \Arg{A_4} +% ~~\Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} \meta{sign} +% \end{quote} +% The goal here is to expand to +% \begin{quote} +% \meta{$10^6+{}$Q_1} |;| \meta{B_1} \meta{B_2} |;| \Arg{B_3} \Arg{B_4} +% ~~\Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} \meta{sign} +% \end{quote} +% where $B = 10^4 A - Q_{1} \cdot Z$. More generally, this function +% is used with $A\to B$, $B\to C$ and $Q_{1} \to Q_{2}$, etc. +% +% Computing the product $Q_{1} \cdot Z$ is almost simple, since +% $Q_{1}$ is rather small, but not quite: +% the product of $Q_{1}$ with each block of four digits $Z_{i}$ +% is within \TeX{}'s bounds, but we wouldn't be able to use the +% usual trick of adding a large power of $10$ to ensure that the +% number of digits is fixed (see other operations for many examples +% of this). Instead, we split off the digit of $10^5$ in $Q_{1}$ +% (and more generally $Q_{i}$), and do something similar to the +% case of the full multiplication. +% +% We know that $0<Q_{i}<1.8\cdot 10^5$, so $10^6+Q_{i}$ starts +% with the digit $1$, followed by $\#1 = 1$ or $0$, then |#2|, which +% is $5$ more digits. It would be somewhat simpler if we got |#1| +% to be two digits, and |#2| four, but we are constrained by the $9$ +% arguments limit. +% +% The result we want is then (the overall power of $10$ is arbitrary): +% \begin{align*} +% &10^{-4} ( \#3 - \#2 \cdot \#6 - 10 \cdot \#1 \cdot \#6\#7 ) +% + 10^{-8} ( \#4 - \#2 \cdot \#7 - 10 \cdot \#1 \cdot \#8 ) \\ +% &+ 10^{-12}( \#5 - \#2 \cdot \#8 - 10 \cdot \#1 \cdot \#9 ) +% + 10^{-16}( - \#2 \cdot \#9 ). +% \end{align*} +% The factors of $10$ come from the fact that +% $Q_{i} = 10\cdot 10^4 \cdot \#1 + \#2$. As usual, to combine +% all the terms, we need to choose some shifts which must ensure +% that the number of digits of the second, third, and fourth terms +% are each fixed. Here, a good choice is $2\cdot 10^9$. +% We are flirting with \TeX{}'s limits once more. +% +% If $\#1=0$, then each term in parentheses (omitting the first) +% is in the open interval $(-10^9, 10^4)$. Thus, adding +% $2\cdot 10^9$ to it gives a $10$ digits number.\footnote{Bruno: +% check that the carry from below does not screw that up. This +% requires slightly tighter bounds.} +% +% If $\#1=1$, then $\#2 < 7.8 \cdot 10^4$, and each term +% in parentheses (omitting the first) is in the interval +% $(-8\cdot 10^8, 10^4)$, and we are even safer. +% +% We add the terms containing $\#1$ in a slightly tricky way +% for efficiency reasons: if $\#1=0$, no need to do any computation, +% while if $\#1=1$ we want $10$ times some number, simply obtained +% by appending a $0$ digit. +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_calc:Nwwnnnnnn 1#1#2; #3;#4#5 #6#7#8#9 + { + 1 #1 #2 \exp_after:wN ; + \int_use:N \__int_eval:w + - 200000 + #3 - #2 * #6 + \if_meaning:w 1 #1 + - #6#70 + \fi: + + + \exp_after:wN \@@_div_mantissa_calc_last:NNNNNN + \int_use:N \__int_eval:w + 1999800000 + #4 - #2*#7 + \if_meaning:w 1 #1 + - #80 + \fi: + + + \exp_after:wN \@@_div_mantissa_calc_pack:NNNNNNw + \int_use:N \__int_eval:w + 1999800000 + #5 - #2*#8 + \if_meaning:w 1 #1 + - #90 + \fi: + + + \exp_after:wN \@@_div_mantissa_calc_pack:NNNNNNw + \int_use:N \__int_eval:w 2000000000 - #2*#9 ; + {#6}{#7}{#8}{#9} + } +\cs_new:Npn \@@_div_mantissa_calc_pack:NNNNNNw #1#2#3#4#5#6 #7; + { #1#2#3#4#5#6 ; {#7} } +\cs_new:Npn \@@_div_mantissa_calc_last:NNNNNN #1#2#3#4#5#6 + { #1#2#3#4#5#6 \__int_eval_end: } +% \end{macrocode} +% \begin{quote} +% \cs{@@_div_mantissa_iii:www} \meta{y} |;| \meta{$10^6+{}$Q_1} |;| +% ~~\meta{B_1} \meta{B_2} |;| \Arg{B_3} \Arg{B_4} +% ~~\Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} \meta{sign} +% \end{quote} +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_iii:www #1; #2; #3; + { + \exp_after:wN \@@_div_mantissa_iii_after:w + \int_use:N \__int_eval:w #2 + \exp_after:wN \@@_div_mantissa_iv:www + \__int_value:w #1 \exp_after:wN ; + \__int_value:w + \exp_after:wN \@@_div_mantissa_calc:Nwwnnnnnn + \int_use:N \__int_eval:w #30/#1 + 999999 ; + #3 ; + } +% \end{macrocode} +% \begin{quote} +% \cs{@@_div_mantissa_iv:www} \meta{y} |;| \meta{$10^6+{}$Q_2} |;| +% ~~\meta{C_1} \meta{C_2} |;| \Arg{C_3} \Arg{C_4} +% ~~\Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} \meta{sign} +% \end{quote} +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_iv:www #1; #2; #3; + { + \exp_after:wN \@@_div_mantissa_pack:NNN + \int_use:N \__int_eval:w #2 + \exp_after:wN \@@_div_mantissa_v:www + \__int_value:w #1 \exp_after:wN ; + \__int_value:w + \exp_after:wN \@@_div_mantissa_calc:Nwwnnnnnn + \int_use:N \__int_eval:w #30/#1 + 999999 ; + #3 ; + } +% \end{macrocode} +% \begin{quote} +% \cs{@@_div_mantissa_v:www} \meta{y} |;| \meta{$10^6+{}$Q_3} |;| +% ~~\meta{D_1} \meta{D_2} |;| \Arg{D_3} \Arg{D_4} +% ~~\Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} \meta{sign} +% \end{quote} +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_v:www #1; #2; #3; + { + \exp_after:wN \@@_div_mantissa_pack:NNN + \int_use:N \__int_eval:w #2 + \exp_after:wN \@@_div_mantissa_vi:wwnnnn + \__int_value:w + \exp_after:wN \@@_div_mantissa_calc:Nwwnnnnnn + \int_use:N \__int_eval:w #30/#1 + 999999 ; + #3 ; + } +% \end{macrocode} +% \begin{quote} +% \cs{@@_div_mantissa_vi:wwnnnn} \meta{$10^6+{}$Q_4} |;| +% ~~\meta{E_1} \meta{E_2} |;| \Arg{E_3} \Arg{E_4} +% ~~\Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} \meta{sign} +% \end{quote} +% We compute $P$ by rounding $2 E_{1} E_{2}/Z_{1}Z_{2}$. +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_vi:wwnnnn #1; #2;#3#4 #5#6 + { + \exp_after:wN \@@_div_mantissa_pack:NNN + \int_use:N \__int_eval:w #10 + \exp_after:wN \@@_div_mantissa_vii:wwnnnnnn + \int_use:N \__int_eval:w (\c_two*#2)/#5#6 ; % <- P + #2;{#3}{#4} + {#5}{#6} + } +% \end{macrocode} +% Note that we used |#10| instead of |#2| which we had previously. +% Two reasons: firstly, since we dropped $y$, the argument which +% holds $Q_{i}$ has changed, and secondly, we will want the +% fourth piece of the result to have $5$ digits, including the +% \meta{rounding} digit, which we shall compute now from $P$. +% \begin{quote} +% \cs{@@_div_mantissa_vii:wwnnnnnn} \meta{P} |;| +% ~~\meta{E_1} \meta{E_2} |;| \Arg{E_3} \Arg{E_4} +% ~~\Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} \meta{sign} +% \end{quote} +% Then compute $2E-PZ$. Once more, we need to be careful and show +% that the calculation $\#1\cdot\#5\#6$ below does not cause an +% overflow: naively, $P$ can be up to $35$, and $\#5\#6$ up to +% $10^8$, but both cannot happen simultaneously. To show that things +% are fine, we split in two (non-disjoint) cases. +% \begin{itemize} +% \item For small $P$, say, $P< 10$, the product obeys +% $P\cdot\#5\#6 < 10^8 \cdot P < 10^9 $. +% \item For large $P$, say, $P\geq 3$, the rounding error on $P$, +% which is at most $1$, is less than a factor of $2$, hence +% $P\leq 4E/Z$, and $P\cdot \#5\#6 \leq 4E\cdot 10^8 < 10^9$. +% \end{itemize} +% Both inequalities could be made tighter if needed. +% +% Note however that $P\cdot \#7\#8$ may overflow, +% since the two factors are now independent, and the result may reach +% $3.5\cdot 10^9$. +% +% Also, we add $10\cdot P/2$ to the \enquote{fourth piece} of the result +% as a first estimate of $10$ times $E/Z$. The goal is that the last digit +% (for now $0$ or $5$) should be the \meta{rounding} digit. More precisely, +% it will be corrected later by adding or subtracting $1$ depending on +% whether $F$ was the correct integer part, or an overestimate (and nothing +% is added when the quotient was exact). This does not give the +% \enquote{correct} \meta{rounding} digit, but it always gives a digit +% in the right \enquote{class} ($0$, $[1,4]$, $5$, or $[6-9]$), enough +% for rounding purposes. +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_vii:wwnnnnnn #1; #2;#3#4 #5#6#7#8 + { + + \c_five * #1 + \exp_after:wN \@@_div_mantissa_ix:Nww + \int_use:N \__int_eval:w -20 + 2*#2 - #1*#5#6 + + \exp_after:wN \@@_div_mantissa_viii:NNw + \int_use:N \__int_eval:w 199980 + 2*#3 - #1*#7 + + \exp_after:wN \@@_div_mantissa_viii:NNw + \int_use:N \__int_eval:w 200000 + 2*#4 - #1*#8 ; ; + } +\cs_new:Npn \@@_div_mantissa_viii:NNw #1#2#3; { #1#2 ; + #3 } +% \end{macrocode} +% \begin{quote} +% \cs{@@_div_mantissa_ix:Nww} +% ~~\meta{F_1} \meta{F_2} |;| |+| \meta{F_3} |+| \meta{F_4} |;| \meta{sign} +% \end{quote} +% where $F=2E-PZ$. We only need to know whether it is positive, +% negative, or exactly zero. +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_ix:Nww #1#2;#3; + { + \if_meaning:w 0 #1 + \exp_after:wN \@@_div_mantissa_x:w + \int_use:N \__int_eval:w #3 + \else: + \if_meaning:w - #1 + - + \else: + + + \fi: + \c_one + \fi: + ; + } +\cs_new:Npn \@@_div_mantissa_x:w #1; + { + \if_int_compare:w #1 > \c_zero + + \c_one + \fi: + ; + } +% \end{macrocode} +% We now obtain the following code, where \TeX{} is in the process +% of expanding each of the integer expressions, and thus expands +% the function at the bottom before the ones above it. +% \begin{quote} +% \cs{@@_div_mantissa_iii_after:w} $10^6 + Q_{1}$ +% \cs{@@_div_mantissa_pack:NNN} $10^6 + Q_{2}$ +% \cs{@@_div_mantissa_pack:NNN} $10^6 + Q_{3}$ +% \cs{@@_div_mantissa_pack:NNN} +% $10^7 + 10\cdot Q_{4} + 5 \cdot P + \varepsilon$ |;| \meta{sign} +% \end{quote} +% Here, $\varepsilon$ is $0$ in case $2E=PZ$ (\emph{i.e.}, $F=0$), +% $1$ in case $2E>PZ$, which means that $P$ was the correct value, +% but not with an exact quotient, and $-1$ if $2E<PZ$, \emph{i.e.}, +% $P$ was an overestimate. +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_pack:NNN 1 #1 #2 { + #1 #2 ; } +% \end{macrocode} +% Once those have been expanded, we get +% \begin{quote} +% \cs{@@_div_mantissa_iii_after:w} |1| |0| \meta{5d} |;| +% ~~\meta{4d} |;| \meta{4d} |;| \meta{5d} |;| \meta{sign} +% \end{quote} +% The reason we know that the first two digits are |1| and |0| +% is that the final result is known to be between $0.1$ (inclusive) +% and $10$, hence $\widetilde{Q_{1}}$ (the tilde denoting the +% contribution from the other $Q_{i}$) is at most $99999$, +% and $10^6+\widetilde{Q_{1}} = 10\cdots$. +% +% It is now time to round. This depends on how many digits +% the final result will have. +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_iii_after:w 10 #1 + { + \if_meaning:w 0 #1 + \exp_after:wN \@@_div_mantissa_small:wwwNNNNwN + \else: + \exp_after:wN \@@_div_mantissa_large:wwwNNNNwN + \fi: + #1 + } +% \end{macrocode} +% \begin{quote} +% \cs{@@_div_mantissa_small:wwwNNNNwN} |0| \meta{4d} |;| +% ~~\meta{4d} |;| \meta{4d} |;| \meta{5d} |;| \meta{sign} +% \end{quote} +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_small:wwwNNNNwN + 0 #1; #2; #3; #4#5#6#7#8; #9 + { + \exp_after:wN \@@_basics_pack_high:NNNNNw + \int_use:N \__int_eval:w 1 #1#2 + \exp_after:wN \@@_basics_pack_low:NNNNNw + \int_use:N \__int_eval:w 1 #3#4#5#6#7 + + \@@_round:NNN #9 #7 #8 + \exp_after:wN ; + } +% \end{macrocode} +% \begin{quote} +% \cs{@@_div_mantissa_large:wwwNNNNwN} \meta{5d} |;| +% ~~\meta{4d} |;| \meta{4d} |;| \meta{5d} |;| \meta{sign} +% \end{quote} +% \footnote{Bruno: rename the \enquote{add mantissa carry pack} function.} +% \begin{macrocode} +\cs_new:Npn \@@_div_mantissa_large:wwwNNNNwN + #1; #2; #3; #4#5#6#7#8; #9 + { + + \c_one + \exp_after:wN \@@_div_mantissa_large_pack:NNNNNNNNw + \int_use:N \__int_eval:w 1 #1 #2 %<- 1+9d + \exp_after:wN \@@_add_mantissa_carry_pack_ii:NNNNw + \int_use:N \__int_eval:w 1 #3 #4 #5 #6 + + \@@_round:NNNN #9 #6 #7 #8 + \exp_after:wN ; + } +\cs_new:Npn \@@_div_mantissa_large_pack:NNNNNNNNw + 1 #1#2#3#4 #5#6#7#8 #9; { ; {#1#2#3#4} {#5#6#7#8} {#9} } +% \end{macrocode} +% \end{macro} +% +% \subsection{Unary operations} +% +% \begin{macro}{\@@_neg:w} +% This function flips the sign of the \meta{floating point} +% and expands after it in the input stream, just like +% \cs{@@_+_o:ww} etc. +% \begin{macrocode} +\cs_new:Npn \@@_neg:w \s_@@ \@@_chk:w #1 #2 + { + \exp_after:wN \@@_exp_after_o:w + \exp_after:wN \s_@@ + \exp_after:wN \@@_chk:w + \exp_after:wN #1 + \int_use:N \__int_eval:w \c_two - #2 \__int_eval_end: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_abs:w} +% This function sets the sign of the \meta{floating point} to be +% positive, and expands after itself in the input stream, just like +% \cs{@@_neg:w}. +% \begin{macrocode} +\cs_new:Npn \@@_abs:w \s_@@ \@@_chk:w #1 #2 + { \@@_exp_after_o:w \s_@@ \@@_chk:w #1 0 } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx new file mode 100644 index 00000000000..057cef4b176 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx @@ -0,0 +1,476 @@ +% \iffalse meta-comment +% +%% File: l3fp-convert.dtx Copyright(C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-convert.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Floating-point conversion} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \textsf{l3fp-convert} package\\ Floating point conversion^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% ^^A todo: tests +% ^^A todo: doc functions +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\texttt{l3fp-convert} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{Trimming trailing zeros} +% +% \begin{macro}[int, EXP]{\@@_trim_zeros:w} +% \begin{macro}[aux, EXP] +% {\@@_trim_zeros_loop:w, \@@_trim_zeros_dot:w, \@@_trim_zeros_end:w} +% If |#1| ends with a $0$, the \texttt{loop} auxiliary takes that zero +% as an end-delimiter for its first argument, and the second argument +% is the same \texttt{loop} auxiliary. Once the last trailing zero is +% reached, the second argument will be the \texttt{dot} auxiliary, +% which removes a trailing dot if any. We then cleanup with the +% \texttt{end} auxiliary, keeping only the number. +% \begin{macrocode} +\cs_new:Npn \@@_trim_zeros:w #1 ; + { + \@@_trim_zeros_loop:w #1 + ; \@@_trim_zeros_loop:w 0; \@@_trim_zeros_dot:w .; \s__stop + } +\cs_new:Npn \@@_trim_zeros_loop:w #1 0; #2 { #2 #1 ; #2 } +\cs_new:Npn \@@_trim_zeros_dot:w #1 .; { \@@_trim_zeros_end:w #1 ; } +\cs_new:Npn \@@_trim_zeros_end:w #1 ; #2 \s__stop { #1 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Scientific notation} +% +% \begin{variable}{\c_@@_scientific_inf_tl} +% Result of converting $\infty$ to a scientific representation: after +% triggering an \enquote{invalid operation} exception, +% \cs{fp_to_scientific:n} yields that result, larger than any finite +% floating point number. +% \begin{macrocode} +\tl_const:Nx \c_@@_scientific_inf_tl + { 1e \int_use:N \c_@@_max_exponent_int } +% \end{macrocode} +% \end{variable} +% +% \begin{macro} +% {\fp_to_scientific:N, \fp_to_scientific:c, \fp_to_scientific:n} +% The three public functions evaluate their argument, then pass it to +% \cs{@@_to_scientific:w}. +% \begin{macrocode} +\cs_new:Npn \fp_to_scientific:N #1 { \exp_after:wN \@@_to_scientific:w #1 } +\cs_generate_variant:Nn \fp_to_scientific:N { c } +\cs_new:Npn \fp_to_scientific:n #1 + { + \exp_after:wN \@@_to_scientific:w + \tex_romannumeral:D -`0 \@@_parse:n {#1} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP] +% { +% \@@_to_scientific:w, +% \@@_to_scientific_normal:wnnnnn, +% \@@_to_scientific_normal:wNw +% } +% Expressing an internal floating point number in scientific notation +% is quite easy: no rounding, and the format is very well defined. +% First cater for the sign: negative numbers (|#2=2|) start with |-|. +% Then filter the special cases: we insert \cs{prg_do_nothing:} +% because \cs{@@_invalid_operation:Nnw} expands after taking one +% floating point argument. In the normal case, decrement the exponent +% and unbrace the $4$ brace groups, then in a second step grab the +% first digit (previously hidden in braces) to order the various parts +% correctly. Finally trim zeros. +% \begin{macrocode} +\cs_new:Npn \@@_to_scientific:w \s_@@ \@@_chk:w #1#2#3 ; + { + \if_meaning:w 2 #2 \exp_after:wN - \tex_romannumeral:D -`0 \fi: + \if_case:w #1 \exp_stop_f: + \@@_case_return:nw { \exp_after:wN 0 } + \or: \exp_after:wN \@@_to_scientific_normal:wnnnnn + \or: + \@@_case_use:nw + { + \@@_invalid_operation:Nnw + \c_@@_scientific_inf_tl { fp_to_scientific } + } + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw 0 { fp_to_scientific } } + \fi: + \s_@@ \@@_chk:w #1 #2 #3 ; \prg_do_nothing: + } +\cs_new:Npn \@@_to_scientific_normal:wnnnnn + \s_@@ \@@_chk:w 1 #1 #2 #3#4#5#6 ; \prg_do_nothing: + { + \if_int_compare:w #2 = \c_one + \exp_after:wN \@@_to_scientific_normal:wNw + \else: + \exp_after:wN \@@_to_scientific_normal:wNw + \exp_after:wN e + \int_use:N \__int_eval:w #2 - \c_one + \fi: + ; #3 #4 #5 #6 ; + } +\cs_new:Npn \@@_to_scientific_normal:wNw #1 ; #2#3; + { \@@_trim_zeros:w #2.#3 ; #1 } +% \end{macrocode} +% \end{macro} +% +% \subsection{Decimal representation} +% +% \begin{variable}{\c_@@_decimal_inf_tl} +% Result of converting $\infty$ to a decimal representation: after +% triggering an \enquote{invalid operation} exception, +% \cs{fp_to_decimal:n} yields a~$1$ followed by $\ExplSyntaxOn +% \int_use:N \c__fp_max_exponent_int$~$0$, larger than any finite +% floating point number. Since the expanded token list is very long, +% we use an \texttt{n}-type assignment. +% \begin{macrocode} +\tl_const:Nn \c_@@_decimal_inf_tl + { + \exp_after:wN \exp_after:wN \exp_after:wN 1 + \prg_replicate:nn \c_@@_max_exponent_int 0 + } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[EXP] +% {\fp_to_decimal:N, \fp_to_decimal:c, \fp_to_decimal:n} +% All three public variants are based on the same \cs{@@_to_decimal:w} +% after evaluating their argument to an internal floating point. +% \begin{macrocode} +\cs_new:Npn \fp_to_decimal:N #1 { \exp_after:wN \@@_to_decimal:w #1 } +\cs_generate_variant:Nn \fp_to_decimal:N { c } +\cs_new_nopar:Npn \fp_to_decimal:n + { + \exp_after:wN \@@_to_decimal:w + \tex_romannumeral:D -`0 \@@_parse:n + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP, aux] +% { +% \@@_to_decimal:w, +% \@@_to_decimal_normal:wnnnnn, +% \@@_to_decimal_large:Nnnw, +% \@@_to_decimal_huge:wnnnn, +% } +% The structure is similar to \cs{@@_to_scientific:w}. Insert |-| for +% negative numbers. Zero gives $0$, $\pm\infty$ and \nan{} yield an +% \enquote{invalid operation} exception. Normal numbers with an +% exponent in the range $[1,15]$ have that number of digits before the +% decimal separator: \enquote{decimate} them, and remove leading zeros +% with \cs{__int_value:w}, then trim trailing zeros and dot. Normal +% numbers with an exponent $16$ or larger have no decimal separator, +% we only need to add trailing zeros. When the exponent is +% non-positive, the result should be $0.\meta{zeros}\meta{digits}$, +% trimmed. +% \begin{macrocode} +\cs_new:Npn \@@_to_decimal:w \s_@@ \@@_chk:w #1#2#3 ; + { + \if_meaning:w 2 #2 \exp_after:wN - \tex_romannumeral:D -`0 \fi: + \if_case:w #1 \exp_stop_f: + \@@_case_return:nw { \exp_after:wN 0 } + \or: \exp_after:wN \@@_to_decimal_normal:wnnnnn + \or: + \@@_case_use:nw + { + \@@_invalid_operation:Nnw + \c_@@_decimal_inf_tl { fp_to_decimal } + } + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw 0 { fp_to_decimal } } + \fi: + \s_@@ \@@_chk:w #1 #2 #3 ; \prg_do_nothing: + } +\cs_new:Npn \@@_to_decimal_normal:wnnnnn + \s_@@ \@@_chk:w 1 #1 #2 #3#4#5#6 ; \prg_do_nothing: + { + \int_compare:nNnTF {#2} > \c_zero + { + \int_compare:nNnTF {#2} < \c_sixteen + { + \@@_decimate:nNnnnn { \c_sixteen - #2 } + \@@_to_decimal_large:Nnnw + } + { + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_to_decimal_huge:wnnnn + \prg_replicate:nn { #2 - \c_sixteen } { 0 } ; + } + {#3} {#4} {#5} {#6} + } + { + \exp_after:wN \@@_trim_zeros:w + \exp_after:wN 0 + \exp_after:wN . + \tex_romannumeral:D -`0 \prg_replicate:nn { - #2 } { 0 } + #3#4#5#6 ; + } + } +\cs_new:Npn \@@_to_decimal_large:Nnnw #1#2#3#4; + { + \exp_after:wN \@@_trim_zeros:w \__int_value:w + \if_int_compare:w #2 > \c_zero + #2 + \fi: + \exp_stop_f: + #3.#4 ; + } +\cs_new:Npn \@@_to_decimal_huge:wnnnn #1; #2#3#4#5 { #2#3#4#5 #1 } +% \end{macrocode} +% \end{macro} +% +% \subsection{Token list representation} +% +% \begin{macro}[EXP]{\fp_to_tl:N, \fp_to_tl:c, \fp_to_tl:n} +% These three public functions evaluate their argument, then pass it +% to \cs{@@_to_tl:w}. +% \begin{macrocode} +\cs_new:Npn \fp_to_tl:N #1 { \exp_after:wN \@@_to_tl:w #1 } +\cs_generate_variant:Nn \fp_to_tl:N { c } +\cs_new_nopar:Npn \fp_to_tl:n + { + \exp_after:wN \@@_to_tl:w + \tex_romannumeral:D -`0 \@@_parse:n + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP, aux]{\@@_to_tl:w, \@@_to_tl_normal:nnnnn} +% A structure similar to \cs{@@_to_scientific:w} and +% \cs{@@_to_decimal:w}, but without the \enquote{invalid operation} +% exception. First filter special cases. We express normal numbers +% in decimal notation if the exponent is in the range $[-2,16]$, and +% otherwise use scientific notation. The weird \cs{prg_do_nothing:} +% is needed because the \texttt{decimal} and \texttt{scientific} +% auxiliaries we use expect it. +% \begin{macrocode} +\cs_new:Npn \@@_to_tl:w \s_@@ \@@_chk:w #1#2 + { + \if_meaning:w 2 #2 \exp_after:wN - \tex_romannumeral:D -`0 \fi: + \if_case:w #1 \exp_stop_f: + \@@_case_return:nw { 0 } + \or: \exp_after:wN \@@_to_tl_normal:nnnnn + \or: \@@_case_return:nw { inf } + \else: \@@_case_return:nw { nan } + \fi: + } +\cs_new:Npn \@@_to_tl_normal:nnnnn #1#2 ; + { + \if_int_compare:w #1 > \c_sixteen + \exp_after:wN \@@_to_scientific_normal:wnnnnn + \else: + \if_int_compare:w #1 < - \c_two + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_to_scientific_normal:wnnnnn + \else: + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_to_decimal_normal:wnnnnn + \fi: + \fi: + \s_@@ \@@_chk:w 1 0 {#1} #2 ; \prg_do_nothing: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Formatting} +% +% ^^A todo +% +% \subsection{Convert to dimension or integer} +% +% \begin{macro}[EXP]{\fp_to_dim:N, \fp_to_dim:c, \fp_to_dim:n} +% These three public functions rely on \cs{fp_to_decimal:n} +% internally. +% \begin{macrocode} +\cs_new:Npn \fp_to_dim:N #1 { \fp_to_decimal:N #1 pt } +\cs_generate_variant:Nn \fp_to_dim:N { c } +\cs_new:Npn \fp_to_dim:n #1 { \fp_to_decimal:n {#1} pt } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\fp_to_int:N, \fp_to_int:c, \fp_to_int:n} +% These three public functions evaluate their argument, then pass it +% to \cs{fp_to_int:w}. +% \begin{macrocode} +\cs_new:Npn \fp_to_int:N #1 { \exp_after:wN \@@_to_int:w #1 } +\cs_generate_variant:Nn \fp_to_int:N { c } +\cs_new_nopar:Npn \fp_to_int:n + { + \exp_after:wN \@@_to_int:w + \tex_romannumeral:D -`0 \@@_parse:n + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_to_int:w} +% To convert to an integer, first round to $0$ places (to the nearest +% integer), then express the result as a decimal number: the +% definition of \cs{@@_to_decimal:w} is such that there will be no +% trailing dot nor zero. +% \begin{macrocode} +\cs_new:Npn \@@_to_int:w #1; + { + \exp_after:wN \@@_to_decimal:w \tex_romannumeral:D -`0 + \@@_round:Nwn \@@_round_to_nearest:NNN #1; { 0 } \prg_do_nothing: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Convert from a dimension} +% +% \begin{macro}[EXP]{\dim_to_fp:n} +% \begin{macro}[aux, EXP] +% { +% \@@_from_dim_test:N, +% \@@_from_dim:Nw, +% \@@_from_dim_ii:wNNnnnnnn, +% \@@_from_dim_iii:wnnnnwN, +% } +% The dimension expression (which can in fact be a glue expression) +% is evaluated, converted to a number (\emph{i.e.}, expressed in +% scaled points), then multiplied by $2^{-16} = 0.0000152587890625$ +% to give a value expressed in points. We use the auxiliary function +% \begin{quote} +% \cs{@@_mul_npos:Nnwnw} \meta{sign} \newline +% ~~\Arg{exp_1} \meta{body_1} |;| \Arg{exp_2} \meta{body_2} |;| +% \end{quote} +% \begin{macrocode} +\cs_new:Npn \dim_to_fp:n #1 + { + \exp_after:wN \@@_from_dim_test:N + \__int_value:w \etex_glueexpr:D #1 ; + } +\cs_new:Npn \@@_from_dim_test:N #1 + { + \if_meaning:w 0 #1 + \exp_after:wN \@@_use_i_until_s:nw + \exp_after:wN \c_zero_fp + \else: + \if_meaning:w - #1 + \exp_after:wN \@@_from_dim:Nw + \exp_after:wN 2 + \__int_value:w + \else: + \exp_after:wN \@@_from_dim:Nw + \exp_after:wN 0 + \__int_value:w #1 + \fi: + \fi: + } +\cs_new:Npn \@@_from_dim:Nw #1 #2; + { + \@@_pack_twice_four:wNNNNNNNN \@@_from_dim_ii:wNNnnnnnn ; + #2 000 0000 00 {10}987654321; #1 + } +\cs_new:Npn \@@_from_dim_ii:wNNnnnnnn #1; #2#3#4#5#6#7#8#9 + { \@@_from_dim_iii:wnnnnwN #1 {#2#300} {0000} ; } +\cs_new:Npn \@@_from_dim_iii:wnnnnwN #1; #2#3#4#5#6; #7 + { + \@@_mul_npos:Nnwnw #7 {#5} #1 ; + {-4} {1525} {8789} {0625} {0000} ; + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Use and eval} +% +% \begin{macro}[EXP]{\fp_use:N, \fp_use:c, \fp_eval:n} +% Those public functions are simple copies of the decimal conversions. +% \begin{macrocode} +\cs_new_eq:NN \fp_use:N \fp_to_decimal:N +\cs_generate_variant:Nn \fp_use:N { c } +\cs_new_eq:NN \fp_eval:n \fp_to_decimal:n +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\fp_abs:n} +% Trivial but useful. +% \begin{macrocode} +\cs_new:Npn \fp_abs:n #1 { \fp_to_decimal:n { abs ( #1 ) } } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx new file mode 100644 index 00000000000..edf9ac2ad35 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx @@ -0,0 +1,1252 @@ +% \iffalse meta-comment +% +%% File: l3fp-expo.dtx Copyright (C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-expo.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Floating-point exponential-related functions} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp-expo} package\thanks{This file +% has version number \ExplFileVersion, last +% revised \ExplFileDate.}\\ +% Floating point exponential-related functions} +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-expo} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{General comments} +% +%^^A todo: redoc +% The algorithm for computing the logarithm of the significand could be +% made to use a $5$ terms Taylor series instead of $10$ terms by taking +% $c = 2000/(\lfloor 200x\rfloor +1) \in [10,95]$ instead of $c\in +% [1,10]$. Also, it would then be possible to simplify the computation +% of $t$, using methods similar to \cs{@@_fixed_div_to_float:ww}. +% However, we would then have to hard-code the logarithms of $44$ small +% integers instead of $9$. +% +% \subsection{Some constants} +% +% ^^A todo: very odd: can I delete ln_ten? +% \begin{variable} +% { +% \c_@@_ln_i_fixed_tl , +% \c_@@_ln_ii_fixed_tl , +% \c_@@_ln_iii_fixed_tl , +% \c_@@_ln_iv_fixed_tl , +% \c_@@_ln_vi_fixed_tl , +% \c_@@_ln_vii_fixed_tl , +% \c_@@_ln_viii_fixed_tl , +% \c_@@_ln_ix_fixed_tl , +% \c_@@_ln_x_fixed_tl, +% \c_@@_ln_ten_fixed_tl, +% } +% A few values of the logarithm which are needed in the +% implementation. It turns out that we don't need the value of +% $\log(5)$. +% \begin{macrocode} +\tl_const:Nn \c_@@_ln_i_fixed_tl { {0000}{0000}{0000}{0000}{0000}{0000} } +\tl_const:Nn \c_@@_ln_ii_fixed_tl { {6931}{4718}{0559}{9453}{0941}{7232} } +\tl_const:Nn \c_@@_ln_iii_fixed_tl {{10986}{1228}{8668}{1096}{9139}{5245} } +\tl_const:Nn \c_@@_ln_iv_fixed_tl {{13862}{9436}{1119}{8906}{1883}{4464} } + % \tl_const:Nn \c_@@_ln_v_fixed_tl {{16094}{3791}{2434}{1003}{7460}{0759} } +\tl_const:Nn \c_@@_ln_vi_fixed_tl {{17917}{5946}{9228}{0550}{0081}{2477} } +\tl_const:Nn \c_@@_ln_vii_fixed_tl {{19459}{1014}{9055}{3133}{0510}{5353} } +\tl_const:Nn \c_@@_ln_viii_fixed_tl{{20794}{4154}{1679}{8359}{2825}{1696} } +\tl_const:Nn \c_@@_ln_ix_fixed_tl {{21972}{2457}{7336}{2193}{8279}{0490} } +\tl_const:Nn \c_@@_ln_x_fixed_tl {{23025}{8509}{2994}{0456}{8401}{7991} } + %\tl_const:Nn \c_@@_ln_ten_fixed_tl {{23025}{8509}{2994}{0456}{8401}{7991} } +% \end{macrocode} +% \end{variable} +% +% \subsection{Logarithm} +% +% \subsubsection{Sign, exponent, and special numbers} +% +% \begin{macro}[EXP]{\@@_ln:w} +% The logarithm of $\pm 0$ is $-\infty$, raising a division by zero +% exception. The logarithm of negative numbers (including $-\infty$, +% but not $-0$) raises the \enquote{invalid} exception. The logarithm +% of $+\infty$ or a \texttt{nan} is itself. Positive normal numbers +% call \cs{@@_ln_npos:w}. +% \begin{macrocode} +\cs_new:Npn \@@_ln:w \s_@@ \@@_chk:w #1 #2 + { + \if_meaning:w 0 #1 + \@@_case_use:nw + { \@@_division_by_zero:Nnw \c_minus_inf_fp { ln } } + \fi: + \if_meaning:w 2 #2 + \@@_case_use:nw + { \@@_invalid_operation:Nnw \c_nan_fp { ln } } + \fi: + \if_meaning:w 1 #1 \else: + \@@_case_return_same_o:w + \fi: + \@@_ln_npos:w \s_@@ \@@_chk:w #1#2 + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Absolute ln} +% +% We are given a positive normal number, of the form $a\cdot 10^{b}$ +% with $a\in[0.1,1)$. To compute its logarithm, we find a small integer +% $5\leq c < 50$ such that $0.91 \leq a c / 5 < 1.1$, and use the +% relation +% \[ +% \ln (a \cdot 10^b) = b \cdot \ln (10) - \ln (c/5) + \ln (ac/5). +% \] +% The logarithms $\ln(10)$ and $\ln(c/5)$ are looked up in a table. The +% last term is computed using the following Talor series of $\ln$ near +% $1$: +% \[ +% \ln\left(\frac{ac}{5}\right) +% = \ln\left(\frac{1+t}{1-t}\right) +% = 2t\left(1 + t^2 \left(\frac{1}{3} + t^2 \left(\frac{1}{5} +% + t^2 \left(\frac{1}{7} + t^2 \left( \frac{1}{9} + \cdots +% \right)\right)\right)\right)\right) +% \] +% where $t=1-10/(ac+5)$. We can now see one reason for the choice of +% $ac\sim 5$: then $ac+5=10(1-\epsilon)$ with $-0.05<\epsilon\leq +% 0.045$, hence +% \[ +% t = \frac{\epsilon}{1-\epsilon} +% = \epsilon (1+\epsilon)(1+\epsilon^2)(1+\epsilon^4)\ldots, +% \] +% is not too difficult to compute. +% +% \begin{macro}{\@@_ln_npos:w} +% We catch the case of a significand very close to $0.1$ or to $1$. +% In all other cases, the final result is at least $10^{-4}$, and +% then an error of $0.5\cdot 10^{-20}$ is acceptable. +% \begin{macrocode} +\cs_new:Npn \@@_ln_npos:w \s_@@ \@@_chk:w 10#1#2#3; + { %^^A todo: ln(1) should be "exact zero", not "underflow" + \exp_after:wN \@@_sanitize:Nw + \__int_value:w % for the overall sign + \if_int_compare:w #1 < \c_one + 2 + \else: + 0 + \fi: + \exp_after:wN \exp_stop_f: + \int_use:N \__int_eval:w % for the exponent + \@@_ln_significand:NNNNnnnN #2#3 + \@@_ln_exponent:wn {#1} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_ln_significand:NNNNnnnN} +% \begin{syntax} +% \cs{@@_ln_significand:NNNNnnnN} \meta{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \meta{continuation} +% \end{syntax} +% This function expands to +% \begin{quote} +% \meta{continuation} \Arg{Y_1} \Arg{Y_2} \Arg{Y_3} \Arg{Y_4} \Arg{Y_5} \Arg{Y_6} |;| +% \end{quote} +% where $Y = - \log X$. +% \begin{macrocode} +\cs_new:Npn \@@_ln_significand:NNNNnnnN #1#2#3#4 + { + \exp_after:wN \@@_ln_x_ii:wnnnn + \__int_value:w + \if_case:w #1 \exp_stop_f: + \or: + \if_int_compare:w #2 < \c_four + \__int_eval:w \c_ten - #2 + \else: + 6 + \fi: + \or: 4 + \or: 3 + \or: 2 + \or: 2 + \or: 2 + \else: 1 + \fi: + ; { #1 #2 #3 #4 } + } +% \end{macrocode} +% We have thus found $c$. It is chosen such that $0.7\leq ac < 1.4$ +% in all cases. Compute $ 1 + x = 1 + ac \in [1.7,2.4)$. +% \begin{macrocode} +\cs_new:Npn \@@_ln_x_ii:wnnnn #1; #2#3#4#5 + { + \exp_after:wN \@@_ln_div_after:Nw + \cs:w c_@@_ln_ \tex_romannumeral:D #1 _fixed_tl \exp_after:wN \cs_end: + \__int_value:w + \exp_after:wN \@@_ln_x_iv:nnnnnnnn + \tex_romannumeral:D -`0 + \exp_after:wN \@@_ln_x_iii_var:NNNNNw + \int_use:N \__int_eval:w 9999 9999 + #1*#2#3 + + \exp_after:wN \@@_ln_x_iii:NNNNNw + \int_use:N \__int_eval:w 1 0000 0000 + #1*#4#5 ; + {20000} {0000} {0000} {0000} + } %^^A todo: reoptimize (a generalization attempt failed). +\cs_new:Npn \@@_ln_x_iii:NNNNNw #1 #2#3#4#5 #6; { #1; {#2#3#4#5} {#6} } +\cs_new:Npn \@@_ln_x_iii_var:NNNNNw #1 #2#3#4#5 #6; { {#1#2#3#4#5} {#6} } +% \end{macrocode} +% The Taylor series will be expressed in terms of +% $t = (x-1)/(x+1) = 1 - 2/(x+1)$. We now compute the +% quotient with extended precision, reusing some code +% from \cs{@@_/_o:ww}. Note that $1+x$ is known exactly. +% +% To reuse notations from \pkg{l3fp-basics}, we want to +% compute $ A / Z $ with $ A = 2 $ and $ Z = x + 1 $. +% In \pkg{l3fp-basics}, we considered the case where +% both $A$ and $Z$ are arbitrary, in the range $[0.1,1)$, +% and we had to monitor the growth of the sequence of +% remainders $A$, $B$, $C$, etc. to ensure that no overflow +% occured during the computation of the next quotient. +% The main source of risk was our choice to define the +% quotient as roughly $10^9 \cdot A / 10^5 \cdot Z$: then +% $A$ was bound to be below $2.147\cdots$, and this limit +% was never far. +% +% In our case, we can simply work with $10^8 \cdot A$ and +% $10^4 \cdot Z$, because our reason to work with higher +% powers has gone: we needed the integer $y \simeq 10^5 \cdot Z$ +% to be at least $10^4$, and now, the definition +% $y \simeq 10^4 \cdot Z$ suffices. +% +% Let us thus define $y = \left\lfloor 10^4 \cdot Z \right\rfloor + 1 +% \in ( 1.7 \cdot 10^4, 2.4 \cdot 10^4 ] $, and +% \[ +% Q_{1} +% = +% \left\lfloor +% \frac {\left\lfloor 10^8 \cdot A\right\rfloor} {y} - \frac{1}{2} +% \right\rfloor. +% \] +% (The $1/2$ comes from how e\TeX{} rounds.) As for division, it is +% easy to see that $Q_{1} \leq 10^4 A / Z$, \emph{i.e.}, $Q_{1}$ +% is an underestimate. +% +% Exactly as we did for division, we set $B = 10^4 A - Q_{1}Z$. Then +% \begin{align*} +% 10^4 B +% \leq +% A_{1}A_{2}.A_{3}A_{4} +% - \left( \frac{A_{1}A_{2}}{y} - \frac{3}{2} \right) 10^4 Z +% \leq +% A_{1}A_{2} \left( 1 - \frac{10^4 Z}{y} \right) + 1 + \frac{3}{2} y +% \leq +% 10^8 \frac{A}{y} + 1 + \frac{3}{2} y +% \end{align*} +% In the same way, and using $1.7\cdot 10^4\leq y\leq 2.4\cdot 10^4$, +% and convexity, we get +% \begin{align*} +% 10^4 A &= 2\cdot 10^4 \\ +% 10^4 B &\leq 10^8 \frac{A}{y} + 1.6 y \leq 4.7\cdot 10^4\\ +% 10^4 C &\leq 10^8 \frac{B}{y} + 1.6 y \leq 5.8\cdot 10^4\\ +% 10^4 D &\leq 10^8 \frac{C}{y} + 1.6 y \leq 6.3\cdot 10^4\\ +% 10^4 E &\leq 10^8 \frac{D}{y} + 1.6 y \leq 6.5\cdot 10^4\\ +% 10^4 F &\leq 10^8 \frac{E}{y} + 1.6 y \leq 6.6\cdot 10^4\\ +% \end{align*} +% Note that we compute more steps than for division: since $t$ is +% not the end result, we need to know it with more accuracy +% (on the other hand, the ending is much simpler, as we don't +% need an exact rounding for transcendental functions, but just +% a faithful rounding).\footnote{Bruno: to be completed.} +% +% \begin{quote} +% \cs{@@_ln_x_iv:NNNNNwnn} +% \meta{1 or 2} \meta{8d} |;| \Arg{4d} \Arg{4d} \meta{fixed-tl} +% \end{quote} +% The number is $x$. Compute $y$ by adding 1 to the five first digits. +% \begin{macrocode} +\cs_new:Npn \@@_ln_x_iv:nnnnnnnn #1#2#3#4 #5#6#7#8 + { + \exp_after:wN \@@_ln_div_i:w + \int_use:N \__int_eval:w #1 + \c_one ; + #5 #6 ; {#7} {#8} + {#1} {#2} {#3} {#4} + } +\cs_new:Npn \@@_ln_div_i:w #1; + { + \exp_after:wN \@@_ln_div_ii:www + \__int_value:w #1 \exp_after:wN ; + \__int_value:w + \exp_after:wN \@@_div_mantissa_calc:Nwwnnnnnn + \int_use:N \__int_eval:w 999999 + 2 0000 0000 / #1 ; % Q1 + } +\cs_set_protected:Npn \@@_tmp:w #1#2 + { + \cs_new:Npn #1 ##1; ##2; ##3; % y; Q1; B1B2; <- for k=1 + { + \exp_after:wN \@@_div_mantissa_pack:NNN + \int_use:N \__int_eval:w ##2 + \exp_after:wN #2 + \__int_value:w ##1 \exp_after:wN ; + \__int_value:w + \exp_after:wN \@@_div_mantissa_calc:Nwwnnnnnn + \int_use:N \__int_eval:w 999999 + ##3 / ##1 ; % Q2 + ##3 ; + } + } +\@@_tmp:w \@@_ln_div_ii:www \@@_ln_div_iii:www +\@@_tmp:w \@@_ln_div_iii:www \@@_ln_div_iv:www +\@@_tmp:w \@@_ln_div_iv:www \@@_ln_div_v:www +\@@_tmp:w \@@_ln_div_v:www \@@_ln_div_vi:www +\cs_new:Npn \@@_ln_div_vi:www #1; #2; #3;#4#5 #6#7#8#9 %y;Q5;F1F2;F3F4x1x2x3x4 + { + \exp_after:wN \@@_div_mantissa_pack:NNN + \int_use:N \__int_eval:w #2 + \exp_after:wN \@@_div_mantissa_pack:NNN + \int_use:N \__int_eval:w 1000000 + #3 / #1 ; % Q6 + } +% \end{macrocode} +% We now have essentially\footnote{Bruno: add a mention that +% the error on $Q_{6}$ is bounded by $10$ (probably $6.7$), +% and thus corresponds to an error of $10^{-23}$ on the final +% result, small enough in all cases.} +% \begin{quote} +% \cs{@@_ln_div_after:Nw} \meta{fixed tl} +% \cs{@@_div_mantissa_pack:NNN} $10^6 + Q_{1}$ +% \cs{@@_div_mantissa_pack:NNN} $10^6 + Q_{2}$ +% \cs{@@_div_mantissa_pack:NNN} $10^6 + Q_{3}$ +% \cs{@@_div_mantissa_pack:NNN} $10^6 + Q_{4}$ +% \cs{@@_div_mantissa_pack:NNN} $10^6 + Q_{5}$ +% \cs{@@_div_mantissa_pack:NNN} $10^6 + Q_{6}$ |;| +% \meta{exponent} |;| \meta{continuation} +% \end{quote} +% where \meta{fixed tl} holds the logarithm of a number +% in $[1,10]$, and \meta{exponent} is +% the exponent. Also, the expansion is done backwards. Then +% \cs{@@_div_mantissa_pack:NNN} puts things in the +% correct order to add the $Q_{i}$ together and put semicolons +% between each piece. Once those have been expanded, we get +% \begin{quote} +% \cs{@@_ln_div_after:Nw} \meta{fixed-tl} \meta{1d} |;| \meta{4d} |;| \meta{4d} |;| \meta{4d} |;| \meta{4d} |;| \meta{4d} |;| \meta{4d} |;| \meta{exponent} |;| +% \end{quote} +% ^^A todo: redoc. +% Just as with division, we know that the first two digits +% are |1| and |0| because of bounds on the final result of +% the division $2/(x+1)$, which is between roughly $0.8$ and $1.2$. +% We then compute $1-2/(x+1)$, after testing whether $2/(x+1)$ is +% greater than or smaller than $1$. +% \begin{macrocode} +\cs_new:Npn \@@_ln_div_after:Nw #1#2; + { + \if_meaning:w 0 #2 + \exp_after:wN \@@_ln_t_small:Nw + \else: + \exp_after:wN \@@_ln_t_large:NNw + \exp_after:wN - + \fi: + #1 + } +\cs_new:Npn \@@_ln_t_small:Nw #1 #2; #3; #4; #5; #6; #7; + { + \exp_after:wN \@@_ln_t_large:NNw + \exp_after:wN + % <sign> + \exp_after:wN #1 + \int_use:N \__int_eval:w 9999 - #2 \exp_after:wN ; + \int_use:N \__int_eval:w 9999 - #3 \exp_after:wN ; + \int_use:N \__int_eval:w 9999 - #4 \exp_after:wN ; + \int_use:N \__int_eval:w 9999 - #5 \exp_after:wN ; + \int_use:N \__int_eval:w 9999 - #6 \exp_after:wN ; + \int_use:N \__int_eval:w 1 0000 - #7 ; + } +% \end{macrocode} +% +% \begin{quote} +% \cs{@@_ln_t_large:NNw} \meta{sign}\meta{fixed tl} \meta{t_1}|;| \meta{t_2} |;| \meta{t_3}|;| \meta{t_4}|;| \meta{t_5} |;| \meta{t_6}|;| \meta{exponent} |;| \meta{continuation} +% \end{quote} +% Compute the square $|t|^2$, and keep $|t|$ at the end with its +% sign. We know that $|t|<0.1765$, so every piece has at most $4$ +% digits. However, since we were not careful in \cs{@@_ln_t_small:w}, +% they can have less than $4$ digits. +% \begin{macrocode} +\cs_new:Npn \@@_ln_t_large:NNw #1 #2 #3; #4; #5; #6; #7; #8; + { + \exp_after:wN \@@_ln_square_t_after:w + \int_use:N \__int_eval:w 9999 0000 + #3*#3 + \exp_after:wN \@@_ln_square_t_pack:NNNNNw + \int_use:N \__int_eval:w 9999 0000 + 2*#3*#4 + \exp_after:wN \@@_ln_square_t_pack:NNNNNw + \int_use:N \__int_eval:w 9999 0000 + 2*#3*#5 + #4*#4 + \exp_after:wN \@@_ln_square_t_pack:NNNNNw + \int_use:N \__int_eval:w 9999 0000 + 2*#3*#6 + 2*#4*#5 + \exp_after:wN \@@_ln_square_t_pack:NNNNNw + \int_use:N \__int_eval:w 1 0000 0000 + 2*#3*#7 + 2*#4*#6 + #5*#5 + + (2*#3*#8 + 2*#4*#7 + 2*#5*#6) / 1 0000 + % ; ; ; + \exp_after:wN \@@_ln_twice_t_after:w + \int_use:N \__int_eval:w -1 + 2*#3 + \exp_after:wN \@@_ln_twice_t_pack:Nw + \int_use:N \__int_eval:w 9999 + 2*#4 + \exp_after:wN \@@_ln_twice_t_pack:Nw + \int_use:N \__int_eval:w 9999 + 2*#5 + \exp_after:wN \@@_ln_twice_t_pack:Nw + \int_use:N \__int_eval:w 9999 + 2*#6 + \exp_after:wN \@@_ln_twice_t_pack:Nw + \int_use:N \__int_eval:w 9999 + 2*#7 + \exp_after:wN \@@_ln_twice_t_pack:Nw + \int_use:N \__int_eval:w 10000 + 2*#8 ; ; + { \@@_ln_c:NwNw #1 } + #2 + } +\cs_new:Npn \@@_ln_twice_t_pack:Nw #1 #2; { + #1 ; {#2} } +\cs_new:Npn \@@_ln_twice_t_after:w #1; { ;;; {#1} } +\cs_new:Npn \@@_ln_square_t_pack:NNNNNw #1 #2#3#4#5 #6; + { + #1#2#3#4#5 ; {#6} } +\cs_new:Npn \@@_ln_square_t_after:w 1 0 #1#2#3 #4; + { \@@_ln_Taylor:wwNw {0#1#2#3} {#4} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_ln_Taylor:wwNw} +% Denoting $T=t^2$, we get +% \begin{quote} +% \cs{@@_ln_Taylor:wwNw} +% \Arg{T_1} \Arg{T_2} \Arg{T_3} \Arg{T_4} \Arg{T_5} \Arg{T_6} |;| |;| +% \Arg{(2t)_1} \Arg{(2t)_2} \Arg{(2t)_3} \Arg{(2t)_4} \Arg{(2t)_5} \Arg{(2t)_6} |;| +% |{| \cs{@@_ln_c:NwNn} \meta{sign} |}| +% \meta{fixed tl} \meta{exponent} |;| \meta{continuation} +% \end{quote} +% And we want to compute +% \[ +% \ln\left(\frac{1+t}{1-t}\right) +% = 2t\left(1 + T \left(\frac{1}{3} + T \left(\frac{1}{5} +% + T \left(\frac{1}{7} + T \left( \frac{1}{9} + \cdots +% \right)\right)\right)\right)\right) +% \] +% The process looks as follows +% \begin{verbatim} +% \loop 5; A; +% \div_int 5; 1.0; \add A; \mul T; {\loop \eval 5-2;} +% \add 0.2; A; \mul T; {\loop \eval 5-2;} +% \mul B; T; {\loop 3;} +% \loop 3; C; +% \end{verbatim} +% \footnote{Bruno: add explanations.} +% +% This uses the routine for dividing a number by a small integer +% (${}<10^4$). +% \begin{macrocode} +\cs_new:Npn \@@_ln_Taylor:wwNw + { \@@_ln_Taylor_loop:www 21 ; {0000}{0000}{0000}{0000}{0000}{0000} ; } +\cs_new:Npn \@@_ln_Taylor_loop:www #1; #2; #3; + { + \if_int_compare:w #1 = \c_one + \@@_ln_Taylor_break:w + \fi: + \exp_after:wN \@@_fixed_div_int:wwN \c_@@_one_fixed_tl ; #1; + \@@_fixed_add:wwN #2; + \@@_fixed_mul:wwn #3; + { + \exp_after:wN \@@_ln_Taylor_loop:www + \int_use:N \__int_eval:w #1 - \c_two ; + } + #3; + } +\cs_new:Npn \@@_ln_Taylor_break:w \fi: #1 \@@_fixed_add:wwN #2#3; #4 ;; + { + \fi: + \exp_after:wN \@@_fixed_mul:wwn + \exp_after:wN { \int_use:N \__int_eval:w 10000 + #2 } #3; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_ln_c:NwNw} +% \begin{quote} +% \cs{@@_ln_c:NwNw} \meta{sign} +% \Arg{r_1} \Arg{r_2} \Arg{r_3} \Arg{r_4} \Arg{r_5} \Arg{r_6} |;| +% \meta{fixed tl} \meta{exponent} |;| \meta{continuation} +% \end{quote} +% We are now reduced to finding $\ln c$ and $\meta{exponent}\ln 10$ +% in a table, and adding it to the mixture. The first step is to +% get $\ln c - \ln x = - \ln a$, then we get $|b|\ln 10$ and add +% or subtract. +% +% For now, $\ln x$ is given as $\cdot 10^0$. Unless both the exponent +% is $1$ and $c=1$, we shift to working in units of $\cdot 10^4$, +% since the final result will be at least $\ln 10/7 \simeq +% 0.35$.\footnote{Bruno: that was wrong at some point, I must check.} +% \begin{macrocode} +\cs_new:Npn \@@_ln_c:NwNw #1 #2; #3 + { + \if_meaning:w + #1 + \exp_after:wN \exp_after:wN \exp_after:wN \@@_fixed_sub:wwN + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \@@_fixed_add:wwN + \fi: + #3 ; #2 ; + } +% \end{macrocode} +% \footnote{Bruno: this \emph{\textbf{must}} be updated with correct values!} +% \end{macro} +% +% \begin{macro}{\@@_ln_exponent:wn} +% \begin{quote} +% \cs{@@_ln_exponent:wn} +% \Arg{s_1} \Arg{s_2} \Arg{s_3} \Arg{s_4} \Arg{s_5} \Arg{s_6} |;| +% \Arg{exponent} +% \end{quote} +% Compute \meta{exponent} times $\ln 10$. Apart from the cases where +% \meta{exponent} is $0$ or $1$, the result will necessarily be at +% least $\ln 10 \simeq 2.3$ in magnitude. We can thus drop the least +% significant $4$ digits. In the case of a very large (positive or +% negative) exponent, we can (and we need to) drop $4$ additional +% digits, since the result is of order $10^4$. Naively, one would +% think that in both cases we can drop $4$ more digits than we do, +% but that would be slightly too tight for rounding to happen correctly. +% Besides, we already have addition and subtraction for $24$ digits +% fixed point numbers. +% \begin{macrocode} +\cs_new:Npn \@@_ln_exponent:wn #1; #2 + { + \if_case:w #2 \exp_stop_f: + \c_zero \@@_case_return:nw { \@@_fixed_to_float:Nw 2 } + \or: + \exp_after:wN \@@_ln_exponent_one:ww \__int_value:w + \else: + \if_int_compare:w #2 > \c_zero + \exp_after:wN \@@_ln_exponent_small:NNww + \exp_after:wN 0 + \exp_after:wN \@@_fixed_sub:wwN \__int_value:w + \else: + \exp_after:wN \@@_ln_exponent_small:NNww + \exp_after:wN 2 + \exp_after:wN \@@_fixed_add:wwN \__int_value:w - + \fi: + \fi: + #2; #1; + } +% \end{macrocode} +% Now we painfully write all the cases.\footnote{Bruno: do rounding.} +% No overflow nor underflow can happen, except when computing \texttt{ln(1)}. +% \begin{macrocode} +\cs_new:Npn \@@_ln_exponent_one:ww 1; #1; + { + \c_zero + \exp_after:wN \@@_fixed_sub:wwN \c_@@_ln_x_fixed_tl ; #1; + \@@_fixed_to_float:wN 0 + } +% \end{macrocode} +% For small exponents, we just drop one block of digits, and set the +% exponent of the log to $4$ (minus any shift coming from leading zeros +% in the conversion from fixed point to floating point). Note that here +% the exponent has been made positive. +% \begin{macrocode} +\cs_new:Npn \@@_ln_exponent_small:NNww #1#2#3; #4#5#6#7#8#9; + { + \c_four + \exp_after:wN \@@_fixed_mul:wwn + \c_@@_ln_x_fixed_tl ; + {#3}{0000}{0000}{0000}{0000}{0000} ; + #2 + {0000}{#4}{#5}{#6}{#7}{#8}; + \@@_fixed_to_float:wN #1 + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Exponential} +% +% \subsubsection{Sign, exponent, and special numbers} +% +% \begin{macro}[int, EXP]{\@@_exp:w} +% \begin{macrocode} +\cs_new:Npn \@@_exp:w \s_@@ \@@_chk:w #1#2 + { + \if_case:w #1 \exp_stop_f: + \@@_case_return_o:Nw \c_one_fp + \or: + \exp_after:wN \@@_exp_normal:w + \or: + \if_meaning:w 0 #2 + \exp_after:wN \@@_case_return_o:Nw + \exp_after:wN \c_inf_fp + \else: + \exp_after:wN \@@_case_return_o:Nw + \exp_after:wN \c_zero_fp + \fi: + \or: + \@@_case_return_same_o:w + \fi: + \s_@@ \@@_chk:w #1#2 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_exp_normal:w, \@@_exp_pos:Nnwnw} +% \begin{macrocode} +\cs_new:Npn \@@_exp_normal:w \s_@@ \@@_chk:w 1#1 + { + \if_meaning:w 0 #1 + \@@_exp_pos:NNwnw + \@@_fixed_to_float:wN + \else: + \@@_exp_pos:NNwnw - \@@_fixed_inv_to_float:wN + \fi: + } +\cs_new:Npn \@@_exp_pos:NNwnw #1#2#3 \fi: #4#5; + { + \fi: + \exp_after:wN \@@_sanitize:Nw + \exp_after:wN 0 + \__int_value:w #1 \__int_eval:w + \if_int_compare:w #4 < - \c_eight + \c_one + \exp_after:wN \@@_add_big_i:wNww + \int_use:N \__int_eval:w \c_one - #4 ; + 0 {1000}{0000}{0000}{0000} ; #5; + \tex_romannumeral:D + \else: + \if_int_compare:w #4 > \c_five % cf \c_@@_max_exponent_int + \exp_after:wN \@@_exp_overflow: + \tex_romannumeral:D + \else: + \if_int_compare:w #4 < \c_zero + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { + \c_zero + \@@_decimate:nNnnnn { - #4 } + \@@_exp_Taylor:Nnnwn + } + { + \@@_decimate:nNnnnn { \c_sixteen - #4 } + \@@_exp_pos_large:NnnNwn + } + #5 + {#4} + #2 0 + \tex_romannumeral:D + \fi: + \fi: + \exp_after:wN \c_zero + } +\cs_new:Npn \@@_exp_overflow: + { + \c_two * \c_@@_max_exponent_int ; {1000} {0000} {0000} {0000} ; } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_exp_Taylor:Nnnwn} +% \begin{macro}[aux, EXP]{\@@_exp_Taylor_loop:www, \@@_exp_Taylor_break:Nww} +% This function is called for numbers in the range $[10^{-9}, +% 10^{-1})$. Our only task is to compute the Taylor series. The +% first argument is irrelevant (rounding digit used by some other +% functions). The next three arguments, at least $16$ digits, +% delimited by a semicolon, form a fixed point number, so we pack it +% in blocks of $4$ digits. +% \begin{macrocode} +\cs_new:Npn \@@_exp_Taylor:Nnnwn #1#2#3 #4; #5 + { + \@@_pack_twice_four:wNNNNNNNN + \@@_pack_twice_four:wNNNNNNNN + \@@_pack_twice_four:wNNNNNNNN + \@@_exp_Taylor_ii:ww + ; #2#3#4 0000 0000 ; + } +\cs_new:Npn \@@_exp_Taylor_ii:ww #1; #2; + { \@@_exp_Taylor_loop:www 10 ; #1 ; #1 ; \s__stop } +\cs_new:Npn \@@_exp_Taylor_loop:www #1; #2; #3; + { + \if_int_compare:w #1 = \c_one + \exp_after:wN \@@_exp_Taylor_break:Nww + \fi: + \@@_fixed_div_int:wwN #3 ; #1 ; + \@@_fixed_add_one:wN + \@@_fixed_mul:wwn #2 ; + { + \exp_after:wN \@@_exp_Taylor_loop:www + \int_use:N \__int_eval:w #1 - 1 ; + #2 ; + } + } +\cs_new:Npn \@@_exp_Taylor_break:Nww #1 #2; #3 \s__stop + { \@@_fixed_add_one:wN #2 ; } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux, rEXP] +% { +% \@@_exp_pos_large:NnnNwn , +% \@@_exp_large_after:wwn , +% \@@_exp_large:w , +% \@@_exp_large_v:wN, +% \@@_exp_large_iv:wN, +% \@@_exp_large_iii:wN, +% \@@_exp_large_ii:wN, +% \@@_exp_large_i:wN, +% \@@_exp_large_:wN, +% } +% The first two arguments are irrelevant (a rounding digit, and a +% brace group with $8$ zeros). The third argument is the integer part +% of our number, then we have the decimal part delimited by a +% semicolon, and finally the exponent, in the range $[0,5]$. Remove +% leading zeros from the integer part: putting |#4| in there too +% ensures that an integer part of $0$ is also removed. Then read +% digits one by one, looking up $\exp(\meta{digit}\cdot +% 10^{\meta{exponent}})$ in a table, and multiplying that to the +% current total. The loop is done by having the auxiliary for one +% exponent call the auxiliary for the next exponent. The current +% total is expressed by leaving the exponent behind in the input +% stream (we are currently within an \cs{__int_eval:w}), and keeping +% track of a fixed point number, |#1| for the numbered auxiliaries. +% Our usage of \cs{if_case:w} is somewhat dirty for optimization: +% \TeX{} jumps to the appropriate case, but we then lose the +% \cs{if_case:w} \enquote{by hand}, using \cs{or:} and \cs{fi:} as +% delimiters. +% \begin{macrocode} +\cs_new:Npn \@@_exp_pos_large:NnnNwn #1#2#3 #4#5; #6 + { + \exp_after:wN \exp_after:wN + \cs:w @@_exp_large_\tex_romannumeral:D #6:wN \exp_after:wN \cs_end: + \exp_after:wN \c_@@_one_fixed_tl + \exp_after:wN ; + \__int_value:w #3 #4 \exp_stop_f: + #5 00000 ; + } +\cs_new:Npn \@@_exp_large:w #1 \or: #2 \fi: + { \fi: \@@_fixed_mul:wwn #1; } +\cs_new:Npn \@@_exp_large_v:wN #1; #2 + { + \if_case:w #2 ~ \exp_after:wN \@@_fixed_continue:wn \or: + + 4343 \@@_exp_large:w {8806}{8182}{2566}{2921}{5872}{6150} \or: + + 8686 \@@_exp_large:w {7756}{0047}{2598}{6861}{0458}{3204} \or: + + 13029 \@@_exp_large:w {6830}{5723}{7791}{4884}{1932}{7351} \or: + + 17372 \@@_exp_large:w {6015}{5609}{3095}{3052}{3494}{7574} \or: + + 21715 \@@_exp_large:w {5297}{7951}{6443}{0315}{3251}{3576} \or: + + 26058 \@@_exp_large:w {4665}{6719}{0099}{3379}{5527}{2929} \or: + + 30401 \@@_exp_large:w {4108}{9724}{3326}{3186}{5271}{5665} \or: + + 34744 \@@_exp_large:w {3618}{6973}{3140}{0875}{3856}{4102} \or: + + 39087 \@@_exp_large:w {3186}{9209}{6113}{3900}{6705}{9685} \or: + \fi: + #1; + \@@_exp_large_iv:wN + } +\cs_new:Npn \@@_exp_large_iv:wN #1; #2 + { + \if_case:w #2 ~ \exp_after:wN \@@_fixed_continue:wn \or: + + 435 \@@_exp_large:w {1970}{0711}{1401}{7046}{9938}{8888} \or: + + 869 \@@_exp_large:w {3881}{1801}{9428}{4368}{5764}{8232} \or: + + 1303 \@@_exp_large:w {7646}{2009}{8905}{4704}{8893}{1073} \or: + + 1738 \@@_exp_large:w {1506}{3559}{7005}{0524}{9009}{7592} \or: + + 2172 \@@_exp_large:w {2967}{6283}{8402}{3667}{0689}{6630} \or: + + 2606 \@@_exp_large:w {5846}{4389}{5650}{2114}{7278}{5046} \or: + + 3041 \@@_exp_large:w {1151}{7900}{5080}{6878}{2914}{4154} \or: + + 3475 \@@_exp_large:w {2269}{1083}{0850}{6857}{8724}{4002} \or: + + 3909 \@@_exp_large:w {4470}{3047}{3316}{5442}{6408}{6591} \or: + \fi: + #1; + \@@_exp_large_iii:wN + } +\cs_new:Npn \@@_exp_large_iii:wN #1; #2 + { + \if_case:w #2 ~ \exp_after:wN \@@_fixed_continue:wn \or: + + 44 \@@_exp_large:w {2688}{1171}{4181}{6135}{4484}{1263} \or: + + 87 \@@_exp_large:w {7225}{9737}{6812}{5749}{2581}{7748} \or: + + 131 \@@_exp_large:w {1942}{4263}{9524}{1255}{9365}{8421} \or: + + 174 \@@_exp_large:w {5221}{4696}{8976}{4143}{9505}{8876} \or: + + 218 \@@_exp_large:w {1403}{5922}{1785}{2837}{4107}{3977} \or: + + 261 \@@_exp_large:w {3773}{0203}{0092}{9939}{8234}{0143} \or: + + 305 \@@_exp_large:w {1014}{2320}{5473}{5004}{5094}{5533} \or: + + 348 \@@_exp_large:w {2726}{3745}{7211}{2566}{5673}{6478} \or: + + 391 \@@_exp_large:w {7328}{8142}{2230}{7421}{7051}{8866} \or: + \fi: + #1; + \@@_exp_large_ii:wN + } +\cs_new:Npn \@@_exp_large_ii:wN #1; #2 + { + \if_case:w #2 ~ \exp_after:wN \@@_fixed_continue:wn \or: + + 5 \@@_exp_large:w {2202}{6465}{7948}{0671}{6516}{9579} \or: + + 9 \@@_exp_large:w {4851}{6519}{5409}{7902}{7796}{9107} \or: + + 14 \@@_exp_large:w {1068}{6474}{5815}{2446}{2146}{9905} \or: + + 18 \@@_exp_large:w {2353}{8526}{6837}{0199}{8540}{7900} \or: + + 22 \@@_exp_large:w {5184}{7055}{2858}{7072}{4640}{8745} \or: + + 27 \@@_exp_large:w {1142}{0073}{8981}{5684}{2836}{6296} \or: + + 31 \@@_exp_large:w {2515}{4386}{7091}{9167}{0062}{6578} \or: + + 35 \@@_exp_large:w {5540}{6223}{8439}{3510}{0525}{7117} \or: + + 40 \@@_exp_large:w {1220}{4032}{9431}{7840}{8020}{0271} \or: + \fi: + #1; + \@@_exp_large_i:wN + } +\cs_new:Npn \@@_exp_large_i:wN #1; #2 + { + \if_case:w #2 ~ \exp_after:wN \@@_fixed_continue:wn \or: + + 1 \@@_exp_large:w {2718}{2818}{2845}{9045}{2353}{6029} \or: + + 1 \@@_exp_large:w {7389}{0560}{9893}{0650}{2272}{3043} \or: + + 2 \@@_exp_large:w {2008}{5536}{9231}{8766}{7740}{9285} \or: + + 2 \@@_exp_large:w {5459}{8150}{0331}{4423}{9078}{1103} \or: + + 3 \@@_exp_large:w {1484}{1315}{9102}{5766}{0342}{1116} \or: + + 3 \@@_exp_large:w {4034}{2879}{3492}{7351}{2260}{8387} \or: + + 4 \@@_exp_large:w {1096}{6331}{5842}{8458}{5992}{6372} \or: + + 4 \@@_exp_large:w {2980}{9579}{8704}{1728}{2747}{4359} \or: + + 4 \@@_exp_large:w {8103}{0839}{2757}{5384}{0077}{1000} \or: + \fi: + #1; + \@@_exp_large_:wN + } +\cs_new:Npn \@@_exp_large_:wN #1; #2 + { + \if_case:w #2 ~ \exp_after:wN \@@_fixed_continue:wn \or: + + 1 \@@_exp_large:w {1105}{1709}{1807}{5647}{6248}{1171} \or: + + 1 \@@_exp_large:w {1221}{4027}{5816}{0169}{8339}{2107} \or: + + 1 \@@_exp_large:w {1349}{8588}{0757}{6003}{1039}{8374} \or: + + 1 \@@_exp_large:w {1491}{8246}{9764}{1270}{3178}{2485} \or: + + 1 \@@_exp_large:w {1648}{7212}{7070}{0128}{1468}{4865} \or: + + 1 \@@_exp_large:w {1822}{1188}{0039}{0508}{9748}{7537} \or: + + 1 \@@_exp_large:w {2013}{7527}{0747}{0476}{5216}{2455} \or: + + 1 \@@_exp_large:w {2225}{5409}{2849}{2467}{6045}{7954} \or: + + 1 \@@_exp_large:w {2459}{6031}{1115}{6949}{6638}{0013} \or: + \fi: + #1; + \@@_exp_large_after:wwn + } +\cs_new:Npn \@@_exp_large_after:wwn #1; #2; + { + \@@_exp_Taylor:Nnnwn ? { } { } 0 #2; {} + \@@_fixed_mul:wwn #1; + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Power} +% +% Raising a number $a$ to a power $b$ leads to many distinct situations. +% \begin{center} +% \begin{tabular}{>{$}c<{$}|*8{>{$}l<{$}}} +% a^b &-\infty&-y &-n &\pm 0&+n &+y &+\infty&\nan \\ +% \hline +% +\infty&+0 &+0 &+0 &+1&+\infty &+\infty&+\infty&\nan \\ +% 1<x &+0 &+x^{-y}&+x^{-n} &+1&+x^{n} &+x^{y} &+\infty&\nan \\ +% +1 &+1 &+1 &+1 &+1&+1 &+1 &+1 &+1 \\ +% 0<x<1 &+\infty&+x^{-y}&+x^{-n} &+1&+x^{n} &+x^{y} &+0 &\nan \\ +% +0 &+\infty&+\infty&+\infty &+1&+0 &+0 &+0 &\nan \\ +% -0 &\nan &\nan &\pm\infty &+1&\pm 0 &+0 &+0 &\nan \\ +% -1<-x<0&\nan &\nan &\pm x^{-n}&+1&\pm x^{n}&\nan &+0 &\nan \\ +% -1 &\nan &\nan &\pm 1 &+1&\pm 1 &\nan &\nan &\nan \\ +% -x<-1 &+0 &\nan &\pm x^{-n}&+1&\pm x^{n}&\nan &\nan &\nan \\ +% -\infty&+0 &+0 &\pm 0 &+1&\pm\infty&\nan &\nan &\nan \\ +% \nan &\nan &\nan &\nan &+1&\nan &\nan &\nan &\nan \\ +% \end{tabular} +% \end{center} +% One peculiarity of this operation is that $\nan^0 = 1^\nan = 1$, +% because this relation is obeyed for any number, even $\pm\infty$. +% +% \begin{macro}[int, EXP]+\@@_^_o:ww+ +% We cram a most of the tests into a single function to save csnames. +% First treat the case $b=0$: $a^0=1$ for any $a$, even \texttt{nan}. +% Then test the sign of $a$. +% \begin{itemize} +% \item If it is positive, and $a$ is a normal number, call +% \cs{@@_pow_normal:ww} followed by the two \texttt{fp} $a$ and $b$. +% For $a=+0$ or $+\inf$, call \cs{@@_pow_zero_or_inf:ww} instead, to +% return either $+0$ or $+\infty$ as appropriate. +% \item If $a$ is a \texttt{nan}, then skip to the next semicolon +% (which happens to be conveniently the end of $b$) and return +% \texttt{nan}. +% \item Finally, if $a$ is negative, compute $|a|^b$ +% (\cs{@@_pow_normal:ww} which ignores the sign of its first +% operand), and keep an extra copy of $a$ and $b$ (the second brace +% group, containing \{~$b$~$a$~\}, is inserted between $a$ and $b$). +% Then do some tests to find the final sign of the result if it +% exists. +% \end{itemize} +% \begin{macrocode} +\cs_new:cpn { @@_ \iow_char:N \^ _o:ww } + \s_@@ \@@_chk:w #1#2#3; \s_@@ \@@_chk:w #4#5#6; + { + \if_meaning:w 0 #4 + \@@_case_return_o:Nw \c_one_fp + \fi: + \if_case:w #2 \exp_stop_f: + \exp_after:wN \use_i:nn + \or: + \@@_case_return_o:Nw \c_nan_fp + \else: + \exp_after:wN \@@_pow_neg:www + \tex_romannumeral:D -`0 \exp_after:wN \use:nn + \fi: + { + \if_meaning:w 1 #1 + \exp_after:wN \@@_pow_normal:ww + \else: + \exp_after:wN \@@_pow_zero_or_inf:ww + \fi: + \s_@@ \@@_chk:w #1#2#3; + } + { \s_@@ \@@_chk:w #4#5#6; \s_@@ \@@_chk:w #1#2#3; } + \s_@@ \@@_chk:w #4#5#6; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_pow_zero_or_inf:ww} +% Raising $-0$ or $-\infty$ to \texttt{nan} yields \texttt{nan}. For +% other powers, the result is $+0$ if $0$ is raised to a positive +% power or $\infty$ to a negative power, and $+\infty$ otherwise. We +% can thus know the result by comparing the type of $a$ with the sign +% of $b$, since those conveniently take the same possible values, $0$ +% and~$2$. +% \begin{macrocode} +\cs_new:Npn \@@_pow_zero_or_inf:ww \s_@@ \@@_chk:w #1#2; \s_@@ \@@_chk:w #3#4 + { + \if_meaning:w 1 #4 + \@@_case_return_same_o:w + \fi: + \if_meaning:w #1 #4 + \@@_case_return_o:Nw \c_zero_fp + \else: + \@@_case_return_o:Nw \c_inf_fp + \fi: + \s_@@ \@@_chk:w #3#4 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_pow_normal:ww} +% We have in front of us $a$, and $b\neq 0$, we know that $a$ is a +% normal number, and we wish to compute $\lvert a\rvert^{b}$. If +% $\lvert a\rvert=1$, we return $1$, unless $a=-1$ and $b$ is +% \texttt{nan}. Indeed, returning $1$ at this point would wrongly +% raise \enquote{invalid} when the sign is considered. If $\lvert +% a\rvert\neq 1$, test the type of $b$: +% \begin{itemize} +% \item[0] Impossible, we already filtered $b=\pm 0$. +% \item[1] Call \cs{@@_pow_npos:ww}. +% \item[2] Return $+\infty$ or $+0$ depending on the sign of $b$ and +% whether the exponent of $a$ is positive or not. +% \item[3] Return $b$. +% \end{itemize} +% \begin{macrocode} +\cs_new:Npn \@@_pow_normal:ww \s_@@ \@@_chk:w 1 #1#2#3; \s_@@ \@@_chk:w #4#5 + { + \if_int_compare:w \pdftex_strcmp:D { #2 #3 } + { 1 {1000} {0000} {0000} {0000} } = \c_zero + \if_int_compare:w #4 #1 = 32 \exp_stop_f: + \exp_after:wN \@@_case_return_ii_o:ww + \fi: + \@@_case_return_o:Nww \c_one_fp + \fi: + \if_case:w #4 ~ + \or: + \exp_after:wN \@@_pow_npos:Nww + \exp_after:wN #5 + \or: + \if_meaning:w 2 #5 \exp_after:wN \reverse_if:N \fi: + \if_int_compare:w #2 > \c_zero + \exp_after:wN \@@_case_return_o:Nww + \exp_after:wN \c_inf_fp + \else: + \exp_after:wN \@@_case_return_o:Nww + \exp_after:wN \c_zero_fp + \fi: + \or: + \@@_case_return_ii_o:ww + \fi: + \s_@@ \@@_chk:w 1 #1 {#2} #3 ; + \s_@@ \@@_chk:w #4 #5 + } +% \end{macrocode} +% \end{macro} +% +% ^^A todo: check that we compute ln to 21 digits! +% \begin{macro}[aux, EXP]{\@@_pow_npos:Nww} +% We now know that $a\neq\pm 1$ is a normal number, and $b$ is a +% normal number too. We want to compute $\lvert a\rvert^{b} = (\lvert +% x\rvert\cdot 10^{n})^{y\cdot 10^{p}} = \exp((\log\lvert x\rvert + n +% \log 10)\cdot y \cdot 10^{p}) = \exp(z)$. To compute the +% exponential accurately, we need to know the digits of $z$ up to the +% $16$-th position. Since the exponential of $10^{5}$ is infinite, we +% only need at most $21$ digits, hence the fixed point result of +% \cs{@@_ln:w} is precise enough for our needs. Start an integer +% expression for the decimal exponent of $e^{\lvert z\rvert}$. If $z$ +% is negative, negate that decimal exponent, and prepare to take the +% inverse when converting from the fixed point to the floating point result. +% \begin{macrocode} +\cs_new:Npn \@@_pow_npos:Nww #1 \s_@@ \@@_chk:w 1#2#3 + { + \exp_after:wN \@@_sanitize:Nw + \exp_after:wN 0 + \__int_value:w + \if:w #1 \if_int_compare:w #3 > \c_zero 0 \else: 2 \fi: + \exp_after:wN \@@_pow_npos_aux:Nnww + \exp_after:wN \@@_fixed_to_float:wN + \else: + - + \exp_after:wN \@@_pow_npos_aux:Nnww + \exp_after:wN \@@_fixed_inv_to_float:wN + \fi: + {#3} + } +% \end{macrocode} +% \end{macro} +% +%^^A begin[todo] +% \begin{macro}[aux, EXP]{\@@_pow_npos_aux:Nnww} +% The first argument is the conversion function from fixed point to +% float. Then comes an exponent and the $4$ brace groups of $x$, +% followed by $b$. Compute $-\log x$. +% \begin{macrocode} +\cs_new:Npn \@@_pow_npos_aux:Nnww #1#2#3#4; \s_@@ \@@_chk:w 1#5#6#7; + { + \__int_eval:w + \@@_ln_significand:NNNNnnnN #3#4 + \@@_pow_exponent:wnN {#2} + \@@_fixed_mul:wwn #7 {0000}{0000} ; + \@@_pow_B:wwN #6; + #1 0 % fixed_to_float:wN + } +\cs_new:Npn \@@_pow_exponent:wnN #1; #2 + { + \if_int_compare:w #2 > \c_zero + \exp_after:wN \@@_pow_exponent:Nwnnnnnn % n\log 10 - (-\log x) + \exp_after:wN + + \else: + \exp_after:wN \@@_pow_exponent:Nwnnnnnn % -( |n|\log 10 + (-\log x) ) + \exp_after:wN - + \fi: + #2; #1; + } +\cs_new:Npn \@@_pow_exponent:Nwnnnnnn #1#2; #3#4#5#6#7#8; + { %^^A todo: use that in ln. %^^A todo: log(1.00...) too inaccurate? + \exp_after:wN \@@_fixed_mul_after:wwn + \int_use:N \__int_eval:w -5 0000 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 4 9995 0000 #1#2*23025 - #1 #3 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 4 9995 0000 #1 #2*8509 - #1 #4 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 4 9995 0000 #1 #2*2994 - #1 #5 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 4 9995 0000 #1 #2*0456 - #1 #6 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 5 0000 0000 #1 #2*8401 - #1 #7 + #1 ( #2*7991 - #8 ) / 1 0000 ; ; + } +\cs_new:Npn \@@_pow_B:wwN #1#2#3#4#5#6; #7; + { + \if_int_compare:w #7 < \c_zero + \exp_after:wN \@@_pow_C_neg:w \__int_value:w - + \else: + \if_int_compare:w #7 < 22 \exp_stop_f: + \exp_after:wN \@@_pow_C_pos:w \__int_value:w + \else: + \exp_after:wN \@@_pow_C_overflow:w \__int_value:w + \fi: + \fi: + #7 \exp_after:wN ; + \int_use:N \__int_eval:w 10 0000 + #1 \__int_eval_end: + #2#3#4#5#6 0000 0000 0000 0000 0000 0000 ; %^^A todo: how many 0? + } +\cs_new:Npn \@@_pow_C_overflow:w #1; #2; + { + + \c_two * \c_@@_max_exponent_int + \exp_after:wN \@@_fixed_continue:wn \c_@@_one_fixed_tl ; + } +\cs_new:Npn \@@_pow_C_neg:w #1 ; 1 + { + \exp_after:wN \exp_after:wN \exp_after:wN \@@_pow_C_pack:w + \prg_replicate:nn {#1} {0} + } +\cs_new:Npn \@@_pow_C_pos:w #1; 1 + { \@@_pow_C_pos_loop:wN #1; } +\cs_new:Npn \@@_pow_C_pos_loop:wN #1; #2 + { + \if_meaning:w 0 #1 + \exp_after:wN \@@_pow_C_pack:w + \exp_after:wN #2 + \else: + \if_meaning:w 0 #2 + \exp_after:wN \@@_pow_C_pos_loop:wN \__int_value:w + \else: + \exp_after:wN \@@_pow_C_overflow:w \__int_value:w + \fi: + \__int_eval:w #1 - \c_one \exp_after:wN ; + \fi: + } +\cs_new:Npn \@@_pow_C_pack:w + { \exp_after:wN \@@_exp_large_v:wN \c_@@_one_fixed_tl ; } +% \end{macrocode} +% \end{macro} +%^^A end[todo] +% +% \begin{macro}[aux, EXP]{\@@_pow_neg:www, \@@_pow_neg_neg:w} +% This function is followed by three floating point numbers: $|a|^b$, +% $a\in[-\infty,-0]$, and $b$. If $b$ is an even integer (case $-1$), +% $a^b=|a|^b$. If $b$ is an odd integer (case $0$), $a^b=-|a|^b$, +% obtained by a call to \cs{@@_pow_neg_neg:w}. Otherwise, the sign is +% undefined. This is invalid, unless $|a|^b$ turns out to be $+0$ or +% \texttt{nan}, in which case we return that as $a^b$. In particular, +% since the underflow detection occurs before \cs{@@_pow_neg:www} is +% called, |(-0.1)**(12345.6)| will give $+0$ rather than complaining +% that the sign is not defined. +% \begin{macrocode} +\cs_new:Npn \@@_pow_neg:www \s_@@ \@@_chk:w #1#2; #3; #4; + { + \if_case:w \@@_pow_neg_case:w #4 ; + \exp_after:wN \@@_pow_neg_neg:w + \or: + \if_int_compare:w \__int_eval:w #1 / \c_two = \c_one + \@@_invalid_operation:Nnww \c_nan_fp { ^ } #3; #4; + \tex_romannumeral:D -`0 + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_use_none_until_s:w + \fi: + \fi: + \@@_exp_after_o:w + \s_@@ \@@_chk:w #1#2; + } +\cs_new:Npn \@@_pow_neg_neg:w \@@_exp_after_o:w \s_@@ \@@_chk:w #1#2 + { + \exp_after:wN \@@_exp_after_o:w + \exp_after:wN \s_@@ + \exp_after:wN \@@_chk:w + \exp_after:wN #1 + \int_use:N \__int_eval:w \c_two - #2 \__int_eval_end: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP] +% { +% \@@_pow_neg_case:w, \@@_pow_neg_case_aux:nnnnn, +% \@@_pow_neg_case_aux:NNNNNNNNw +% } +% This function expects a floating point number, and \enquote{returns} +% $-1$ if it is an even integer, $0$ if it is an odd integer, and $1$ +% if it is not an integer. Zeros are even, $\pm\infty$ and +% \texttt{nan} are non-integers. The sign of normal numbers is +% irrelevant to parity. If the exponent is greater than sixteen, then +% the number is even. If the exponent is non-positive, the number +% cannot be an integer. We also separate the ranges of exponent +% $[1,8]$ and $[9,16]$. In the former case, check that the last $8$ +% digits are zero (otherwise we don't have an integer). In both +% cases, consider the appropriate $8$ digits, either |#4#5| or |#2#3|, +% remove the first few: we are then left with \meta{digit} +% \meta{digits} |;| which would be the digits surrounding the decimal +% period. If the \meta{digits} are non-zero, the number is not an +% integer. Otherwise, check the parity of the \meta{digit} and return +% \cs{c_zero} or \cs{c_minus_one}. +% \begin{macrocode} +\cs_new:Npn \@@_pow_neg_case:w \s_@@ \@@_chk:w #1#2#3; + { + \if_case:w #1 \exp_stop_f: + \c_minus_one + \or: \@@_pow_neg_case_aux:nnnnn #3 + \else: \c_one + \fi: + } +\cs_new:Npn \@@_pow_neg_case_aux:nnnnn #1#2#3#4#5 + { + \if_int_compare:w #1 > \c_eight + \if_int_compare:w #1 > \c_sixteen + \c_minus_one + \else: + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_pow_neg_case_aux:NNNNNNNNw + \prg_replicate:nn { \c_sixteen - #1 } { 0 } #4#5 ; + \fi: + \else: + \if_int_compare:w #1 > \c_zero + \if_int_compare:w #4#5 = \c_zero + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_pow_neg_case_aux:NNNNNNNNw + \prg_replicate:nn { \c_eight - #1 } { 0 } #2#3 ; + \else: + \c_one + \fi: + \else: + \c_one + \fi: + \fi: + } +\cs_new:Npn \@@_pow_neg_case_aux:NNNNNNNNw #1#2#3#4#5#6#7#8#9; + { + \if_int_compare:w 0 #9 = \c_zero + \if_int_odd:w #8 \exp_stop_f: + \c_zero + \else: + \c_minus_one + \fi: + \else: + \c_one + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx new file mode 100644 index 00000000000..d38c6de8e17 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx @@ -0,0 +1,674 @@ +% \iffalse meta-comment +% +%% File: l3fp-extended.dtx Copyright (C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-extended.dtx 2474 2011-06-17 12:54:02Z bruno $ + {L3 Floating-point extended precision fixed-points} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp-extended} package\thanks{This file +% has version number \ExplFileVersion, last +% revised \ExplFileDate.}\\ +% Fixed points with extended precision for internal use} +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-extended} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% In this module, we work on (almost) fixed-point numbers with +% extended ($24$ digits) precision. This is used in the computation of +% Taylor series for the logarithm, exponential, and trigonometric +% functions. Since we eventually only care about the $16$ first digits +% of the final result, some of the calculations are not performed with +% the full $24$-digit precision. In other words, the last two blocks of +% each fixed point number may be wrong as long as the error is small +% enough to be rounded away when converting back to a floating point +% number. The fixed point numbers are expressed as +% \begin{quote} +% \Arg{a_1} \Arg{a_2} \Arg{a_3} \Arg{a_4} \Arg{a_5} \Arg{a_6} |;| +% \end{quote} +% where each \meta{a_i} is exactly $4$ digits, except +% \meta{a_1}, which may be any positive \TeX{} integer. The fixed point +% number $a$ corresponding to the representation above is $a = +% \sum_{i=1}^{6} \meta{a_i} \cdot 10^{-4i}$. +% +% Most functions we define here have the form +% \begin{syntax} +% \cs{@@_fixed_\meta{calculation}:wwN} \meta{operand_1} |;| \meta{operand_2} |;| \meta{continuation} +% \end{syntax} +% They perform the \meta{calculation} on the two \meta{operands}, then +% feed the result ($6$ brace groups followed by a semicolon) to the +% \meta{continuation}, responsible for the next step of the calculation. +% This allows constructions such as +% \begin{quote} +% \cs{@@_fixed_add:wwN} \meta{X_1} |;| \meta{X_2} |;| \\ +% \cs{@@_fixed_mul:wwn} \meta{X_3} |;| \\ +% \cs{@@_fixed_add:wwN} \meta{X_4} |;| \\ +% \end{quote} +% to compute $(X_1+X_2)\cdot X_3 + X_4$. This turns out to be very +% appropriate for computing continued fractions and Taylor series. +% +% At the end of the calculation, the result is turned back to a floating +% point number using \cs{@@_fixed_to_float:Nw}. This function has to +% change the exponent of the floating point number: it must be used +% after starting an integer expression for the overall exponent of the +% result. +% +% \begin{variable}{\c_@@_one_fixed_tl} +% \begin{macrocode} +\tl_const:Nn \c_@@_one_fixed_tl + { {10000} {0000} {0000} {0000} {0000} {0000} } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[int, EXP]{\@@_fixed_continue:wn} +% This function does nothing. +% \begin{macrocode} +\cs_new:Npn \@@_fixed_continue:wn #1; #2 { #2 #1; } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_fixed_div_int:wwN} +% \begin{macro}[aux, EXP] +% { +% \@@_fixed_div_int_i:wnN, \@@_fixed_div_int_ii:wnn, +% \@@_fixed_div_int_end:wnn, \@@_fixed_div_int_pack:Nw, +% \@@_fixed_div_int_after:Nw +% } +% \begin{syntax} +% \cs{@@_fixed_div_int:wwN} \meta{a} |;| \meta{n} |;| \meta{function} +% \end{syntax} +% Divides the fixed point number \meta{a} by the (small) integer +% $0<\meta{n}<10^4$ and feeds the result to the \meta{function}. The +% \texttt{wnN} auxiliary receives $a_{i}$, $n$, and a continuation +% function as arguments, and computes a (rather tight) lower bound +% $Q_{i}$ for the quotient. The \texttt{wnn} auxiliary receives +% $Q_{i}$, $n$, and $a_{i}$. It adds $Q_{i}$ to a surrounding integer +% expression, and starts a new one. It also computes $a_{i}-n\cdot +% Q_{i}$, putting the result in front of $a_{i+1}$ to serve as the +% first argument for a new call to the \texttt{wnN} auxiliary. At the +% end, the path we took to the lowest levels rewinds: the +% \texttt{pack} auxiliary receives $5$ digits, braces the last $4$, +% and carries the leading digit to the level above. The offsets used +% to ensure a given number of digits are as follows: we first subtract +% $1$ from the top-level, then add $9999$ at every subsequent level, +% and add $2$ to the last level. This last number is not $1$, because +% it compensates for the |- \c_one| in the \texttt{wnN} auxiliary. +% \begin{macrocode} +\cs_new:Npn \@@_fixed_div_int:wwN #1#2#3#4#5#6 ; #7 ; #8 + { + \exp_after:wN \@@_fixed_div_int_after:Nw + \exp_after:wN #8 + \int_use:N \__int_eval:w \c_minus_one + \@@_fixed_div_int_i:wnN + #1; {#7} \@@_fixed_div_int_ii:wnn + #2; {#7} \@@_fixed_div_int_ii:wnn + #3; {#7} \@@_fixed_div_int_ii:wnn + #4; {#7} \@@_fixed_div_int_ii:wnn + #5; {#7} \@@_fixed_div_int_ii:wnn + #6; {#7} \@@_fixed_div_int_end:wnn ; + } +\cs_new:Npn \@@_fixed_div_int_i:wnN #1; #2 #3 + { + \exp_after:wN #3 + \int_use:N \__int_eval:w #1 / #2 - \c_one ; + {#2} + {#1} + } +\cs_new:Npn \@@_fixed_div_int_ii:wnn #1; #2 #3 + { + + #1 + \exp_after:wN \@@_fixed_div_int_pack:Nw + \int_use:N \__int_eval:w 9999 + \exp_after:wN \@@_fixed_div_int_i:wnN + \int_use:N \__int_eval:w #3 - #1*#2 \__int_eval_end: + } +\cs_new:Npn \@@_fixed_div_int_end:wnn #1; #2 #3 { + #1 + \c_two ; } +\cs_new:Npn \@@_fixed_div_int_pack:Nw #1 #2; { + #1; {#2} } +\cs_new:Npn \@@_fixed_div_int_after:Nw #1 #2; { #1 {#2} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_fixed_add_one:wN} +% \begin{syntax} +% \cs{@@_fixed_add_one:wN} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \Arg{X_5} \Arg{X_6} |;| \meta{function} +% \end{syntax} +% \begin{macrocode} +\cs_new:Npn \@@_fixed_add_one:wN #1#2; #3 + { + \exp_after:wN #3 \exp_after:wN + { \int_use:N \__int_eval:w 10000 + #1 } #2 ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP] +% {\@@_fixed_add:wwN, \@@_fixed_sub:wwN, \@@_fixed_sub_back:wwN} +%^^A todo: remove sub_back. +% \begin{macro}[aux, EXP] +% { +% \@@_fixed_add_i:NNnnnnwnn, +% \@@_fixed_add_ii:NnnNnnnnw, +% \@@_fixed_add_pack:NNNNNwN, +% \@@_fixed_add_after:NNNNNwN +% } +% \begin{syntax} +% \cs{@@_fixed_add:wwN} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \Arg{X_5} \Arg{X_6} |;| \Arg{Y_1} \Arg{Y_2} \Arg{Y_3} \Arg{Y_4} \Arg{Y_5} \Arg{Y_6} |;| \meta{function} +% \end{syntax} +% Computes $X+Y$ (resp.\ $X-Y$ and $Y-X$) and feeds the result to +% \meta{function}. The three functions only differ by some signs and +% use a common auxiliary. It would be nice to grab the $12$ brace +% groups in one go, only $9$ arguments are allowed. Start by grabbing +% the two signs, $X_{1}, \ldots, X_{4}$, the rest of $X$, and $Y_{1}$ +% and $Y_{2}$. The second auxiliary receives the sign of $X$, the +% rest of $X$, the sign of $Y$, the rest of $Y$, and the +% \meta{function}. After going down through the various level, we go +% back up, packing digits and bringing the \meta{function} (|#9|, then +% |#7|) from the end of the argument list to its start. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_fixed_add:wwN { \@@_fixed_add_i:NNnnnnwnn + + } +\cs_new_nopar:Npn \@@_fixed_sub:wwN { \@@_fixed_add_i:NNnnnnwnn + - } +\cs_new_nopar:Npn \@@_fixed_sub_back:wwN { \@@_fixed_add_i:NNnnnnwnn - + } +\cs_new:Npn \@@_fixed_add_i:NNnnnnwnn #1#2 #3#4#5#6 #7; #8#9 + { + \exp_after:wN \@@_fixed_add_after:NNNNNwN + \int_use:N \__int_eval:w 1 9999 9998 #1 #3#4 #2 #8#9 + \exp_after:wN \@@_fixed_add_pack:NNNNNwN + \int_use:N \__int_eval:w 1 9999 9998 #1 #5#6 + \@@_fixed_add_ii:NnnNnnnnw #1 #7 #2 + } +\cs_new:Npn \@@_fixed_add_ii:NnnNnnnnw #1 #2#3 #4 #5#6 #7#8 ; #9 + { + #4 #5#6 + \exp_after:wN \@@_fixed_add_pack:NNNNNwN + \int_use:N \__int_eval:w 2 0000 0000 #4 #7#8 #1 #2#3 ; #9 ; + } +\cs_new:Npn \@@_fixed_add_pack:NNNNNwN #1 #2#3#4#5 #6; #7 + { + #1 ; #7 {#2#3#4#5} {#6} } +\cs_new:Npn \@@_fixed_add_after:NNNNNwN #1 #2#3#4#5 #6; #7 + { + \exp_after:wN #7 + \exp_after:wN { \int_use:N \__int_eval:w - 2 0000 + #1#2#3#4#5 } + {#6} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_fixed_mul:wwn} +% \begin{macro}[aux, EXP] +% { +% \@@_fixed_mul_i:nnnnnnnn , +% \@@_fixed_mul_pack:NNNNNw , +% \@@_fixed_mul_after:wwn +% } +% \begin{syntax} +% \cs{@@_fixed_mul:wwn} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \Arg{X_5} \Arg{X_6} |;| \Arg{Y_1} \Arg{Y_2} \Arg{Y_3} \Arg{Y_4} \Arg{Y_5} \Arg{Y_6} |;| \Arg{tokens} +% \end{syntax} +% Computes $X\times Y$ and feeds the result to \meta{function}. It +% would be nice to grab the $12$ brace groups in one go, but that's +% not possible. On the other hand, we don't need to obtain an exact +% rounding, contrarily to the case in \cs{@@_*_o:ww}, so things are +% not quite as bad as they may seem. The parenthesis computing the +% seventh group of digits (computed because we need to know its +% potentially large carry) is closed by +% \cs{@@_fixed_mul_i:nnnnnnnn}, once we access the last two brace +% groups, which were not read before. Also, in +% \cs{@@_fixed_mul_after:wwn}, |#3| is the continuation +% tokens.\footnote{Bruno: insist on the difference compared to +% \cs{@@_fixed_add:wwN}.} +% \begin{macrocode} +\cs_new:Npn \@@_fixed_mul:wwn #1#2#3#4 #5; #6#7#8#9 + { + \exp_after:wN \@@_fixed_mul_after:wwn + \int_use:N \__int_eval:w \c_@@_leading_shift_int + \exp_after:wN \@@_pack:NNNNNw + \int_use:N \__int_eval:w \c_@@_middle_shift_int + + #1*#6 + \exp_after:wN \@@_pack:NNNNNw + \int_use:N \__int_eval:w \c_@@_middle_shift_int + + #1*#7 + #2*#6 + \exp_after:wN \@@_pack:NNNNNw + \int_use:N \__int_eval:w \c_@@_middle_shift_int + + #1*#8 + #2*#7 + #3*#6 + \exp_after:wN \@@_pack:NNNNNw + \int_use:N \__int_eval:w \c_@@_middle_shift_int + + #1*#9 + #2*#8 + #3*#7 + #4*#6 + \exp_after:wN \@@_pack:NNNNNw + \int_use:N \__int_eval:w \c_@@_trailing_shift_int + + #2*#9 + #3*#8 + #4*#7 + + ( #3*#9 + #4*#8 + + \@@_fixed_mul_i:nnnnnnnn #5 {#6}{#7} {#1}{#2} + } +\cs_new:Npn \@@_fixed_mul_i:nnnnnnnn #1#2 #3#4 #5#6 #7#8 + { #1*#4 + #2*#3 + #5*#8 + #6*#7 )/10000 + #1*#3 + #5*#7 ; } +\cs_new:Npn \@@_fixed_mul_pack:NNNNNw + #1 #2#3#4#5 #6; { + #1#2#3#4#5 ; {#6} } +\cs_new:Npn \@@_fixed_mul_after:wwn #1; #2; #3 { #3 {#1} #2 ; } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_fixed_mul_add:wwwn, \@@_fixed_mul_sub_back:wwwn} +% \begin{syntax} +% \cs{@@_fixed_mul_add:wwn} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \Arg{X_5} \Arg{X_6} |;| \Arg{Y_1} \Arg{Y_2} \Arg{Y_3} \Arg{Y_4} \Arg{Y_5} \Arg{Y_6} |;| \Arg{Z_1} \Arg{Z_2} \Arg{Z_3} \Arg{Z_4} \Arg{Z_5} \Arg{Z_6} |;| \Arg{tokens} +% \end{syntax} +% These functions compute $X\times Y + Z$ or $Z-X\times Y$ and feed +% the result to the \meta{tokens}. This is tough because we have $18$ +% brace groups in front of us. +% \begin{macrocode} +\cs_new:Npn \@@_fixed_one_minus_mul:wwn #1; #2#3#4#5; + { + \exp_after:wN \@@_fixed_mul_after:wwn + \int_use:N \__int_eval:w \c_@@_big_leading_shift_int + \c_ten_thousand + \exp_after:wN \@@_pack_big:NNNNNNw + \int_use:N \__int_eval:w \c_@@_big_middle_shift_int + \@@_fixed_mul_add_i:Nnwnnwnnn + - 00; {#2}{#3}{#4}; #1; {#2}{#3}{#4}#5; - 00 ; + } +\cs_new:Npn \@@_fixed_mul_add:wwwn #1; #2#3#4#5; #6#7#8#9 + { + \exp_after:wN \@@_fixed_mul_after:wwn + \int_use:N \__int_eval:w \c_@@_big_leading_shift_int + #6 + \exp_after:wN \@@_pack_big:NNNNNNw + \int_use:N \__int_eval:w \c_@@_big_middle_shift_int + #7 + \@@_fixed_mul_add_i:Nnwnnwnnn + + {#8}{#9}; {#2}{#3}{#4}; #1; {#2}{#3}{#4}#5; + + } +\cs_new:Npn \@@_fixed_mul_sub_back:wwwn #1; #2#3#4#5; #6#7#8#9 + { + \exp_after:wN \@@_fixed_mul_after:wwn + \int_use:N \__int_eval:w \c_@@_big_leading_shift_int + #6 + \exp_after:wN \@@_pack_big:NNNNNNw + \int_use:N \__int_eval:w \c_@@_big_middle_shift_int + #7 + \@@_fixed_mul_add_i:Nnwnnwnnn + - {#8}{#9}; {#2}{#3}{#4}; #1; {#2}{#3}{#4}#5; - + } +\cs_new:Npn \@@_fixed_mul_add_i:Nnwnnwnnn #1 #2#3; #4#5#6; #7#8#9 + { % sg z3z4; y1y2y3; x1x2x3 x4x5x6; y1y2y3y4y5y6; sg z5z6; + #1 #7*#4 + \exp_after:wN \@@_pack_big:NNNNNNw + \int_use:N \__int_eval:w \c_@@_big_middle_shift_int + #2 + #1 #7*#5 #1 #8*#4 + \exp_after:wN \@@_pack_big:NNNNNNw + \int_use:N \__int_eval:w \c_@@_big_middle_shift_int + #3 + #1 #7*#6 #1 #8*#5 #1 #9*#4 + \exp_after:wN \@@_pack_big:NNNNNNw + \int_use:N \__int_eval:w \c_@@_big_middle_shift_int + #1 \@@_fixed_mul_add_ii:nnnnwnnnn {#7}{#8}{#9} + } +\cs_new:Npn \@@_fixed_mul_add_ii:nnnnwnnnn #1#2#3#4#5; #6#7#8#9 + { % x1x2x3x4 x5x6; y1y2y3y4 y5y6; sg z5z6; + ( #1*#9 + #2*#8 + #3*#7 + #4*#6 ) + \exp_after:wN \@@_pack_big:NNNNNNw + \int_use:N \__int_eval:w \c_@@_big_trailing_shift_int + \@@_fixed_mul_add_iii:nnnnwnnwN + { #6 + #4*#7 + #3*#8 + #2*#9 + #1 } + { #7 + #4*#8 + #3*#9 + #2 } + {#1} #5; + {#6} + } +\cs_new:Npn \@@_fixed_mul_add_iii:nnnnwnnwN #1#2 #3#4#5; #6#7#8; #9 + { % {y1+x4*y2+x3*y3+x2*y4+x1} {y2+x4*y3+x3*y4+x2} + % x1x5x6; y1y5y6; sg z5z6; + % => + % sg (x5*y1+x4*y2+x3*y3+x2*y4+x1*y5) + % sg (x6*y1+x5*y2+x4*y3+x3*y4+x2*y5+x1*y6)/10000 + % + z5z6; + #9 (#4* #1 *#7) + #9 (#5*#6+#4* #2 *#7+#3*#8) / \c_ten_thousand + + \@@_use_s:nn + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\cs_new:Npn \@@_fixed_to_float:Nw #1#2; { \@@_fixed_to_float:wN #2; #1 } +% \end{macrocode} +% +% \begin{macro}[int, rEXP]{\@@_fixed_to_float:wN} +% \begin{syntax} +% \ldots{} \cs{__int_eval:w} \meta{exponent} \cs{@@_fixed_to_float:wN} \Arg{a_1} \Arg{a_2} \Arg{a_3} \Arg{a_4} \Arg{a_5} \Arg{a_6} |;| \meta{sign} +% \end{syntax} +% yields +% \begin{quote} +% \meta{exponent'} |;| \Arg{a'_1} \Arg{a'_2} \Arg{a'_3} \Arg{a'_4} |;| +% \end{quote} +% And the \texttt{to_fixed} version gives six brace groups instead of +% $4$, ensuring that $1000\leq\meta{a'_1}\leq 9999$. At this stage, we +% know that \meta{a_1} is positive (otherwise, it is sign of an error +% before), and we assume that it is less than $10^8$.\footnote{Bruno: +% I must double check this assumption.} +% +%^^A todo: round properly when rounding to infinity: I need to know the sign. +% \begin{macrocode} +\cs_new:Npn \@@_fixed_to_float:wN #1#2#3#4#5#6; #7 + { + + \c_four % for the 8-digit-at-the-start thing. + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_fixed_to_loop:N + \exp_after:wN \use_none:n + \int_use:N \__int_eval:w + 1 0000 0000 + #1 \exp_after:wN \@@_use_none_stop_f:n + \__int_value:w 1#2 \exp_after:wN \@@_use_none_stop_f:n + \__int_value:w 1#3#4 \exp_after:wN \@@_use_none_stop_f:n + \__int_value:w 1#5#6 + \exp_after:wN ; + \exp_after:wN ; + } +\cs_new:Npn \@@_fixed_to_loop:N #1 + { + \if_meaning:w 0 #1 + - \c_one + \exp_after:wN \@@_fixed_to_loop:N + \else: + \exp_after:wN \@@_fixed_to_loop_end:w + \exp_after:wN #1 + \fi: + } +\cs_new:Npn \@@_fixed_to_loop_end:w #1 #2 ; + { + \if_meaning:w ; #1 + \exp_after:wN \@@_fixed_to_float_zero:w + \else: + \exp_after:wN \@@_pack_twice_four:wNNNNNNNN + \exp_after:wN \@@_pack_twice_four:wNNNNNNNN + \exp_after:wN \@@_fixed_to_float_pack:ww + \exp_after:wN ; + \fi: + #1 #2 0000 0000 0000 0000 ; + } +\cs_new:Npn \@@_fixed_to_float_zero:w ; 0000 0000 0000 0000 ; + { + - \c_two * \c_@@_max_exponent_int ; + {0000} {0000} {0000} {0000} ; + } +\cs_new:Npn \@@_fixed_to_float_pack:ww #1 ; #2#3 ; ; + { + \if_int_compare:w #2 > \c_four + \exp_after:wN \@@_fixed_to_float_round_up:wnnnnw + \fi: + ; #1 ; + } +\cs_new:Npn \@@_fixed_to_float_round_up:wnnnnw ; #1#2#3#4 ; + { + \exp_after:wN \@@_basics_pack_high:NNNNNw + \int_use:N \__int_eval:w 1 #1#2 + \exp_after:wN \@@_basics_pack_low:NNNNNw + \int_use:N \__int_eval:w 1 #3#4 + \c_one ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[rEXP, int]{\@@_fixed_inv_to_float:wN, \@@_fixed_div_to_float:ww} +% Starting from \texttt{fixed_dtf} $A$ |;| $B$ |;| we want to compute +% $A/B$, and express it as a floating point number. Normalize both +% numbers by removing leading brace groups of zeros and leaving the +% appropriate exponent shift in the input stream. +% \begin{macrocode} +\cs_new:Npn \@@_fixed_inv_to_float:wN #1#2; #3 + { + - \__int_eval:w + \if_int_compare:w #1 < \c_one_thousand + \@@_fixed_dtf_zeros:wNnnnnnn + \fi: + \@@_fixed_dtf_no_zero:Nwn + {#1} #2 \s_@@ + \@@_fixed_dtf_approx:n + {10000} {0000} {0000} {0000} {0000} {0000} ; + } +\cs_new:Npn \@@_fixed_div_to_float:ww #1#2; #3#4; + { + \if_int_compare:w #1 < \c_one_thousand + \@@_fixed_dtf_zeros:wNnnnnnn + \fi: + \@@_fixed_dtf_no_zero:Nwn - {#1} #2 \s_@@ + { + \if_int_compare:w #3 < \c_one_thousand + \@@_fixed_dtf_zeros:wNnnnnnn + \fi: + \@@_fixed_dtf_no_zero:Nwn + {#3} #4 \s_@@ + \@@_fixed_dtf_approx:n + } + } +\cs_new:Npn \@@_fixed_dtf_no_zero:Nwn #1#2 \s_@@ #3 { #3 #2; } +\cs_new:Npn \@@_fixed_dtf_zeros:wNnnnnnn + \fi: \@@_fixed_dtf_no_zero:Nwn #1#2#3#4#5#6#7 + { + \fi: + #1 \c_minus_one + \exp_after:wN \use_i_ii:nnn + \exp_after:wN \@@_fixed_dtf_zeros:NN + \exp_after:wN #1 + \int_use:N \__int_eval:w 10 0000 + #2 \__int_eval_end: #3#4#5#6#7 + ; 1 ; + } +\cs_new:Npn \@@_fixed_dtf_zeros:NN #1#2 + { + \if_meaning:w 0 #2 + #1 \c_one + \else: + \@@_fixed_dtf_zeros_end:wNww #2 + \fi: + \@@_fixed_dtf_zeros:NN #1 + } +\cs_new:Npn \@@_fixed_dtf_zeros_end:wNww + #1 \fi: \@@_fixed_dtf_zeros:NN #2 #3; #4 \s_@@ + { + \fi: + \if_meaning:w ; #1 + #2 \c_two * \c_@@_max_exponent_int + \use_i_ii:nnn + \fi: + \@@_fixed_dtf_zeros_ii:ww + #1#3 0000 0000 0000 0000 0000 0000 ; + } +\cs_new:Npn \@@_fixed_dtf_zeros_ii:ww + { + \@@_pack_twice_four:wNNNNNNNN + \@@_pack_twice_four:wNNNNNNNN + \@@_pack_twice_four:wNNNNNNNN + \@@_fixed_dtf_zeros_iii:ww + ; + } +\cs_new:Npn \@@_fixed_dtf_zeros_iii:ww #1; #2; #3 { #3 #1; } +% \end{macrocode} +% \newcommand{\eTeXfrac}[2]{\left[\frac{#1}{#2}\right]} +% We get +% \begin{quote} +% \cs{@@_fixed_dtf_approx:n} \meta{B'} |;| \meta{A'} |;| +% \end{quote} +% where \meta{B'} and \meta{A'} are each $6$ brace groups, +% representing fixed point numbers in the range $[0.1,1)$. Denote by +% $x\in[1000,9999]$ and $y\in[0,9999]$ the first two groups of +% \meta{B'}. We first find an estimate $a$ for the inverse of $B'$ by +% computing +% \begin{align*} +% \alpha &= \eTeXfrac{10^{9}}{x+1} \\ +% \beta &= \eTeXfrac{10^{9}}{x} \\ +% a &= 10^{3} \alpha + (\beta-\alpha) \cdot +% \left(10^{3}-\eTeXfrac{y}{10}\right) - 1750, +% \end{align*} +% where $\eTeXfrac{\bullet}{\bullet}$ denotes \eTeX{}'s rounding +% division. The idea is to interpolate between $\alpha$ and $\beta$ +% with a parameter $y/10^{4}$. The shift by $1750$ helps to ensure +% that $a$ is an underestimate of the correct value. We will prove +% that +% \[ +% 1 - 2.255\cdot 10^{-5} < \frac{B'a}{10^{8}} < 1 . +% \] +% We can then compute the inverse $B'a/10^{8}$ using $1/(1-\epsilon) +% \simeq (1+\epsilon)(1+\epsilon^{2})$, which is correct up to a +% relative error of $\epsilon^4 < 2.6\cdot 10^{-19}$. Since we target +% a $16$-digit value, this is small enough. +% +% Let us prove the upper bound first. +% \begin{align}\label{l3fp-fixed-eTeXfrac} +% 10^{7} B'a +% & < \left(10^{3} x + \eTeXfrac{y}{10} + \frac{3}{2}\right) +% \left(\left(10^{3}-\eTeXfrac{y}{10}\right) \beta +% + \eTeXfrac{y}{10} \alpha - 1750\right) +% \\& < \left(10^{3} x + \eTeXfrac{y}{10} + \frac{3}{2}\right) +% \left(\left(10^{3}-\eTeXfrac{y}{10}\right) +% \left(\frac{10^{9}}{x} + \frac{1}{2} \right) +% + \eTeXfrac{y}{10} \left(\frac{10^{9}}{x+1} + \frac{1}{2} \right) +% - 1750\right) +% \\& < \left(10^{3} x + \eTeXfrac{y}{10} + \frac{3}{2}\right) +% \left(\frac{10^{12}}{x} +% - \eTeXfrac{y}{10} \frac{10^{9}}{x(x+1)} +% - 1250\right) +% \end{align} +% We recognize a quadratic polynomial in $[y/10]$ with a negative +% leading coefficient, $([y/10]+a)(b-c[y/10]) \leq (b+ca)^2/(4c)$. +% Hence, +% \[ +% 10^{7} B'a +% < \frac{10^{15}}{x(x+1)} \left( +% x + \frac{1}{2} + \frac{3}{4} 10^{-3} +% - 6.25\cdot 10^{-10} x(x+1) \right)^2 +% \] +% We want to prove that the squared expression is less than $x(x+1)$, +% which we do by simplifying the difference, and checking its sign, +% \[ +% x(x+1) - \left(x + \frac{1}{2} + \frac{3}{4} 10^{-3} +% - 6.25\cdot 10^{-10} x(x+1) \right)^2 +% > - \frac{1}{4} (1+1.5\cdot 10^{-3})^2 - 10^{-3} x +% + 1.25\cdot 10^{-9} x(x+1)(x+0.5) +% > 0. +% \] +% +% Now, the lower bound. The same computation as +% \eqref{l3fp-fixed-eTeXfrac} imply +% \[ +% 10^{7} B'a +% > \left(10^{3} x + \eTeXfrac{y}{10} - \frac{1}{2}\right) +% \left(\frac{10^{12}}{x} - \eTeXfrac{y}{10} \frac{10^{9}}{x(x+1)} +% - 2250\right) +% \] +% This time, we want to find the minimum of this quadratic polynomial. +% Since the leading coefficient is still negative, the minimum is +% reached for one of the extreme values $y=0$ or $y=9999$, and we +% easily check the bound for those values. +% +% We have proven that the algorithm will give us a precise enough +% answer. Incidentally, the upper bound that we derived tells us that +% $a < 10^{8}/B \leq 10^{9}$, hence we can compute $a$ safely as a +% \TeX{} integer, and even add $10^{9}$ to it to ease grabbing of all +% the digits. +% \begin{macrocode} +\cs_new:Npn \@@_fixed_dtf_approx:n #1 + { + \exp_after:wN \@@_fixed_dtf_approx_ii:wnn + \int_use:N \__int_eval:w 10 0000 0000 / ( #1 + \c_one ) ; + {#1} + } +\cs_new:Npn \@@_fixed_dtf_approx_ii:wnn #1; #2#3 + { +%<assert> \assert:n { \tl_count:n {#1} = 6 } + \exp_after:wN \@@_fixed_dtf_approx_iii:NNNNNw + \int_use:N \__int_eval:w 10 0000 0000 - 1750 + + #1000 + (10 0000 0000/#2-#1) * (1000-#3/10) ; + {#2}{#3} + } +\cs_new:Npn \@@_fixed_dtf_approx_iii:NNNNNw 1#1#2#3#4#5#6; #7; #8; + { + + \c_four % because of the line below "dtf_epsilon" here. + \@@_fixed_mul:wwn {000#1}{#2#3#4#5}{#6}{0000}{0000}{0000} ; #7; + \@@_fixed_dtf_epsilon:wN + \@@_fixed_mul:wwn {000#1}{#2#3#4#5}{#6}{0000}{0000}{0000} ; + \@@_fixed_mul:wwn #8; + \@@_fixed_to_float:wN ? + } +\cs_new:Npn \@@_fixed_dtf_epsilon:wN #1#2#3#4#5#6; + { +%<assert> \assert:n { #1 = 0000 } +%<assert> \assert:n { #2 = 9999 } + \exp_after:wN \@@_fixed_dtf_epsilon_ii:NNNNNww + \int_use:N \__int_eval:w 1 9999 9998 - #3#4 + + \exp_after:wN \@@_fixed_dtf_epsilon_pack:NNNNNw + \int_use:N \__int_eval:w 2 0000 0000 - #5#6 ; {0000} ; + } +\cs_new:Npn \@@_fixed_dtf_epsilon_pack:NNNNNw #1#2#3#4#5#6; + { #1 ; {#2#3#4#5} {#6} } +\cs_new:Npn \@@_fixed_dtf_epsilon_ii:NNNNNww #1#2#3#4#5#6; #7; + { + \@@_fixed_mul:wwn %^^A todo: optimize to use \@@_mul_mantissa. + {0000} {#2#3#4#5} {#6} #7 ; + {0000} {#2#3#4#5} {#6} #7 ; + \@@_fixed_add_one:wN + \@@_fixed_mul:wwn {10000} {#2#3#4#5} {#6} #7 ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx new file mode 100644 index 00000000000..2517236fb21 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx @@ -0,0 +1,393 @@ +% \iffalse meta-comment +% +%% File: l3fp-logic.dtx Copyright (C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-logic.dtx 3504 2012-03-06 06:38:45Z bruno $ + {L3 Floating-point conditionals} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp-logic} package\thanks{This file +% has version number \ExplFileVersion, last +% revised \ExplFileDate.}\\ +% Floating point conditionals} +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-logic} Implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{Existence test} +% +% \begin{macro}[pTF]{\fp_if_exist:N, \fp_if_exist:c} +% Copies of the \texttt{cs} functions defined in \pkg{l3basics}. +% \begin{macrocode} +\cs_new_eq:NN \fp_if_exist:NTF \cs_if_exist:NTF +\cs_new_eq:NN \fp_if_exist:NT \cs_if_exist:NT +\cs_new_eq:NN \fp_if_exist:NF \cs_if_exist:NF +\cs_new_eq:NN \fp_if_exist_p:N \cs_if_exist_p:N +\cs_new_eq:NN \fp_if_exist:cTF \cs_if_exist:cTF +\cs_new_eq:NN \fp_if_exist:cT \cs_if_exist:cT +\cs_new_eq:NN \fp_if_exist:cF \cs_if_exist:cF +\cs_new_eq:NN \fp_if_exist_p:c \cs_if_exist_p:c +% \end{macrocode} +% \end{macro} +% +% \subsection{Comparison} +% +% \begin{macro}[int, EXP]{\@@_compare:ww} +% \begin{macro}[aux, EXP] +% { +% \@@_compare_nan:w, \@@_compare_mantissa:ww, +% \@@_compare_mantissa:nnnnnnnn +% } +% \begin{syntax} +% \cs{@@_compare:ww} \meta{X} |;| \meta{Y} |;| +% \end{syntax} +% Expands (in the same way as \cs{int_eval:n}) to $-1$ if $x<y$, $0$ +% if $x=y$, $1$ if $x>y$, and $2$ otherwise (denoted as $x?y$). A +% trick that will later be useful is that the character codes of |<|, +% |=|, |>| and |?| are contiguous, and in the same order as the return +% codes of \cs{@@_compare:ww}. +% \begin{macrocode} +\cs_new:Npn \@@_compare:ww \s_@@ \@@_chk:w #1#2#3; \s_@@ \@@_chk:w #4#5#6; + { + \__int_value:w + \if_meaning:w 3 #1 \exp_after:wN \@@_compare_nan:w \fi: + \if_meaning:w 3 #4 \exp_after:wN \@@_compare_nan:w \fi: + \if_meaning:w 2 #2 - \fi: + \if_meaning:w #2 #5 + \if_meaning:w #1 #4 + \if_meaning:w 1 #1 + \@@_compare_mantissa:ww #3; #6; + \else: + 0 + \fi: + \else: + \if_int_compare:w #1 < #4 - \fi: 1 + \fi: + \else: + \if_meaning:w 0 #1 + \if_meaning:w 0 #4 + 0 + \else: + 1 + \fi: + \else: + 1 + \fi: + \fi: + \exp_stop_f: + } +\cs_new:Npn \@@_compare_nan:w #1 \exp_stop_f: { \c_two } +\cs_new:Npn \@@_compare_mantissa:ww #1#2; #3#4; + { + \if_int_compare:w #1 = #3 \exp_stop_f: + \@@_compare_mantissa:nnnnnnnn #2 #4 + \else: + \if_int_compare:w #1 < #3 - \fi: 1 + \fi: + } +\cs_new:Npn \@@_compare_mantissa:nnnnnnnn #1#2#3#4#5#6#7#8 + { + \if_int_compare:w #1 = #5 \exp_stop_f: + \if_int_compare:w #2 = #6 \exp_stop_f: + \if_int_compare:w #3 = #7 \exp_stop_f: + \if_int_compare:w #4 = #8 \exp_stop_f: + 0 + \else: + \if_int_compare:w #4 < #8 - \fi: 1 + \fi: + \else: + \if_int_compare:w #3 < #7 - \fi: 1 + \fi: + \else: + \if_int_compare:w #2 < #6 - \fi: 1 + \fi: + \else: + \if_int_compare:w #1 < #5 - \fi: 1 + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF, EXP]{\fp_compare:nNn} +% \begin{macro}[aux, EXP]{\@@_compare_aux:wn} +% Evaluate |#1| and |#3|, using an auxiliary to expand both, in the +% correct order. Then compare this to |`#2-`=|, which is $-1$ for +% |<|, $0$ for |=|, $1$ for |>| and $2$ for |?|. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_compare:nNn #1#2#3 { p , T , F , TF } + { + \if_int_compare:w + \exp_after:wN \@@_compare_aux:wn + \tex_romannumeral:D -`0 \@@_parse:n {#3} {#1} + = \__int_eval:w `#2 - `= \__int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new:Npn \@@_compare_aux:wn #1; #2 + { + \exp_after:wN \@@_compare:ww + \tex_romannumeral:D -`0 \@@_parse:n {#2} #1; + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP,pTF]{\fp_compare:n} +% \begin{macro}[aux,EXP]{\@@_compare_aux:w} +% For floating points the comparison operators are treated as +% operations, so we simply evaluate then compare with \cs{c_zero_fp}. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_compare:n #1 { p , T , F , TF } + { + \exp_after:wN \@@_compare_aux:w + \tex_romannumeral:D -`0 \@@_parse:n {#1} + } +\cs_new:Npn \@@_compare_aux:w \s_@@ \@@_chk:w #1#2; + { + \if_meaning:w 0 #1 + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Boolean operations} +% +% \begin{macro}[int, EXP]{\@@_not:w} +% Return \texttt{true} or \texttt{false}, with two expansions, one to +% exit the conditional, and one to please \pkg{l3fp-parse}. +% \begin{macrocode} +\cs_new:Npn \@@_not:w \s_@@ \@@_chk:w #1#2; + { + \if_meaning:w 0 #1 + \exp_after:wN \exp_after:wN \exp_after:wN \c_one_fp + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \c_zero_fp + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]+\@@_&_o:ww+ +% \begin{macro}[int, EXP]+\@@_|_o:ww+ +% \begin{macro}[aux, EXP]{\@@_and_return:wNw} +% For \texttt{and}, if the first number is zero, return it (with the +% same sign). Otherwise, return the second one. For \texttt{or}, the +% logic is reversed: if the first number is non-zero, return it, +% otherwise return the second number: we achieve that by hi-jacking +% \cs{@@_\&_o:ww}, inserting an extra argument, \cs{else:}, before +% \cs{s_@@}. In all cases, expand after the floating point number. +% \begin{macrocode} +\cs_new:cpn { @@_ \iow_char:N \& _o:ww } #1 \s_@@ \@@_chk:w #2#3; + { + \if_meaning:w 0 #2 #1 + \@@_and_return:wNw \s_@@ \@@_chk:w #2#3; + \fi: + \@@_exp_after_o:w + } +\cs_new_nopar:cpx { @@_ \iow_char:N \| _o:ww } + { \exp_not:c { @@_ \iow_char:N \& _o:ww } \exp_not:N \else: } +\cs_new:Npn \@@_and_return:wNw #1; \fi: #2#3; { \fi: #2 #1; } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int, EXP] +% {\@@_ternary:NwwN, \@@_ternary_i:NwwN, \@@_ternary_ii:NwwN} +% The first function receives the test and the true branch of the |?:| +% ternary operator. It returns the true branch, unless the test +% branch is zero. In that case, the function returns a very specific +% \texttt{nan}. The second function receives the output of the first +% function, and the false branch. It returns the previous input, +% unless that is the special \texttt{nan}, in which case we return the +% false branch. +%^^A todo: optimize. +% \begin{macrocode} +\cs_new:Npn \@@_ternary:NwwN #1 #2@ #3@ #4 + { + \if_meaning:w \@@_parse_infix_::N #4 + \@@_ternary_loop:Nw + #2 + \s_@@ \@@_chk:w { \@@_ternary_loop_break:w } ; + \@@_ternary_break_point:n { \exp_after:wN \@@_ternary_i:NwwN } + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \@@_parse_exp_after_array:wf #3 \s_@@_stop + \exp_after:wN @ + \tex_romannumeral:D + \@@_parse_until:Nw \c_two + \@@_parse_expand:w + \else: + \@@_error:n { Missing~':'~clause~for~'?:'. } + \exp_after:wN \@@_parse_until_test:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \@@_parse_exp_after_array:wf #3 \s_@@_stop + \exp_after:wN #4 + \exp_after:wN #1 + \fi: + } +\cs_new:Npn \@@_ternary_loop_break:w #1 \fi: #2 \@@_ternary_break_point:n #3 + { + \c_zero = \c_zero \fi: + \exp_after:wN \@@_ternary_ii:NwwN + } +\cs_new:Npn \@@_ternary_loop:Nw \s_@@ \@@_chk:w #1#2; + { + \if_int_compare:w #1 > \c_zero + \exp_after:wN \@@_ternary_map_break: + \fi: + \@@_ternary_loop:Nw + } +\cs_new:Npn \@@_ternary_map_break: #1 \@@_ternary_break_point:n #2 {#2} +\cs_new:Npn \@@_ternary_i:NwwN #1#2@#3@#4 + { + \exp_after:wN \@@_parse_until_test:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \@@_parse_exp_after_array:wf #2 \s_@@_stop + #4 #1 + } +\cs_new:Npn \@@_ternary_ii:NwwN #1#2@#3@#4 + { + \exp_after:wN \@@_parse_until_test:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \@@_parse_exp_after_array:wf #3 \s_@@_stop + #4 #1 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_max:w, \@@_min:w} +% \begin{macrocode} +\cs_new:Npn \@@_max:w #1@ + { + \exp_after:wN \@@_minmax_loop:Nww + \exp_after:wN \c_minus_one + \c_minus_inf_fp + #1 + \s_@@ \@@_chk:w { 3 \@@_minmax_break:w } ; + } +\cs_new:Npn \@@_min:w #1@ + { + \exp_after:wN \@@_minmax_loop:Nww + \exp_after:wN \c_one + \c_inf_fp + #1 + \s_@@ \@@_chk:w { 3 \@@_minmax_break:w } ; + } +\cs_new:Npn \@@_minmax_loop:Nww + #1 \s_@@ \@@_chk:w #2#3; \s_@@ \@@_chk:w #4#5; + { + \if_meaning:w 3 #4 + \if_meaning:w 3 #2 + \@@_minmax_i:ww + \else: + \@@_minmax_ii:ww + \fi: + \else: + \if_int_compare:w \@@_compare:ww \s_@@ \@@_chk:w #2#3; + \s_@@ \@@_chk:w #4#5; = #1 + \@@_minmax_ii:ww + \else: + \@@_minmax_i:ww + \fi: + \fi: + \@@_minmax_loop:Nww #1 + \s_@@ \@@_chk:w #2#3; + \s_@@ \@@_chk:w #4#5; + } +\cs_new:Npn \@@_minmax_i:ww + #1 \@@_minmax_loop:Nww #2 \s_@@ #3; \s_@@ #4; + { #1 \@@_minmax_loop:Nww #2 \s_@@ #3; } +\cs_new:Npn \@@_minmax_ii:ww + #1 \@@_minmax_loop:Nww #2 \s_@@ #3; \s_@@ #4; + { #1 \@@_minmax_loop:Nww #2 \s_@@ #4; } +\cs_new:Npn \@@_minmax_break:w #1 \@@_minmax_loop:Nww #2 #3; #4; + { + \fi: + \@@_exp_after_o:w #3; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-old.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-old.dtx new file mode 100644 index 00000000000..b195f766d52 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-old.dtx @@ -0,0 +1,273 @@ +% \iffalse meta-comment +% +%% File: l3fp-old.dtx Copyright (C) 2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX3 Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-old.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Experimental floating-points (old)} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3fp-old} package\\ Floating-points (old)^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-old} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{Compatibility} +% +% \begin{variable}{\c_undefined_fp} +% The old floating point number \cs{c_undefined_fp} is now implemented +% as a \texttt{nan}. +% \begin{macrocode} +\fp_const:Nn \c_undefined_fp { nan } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[pTF]{\fp_if_undefined:N} +% An old floating point is undefined if it is \texttt{inf} or +% \texttt{nan}, \emph{i.e.}, if its type is $2$ or $3$. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_if_undefined:N #1 { p , T , F , TF } + { \exp_after:wN \@@_if_undefined:w #1 } +\cs_new:Npn \@@_if_undefined:w \s_@@ \@@_chk:w #1#2; + { + \if_int_compare:w #1 > \c_one + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\fp_if_zero:N} +% An old floating point is zero if it is $\pm 0$, \emph{i.e.}, its +% type is $0$. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_if_zero:N #1 { p , T , F , TF } + { \exp_after:wN \@@_if_zero:w #1 } +\cs_new:Npn \@@_if_zero:w \s_@@ \@@_chk:w #1#2; + { \if_meaning:w #1 0 \prg_return_true: \else: \prg_return_false: \fi: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \fp_abs:N , \fp_abs:c , \fp_gabs:N , \fp_gabs:c , +% \fp_neg:N , \fp_neg:c , \fp_gneg:N , \fp_gneg:c , +% } +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_abs:N { \@@_abs:NNN \tl_set:Nx \@@_abs:w } +\cs_new_protected_nopar:Npn \fp_gabs:N { \@@_abs:NNN \tl_gset:Nx \@@_abs:w } +\cs_new_protected_nopar:Npn \fp_neg:N { \@@_abs:NNN \tl_set:Nx \@@_neg:w } +\cs_new_protected_nopar:Npn \fp_gneg:N { \@@_abs:NNN \tl_gset:Nx \@@_neg:w } +\cs_new_protected:Npn \@@_abs:NNN #1#2#3 + { #1 #3 { \exp_after:wN #2 #3 \prg_do_nothing: } } +\cs_generate_variant:Nn \fp_abs:N { c } +\cs_generate_variant:Nn \fp_gabs:N { c } +\cs_generate_variant:Nn \fp_neg:N { c } +\cs_generate_variant:Nn \fp_gneg:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \fp_mul:Nn, \fp_mul:cn, \fp_gmul:Nn, \fp_gmul:cn, +% \fp_div:Nn, \fp_div:cn, \fp_gdiv:Nn, \fp_gdiv:cn, +% \fp_pow:Nn, \fp_pow:cn, \fp_gpow:Nn, \fp_gpow:cn, +% } +% \begin{macro}[aux]{\@@_mul:NNNn} +% See \cs{fp_add:Nn} for details. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_mul:Nn { \@@_mul:NNNn \fp_set:Nn * } +\cs_new_protected_nopar:Npn \fp_gmul:Nn { \@@_mul:NNNn \fp_gset:Nn * } +\cs_new_protected_nopar:Npn \fp_div:Nn { \@@_mul:NNNn \fp_set:Nn / } +\cs_new_protected_nopar:Npn \fp_gdiv:Nn { \@@_mul:NNNn \fp_gset:Nn / } +\cs_new_protected_nopar:Npn \fp_pow:Nn { \@@_mul:NNNn \fp_set:Nn ^ } +\cs_new_protected_nopar:Npn \fp_gpow:Nn { \@@_mul:NNNn \fp_gset:Nn ^ } +\cs_new_protected:Npn \@@_mul:NNNn #1#2#3#4 { #1 #3 { #3 #2 (#4) } } +\cs_generate_variant:Nn \fp_mul:Nn { c } +\cs_generate_variant:Nn \fp_gmul:Nn { c } +\cs_generate_variant:Nn \fp_div:Nn { c } +\cs_generate_variant:Nn \fp_gdiv:Nn { c } +\cs_generate_variant:Nn \fp_pow:Nn { c } +\cs_generate_variant:Nn \fp_gpow:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \fp_exp:Nn, \fp_exp:cn, \fp_gexp:Nn, \fp_gexp:cn, +% \fp_ln:Nn , \fp_ln:cn , \fp_gln:Nn , \fp_gln:cn , +% \fp_sin:Nn, \fp_sin:cn, \fp_gsin:Nn, \fp_gsin:cn, +% \fp_cos:Nn, \fp_cos:cn, \fp_gcos:Nn, \fp_gcos:cn, +% \fp_tan:Nn, \fp_tan:cn, \fp_gtan:Nn, \fp_gtan:cn, +% } +% \begin{macro}[aux] +% {\@@_assign_to:nNNNn, \@@_assign_to_i:wNNNn, \@@_assign_to_ii:NnNNN} +% Here, an added twist +% is that each value computed by these expensive unary operations is +% stored as a constant floating point number. +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1#2#3#4#5 + { + \cs_new_protected_nopar:Npn #1 { #5 {#4} \tl_set_eq:NN #3 } + \cs_new_protected_nopar:Npn #2 { #5 {#4} \tl_gset_eq:NN #3 } + \cs_generate_variant:Nn #1 { c } + \cs_generate_variant:Nn #2 { c } + } +\@@_tmp:w \fp_exp:Nn \fp_gexp:Nn \@@_exp:w {exp} \@@_assign_to:nNNNn +\@@_tmp:w \fp_ln:Nn \fp_gln:Nn \@@_ln:w {ln } \@@_assign_to:nNNNn +\@@_tmp:w \fp_sin:Nn \fp_gsin:Nn \@@_sin:w {sin} \@@_assign_to:nNNNn +\@@_tmp:w \fp_cos:Nn \fp_gcos:Nn \@@_cos:w {cos} \@@_assign_to:nNNNn +\@@_tmp:w \fp_tan:Nn \fp_gtan:Nn \@@_tan:w {tan} \@@_assign_to:nNNNn +\cs_new_protected:Npn \@@_assign_to:nNNNn #1#2#3#4#5 + { + \exp_after:wN \@@_assign_to_i:wNNNn + \tex_romannumeral:D -`0 \@@_parse:n {#5} {#1} #2#3#4 + } +\cs_new_protected:Npn \@@_assign_to_i:wNNNn \s_@@ \@@_chk:w #1#2#3; #4 + { + \exp_args:Nc \@@_assign_to_ii:NnNNN + { c_@@_ #4 ( #2 \if_meaning:w 1 #1 #3 \fi: ) _fp } + { #1#2#3 } + } +\cs_new_protected:Npn \@@_assign_to_ii:NnNNN #1#2#3#4#5 + { + \cs_if_exist:NF #1 + { \tl_const:Nx #1 { #4 \s_@@ \@@_chk:w #2; } } + #3 #5 #1 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF, EXP]{\fp_compare:NNN} +% Comparisons used to be easier between floating points stored in +% variables. No more. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_compare:NNNTF { \fp_compare:nNnTF } +\cs_new_protected_nopar:Npn \fp_compare:NNNT { \fp_compare:nNnT } +\cs_new_protected_nopar:Npn \fp_compare:NNNF { \fp_compare:nNnF } +\cs_new_protected_nopar:Npn \fp_compare_p:NNN { \fp_compare_p:nNn } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_round_places:Nn, \fp_ground_places:Nn} +% \begin{macro}[aux]{\@@_round_places:NNn} +% Rounding to a given number of places is easy, since it is provided +% by the \pkg{l3fp-round} module. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_round_places:Nn + { \@@_round_places:NNn \tl_set:Nx } +\cs_new_protected_nopar:Npn \fp_ground_places:Nn + { \@@_round_places:NNn \tl_gset:Nx } +\cs_new_protected:Npn \@@_round_places:NNn #1#2#3 + { + #1 #2 + { + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_round:Nwn + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_round_to_nearest:NNN + \exp_after:wN #2 + \exp_after:wN { \int_use:N \__int_eval:w #3 } + } + } +\cs_generate_variant:Nn \fp_round_places:Nn { c } +\cs_generate_variant:Nn \fp_ground_places:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_round_figures:Nn, \fp_ground_figures:Nn} +% Rounding to a given number of figures is the same as rounding to a +% number of places, after shifting by the exponent of the argument. +% \begin{macrocode} +\cs_new_protected:Npn \fp_round_figures:Nn #1#2 + { + \@@_round_places:NNn \tl_set:Nx #1 + { #2 - \exp_after:wN \@@_exponent:w #1 } + } +\cs_new_protected:Npn \fp_ground_figures:Nn #1#2 + { + \@@_round_places:NNn \tl_gset:Nx #1 + { #2 - \exp_after:wN \@@_exponent:w #1 } + } +\cs_generate_variant:Nn \fp_round_figures:Nn { c } +\cs_generate_variant:Nn \fp_ground_figures:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx new file mode 100644 index 00000000000..11ec4e11b54 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx @@ -0,0 +1,2601 @@ +% \iffalse meta-comment +% +%% File: l3fp-parse.dtx Copyright (C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-parse.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Floating-point expression parsing} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp-parse} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Floating point expression parsing} +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% \date{Released \filedate} +% +% \maketitle +% +% ^^A begin[todo] +% +% ^^A To typeset the examples of expansion control, I'm using a hand-made +% ^^A environment. +% \newcommand{\fpOperation}[1] +% {\textcolor[rgb]{.6,.2,.2}{\ttfamily#1}} +% \newcommand{\fpPrecedence}[1] +% {\textcolor[rgb]{.2,.2,.6}{\ttfamily#1}} +% \newcommand{\fpExpand}[2] +% {\underline{\textcolor{red}{#1{#2}}}} +% \newenvironment{l3fp-code-example} +% {\begin{quote}^^A +% \edef\^{\string^}^^A +% \let\*\fpExpand +% \let\o\fpOperation +% \let\p\fpPrecedence +% \def\!{\begingroup\def\!{\endgroup\par}\color[gray]{0.5}}^^A +% \ttfamily\frenchspacing +% }{\end{quote}} +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-parse} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \section{Precedences} +% +% In order of evaluation (some distinctions are irrelevant for the order +% of evaluation, but serve as signals). +% \begin{itemize} +% \item[32] Juxtaposition for implicit multiplication. +% \item[16] Function calls with multiple arguments. +% \item[15] Function calls expecting exactly one argument. +% \item[14] Binary |**| and |^| (right to left). +% \item[12] Unary |+|, |-|, |!| (right to left). +% \item[10] Binary |*|, |/| and |%|. +% \item[9] Binary |+| and |-|. +% \item[7] Comparisons. +% \item[5] Logical \texttt{and}, denoted by |&&|. +% \item[4] Logical \texttt{or}, denoted by \verb*+||+. +% \item[3] Ternary operator |?:|, piece |?|. +% \item[2] Ternary operator |?:|, piece |:|. +% \item[1] Commas, and parentheses accepting commas. +% \item[0] Parentheses expecting exactly one argument. +% \item[-1] Start and end of the expression. +% \end{itemize} +% +% ^^A todo: change 'mantissa' => 'significand' everywhere. +% ^^A todo: ask SO when sNaN can arise. +% +% \section{Evaluating an expression} +% +% \begin{macro}[EXP, int]{\@@_parse:n} +% \begin{syntax} +% \cs{@@_parse:n} \Arg{floating point expression} +% \end{syntax} +% This \texttt{f}-expands to the internal floating point number +% obtained by evaluating the \meta{floating point expression}. During +% this evaluation, each token is fully \texttt{f}-expanded. +% \begin{texnote} +% Registers (integers, toks, etc.) are automatically unpacked, +% without requiring a function such as \cs{int_use:N}. Invalid +% tokens remaining after \texttt{f}-expansion will lead to +% unrecoverable low-level TeX errors.\footnote{Bruno: describe what +% happens in cases like $2\cs{c_three} = 6$.} +% \end{texnote} +% \end{macro} +% +% \section{Work plan}\label{subsec:fp-parse-workplan} +% +% The task at hand is non-trivial, and some previous failed attempts have +% shown me that the code ends up giving unreadable logs, so we'd better get +% it (almost) right the first time. Let us thus first discuss precisely +% the design before starting to write the code. To simplify matters, +% we first consider expressions with integers only. +% +% \subsection{Storing results} +% +% The main issue in parsing expressions expandably is: \enquote{where +% in the input stream should the result be put?} +% +% One option is to place the result at the end of the expression, +% but this has several drawbacks: +% \begin{itemize} +% \item firstly it means that for long expressions we would be reaching +% all the way to the end of the expression at every step of the +% calculation, which can be rather expensive; +% \item secondly, when parsing parenthesized sub-expressions, we would +% naturally place the result after the corresponding closing parenthesis. +% But since \cs{@@_parse:n} does not assume that its argument is expanded, +% this closing parenthesis may be hidden in a macro, and not present yet, +% causing havoc. +% \end{itemize} +% +% The other natural option is to store the result at the start of the +% expression, and carry it as an argument of each macro. This does not +% really work either: in order to expand what follows on the input stream, +% we need to skip at each step over all the tokens in the result using +% \cs{exp_after:wN}. But this requires adding many \cs{exp_after:wN} to +% the result at each step, also an expensive process. +% +% Hence, we need to go for some fine expansion control: the result is +% stored \emph{before} the start\ldots{} A toy model that illustrates this +% idea is to try and add some positive integers which may be hidden +% within macros, or registers. Assume that one number has already been +% found, and that we want to parse the next number. The current status +% of the code may look as follows. +% \begin{quote}\ttfamily +% \cs{exp_after:wN} \cs{add:ww} +% \cs{__int_value:w} 12345 \cs{exp_after:wN} ; \newline +% \cs{tex_romannumeral:D} -`0 \cs{clean:w} \meta{stuff} +% \end{quote} +% Hitting this construction by one step of expansion expands +% \cs{exp_after:wN}, which triggers the primitive \cs{__int_value:w}, +% which reads an integer, \texttt{12345}. This integer is unfinished, +% causing the second \cs{exp_after:wN} to expand, and trigger +% the construction \cs{tex_romannumeral:D} |-`0|, which f-expands +% \cs{clean:w} (see \pkg{l3expan.dtx} for an explanation). Assume +% then that \cs{clean:w} is such that it expands \meta{stuff} to +% \emph{e.g.}, |333444;|. Once \cs{clean:w} is done expanding, we +% will obtain essentially +% \begin{quote}\ttfamily +% \cs{exp_after:wN} \cs{add:ww} \cs{__int_value:w} 12345 ; 333444 ; +% \end{quote} +% where in fact \cs{exp_after:wN} has already been expanded, and +% \cs{__int_value:w} has already seen \texttt{12345}. Now, +% \cs{__int_value:w} sees the \texttt{;}, and stops expanding, and +% we are left with +% \begin{quote}\ttfamily +% \cs{add:ww} 12345 ; 333444 ; +% \end{quote} +% which can safely perform the addition by grabbing two arguments +% delimited by \texttt{;}. +% +% On this toy example, we could note that if we were to continue +% parsing the expression, then the following number should also +% be cleaned up before the next use of a binary operation such as +% \cs{add:ww}. Just like \cs{__int_value:w} \texttt{12345} +% \cs{exp_after:wN} \texttt{;} expanded what follows once, we need +% \cs{add:ww} to do the calculation, and in the process to expand +% the following once. This is also true in our real application: +% all the functions of the form \cs{@@_..._o:ww} expand what +% follows once. This comes at the cost of leaving tokens in the +% input stack, and we will need to be careful to waste as little +% as possible of this precious memory. +% +% \subsection{Precedence} +% +% A major point to keep in mind when parsing expressions is that +% different operators have different precedence. The true analog +% of our toy \cs{clean:w} macro must thus take care of that. For +% definiteness, let us assume that the operation which prompted +% \cs{clean:w} was a multiplication. Then \cs{clean:w} (expand +% and) read digits until the number is ended by some operation. +% If this is \texttt{+} or~\texttt{-}, then the multiplication +% should be calculated next, so \cs{clean:w} can simply decide +% that its job is done. However, if the operator we find is |^|, +% then this operation must be performed before returning control +% to the multiplication. This means that we need to \cs{clean:w} +% the number following |^|, and perform the calculation, then just +% end our job. +% +% Hence, each time a number is cleaned, the precedence of the +% following operation must be compared to that of the previous +% operation. The process of course has to happen recursively. +% For instance, |1+2^3*4| would involve the following steps. +% \begin{itemize} +% \item |1| is cleaned up. +% \item |2| is cleaned up. +% \item The precedences of |+| and |^| are compared. Since the +% latter is higher, the second operand of |^| should be cleaned. +% \item |3| is cleaned up. +% \item The precedences of |^| and |*| are compared. Since the +% former is higher, the cleaning step stops. +% \item Compute |2^3 = 8|. +% \item We now have |1+8*4|, and the operation |+| is still +% looking for a second operand. Clean |8|. +% \item The precedences of |+| and |*| are compared. Since the +% latter is higher, the second operand of |*| should be cleaned. +% \item |4| is cleaned up, and the end of the expression is reached. +% \item Compute |8*4 = 32|. +% \item We now have |1+8*4|, and the operation |+| is still +% looking for a second operand. Clean |32|, and reach the end +% of the expression. +% \item Compute |1+32 = 33|. +% \end{itemize} +% Here, there is some (expensive) redundant work: the results of +% computations should not need to be cleaned again. Thus the true definition +% is slightly more elaborate. +% +% The precedence of |(| and |)| are defined to be equal, and smaller than +% the precedence of |+| and |-|, itself smaller than |*| and |/|, smaller, +% finally, then the power operator |**| (or |^|). +% +% +% \subsection{Infix operators} +% +% The implementation that was chosen is slightly wasteful: it causes +% more nesting than necessary. ^^A todo: clarify. +% However, it is simpler to implement and to explain than a slightly +% optimized variant. ^^A todo: implement optimized version; compare. +% +% The cornerstone of that method is a pair of functions, +% \cs{until} and \cs{one}, which both take as their first +% argument the precedence (an integer) of the last operation. +% The f-expansion of +% \begin{quote} +% \cs{until} \meta{prec} \cs{one} \meta{prec} \meta{stuff} +% \end{quote} +% is the internal floating point obtained by \enquote{cleaning} +% numbers which follow in the input stream, and performing +% computations until reaching an operation with a precedence +% less than or equal to \meta{prec}. This is followed by a control +% sequence of the form \cs{infix_?}, namely, +% \begin{quote} +% \meta{floating point} \cs{infix_?} +% \end{quote} +% where |?| is the operation following that number in the input +% stream (we thus know that this operation has at most the +% precedence \meta{prec}, otherwise it would have been performed +% already). +% +% How is that expansion achieved? First, \cs{one} \meta{prec} +% reads one \meta{floating point} number, and converts it to an +% internal form, then the following operation, say |*|, is +% packed in the form \cs{infix_*}, which is fed the \meta{prec}. +% This function (one per infix operator) compares \meta{prec} +% with the precedence of the operator we just read (here |*|). +% If \meta{prec} is higher, our job is finished, and \cs{one} +% leaves \cs{@@_parse_stop_until:N} so that \cs{until} knows to stop. +% Otherwise, \cs{infix_*} triggers a new pair +% \cs{until} \meta{prec(*)} \cs{one} \meta{prec(*)}, +% which produces the second operand \meta{floating point_2} +% for the multiplication: +% \begin{quote} +% \cs{until} \meta{prec} \meta{floating point} \newline +% \texttt{...} \meta{floating point_2} |;| \cs{infix_?} +% \end{quote} +% The dots are \cs{@@_parse_apply_binary:NwNwN} |*|. The boolean +% tells \cs{until} that it is not done, and it expands +% (essentially) to +% \begin{quote} +% \cs{until} \meta{prec} +% \cs{@@_mul_o:ww} \meta{floating point} \meta{floating point_2} +% \cs{tex_romannumeral:D} \texttt{-`0} \cs{infix_?} \meta{prec} +% \end{quote} +% making \TeX{} expand \cs{@@_mul_o:ww} before \cs{until}. As +% implemented in \pkg{l3fp-basics}, this operation expands what follows +% its result exactly once. This triggers \cs{tex_romannumeral:D}, +% which fully expands \cs{infix_?} \meta{prec}. This compares +% the precedence of the next operation, |?|, and \meta{prec}, +% and leaves a boolean (and possibly more things), which is then +% checked by \cs{until} \meta{prec} to know if the result +% of the multiplication is the end of the story, or if |?| +% should be computed as well before \cs{until} \meta{prec} ends. +% +% This should be easier to see on an example. To each infix +% operator, for instance, |*|, is associated the following data: +% \begin{itemize} +% \item a test function, \cs{infix_*}, which conditionally continues +% the calculation or waits to be hit again by expansion; +% \item a function \fpOperation{*} (notation for \cs{@@_mul_o:ww}) +% which performs the actual calculation; +% \item an integer, \fpPrecedence{*}, which encodes the precedence of +% the operator. +% \end{itemize} +% The token that is currently being expanded is underlined, +% and in red. Tokens that have not yet been read (and could +% still be hidden in macros) are in gray. +% +% In a first reading, the disinction between the \meta{precedence} +% \fpPrecedence{+}, the operation \fpOperation{+}, and the character +% token |+| should not matter. It is only required to accomodate for +% multi-token infix operators such as |**|: indeed, when controlling +% expansion, we need to skip over those tokens using \cs{exp_after:wN}, +% and this only skips one token. Thus |**| needs to be replaced by a +% single token (either its precedence or its calculating function, +% depending on the place). +% +% To end the computation cleanly, we add a trailing right +% parenthesis, and give |(| and |)| the lowest precedence, +% so that \cs{until}\fpPrecedence{(} \cs{one}\fpPrecedence{(} +% reads numbers and performs operations until meeting a right +% parenthesis. This is discussed more precisely in the next section. +% +% \begin{l3fp-code-example} +% \cs{until}\p( \*\cs{one}\p( \! 11 + 2**3 * 5 - 9 )\! +% \cs{until}\p( 1 \*\cs{one}\p( \! 1 + 2**3 * 5 - 9 )\! +% \cs{until}\p( 11 \*\cs{one}\p( \! + 2**3 * 5 - 9 )\! +% \cs{until}\p( 11; \*\cs{infix_+}\p( \! 2**3 * 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ \*\cs{one}\p+ \! 2**3 * 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2 \*\cs{one}\p+ \! **3 * 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2; \*\cs{infix_**}\p+ \! 3 * 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2; +% F \o{**} \cs{until}\p{**} \*\cs{one}\p{**} \! 3 * 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2; +% F \o{**} \cs{until}\p{**} 3 \*\cs{one}\p{**} \! * 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2; +% F \o{**} \cs{until}\p{**} 3; \*\cs{infix_*}\p{**} \! 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2; +% F \o{**} \*\cs{until}\p{**} 3; T \cs{infix_*} \! 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \*\cs{until}\p+ 2; +% F \o{**} 3; \cs{infix_*} \! 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ \*\o{**} 2; 3; +% \cs{infix_*}\p+ \! 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 8; \*\cs{infix_*}\p+ \! 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 8; +% F \o* \cs{until}\p* \*\cs{one}\p* \! 5 - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 8; +% F \o* \cs{until}\p* 5 \*\cs{one}\p* \! - 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 8; +% F \o* \cs{until}\p* 5; \*\cs{infix_-}\p* \! 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 8; +% F \o* \*\cs{until}\p* 5; T \cs{infix_-} \! 9 )\! +% \cs{until}\p( 11; F \o+ \*\cs{until}\p+ 8; F \o* 5; \cs{infix_-} \! 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ \*\o{*} 8; 5; \cs{infix_-}\p+ \! 9 )\! +% \cs{until}\p( 11; F \o+ \cs{until}\p+ 40; \*\cs{infix_-}\p+ \! 9 )\! +% \cs{until}\p( 11; F \o+ \*\cs{until}\p+ 40; T \cs{infix_-} \! 9 )\! +% \*\cs{until}\p( 11; F \o+ 40; \cs{infix_-} \! 9 )\! +% \cs{until}\p( \*\o{+} 11; 40; \cs{infix_-}\p( \! 9 )\! +% \cs{until}\p( 51; \*\cs{infix_-}\p( \! 9 )\! +% \cs{until}\p( 51; F \o- \cs{until}\p- \*\cs{one}\p- \! 9 )\! +% \cs{until}\p( 51; F \o- \cs{until}\p- 9 \*\cs{one}\p- \! )\! +% \cs{until}\p( 51; F \o- \cs{until}\p- 9; \*\cs{infix_)}\p- \!\! +% \cs{until}\p( 51; F \o- \*\cs{until}\p- 9; T \cs{infix_)} \!\! +% \*\cs{until}\p( 51; F \o- 9; \cs{infix_)} \!\! +% \cs{until}\p( \*\o{-} 51; 9; \cs{infix_)}\p( \!\! +% \cs{until}\p( 42; \*\cs{infix_)}\p( \!\! +% \*\cs{until}\p( 42; T \cs{infix_)} \!\! +% 42; \cs{infix_)} \!\! +% \end{l3fp-code-example} +% +% The only missing step is to clean the output by removing \cs{infix_)}, +% and possibly checking that nothing else remains. +% +% \subsection{Prefix operators, parentheses, and functions} +% +% Prefix operators (typically the unary |-|) and parentheses are +% taken care of by the same mechanism, and functions (\texttt{sin}, +% \texttt{exp}, etc.) as well. Finding the argument of the unary +% |-|, for instance, is very similar to grabbing the second operand +% of a binary infix operator, with a small subtelty on precedence +% explained below. Once that argument is found, its sign can be +% flipped. A left parenthesis is just a prefix operator which +% removes the closing parenthesis (with some extra checks). +% +% Detecting prefix operators is done by \cs{one}. Before looking +% for a number, it tests the first character. If it is a digit, a +% dot, or a register, then we have a number. Otherwise, it is put +% in a function, \cs{prefix_?} (where |?| is roughly that first +% character), which is expanded. For instance, with a left +% parenthesis we would have the following. +% \begin{l3fp-code-example} +% \*\cs{one}\p* \! ( 2 + 3 ) \! +% \*\cs{prefix_(}\p* \! 2 + 3 ) \! +% \o(\p* \cs{until}\p( \*\cs{one}\p( \! 2 + 3 ) \! +% ... \!\! +% \o(\p* 5; \cs{infix_)} \! \! +% \end{l3fp-code-example} +% As usual, the \cs{until}--\cs{one} pair reads and compute +% until reaching an operator of precedence at most \fpPrecedence{(}. +% Then \fpOperation{(} removes \cs{infix_)} and looks ahead for +% the next operation, comparing its precedence with the precedence +% \fpPrecedence{*} of the previous operation (in fact, this comparison +% is done by the relevant \cs{infix_?} built from the next operation). +% +% To support multi-character function (and constant) names, we +% may need to put more than one character in the \cs{prefix_?} +% construction. See implementation for details. +% +% Note that contrarily to \cs{infix_?} functions, the \cs{prefix_?} +% functions perform no test on their argument (which is once more +% the previous precedence), since we know that we need a number, +% and must never stop there. +% +% Functions are implemented as prefix operators with infinitely high +% precedence, so that their argument is the first number that can +% possibly be built. For instance, something like the following could +% happen in a computation +% \begin{l3fp-code-example} +% \*\cs{one}\p* \! sqrt 4 + 3 ) \! +% \*\cs{prefix_sqrt}\p* \! 4 + 3 ) \! +% \o{sqrt}\p* \cs{until}\p{$\infty$} \*\cs{one}\p{$\infty$} \! 4 + 3 ) \! +% ... \!\! +% \o{sqrt}\p* 4; \cs{infix_+} \! 3 ) \! +% 2; \*\cs{infix_+}\p* \! 3 ) \! +% \end{l3fp-code-example} +% +% Lonely example, to be put somewhere: |2+sin 1 * 3| is $2+(\sin(1)\times 3)$. +% +% A further complication arises in the case of the unary |-| sign: +% |-3**2| should be $-(3^2)=-9$, and not $(-3)^2=9$. Easy, just give +% |-| a lower precedence, equal to that of the infix |+| and |-|. +% Unfortunately, this fails in subtle cases such as |3**-2*4|, +% yielding $3^{-2\times 4}$ instead of the correct $3^{-2}\times 4$. +% In fact, a unary |-| should only perform operations whose precedence +% is greater than that of the last operation, as well as +% |-|.\footnote{Taking into account the precedence of \texttt{-} itself +% only matters when it follows a left parenthesis: +% \texttt{(-2*4+3)} should give \texttt{((-8)+3)}, not \texttt{(-(8+3))}.} +% Thus, \cs{prefix_-} \meta{prec} expands to something like +% \begin{l3fp-code-example} +% \o- \meta{prec} \cs{until}\p? \*\cs{one} \p? +% \end{l3fp-code-example} +% where \fpPrecedence{?} is the maximum of \meta{prec} and the +% precedence of |-|. Once the argument of |-| is found, \fpOperation{-} +% gets its opposite, and leaves it for the previous operation to use. +% +% An example with parentheses. +% +% \begin{l3fp-code-example} +% \cs{until}\p( \*\cs{one}\p( \! 11 * ( 2 + 3 ) - 9 )\! +% \cs{until}\p( 1 \*\cs{one}\p( \! 1 * ( 2 + 3 ) - 9 )\! +% \cs{until}\p( 11 \*\cs{one}\p( \! * ( 2 + 3 ) - 9 )\! +% \cs{until}\p( 11; \*\cs{infix_*}\p( \! ( 2 + 3 ) - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \*\cs{one}\p* \! ( 2 + 3 ) - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \*\cs{prefix_(}\p* \! 2 + 3 ) - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( \*\cs{one}\p( \! 2 + 3 ) - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2 \*\cs{one}\p( \! + 3 ) - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2; \*\cs{infix_+}\p( \! 3 ) - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2; F \o+ \cs{until}\p+ \*\cs{one}\p+ \! 3)-9)\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2; F \o+ \cs{until}\p+ 3 \*\cs{one}\p+ \! )-9)\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2; F \o+ \cs{until}\p+ 3; \*\cs{infix_)}\p+ \! -9)\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2; F \o+ \*\cs{until}\p+ 3; T \cs{infix_)} \! -9)\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \*\cs{until}\p( 2; F \o+ 3; \cs{infix_)} \! - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( \*\o+ 2; 3; \cs{infix_)}\p( \! - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 5; \*\cs{infix_)}\p( \! - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \*\cs{until}\p( 5; T \cs{infix_)} \! - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* \*\o(\p* 5; \cs{infix_)} \! - 9 )\! +% \cs{until}\p( 11; F \o* \cs{until}\p* 5; \*\cs{infix_-}\p* \! 9 )\! +% \cs{until}\p( 11; F \o* \*\cs{until}\p* 5; T \cs{infix_-} \! 9 )\! +% \*\cs{until}\p( 11; F \o* 5; \cs{infix_-} \! 9 )\! +% \cs{until}\p( \*\o* 11; 5; \cs{infix_-}\p( \! 9 )\! +% \cs{until}\p( 55; \* \cs{infix_-}\p( \! 9 )\! +% \cs{until}\p( 55; F \o- \cs{until}\p- \*\cs{one}\p- \! 9 )\! +% \cs{until}\p( 55; F \o- \cs{until}\p- 9 \*\cs{one}\p- \! )\! +% \cs{until}\p( 55; F \o- \cs{until}\p- 9; \*\cs{infix_)}\p- \!\! +% \cs{until}\p( 55; F \o- \*\cs{until}\p- 9; T \cs{infix_)} \!\! +% \*\cs{until}\p( 55; F \o- 9; \cs{infix_)} \!\! +% \cs{until}\p( \*\o- 55; 9; \cs{infix_)}\p( \!\! +% \cs{until}\p( 47; \*\cs{infix_)}\p( \!\! +% \*\cs{until}\p( 47; T \cs{infix_)} \!\! +% 47; \cs{infix_)} \!\! +% \end{l3fp-code-example} +% +% The end of this (sub)section was not revised yet +% +% \begin{itemize} +% \item If it is a sign (|-| or |+|), then any following sign will be +% combined with this initial sign, forming \cs{prefix_+} or \cs{prefix_-}. +% \item If it is a letter, then any following letter is grabbed, forming +% for instance \cs{prefix_sin} or \cs{prefix_sinh}. +% \item Otherwise, only one token\footnote{Some support for multi-character +% prefix operator may be added in the future, but right now, I don't +% see a use for it. Perhaps, for including comments inside +% the computation itself??} is grabbed, for instance \cs{prefix_(}. +% \end{itemize} +% +%^^A todo: make sure that's correct?? +% +% Functions may take several arguments, possibly an unknown +% number\footnote{Keyword argument support may be added later.}, +% for instance \texttt{round(1.23456,2)}. +% \begin{itemize} +% \item \texttt{round} is made into \cs{prefix_round}, which tries to +% grab one number using \cs{one}. +% \item This builds \cs{prefix_(}, which uses \cs{one} to grab one +% number, calculating as necessary. The comma is given the same +% precedence as parentheses, and thus ends the calculation of the +% argument of \texttt{round}. +% \item \texttt{round} now has its first argument. It can check whether +% the argument was closed by |,| or |)|, and branch accordingly. +% \item If it was a comma, then the first argument is skipped over, +% through an expensive set of \cs{exp_after:wN}, and the second +% argument can be grabbed. Here it is simply an integer, easier +% to parse by building upon \cs{etex_numexpr:D}. +% \item The closing parenthesis (or another comma) is seen, and the +% control is given back to \cs{prefix_round}. +% \end{itemize} +% +% \subsection{Type detection} +% +% The type of data should be detected by reading the first few tokens, +% before calling a type-specific function to parse it. Or +% should the type be obtained after the semicolon which indicates the +% end of the thing? And placed there? +% +% ^^A todo: what did I mean in this paragraph? +% Also to grab exponents correctly, build \cs{@@_<abc>:w} when seeing +% some non-numeric |abc| while still looking to complete a number (or +% other data). Then, if \cs{@@_postfix_<type>_<abc>:w} exists, use it. +% +% The internal representation of floating point numbers is quite +% untypable, and we provide here the tools to convert from a more +% user-friendly representation to internal floating point numbers, +% and for various other conversions. Every floating point operation +% calls those functions to normalize the input, so they must be +% optimized. +% +% \section{Internal representation} +% +% Internally, a floating point number \meta{X} is a +% token list containing +% \begin{quote} +% \cs{s_@@} \cs{@@_chk:w} \meta{case} \meta{sign} \meta{body} |;| +% \end{quote} +% Let us explain each piece separately. +% +% Internal floating point numbers will be used in expressions, +% and in this context will be subject to f-expansion. They must +% leave a recognizable mark after \texttt{f}-expansion, to prevent the +% floating point number from being re-parsed. Thus, \cs{s_@@} +% is simply another name for \tn{relax}. +% +% Since floating point numbers are always accessed by the various +% operations using f-expansion, we can safely let them be protected: +% \texttt{x}-expansion will then leave them untouched. However, when +% used directly without an accessor function, floating points should +% produce an error. \cs{s_@@} will do nothing, and \cs{@@_chk:w} +% produces an error. +% +% The (decimal part of the) IEEE-754-2008 standard requires the +% format to be able to represent special floating point numbers +% besides the usual positive and negative cases. The various +% possibilities will be distinguished by their \meta{case}, which +% is a single digit:\footnote{Bruno: I need to implement subnormal +% numbers. Also, quiet and signalling \texttt{nan} must be better +% distinguished.} +% \begin{itemize} +% \item[0] zeros: |+0| and |-0|, +% \item[1] \enquote{normal} numbers (positive and negative), +% \item[2] infinities: |+inf| and |-inf|, +% \item[3] quiet and signalling \texttt{nan}. +% \end{itemize} +% The \meta{sign} is |0| (positive) or |2| (negative), +% except in the case of \texttt{nan}, which have $\meta{sign} = 1$. +% This ensures that changing the \meta{sign} digit to $2-\meta{sign}$ +% is exactly equivalent to changing the sign of the number. +% +% Special floating point numbers have the form +% \begin{quote} +% \cs{s_@@} \cs{@@_chk:w} \meta{case} \meta{sign} \cs{s_@@_...} |;| +% \end{quote} +% where \cs{s_@@_...} is a scan mark carrying information about how the +% number was formed (useful for debugging). +% +% Normal floating point numbers ($\meta{case} = 1$) have the form +% \begin{quote} +% \cs{s_@@} \cs{@@_chk:w} 1 \meta{sign} \Arg{exponent} +% \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} |;| +% \end{quote} +% Here, the \meta{exponent} is an integer, at most +% $\cs{c_@@_max_exponent_int} = +% \the\csname\detokenize{c__fp_max_exponent_int}\endcsname$ +% in absolute value. The body consists in four +% blocks of exactly $4$ digits, $ 0000 \leq \meta{X_i} \leq 9999$, +% such that +% \[ +% \meta{X} +% = (-1)^{\meta{sign}} 10^{-\meta{exponent}} +% \sum_{i=1}^{4} \meta{X_i} 10^{-4i} +% \] +% and such that the \meta{exponent} is minimal. This implies +% $ 1000 \leq \meta{X_1} \leq 9999 $. +% +% \begin{table}\centering +% \caption{Internal representation of floating point numbers.} +% \label{tab:fp-convert-special} +% \begin{tabular}{ll} +% \toprule +% \multicolumn{1}{c}{Representation} & Meaning \\ +% \midrule +% 0 0 \cs{s_@@_...} \texttt{;} & Positive zero. \\ +% 0 2 \cs{s_@@_...} \texttt{;} & Negative zero. \\ +% 1 0 \Arg{exponent} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \texttt{;} +% & Positive floating point. \\ +% 1 2 \Arg{exponent} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \texttt{;} +% & Negative floating point. \\ +% 2 0 \cs{s_@@_...} \texttt{;} & Positive infinity. \\ +% 2 2 \cs{s_@@_...} \texttt{;} & Negative infinity. \\ +% 3 1 \cs{s_@@_...} \texttt{;} & Quiet \texttt{nan}. \\ +% 3 1 \cs{s_@@_...} \texttt{;} & Signalling \texttt{nan}. \\ +% \bottomrule +% \end{tabular} +% \end{table} +% +% \section{Internal parsing functions} +% +% \begin{macro}[EXP, int]{\@@_parse_until:Nw} +% \begin{syntax} +% \cs{tex_romannumeral:D} \cs{@@_parse_until:Nw} \meta{precedence} \cs{@@_parse_expand:w} \meta{tokens} +% \end{syntax} +% Reads the \meta{tokens}, performing every computation with a +% precedence higher than \meta{precedence}, then expands to +% \begin{syntax} +% \meta{objects} |@| \cs{@@_parse_infix_\meta{operation}:N} \ldots{} +% \end{syntax} +% where the \meta{op} is the first operation with a lower precedence, +% possibly \texttt{end}. +% \end{macro} +% +% \begin{macro}[EXP, int]{\@@_parse_operand:Nw} +% \begin{syntax} +% \cs{@@_parse_operand:Nw} \meta{precedence} \ldots{} +% \end{syntax} +% If the following \meta{operation} has a precedence higher than +% \meta{precedence}, expands to +% \begin{syntax} +% \meta{object_1} |@| \cs{@@_parse_apply_binary:NwNwN} \meta{operation} \meta{object_2} |@| \cs{@@_parse_infix_\meta{operation_2}:N} \ldots{} +% \end{syntax} +% and otherwise expands to +% \begin{syntax} +% \meta{object} |@| \cs{@@_parse_stop_until:N} \cs{@@_parse_infix_\meta{operation}:N} \ldots{} +% \end{syntax} +% \end{macro} +% +% \begin{macro}[EXP, int]{\@@_parse_infix_\meta{operation}:N} +% \begin{syntax} +% \cs{@@_parse_infix_\meta{operation}:N} \meta{precedence} +% \end{syntax} +% If the \meta{op} has a precedence higher than \meta{precedence}, expands to +% \begin{syntax} +% |@| \cs{@@_parse_apply_binary:NwNwN} \meta{operation} \meta{object} |@| \cs{@@_parse_infix_\meta{operation_2}:N} +% \end{syntax} +% Otherwise expands to +% \begin{syntax} +% |@| \cs{@@_parse_stop_until:N} \cs{@@_parse_infix_\meta{operation}:N} +% \end{syntax} +% \end{macro} +% +% ^^A end[todo] +% +% \subsection{Expansion control} +% +% At each step in reading a floating point expression, we wish to +% perform \texttt{f}-expansion. Normally, spaces stop this +% \texttt{f}-expansion. This can be problematic: for instance, the +% macro |\X| below will not be expanded if we simply do +% \texttt{f}-expansion. +% \begin{verbatim} +% \DeclareDocumentCommand {\test} {m} { \fp_eval:n {#1} } +% \ExplSyntaxOff +% \test { 1 + \X } +% \end{verbatim} +% To avoid this problem, at every step, we do essentially what +% \cs{use:f} would do: take an argument, put it back in the input +% stream, then \texttt{f}-expand it. This is not a complete solution, +% since a macro's expansion could contain leading spaces which will stop +% the \texttt{f}-expansion before further macro calls are performed. +% However, in practice it should be enough: in particular, floating +% point numbers will correctly be expanded to the underlying \cs{s_@@} +% \ldots{} structure. +% +%^^A begin[todo] +% Floating point expressions should behave as much as possible like +% \eTeX{}-based integer expressions and dimension expressions. In +% particular, full-expansion should be performed as the expression is +% read, token by token, forcing the expansion of protected macros, and +% ignoring spaces. +% +% Full expansion can be done with \cs{tex_romannumeral:D} |-`0|. +% Unfortunately, this expansion is stopped by spaces. Thus using simply +% this will fail on |\fp_eval:n { 1 + ~ \l_tmpa_fp }| since the floating +% point variable will not be expanded. Of course, spaces will not +% appear in a code setting, but may very easily come in document-level +% input, from which some expressions may come. We can avoid being +% stopped by such explicit space characters (and by some braces) if we +% add \cs{use:n} after~|-`0|. +% +% Testing if a character token |#1| is a digit can be done using +% \begin{verbatim} +% \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: +% true code +% \else: +% false code +% \fi: +% \end{verbatim} +% To exclude |0|, replace \cs{c_nine} by \cs{c_ten}. The use of +% \cs{token_to_str:N} ensures that a digit with any catcode is detected. +% +%^^A end[todo] +% +% \begin{macro}[rEXP, aux]{\@@_parse_expand:w} +% \begin{syntax} +% \cs{tex_romannumeral:D} \cs{@@_parse_expand:w} \meta{tokens} +% \end{syntax} +% This function must always come within a \tn{romannumeral} expansion. +% The \meta{tokens} should be the part of the expression that we have +% not yet read. This requires in particular closing all conditionals +% properly before expanding. +% \begin{macrocode} +\cs_new:Npn \@@_parse_expand:w #1 { -`0 #1 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP, aux]{\@@_parse_return_semicolon:w} +% This very odd function swaps its position with the following +% \cs{fi:} and removes \cs{@@_parse_expand:w} normally responsible for +% expansion. That turns out to be useful. +% \begin{macrocode} +\cs_new:Npn \@@_parse_return_semicolon:w + #1 \fi: \@@_parse_expand:w { \fi: ; #1 } +% \end{macrocode} +% \end{macro} +% +% \subsection{Fp object type} +% +% \begin{macro}[EXP, int]{\@@_type_from_scan:N} +% \begin{syntax} +% \cs{@@_type_from_scan:N} \meta{token} +% \end{syntax} +% Grabs the pieces of the stringified \meta{token} which lies after +% the first |s__fp|. If the \meta{token} does not contain that +% string, the result is empty. +% \begin{macrocode} +\group_begin: +\char_set_catcode_other:N \S +\char_set_catcode_other:N \F +\char_set_catcode_other:N \P +\char_set_lccode:nn { `\- } { `\_ } +\tl_to_lowercase:n + { + \group_end: + \cs_new:Npn \@@_type_from_scan:N #1 + { + \exp_after:wN \@@_type_from_scan:w + \token_to_str:N #1 \q_mark S--FP \q_mark \q_stop + } + \cs_new:Npn \@@_type_from_scan:w #1 S--FP #2 \q_mark #3 \q_stop {#2} + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Reading digits} +% +% \begin{macro}[rEXP, aux] +% { +% \@@_parse_digits_vii:N , +% \@@_parse_digits_vi:N , +% \@@_parse_digits_v:N , +% \@@_parse_digits_iv:N , +% \@@_parse_digits_iii:N , +% \@@_parse_digits_ii:N , +% \@@_parse_digits_i:N +% } +% These functions must be called within an \cs{__int_value:w} or +% \cs{__int_eval:w} construction. The first token which follows must be +% \texttt{f}-expanded prior to calling those functions. The functions +% read tokens one by one, and output digits into the input stream, +% until meeting a non-digit, or up to a number of digits equal to +% their index. The full expansion is +% \begin{quote} +% \meta{digits} |;| \meta{filling 0} |;| \meta{length} +% \end{quote} +% where \meta{filling 0} is a string of zeros such that \meta{digits} +% \meta{filling 0} has the length given by the index of the function, +% and \meta{length} is the number of zeros in the \meta{filling 0} +% string. Each function puts a digit into the input stream and calls +% the next function, until we find a non-digit. We are careful to +% pass the tested tokens through \cs{token_to_str:N} to normalize +% their category code. +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1 #2 #3 + { + \cs_new:cpn { @@_parse_digits_ #1 :N } ##1 + { + \if_int_compare:w \c_nine < 1 \token_to_str:N ##1 \exp_stop_f: + \token_to_str:N ##1 \exp_after:wN #2 \tex_romannumeral:D + \else: + \@@_parse_return_semicolon:w #3 ##1 + \fi: + \@@_parse_expand:w + } + } +\@@_tmp:w {vii} \@@_parse_digits_vi:N { 0000000 ; 7 } +\@@_tmp:w {vi} \@@_parse_digits_v:N { 000000 ; 6 } +\@@_tmp:w {v} \@@_parse_digits_iv:N { 00000 ; 5 } +\@@_tmp:w {iv} \@@_parse_digits_iii:N { 0000 ; 4 } +\@@_tmp:w {iii} \@@_parse_digits_ii:N { 000 ; 3 } +\@@_tmp:w {ii} \@@_parse_digits_i:N { 00 ; 2 } +\@@_tmp:w {i} \@@_parse_digits_:N { 0 ; 1 } +\cs_new_nopar:Npn \@@_parse_digits_:N { ; ; 0 } +% \end{macrocode} +% \end{macro} +% +% \subsection{Parsing one operand} +% +% At the start of an expression, or just following a binary operation or +% a function call, we are looking for an operand. This can be an +% explicit floating point number, a floating point variable, a \TeX{} +% register, a function call such as \texttt{sin(3)}, a parenthesized +% expression, \emph{etc.} We distinguish the various cases by their +% first token after \texttt{f}-expansion: +% \begin{itemize} +% \item \cs{tex_relax:D} in some form. That can be an internal +% floating point, a premature end, or an unitialized register. +% \item A register. We interpret this as the significand of a floating +% point number. This is subtely different from unpacking it, for +% instance, \texttt{\cs{c_minus_one}**2} gives $1$, while +% \texttt{-1**2} gives $-1$. +% \item A digit, or a dot. That marks the start of the significand for +% a floating point number. +% \item A letter (lower or upper-case), which starts an identifier, +% either a constant or a function (possibly unknown). +% \item |+|, |-|, or |!|, unary operators, which resume looking for a +% floating point number before acting on it. +% \item |(|, which makes us parse a subexpression until the +% matching~|)|. +% \item Other characters such as |'| or |"| may be given a meaning +% later. Characters such as |*| or |/| have a meaning as infix +% operators but are not valid when we are looking for an operand: for +% instance, |3+*4| is not valid. +% \end{itemize} +% A category code test separates the first two cases from the others, +% and they are further distinguished with a meaning test. We then +% single out digits. Letters are detected using their character code. +% All other characters are taken care of by building a csname from that +% character and using it to continue parsing. Unknown characters lead +% to an error. +% +% \begin{macro}[int, EXP]{\@@_parse_operand:Nw} +% Function called \cs{one} at other places. It grabs one operand, and +% packs the symbol that follows in an \cs{infix_} csname. |#1| is the +% previous \meta{precedence}, and |#2| the first character of the +% operand (already \texttt{f}-expanded). +% \begin{macrocode} +\cs_new:Npn \@@_parse_operand:Nw #1 #2 + { + \if_catcode:w \tex_relax:D #2 + \if_meaning:w \tex_relax:D #2 + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_parse_operand_relax:NN + \else: + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_parse_operand_register:NN + \fi: + \else: + \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f: + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_parse_operand_digit:NN + \else: + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_parse_operand_other:NN + \fi: + \fi: + #1 #2 + } +% \end{macrocode} +% \end{macro} +% +% ^^A todo: rounding of negative dimensions is probably wrong. +% \begin{macro}[aux, EXP] +% {\@@_parse_operand_register:NN, \@@_parse_operand_register_aux:www} +% Find the exponent following the register |#2|, then combine the +% value of |#2| (mapping |1pt| to $1$) with the exponent to produce a +% floating point number. +% \begin{macrocode} +\group_begin: +\char_set_catcode_other:N \P +\char_set_catcode_other:N \T +\tl_to_lowercase:n + { + \group_end: + \cs_new:Npn \@@_parse_operand_register:NN #1#2 + { + \exp_after:wN \@@_parse_infix_after_operand:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \exp_after:wN \@@_parse_operand_register_aux:www + \tex_the:D + \exp_after:wN #2 + \exp_after:wN P + \exp_after:wN T + \exp_after:wN \q_stop + \__int_value:w \@@_parse_exponent:N + } + \cs_new:Npn \@@_parse_operand_register_aux:www #1 PT #2 \q_stop #3 ; + { \@@_parse:n { #1 e #3 } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP] +% {\@@_parse_operand_relax:NN, \@@_parse_operand_relax_aux:wwnw} The +% argument is a token equal to \cs{tex_relax:D}. This can be +% \cs{s_@@}, \cs{s_@@_mark}, or a badly initialized register. We make +% sure that the last argument of \cs{@@_parse_infix:NN} is +% correctly expanded. +% \begin{macrocode} +\cs_new:Npn \@@_parse_operand_relax:NN #1#2 + { + \@@_parse_operand_relax_aux:wwnw + #2 \s_@@_mark + { + \@@_exp_after_o:nw + { + \tex_romannumeral:D -`0 + \exp_after:wN \@@_parse_infix:NN + \exp_after:wN #1 \tex_romannumeral:D \@@_parse_expand:w + } + \s_@@ + } + \s_@@ #2 + { + \@@_error:n { Premature~end~in~fp~expression. } + \exp_after:wN \c_nan_fp + \tex_romannumeral:D -`0 + \@@_parse_infix:NN #1 + \s_@@_mark + } + \s_@@_mark + { + \@@_error:n { Erroneous~variable~#2 used! } + \exp_after:wN \c_nan_fp + \tex_romannumeral:D -`0 + \exp_after:wN \@@_parse_infix:NN + \exp_after:wN #1 + \tex_romannumeral:D \@@_parse_expand:w + } + \s_@@_mark \s_@@_stop + } +\cs_new:Npn \@@_parse_operand_relax_aux:wwnw + #1 \s_@@ #2 \s_@@_mark #3 #4 \s_@@_mark \s_@@_stop { #3 } +% \end{macrocode} +% \end{macro} +% +% ^^A begin[todo] +% +% \begin{macro}[aux, EXP]{\@@_parse_operand_other:NN} +% The interesting bit is \cs{@@_parse_operand_other:NN}. It separates +% letters from non-letters and builds the appropriate \cs{prefix} +% function. If it is not defined (is \cs{tex_relax:D}), make it +% a signalling \texttt{nan}. We don't look for an argument, as the +% unknown \enquote{prefix} can also be a (mistyped) constant such +% as \texttt{Inf}. +% \begin{macrocode} +\cs_new:Npn \@@_parse_operand_other:NN #1 #2 + { + \if_int_compare:w + \__int_eval:w \tex_uccode:D `#2 / 26 = \c_three + \exp_after:wN \@@_parse_operand_other_word_aux:Nw + \exp_after:wN #1 + \tex_romannumeral:D + \exp_after:wN \@@_parse_letters:NN + \exp_after:wN #2 + \tex_romannumeral:D + \else: + \exp_after:wN \@@_parse_operand_other_prefix_aux:NNN + \exp_after:wN #1 + \exp_after:wN #2 + \cs:w @@_parse_prefix_#2:Nw \exp_after:wN \cs_end: + \tex_romannumeral:D + \fi: + \@@_parse_expand:w + } + +\cs_new:Npn \@@_parse_letters:NN #1#2 + { + \exp_after:wN \c_zero + \exp_after:wN #1 + \tex_romannumeral:D + \if_int_compare:w + \if_catcode:w \tex_relax:D #2 + \c_zero + \else: + \__int_eval:w \tex_uccode:D `#2 / 26 + \fi: + = \c_three + \exp_after:wN \@@_parse_letters:NN + \exp_after:wN #2 + \tex_romannumeral:D + \exp_after:wN \@@_parse_expand:w + \else: + \exp_after:wN \c_zero + \exp_after:wN ; + \exp_after:wN #2 + \fi: + } +\cs_new:Npn \@@_parse_operand_other_word_aux:Nw #1 #2; + { + \cs_if_exist_use:cF { @@_parse_word_#2:N } + { + \__msg_expandable_error:n { Unknown~word~#2. } + \exp_after:wN \c_nan_fp + \tex_romannumeral:D -`0 + \@@_parse_infix:NN + } + #1 + } +\cs_new_eq:NN \s_@@_unknown \tex_relax:D +\cs_new:Npn \@@_parse_operand_other_prefix_aux:NNN #1#2#3 + { + \if_meaning:w \tex_relax:D #3 + \exp_after:wN \@@_parse_operand_other_prefix_unknown:NNN + \exp_after:wN #2 + \fi: + #3 #1 + } +\cs_new:Npn \@@_parse_operand_other_prefix_unknown:NNN #1#2#3 + { + \cs_if_exist:cTF { @@_parse_infix_#1:N } + { + \@@_error:n { Missing~number~before~'#1'. } + \exp_after:wN \c_nan_fp + \tex_romannumeral:D -`0 + \@@_parse_infix:NN #3 #1 + } + { + \@@_error:n { Unknown~symbol~#1~ignored. } + \@@_parse_operand:Nw #3 + } + } +% \end{macrocode} +% \end{macro} +% +% The following forms are accepted: +% \begin{itemize} +% \item +% \item \meta{floating point} +% \item \meta{integer} |.| \meta{decimal} |e| \meta{exponent} +% \end{itemize} +% In both cases, \meta{signs} is a (possibly empty) string of +% |+| and |-| (with any category code\footnote{Bruno: except +% 1, 2, 4, 10, 13, and those which cannot be tokens (0, 5, 9), +% so really, just 3, 6, 7, 8, 11, 12.}).\footnote{Bruno: +% test (and implement) non-other digits.} +% +% In the second form, the \meta{integer} is a sequence of digits, +% whose length is not limited by constraints \TeX{}'s integer +% registers. It stops at the first non-digit character. The +% \meta{decimal} part is formed by all digits from the dot +% (if it exists) until the first non-digit character. The +% \meta{exponent} part has the form \meta{exponent sign} +% \meta{exponent body}, where \meta{exponent sign} is any string +% of |+| or |-|, and \meta{exponent body} is a string of digits, +% stopping, as usual, at the first non-digit. +% +% Any missing part will take the appropriate default value. +% \begin{itemize} +% \item A missing \meta{exponent} is considered to be zero. +% \item A number with no dot has zero decimal part. +% \item An empty \meta{integer} part or decimal part is zero. +% \end{itemize} +% +% Border cases: +% \begin{itemize} +% \item \texttt{e1} is considered as invalid input, and gives +% \texttt{qnan}.\footnote{Bruno: now just gives an error.} +% This will be important once parsing expressions is +% implemented, since \texttt{e-1} would be ambiguous otherwise. +% \item \texttt{.e3} and \texttt{.} are zero. +% \end{itemize} +% +% Bruno: expansion, not yet. Only f-expansion at the start, and +% unpacking of registers after signs. +% +% +% Work-plan. +% \begin{itemize} +% \item Remove any leading sign and build the \meta{sign} as we go. +% If the next character is a letter, go to the \enquote{special} +% branch, discussed later. +% \item Drop leading zeros. +% \item If the next character is a dot, drop some more zeros, +% keeping track of how many were dropped after the dot. +% Counting those gives $\meta{exp_1}<0$. Then read the decimal part +% with the \cs{@@_from_str_small} functions. +% \item Otherwise, $\meta{exp_1}=0$, and first read the integer part, +% then the decimal part. This is implemented through the more +% elaborate \cs{@@_from_str_large} functions. +% \item Continuing in the same line of expansion, read the exponent +% \meta{exp_2}. +% \item Finally check that nothing is left.\footnote{Bruno: not done yet.} +% \end{itemize} +% +% \begin{macro}[aux, EXP]{\@@_parse_operand_digit:NN} +% \begin{macrocode} +\cs_new:Npn \@@_parse_operand_digit:NN #1 + { + \exp_after:wN \@@_parse_infix_after_operand:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \exp_after:wN \@@_sanitize:wN + \int_use:N \__int_eval:w \c_zero \@@_parse_trim_zeros:N + } +% \end{macrocode} +% \end{macro} +% +% ^^A end[todo] +% +% \subsubsection{Trimming leading zeros} +% +% \begin{macro}[aux, rEXP]{\@@_parse_trim_zeros:N, \@@_parse_trim_end:w} +% This function expects an already expanded token. It removes any +% leading zero, then distinguished three cases: if the first non-zero +% token is a digit, then call \cs{@@_parse_large:N} (the significand is +% $\geq 1$); if it is |.|, then continue trimming zeros with +% \cs{@@_parse_strim_zeros:N}; otherwise, our number is exactly zero, +% and we call \cs{@@_parse_zero:} to take care of that case. +% \begin{macrocode} +\cs_new:Npn \@@_parse_trim_zeros:N #1 + { + \if:w 0 #1 + \exp_after:wN \@@_parse_trim_zeros:N + \tex_romannumeral:D + \else: + \if:w . #1 + \exp_after:wN \@@_parse_strim_zeros:N + \tex_romannumeral:D + \else: + \@@_parse_trim_end:w #1 + \fi: + \fi: + \@@_parse_expand:w + } +\cs_new:Npn \@@_parse_trim_end:w #1 \fi: \fi: \@@_parse_expand:w + { + \fi: + \fi: + \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: + \exp_after:wN \@@_parse_large:N + \else: + \exp_after:wN \@@_parse_zero: + \fi: + #1 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP]{\@@_parse_strim_zeros:N, \@@_parse_strim_end:w} +% If we have removed all digits until a period (or if the body started +% with a period), then enter the \enquote{\texttt{small_trim}} loop +% which outputs $-1$ for each removed $0$. Those $-1$ are added to an +% integer expression waiting for the exponent. If the first non-zero +% token is a digit, call \cs{@@_parse_small:N} (our significand is +% smaller than~$1$), and otherwise, the number is an exact zero. +% \begin{macrocode} +\cs_new:Npn \@@_parse_strim_zeros:N #1 + { + \if:w 0 #1 + - \c_one + \exp_after:wN \@@_parse_strim_zeros:N + \tex_romannumeral:D + \else: + \@@_parse_strim_end:w #1 + \fi: + \@@_parse_expand:w + } +\cs_new:Npn \@@_parse_strim_end:w #1 \fi: \@@_parse_expand:w + { + \fi: + \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: + \exp_after:wN \@@_parse_small:N + \else: + \exp_after:wN \@@_parse_zero: + \fi: + #1 + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Exact zero} +% +% \begin{macro}[aux, EXP]{\@@_parse_zero:} +% After reading a significand of $0$, we need to remove any exponent, +% then put a sign of |1| for \cs{@@_sanitize:wN}, denoting an +% exact zero. +% \begin{macrocode} +\cs_new:Npn \@@_parse_zero: + { + \exp_after:wN ; \exp_after:wN 1 + \__int_value:w \@@_parse_exponent:N + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Small significand} +% +% \begin{macro}[aux, rEXP]{\@@_parse_small:N} +% This function is called after we have passed the decimal separator +% and removed all leading zeros from the significand. It is followed +% by a non-zero digit (with any catcode). The goal is to read up to +% $16$ digits. But we can't do that all at once, because +% \cs{__int_value:w} (which allows us to collect digits and continue +% expanding) can only go up to $9$ digits. Hence we grab digits in +% two steps of $8$ digits. Since |#1| is a digit, read seven more +% digits using \cs{@@_parse_digits_vii:N}. The \texttt{small_leading} +% auxiliary will leave those digits in the \cs{__int_value:w}, and grab +% some more, or stop if there are no more digits. Then the +% \texttt{pack_leading} auxiliary puts the various parts in the +% appropriate order for the processing further up. +% \begin{macrocode} +\cs_new:Npn \@@_parse_small:N #1 + { + \exp_after:wN \@@_parse_pack_leading:NNNNNww + \int_use:N \__int_eval:w 1 \token_to_str:N #1 + \exp_after:wN \@@_parse_small_leading:wwNN + \__int_value:w 1 + \exp_after:wN \@@_parse_digits_vii:N + \tex_romannumeral:D \@@_parse_expand:w + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP]{\@@_parse_small_leading:wwNN} +% \begin{syntax} +% \cs{@@_parse_small_leading:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} +% \end{syntax} +% We leave \meta{digits} \meta{zeros} in the input stream: the +% functions used to grab digits are such that this constitutes digits +% $1$ through $8$ of the significand. Then prepare to pack $8$ more +% digits, with an exponent shift of \cs{c_zero} (this shift is used in +% the case of a large significand). If |#4| is a digit, leave it +% behind for the packing function, and read $6$ more digits to reach a +% total of $15$ digits: further digits are involved in the rounding. +% Otherwise put $8$ zeros in to complete the significand, then look +% for an exponent. +% \begin{macrocode} +\cs_new:Npn \@@_parse_small_leading:wwNN 1 #1 ; #2; #3 #4 + { + #1 #2 + \exp_after:wN \@@_parse_pack_trailing:NNNNNNww + \exp_after:wN \c_zero + \int_use:N \__int_eval:w 1 + \if_int_compare:w \c_nine < 1 \token_to_str:N #4 \exp_stop_f: + \token_to_str:N #4 + \exp_after:wN \@@_parse_small_trailing:wwNN + \__int_value:w 1 + \exp_after:wN \@@_parse_digits_vi:N + \tex_romannumeral:D + \else: + 0000 0000 \@@_parse_exponent:Nw #4 + \fi: + \@@_parse_expand:w + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP]{\@@_parse_small_trailing:wwNN} +% \begin{syntax} +% \cs{@@_parse_small_trailing:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token} +% \end{syntax} +% Leave digits $10$ to $15$ (arguments |#1| and |#2|) in the input +% stream. If the \meta{next~token} is a digit, it is the $16$th +% digit, we keep it, then the \texttt{small_round} auxiliary considers +% this digit and all further digits to perform the rounding: the +% function expands to nothing or to |+1|. Otherwise, there is no +% $16$-th digit, so we put a $0$, and look for an exponent. +% \begin{macrocode} +\cs_new:Npn \@@_parse_small_trailing:wwNN 1 #1 ; #2; #3 #4 + { + #1 #2 + \if_int_compare:w \c_nine < 1 \token_to_str:N #4 \exp_stop_f: + \token_to_str:N #4 + \exp_after:wN \@@_parse_small_round:NN + \exp_after:wN #4 + \tex_romannumeral:D + \else: + 0 \@@_parse_exponent:Nw #4 + \fi: + \@@_parse_expand:w + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP] +% { +% \@@_parse_pack_trailing:NNNNNNww , +% \@@_parse_pack_leading:NNNNNww , +% \@@_parse_pack_carry:w +% } +% Those functions are expanded after all the digits are found, we took +% care of the rounding, as well as the exponent. The last argument is +% the exponent. The previous five arguments are $8$ digits which we +% pack in groups of $4$, and the argument before that is $1$, except +% in the rare case where rounding lead to a carry, in which case the +% argument is $2$. The \texttt{trailing} function has an exponent +% shift as its first argument, which we add to the exponent found in +% the |e...| syntax. If the trailing digits cause a carry, the +% integer expression for the leading digits is incremented (|+ \c_one| +% in the code below). If the leading digits propagte this carry all +% the way up, the function \cs{@@_parse_pack_carry:w} increments the +% exponent, and changes the mantissa from |0000...| to |1000...|: this +% is simple because such a carry can only occur to give rise to a +% power of $10$. +% \begin{macrocode} +\cs_new:Npn \@@_parse_pack_trailing:NNNNNNww #1 #2 #3#4#5#6 #7; #8 ; + { + \if_meaning:w 2 #2 + \c_one \fi: + ; #8 + #1 ; {#3#4#5#6} {#7}; + } +\cs_new:Npn \@@_parse_pack_leading:NNNNNww #1 #2#3#4#5 #6; #7; + { + + #7 + \if_meaning:w 2 #1 \@@_parse_pack_carry:w \fi: + ; 0 {#2#3#4#5} {#6} + } +\cs_new:Npn \@@_parse_pack_carry:w \fi: ; 0 #1 + { \fi: + \c_one ; 0 {1000} } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Large significand} +% +% Parsing a significand larger than $1$ is a little bit more difficult +% than parsing small significands. We need to count the number of +% digits before the decimal separator, and add that to the final +% exponent. We also need to test for the presence of a dot each time we +% run out of digits, and branch to the appropriate \texttt{parse_small} +% function in those cases. +% +% \begin{macro}[aux, EXP]{\@@_parse_large:N} +% This function is followed by the first non-zero digit of a +% \enquote{large} significand ($\geq 1$). It is called within an +% integer expression for the exponent. Grab up to $7$ more digits, +% for a total of $8$ digits. +% \begin{macrocode} +\cs_new:Npn \@@_parse_large:N #1 + { + \exp_after:wN \@@_parse_large_leading:wwNN + \__int_value:w 1 \token_to_str:N #1 + \exp_after:wN \@@_parse_digits_vii:N + \tex_romannumeral:D \@@_parse_expand:w + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP]{\@@_parse_large_leading:wwNN} +% \begin{syntax} +% \cs{@@_parse_large_leading:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token} +% \end{syntax} +% We shift the exponent by the number of digits in |#1|, namely the +% target number, $8$, minus the \meta{number of zeros} (number of +% digits missing). Then prepare to pack the $8$ first digits. If the +% \meta{next token} is a digit, read up to $6$ more digits (digits +% $10$ to $15$). If it is a period, try to grab the end of our $8$ +% first digits, branching to the \texttt{small} functions since the +% number of digit does not affect the exponent anymore. Finally, if +% this is the end of the significand, insert the \meta{zeros} to +% complete the $8$ first digits, insert $8$ more, and look for an +% exponent. +% \begin{macrocode} +\cs_new:Npn \@@_parse_large_leading:wwNN 1 #1 ; #2; #3 #4 + { + + \c_eight - #3 + \exp_after:wN \@@_parse_pack_leading:NNNNNww + \int_use:N \__int_eval:w 1 #1 + \if_int_compare:w \c_nine < 1 \token_to_str:N #4 \exp_stop_f: + \exp_after:wN \@@_parse_large_trailing:wwNN + \__int_value:w 1 \token_to_str:N #4 + \exp_after:wN \@@_parse_digits_vi:N + \tex_romannumeral:D + \else: + \if:w . #4 + \exp_after:wN \@@_parse_small_leading:wwNN + \__int_value:w 1 + \cs:w + @@_parse_digits_ + \tex_romannumeral:D #3 + :N \exp_after:wN + \cs_end: + \tex_romannumeral:D + \else: + #2 + \exp_after:wN \@@_parse_pack_trailing:NNNNNNww + \exp_after:wN \c_zero + \__int_value:w 1 0000 0000 + \@@_parse_exponent:Nw #4 + \fi: + \fi: + \@@_parse_expand:w + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_parse_large_trailing:wwNN} +% \begin{syntax} +% \cs{@@_parse_large_trailing:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token} +% \end{syntax} +% We have just read $15$ digits. If the \meta{next token} is a digit, +% then the exponent shift caused by this block of $8$ digits is $8$, +% first argument to the \texttt{pack_trailing} function. We keep the +% \meta{digits} and this $16$-th digit, and find how this should be +% rounded using \cs{@@_parse_large_round:NN}. Otherwise, the exponent +% shift is the number of \meta{digits}, $7$ minus the \meta{number of +% zeros}, and we test for a decimal point. This case happens in +% |123451234512345.67| with exactly $15$ digits before the decimal +% separator. Then branch to the appropriate \texttt{small} auxiliary, +% grabbing a few more digits to complement the digits we already +% grabbed. Finally, if this is truly the end of the significand, look +% for an exponent after using the \meta{zeros} and providing a $16$-th +% digit of $0$. +% \begin{macrocode} +\cs_new:Npn \@@_parse_large_trailing:wwNN 1 #1 ; #2; #3 #4 + { + \if_int_compare:w \c_nine < 1 \token_to_str:N #4 \exp_stop_f: + \exp_after:wN \@@_parse_pack_trailing:NNNNNNww + \exp_after:wN \c_eight + \int_use:N \__int_eval:w 1 #1 \token_to_str:N #4 + \exp_after:wN \@@_parse_large_round:NN + \exp_after:wN #4 + \tex_romannumeral:D + \else: + \exp_after:wN \@@_parse_pack_trailing:NNNNNNww + \int_use:N \__int_eval:w \c_seven - #3 \exp_stop_f: + \int_use:N \__int_eval:w 1 #1 + \if:w . #4 + \exp_after:wN \@@_parse_small_trailing:wwNN + \__int_value:w 1 + \cs:w + @@_parse_digits_ + \tex_romannumeral:D #3 + :N \exp_after:wN + \cs_end: + \tex_romannumeral:D + \else: + #2 0 \@@_parse_exponent:Nw #4 + \fi: + \fi: + \@@_parse_expand:w + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Finding the exponent} +% +% Expansion is a little bit tricky here, in part because we accept input +% where multiplication is implicit. +% \begin{verbatim} +% \@@_parse:n { 3.2 erf(0.1) } +% \@@_parse:n { 3.2 e\l_my_int } +% \@@_parse:n { 3.2 \c_pi_fp } +% \end{verbatim} +% The first case indicates that just looking one character ahead for an +% \enquote{\texttt{e}} is not enough, since we would mistake the +% function \texttt{erf} for an exponent of \enquote{\texttt{rf}}. An +% alternative would be to look two tokens ahead and check if what +% follows is a sign or a digit, considering in that case that we must be +% finding an exponent. But taking care of the second case requires that +% we unpack registers after \texttt{e}. However, blindly expanding the +% two tokens ahead completely would break the third example (unpacking +% is even worse). Indeed, in the course of reading $3.2$, \cs{c_pi_fp} +% is expanded to \cs{s_@@} \cs{@@_chk:w} |1| |0| |{-1}| |{3141}| +% $\cdots$ |;| and \cs{s_@@} stops the expansion. Expanding two tokens +% ahead would then force the expansion of \cs{@@_chk:w} (despite it +% being protected), and that function tries to produce an error. +% +% What can we do? Really, the reason why this last case breaks is that +% just as \TeX{} does, we should read ahead as little as possible. +% Here, the only case where there may be an exponent is if the first +% token ahead is |e|. Then we expand (and possibly unpack) the second +% token --- and hopefully that is safe. +% +% \begin{macro}[aux, rEXP]{\@@_parse_exponent:Nw} +% This auxiliary is convenient to smuggle some material through +% \cs{fi:} ending conditional processing. We place those \cs{fi:} +% (argument |#2|) at a very odd place becase this allows us to insert +% \cs{__int_eval:w} \ldots{} there if needed. +% \begin{macrocode} +\cs_new:Npn \@@_parse_exponent:Nw #1 #2 \@@_parse_expand:w + { + \exp_after:wN ; + \__int_value:w #2 \@@_parse_exponent:N #1 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP]{\@@_parse_exponent:N, \@@_parse_exponent_ii:N} +% This function should be called within an \cs{__int_value:w} expansion +% (or within an integer expression. It leaves digits of the exponent +% behind it in the input stream, and terminates the expansion with a +% semicolon. If there is no \texttt{e}, leave an exponent of $0$. If +% there is an \texttt{e}, expand the next token to run some tests on +% it. Namely, if the character code of |#1| is greater than that of +% |9| (largest code valid for an exponent, less than any code valid +% for an identifier), there was in fact no exponent; otherwise, we +% search for the sign of the exponent. +% \begin{macrocode} +\cs_new:Npn \@@_parse_exponent:N #1 + { + \if:w e #1 + \exp_after:wN \@@_parse_exponent_ii:N + \tex_romannumeral:D + \else: + 0 \@@_parse_return_semicolon:w #1 + \fi: + \@@_parse_expand:w + } +\cs_new:Npn \@@_parse_exponent_ii:N #1 + { + \if_int_compare:w \if_catcode:w \tex_relax:D #1 + \c_zero \else: `#1 \fi: > `9 \exp_stop_f: + 0 \exp_after:wN ; \exp_after:wN e + \else: + \exp_after:wN \@@_parse_exponent_sign:N + \fi: + #1 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP]{\@@_parse_exponent_sign:N} +% Read signs one by one (if there is any). +% \begin{macrocode} +\cs_new:Npn \@@_parse_exponent_sign:N #1 + { + \if:w + \if:w - #1 + \fi: \token_to_str:N #1 + \exp_after:wN \@@_parse_exponent_sign:N + \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w + \else: + \exp_after:wN \@@_parse_exponent_body:N + \exp_after:wN #1 + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP]{\@@_parse_exponent_body:N} +% An exponent can be an explicit integer (most common case), or +% various other things (most of which are invalid). +% \begin{macrocode} +\cs_new:Npn \@@_parse_exponent_body:N #1 + { + \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: + \token_to_str:N #1 + \exp_after:wN \@@_parse_exponent_digits:N + \tex_romannumeral:D + \else: + \@@_parse_exponent_keep:NTF #1 + { \@@_parse_return_semicolon:w #1 } + { + \exp_after:wN ; + \tex_romannumeral:D + } + \fi: + \@@_parse_expand:w + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP]{\@@_parse_exponent_digits:N} +% Read digits one by one, and leave them behind in the input stream. +% When finding a non-digit, stop, and insert a semicolon. Note that +% we don't check for overflow of the exponent, hence there can be a +% TeX error. It is mostly harmless, except when parsing +% |0e9876543210|, which should be a valid representation of $0$, but +% is not. +% \begin{macrocode} +\cs_new:Npn \@@_parse_exponent_digits:N #1 + { + \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: + \token_to_str:N #1 + \exp_after:wN \@@_parse_exponent_digits:N + \tex_romannumeral:D + \else: + \@@_parse_return_semicolon:w #1 + \fi: + \@@_parse_expand:w + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, rEXP]{\@@_parse_exponent_keep:NTF} +% This is the last building block for parsing exponents. The argument +% |#1| is already fully expanded, and neither |+| nor |-| nor a digit. +% It can be: +% \begin{itemize} +% \item \cs{s_@@}, marking the start of an internal floating point, +% invalid here; +% \item another control sequence equal to \tn{relax}, probably a bad +% variable; +% \item a register: in this case we make sure that it is an integer +% register, not a dimension; +% \item a character other than |+|, |-| or digits, again, an error. +% \end{itemize} +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_parse_exponent_keep:N #1 { TF } + { + \if_catcode:w \tex_relax:D #1 + \if_meaning:w \tex_relax:D #1 + \if_int_compare:w \pdftex_strcmp:D { \s_@@ } { #1 } = \c_zero + 0 \@@_error:n { Cannot~use~floating~point~after~'e'. } + \prg_return_true: + \else: + 0 \@@_error:n { Erroneous~variable~#1 used. } + \prg_return_false: + \fi: + \else: + \if_int_compare:w + \pdftex_strcmp:D { \__int_value:w #1 } { \tex_the:D #1 } + = \c_zero + \__int_value:w #1 + \else: + 0 \@@_error:n { Cannot~use~a~dimension~(#1)~after~'e'. } + \fi: + \prg_return_false: + \fi: + \else: + 0 \@@_error:n { Missing~exponent~after~'e'. } + \prg_return_true: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% ^^A begin[todo] +% ^^A todo: \@@_sin:Nn should first _set, then \@@_sin:w, +% ^^A both for speed, and error reporting. +% ^^A todo: word 'e' == 'invalid syntax', word 'E' == "use 'e' instead" +% +% \subsubsection{Beyond 16 digits: rounding} +% +% \begin{macro}[int]{\@@_cfs_round_loop:N} +% Used both for \cs{@@_parse_small_round:NN} and +% \cs{@@_parse_large_round:NN}. +% Should appear after a \cs{__int_eval:w} |0|. Reads digits one by one, +% until reaching a non-digit. Adds |+1| for each digit. If all digits +% found are |0|, ends the \cs{__int_eval:w} by |;\c_zero|, otherwise +% by |;\c_one|. This is done by switching the loop to |round_up| +% at the first non-zero digit. +% +% \begin{macrocode} +\cs_new:Npn \@@_cfs_round_loop:N #1 + { + \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: + + \c_one + \if:w 0 #1 + \exp_after:wN \@@_cfs_round_loop:N + \tex_romannumeral:D + \else: + \exp_after:wN \@@_cfs_round_up:N + \tex_romannumeral:D + \fi: + \else: + \@@_parse_return_semicolon:w \c_zero #1 + \fi: + \@@_parse_expand:w + } +\cs_new:Npn \@@_cfs_round_up:N #1 + { + \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: + + 1 + \exp_after:wN \@@_cfs_round_up:N + \tex_romannumeral:D + \else: + \@@_parse_return_semicolon:w \c_one #1 + \fi: + \@@_parse_expand:w + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}[int]{\@@_parse_large_round:NN} +% \begin{syntax} +% \cs{@@_parse_large_round:NN} \meta{digit} \meta{more digits} +% \end{syntax} +% \meta{digit} is the digit that we are currently rounding (we only +% care whether it is even or odd). +% +% The goal is to get \cs{c_zero} or \cs{c_one}, check for an exponent +% afterwards, and combine it to the number of digits before the decimal +% point (which we thus need to keep track of). +% \begin{macrocode} +\cs_new:Npn \@@_parse_large_round:NN #1#2 + { + \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f: + + + \exp_after:wN \@@_round_s:NNNw + \exp_after:wN 0 + \exp_after:wN #1 + \exp_after:wN #2 + \int_use:N \__int_eval:w + \exp_after:wN \@@_parse_large_round_after:wNN + \int_use:N \__int_eval:w \c_one + \exp_after:wN \@@_cfs_round_loop:N + \else: %^^A could be dot, or e, or other + \exp_after:wN \@@_parse_large_round_dot_test:NNw + \exp_after:wN #1 + \exp_after:wN #2 + \fi: + } +\cs_new:Npn \@@_parse_large_round_dot_test:NNw #1#2 + { + \if:w . #2 + \exp_after:wN \@@_parse_small_round:NN + \exp_after:wN #1 + \tex_romannumeral:D + \else: + \@@_parse_exponent:Nw #2 + \fi: + \@@_parse_expand:w + } +% \end{macrocode} +% \begin{syntax} +% \cs{@@_parse_large_round_after:wNN} \meta{exp} |;| +% ~~\meta{0 or 1} \meta{next~token} +% \end{syntax} +% \begin{macrocode} +\cs_new:Npn \@@_parse_large_round_after:wNN #1 ; #2 #3 + { + \if:w . #3 + \exp_after:wN \@@_parse_large_round_after_ii:wN + \int_use:N \__int_eval:w #1 + + \c_zero * \__int_eval:w \c_zero + \exp_after:wN \@@_cfs_round_loop:N + \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w + \else: + + #2 + \exp_after:wN ; + \int_use:N \__int_eval:w #1 + + \exp_after:wN \@@_parse_exponent:N + \exp_after:wN #3 + \fi: + } +\cs_new:Npn \@@_parse_large_round_after_ii:wN #1 ; #2 + { + + #2 + \exp_after:wN ; + \int_use:N \__int_eval:w #1 + + \@@_parse_exponent:N + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}[int]{\@@_parse_small_round:NN} +% \begin{syntax} +% \cs{@@_parse_small_round:NN} \meta{digit} \meta{more digits} +% \end{syntax} +% \meta{digit} is the digit that we are currently rounding (we only +% care whether it is even or odd). +% +% The goal is to get \cs{c_zero} or \cs{c_one} +% \begin{macrocode} +\cs_new:Npn \@@_parse_small_round:NN #1#2 + { + \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f: + + + \exp_after:wN \@@_round_s:NNNw + \exp_after:wN 0 + \exp_after:wN #1 + \exp_after:wN #2 + \int_use:N \__int_eval:w + \exp_after:wN \@@_parse_small_round_after:wN + \int_use:N \__int_eval:w \c_zero + \exp_after:wN \@@_cfs_round_loop:N + \tex_romannumeral:D + \else: + \@@_parse_exponent:Nw #2 + \fi: + \@@_parse_expand:w + } +\cs_new:Npn \@@_parse_small_round_after:wN #1; #2 + { + + #2 \exp_after:wN ; + \__int_value:w \@@_parse_exponent:N + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Main functions} +% +% \begin{macro}[int, EXP]{\@@_parse:n} +% \begin{macro}[aux, EXP]{\@@_parse_after:ww} +% Start a \tn{romannumeral} expansion so that \cs{@@_parse:n} expands +% in two steps. The \cs{@@_parse_until:Nw} function will perform +% computations until reaching an operation with precedence +% \cs{c_minus_one} or less. Then check that there was indeed nothing +% left (this cannot happen), and stop the initial expansion with +% \cs{c_zero}.%^^A todo: simplify a bit. +% \begin{macrocode} +\cs_new:Npn \@@_parse:n #1 + { + \tex_romannumeral:D + \exp_after:wN \@@_parse_after:ww + \tex_romannumeral:D + \@@_parse_until:Nw \c_minus_one + \@@_parse_expand:w #1 \s_@@_mark + \s_@@_stop + } +\cs_new:Npn \@@_parse_after:ww #1@ #2 \s_@@_stop + { +%<assert> \assert_str_eq:nn { #2 } { \@@_parse_infix_end:N \s_@@_mark } + \c_zero #1 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_parse_until:Nw} +% \begin{macro}[aux, EXP]{\@@_parse_until_test:NwN} +% The \cs{@@_parse_until} +% This is just a shorthand which sets up both \cs{@@_parse_until_test} +% and \cs{@@_parse_operand} with the same precedence. Note the +% trailing \cs{tex_romannumeral:D}. This function should be +% used with much care. +% \begin{macrocode} +\cs_new:Npn \@@_parse_until:Nw #1 + { + -`0 + \exp_after:wN \@@_parse_until_test:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \exp_after:wN \@@_parse_operand:Nw + \exp_after:wN #1 + \tex_romannumeral:D + } +\cs_new:Npn \@@_parse_until_test:NwN #1 #2 @ #3 { #3 #1 #2 @ } +\cs_new:Npn \@@_parse_stop_until:N #1 { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_parse_until_test:NwN} +% \begin{syntax} +% \cs{@@_parse_until_test:NwN} \meta{prec} \meta{fp} \meta{bool} +% \end{syntax} +% If \meta{bool} is true, then \meta{fp} is the floating +% point number that we are looking for (it ends with |;|), +% and this expands to \meta{fp}. If \meta{bool} is false, +% then the input stream actually looks like +% \begin{quote} +% \cs{@@_parse_until_test:NwN} \meta{prec} \meta{fp_1} \meta{false} +% \meta{oper} \meta{fp_2} \cs{infix_?} +% \end{quote} +% and we must feed \meta{prec} to \cs{infix_?}, and perform +% \meta{oper} on \meta{fp_1} and \meta{fp_2}: this +% triggers the expansion of \cs{infix_?} \meta{prec}, continuing +% the computation (or stopping). In that case, the function \cs{until} +% yields +% \begin{quote} +% \cs{@@_parse_until_test:NwN} \meta{prec} +% \meta{oper} \meta{fp_1} \meta{fp_2} +% \cs{tex_romannumeral:D} |-`0| \cs{infix_?} \meta{prec} +% \end{quote} +% expanding \meta{oper} next. +% \begin{macrocode} +% \end{macrocode} +% \end{macro} +% +% ^^A 3.5\mydim e4**2 +% ^^A todo: add tests that catcode changes don't mess things up. +% +% \subsection{Main functions} +% +% \begin{macro}[aux, EXP]{\@@_parse_infix_after_operand:NwN} +% \begin{macrocode} +\cs_new:Npn \@@_parse_infix_after_operand:NwN #1 #2; + { + \@@_exp_after_f:nw { \@@_parse_infix:NN #1 } + #2; + } +\group_begin: + \char_set_catcode_letter:N \* + \cs_new:Npn \@@_parse_infix:NN #1 #2 + { + \if_catcode:w \tex_relax:D #2 + \if_int_compare:w + \pdftex_strcmp:D { \s_@@_mark } { #2 } + = \c_zero + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_parse_infix_end:N + \else: + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_parse_infix_juxtapose:N + \fi: + \else: + \if_int_compare:w + \__int_eval:w \tex_uccode:D `#2 / 26 + = \c_three + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_parse_infix_juxtapose:N + \else: + \exp_after:wN \@@_parse_infix_check:NNN + \cs:w + @@_parse_infix_#2:N + \exp_after:wN \exp_after:wN \exp_after:wN + \cs_end: + \fi: + \fi: + #1 + #2 + } + \cs_new:Npn \@@_parse_infix_check:NNN #1#2#3 + { + \if_meaning:w \tex_relax:D #1 + \__msg_expandable_error:n { Missing~*~inserted. } + \exp_after:wN \@@_parse_infix_*:N + \exp_after:wN #2 + \exp_after:wN #3 + \else: + \exp_after:wN #1 + \exp_after:wN #2 + \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w + \fi: + } +\group_end: +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_parse_apply_binary:NwNwN} +% +% \begin{macrocode} +\cs_new:Npn \@@_parse_apply_binary:NwNwN #1 #2#3@ #4 #5#6@ #7 + { + \exp_after:wN \@@_parse_until_test:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \cs:w + @@ + \@@_type_from_scan:N #2 + \@@_type_from_scan:N #5 + _ #4 _o:ww + \cs_end: + #2#3 #5#6 + \tex_romannumeral:D -`0 #7 #1 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP] +% {\@@_parse_apply_unary_array:NNwN, \@@_parse_apply_unary:NNwN} +% Here, |#2| is \emph{e.g.}, \cs{@@_neg_@@:w}, and expands once after the +% calculation.\footnote{Bruno: explain.} The argument |#3| may be an +% array, so either we map through all its items, or we feed all items +% at once to the custom function. +% \begin{macrocode} +\cs_new:Npn \@@_parse_apply_unary_array:NNwN #1#2#3@#4 + { + #2 #3 @ + \tex_romannumeral:D -`0 #4 #1 + } +\cs_new:Npn \@@_parse_apply_unary:NNwN #1#2#3@#4 + { + #2 #3 + \tex_romannumeral:D -`0 #4 #1 + } +\cs_new:Npn \@@_parse_unary_type:N #1 + { \@@_type_from_scan:N #1 :w \cs_end: #1 } +% \end{macrocode} +% \end{macro} +% +% \subsection{Prefix operators} +% +% \subsubsection{Identifiers} +% +% \begin{macro}[aux, EXP] +% { +% \@@_parse_word_inf:N, \@@_parse_word_nan:N, \@@_parse_word_pi:N , +% \@@_parse_word_deg:N, \@@_parse_word_em:N , +% \@@_parse_word_ex:N , \@@_parse_word_in:N , \@@_parse_word_pt:N , +% \@@_parse_word_pc:N , \@@_parse_word_cm:N , \@@_parse_word_mm:N , +% \@@_parse_word_dd:N , \@@_parse_word_cc:N , \@@_parse_word_nd:N , +% \@@_parse_word_nc:N , \@@_parse_word_bp:N , \@@_parse_word_sp:N , +% \@@_parse_word_true:N , \@@_parse_word_false:N , +% } +% A whole bunch of floating point numbers. +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1 #2 + { + \cs_new_nopar:cpn { @@_parse_word_#1:N } + { \exp_after:wN #2 \tex_romannumeral:D -`0 \@@_parse_infix:NN } + } +\@@_tmp:w { inf } \c_inf_fp +\@@_tmp:w { nan } \c_nan_fp +\@@_tmp:w { pi } \c_pi_fp +\@@_tmp:w { deg } \c_one_degree_fp +\@@_tmp:w { true } \c_one_fp +\@@_tmp:w { false } \c_zero_fp +\@@_tmp:w { pt } \c_one_fp +\cs_set_protected:Npn \@@_tmp:w #1 #2 + { + \cs_new_nopar:cpn { @@_parse_word_#1:N } + { + \@@_exp_after_f:nw { \@@_parse_infix:NN } + \s_@@ \@@_chk:w 10 #2 ; + } + } +\@@_tmp:w {in} { {2} {7227} {0000} {0000} {0000} } +\@@_tmp:w {pc} { {2} {1200} {0000} {0000} {0000} } +\@@_tmp:w {cm} { {2} {2845} {2755} {9055} {1181} } +\@@_tmp:w {mm} { {1} {2845} {2755} {9055} {1181} } +\@@_tmp:w {dd} { {1} {1070} {0085} {6496} {0630} } +\@@_tmp:w {cc} { {2} {1284} {0102} {7795} {2756} } +\@@_tmp:w {nd} { {1} {1066} {9783} {4645} {6693} } +\@@_tmp:w {nc} { {2} {1280} {3740} {1574} {8031} } +\@@_tmp:w {bp} { {1} {1003} {7500} {0000} {0000} } +\@@_tmp:w {sp} { {-4} {1525} {8789} {0625} {0000} } +\tl_map_inline:nn { {em} {ex} } + { + \cs_new_nopar:cpn { @@_parse_word_#1:N } + { + \exp_after:wN \dim_to_fp:n \exp_after:wN + { \dim_use:N \__dim_eval:w 1 #1 \exp_after:wN } + \tex_romannumeral:D -`0 \@@_parse_infix:NN + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP] +% { +% \@@_parse_word_abs:N , +% \@@_parse_word_cos:N , +% \@@_parse_word_cot:N , +% \@@_parse_word_exp:N , +% \@@_parse_word_ln:N , +% \@@_parse_word_sin:N , +% \@@_parse_word_tan:N , +% } +% Unary functions, which are applied to all of their arguments when +% receiving an array. +% \begin{macrocode} +\tl_map_inline:nn { {abs} {cos} {cot} {exp} {ln} {sin} {tan} } + { + \cs_new:cpn { @@_parse_word_#1:N } ##1 + { + \exp_after:wN \@@_parse_apply_unary:NNwN + \exp_after:wN ##1 + \cs:w @@_ #1 \exp_after:wN \@@_parse_unary_type:N + \tex_romannumeral:D + \@@_parse_until:Nw \c_fifteen + \@@_parse_expand:w + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP] +% { +% \@@_parse_word_max:N , \@@_parse_word_min:N , +% \@@_parse_word_mod:N , +% } +% Those functions are also unary, but need to mix all of their +% arguments together. +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1#2 + { + \cs_new:Npn #1 ##1 + { + \exp_after:wN \@@_parse_apply_unary_array:NNwN + \exp_after:wN ##1 + \exp_after:wN #2 + \tex_romannumeral:D + \@@_parse_until:Nw \c_sixteen \@@_parse_expand:w + } + } +\@@_tmp:w \@@_parse_word_max:N \@@_max:w +\@@_tmp:w \@@_parse_word_min:N \@@_min:w + % \@@_tmp:w \@@_parse_word_mod:N \@@_mod:w %^^A todo: not implemented! +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_parse_word_round:N} +% This function expects one or two arguments. +% \begin{macrocode} +\cs_new:Npn \@@_parse_word_round:N #1#2 + { + \if_meaning:w + #2 + \@@_parse_round:Nw \@@_round_to_pinf:NNN + \else: + \if_meaning:w 0 #2 + \@@_parse_round:Nw \@@_round_to_zero:NNN + \else: + \if_meaning:w - #2 + \@@_parse_round:Nw \@@_round_to_ninf:NNN + \fi: + \fi: + \fi: + \exp_after:wN \@@_parse_apply_round:NNwN + \exp_after:wN #1 + \exp_after:wN \@@_round_to_nearest:NNN + \tex_romannumeral:D + \@@_parse_until:Nw \c_sixteen \@@_parse_expand:w #2 + } +\cs_new:Npn \@@_parse_round:Nw + #1 #2 \@@_round_to_nearest:NNN #3 \@@_parse_expand:w #4 + { #2 #1 #3 \@@_parse_expand:w } +\cs_new:Npn \@@_parse_apply_round:NNwN #1#2#3@#4 + { + \if_case:w \__int_eval:w \@@_array_count:w #3@ - \c_one \__int_eval_end: + \@@_round:Nwn #2 #3 {0} \tex_romannumeral:D + \or: \@@_round:Nww #2 #3 \tex_romannumeral:D + \else: + \@@_error:n { round()~expects~1~or~2~arguments. } + \exp_after:wN \c_nan_fp \tex_romannumeral:D + \fi: + -`0 #4 #1 + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Unary minus, plus, not} +% +% \begin{macro}[EXP, aux]{\@@_parse_prefix_+:Nw} +% A unary |+| does nothing. +% \begin{macrocode} +\cs_new_eq:cN { @@_parse_prefix_+:Nw } \@@_parse_operand:Nw +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP, aux]{\@@_parse_prefix_-:Nw, \@@_parse_prefix_!:Nw} +% Unary |-| is harder. +% Boolean not. +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1#2 + { + \cs_new:cpn { @@_parse_prefix_#1:Nw } ##1 + { + \exp_after:wN \@@_parse_apply_unary:NNwN + \exp_after:wN ##1 + \cs:w @@_ #2 \exp_after:wN \@@_parse_unary_type:N + \tex_romannumeral:D + \if_int_compare:w \c_twelve < ##1 + \@@_parse_until:Nw ##1 + \else: + \@@_parse_until:Nw \c_twelve + \fi: + \@@_parse_expand:w + } + } +\@@_tmp:w - { neg } +\@@_tmp:w ! { not } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Other prefixes} +% +% \begin{macro}[int]{\@@_parse_prefix_(:Nw} +% \begin{macrocode} +\group_begin: + \char_set_catcode_letter:N \) + \cs_new:cpn { @@_parse_prefix_(:Nw } #1 + { + \exp_after:wN \@@_parse_lparen_after:NwN + \exp_after:wN #1 + \tex_romannumeral:D + \if_int_compare:w #1 = \c_sixteen + \@@_parse_until:Nw \c_one + \else: + \@@_parse_until:Nw \c_zero + \fi: + \@@_parse_expand:w + } + \cs_new:Npn \@@_parse_lparen_after:NwN #1#2@#3 + { + \token_if_eq_meaning:NNTF #3 \@@_parse_infix_):N + { + \@@_parse_exp_after_array:wf #2 \s_@@_stop + \exp_after:wN \@@_parse_infix:NN + \exp_after:wN #1 + \tex_romannumeral:D \@@_parse_expand:w + } + { + \@@_error:n { Missing~')'~inserted. } + #2 @ \@@_parse_stop_until:N #3 + } + } +\group_end: +% \end{macrocode} +% \end{macro} +% +%^^A todo: rename to exp_after_array_f:w +% \begin{macro}[int, EXP]{\@@_parse_exp_after_array:wf} +% \begin{macrocode} +\cs_new:Npn \@@_parse_exp_after_array:wf #1 + { + \cs:w @@ \@@_type_from_scan:N #1 _exp_after_f:nw \cs_end: + { \@@_parse_exp_after_array:wf } + #1 + } +\cs_new:Npn \@@_stop_exp_after_f:nw #1#2 { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_parse_prefix_.:Nw} +% This function is called when a number starts with a dot. +% \begin{macrocode} +\cs_new:cpn {@@_parse_prefix_.:Nw} #1 + { + \exp_after:wN \@@_parse_infix_after_operand:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \exp_after:wN \@@_sanitize:wN + \int_use:N \__int_eval:w \c_zero \@@_parse_strim_zeros:N + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Infix operators} +% +% As described in the \enquote{work plan}, each infix operator has an +% associated \cs{infix} function, a computing function, and +% precedence, given as arguments to \cs{@@_tmp:w}. The +% latter two are only needed when defining the \cs{infix} function. +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1#2#3#4 + { + \cs_new:Npn #1 ##1 + { + \if_int_compare:w ##1 < #3 + \exp_after:wN @ + \exp_after:wN \@@_parse_apply_binary:NwNwN + \exp_after:wN #2 + \tex_romannumeral:D + \@@_parse_until:Nw #4 + \exp_after:wN \@@_parse_expand:w + \else: + \exp_after:wN @ + \exp_after:wN \@@_parse_stop_until:N + \exp_after:wN #1 + \fi: + } + } +% \end{macrocode} +% +% \begin{macro}[int, EXP] +% { +% \@@_parse_infix_+:N, \@@_parse_infix_-:N, +% \@@_parse_infix_/:N, \@@_parse_infix_mul:N, +% \@@_parse_infix_and:N, \@@_parse_infix_or:N, +% } +% Using the general mechanism for arithmetic operations. +% \begin{macrocode} +\group_begin: + \char_set_catcode_other:N \& + \@@_tmp:w \@@_parse_infix_juxtapose:N * \c_thirty_two \c_thirty_two + \exp_args:Nc \@@_tmp:w { @@_parse_infix_ / :N } / \c_ten \c_ten + \exp_args:Nc \@@_tmp:w { @@_parse_infix_mul:N } * \c_ten \c_ten + \exp_args:Nc \@@_tmp:w { @@_parse_infix_ - :N } - \c_nine \c_nine + \exp_args:Nc \@@_tmp:w { @@_parse_infix_ + :N } + \c_nine \c_nine + \exp_args:Nc \@@_tmp:w { @@_parse_infix_and:N } & \c_five \c_five + \exp_args:Nc \@@_tmp:w { @@_parse_infix_ or:N } | \c_four \c_four +\group_end: +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_parse_infix_*:N} +% \begin{macro}[int, EXP]+\@@_parse_infix_^:N+ +% The power operation must be associative in the opposite order from +% all others. For this, we reverse the test, hence treating a +% \enquote{previous precedence} of \cs{c_fourteen} as less binding +% than |^|. +% \begin{macrocode} +\group_begin: + \char_set_catcode_letter:N ^ + \@@_tmp:w \@@_parse_infix_^:N ^ \c_fifteen \c_fourteen + \cs_new:cpn { @@_parse_infix_*:N } #1#2 + { + \if:w * #2 + \exp_after:wN \@@_parse_infix_^:N + \exp_after:wN #1 + \else: + \exp_after:wN \@@_parse_infix_mul:N + \exp_after:wN #1 + \exp_after:wN #2 + \fi: + } +\group_end: +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int, EXP]+\@@_parse_infix_|:Nw+ +% \begin{macro}[int, EXP]+\@@_parse_infix_&:Nw+ +% \begin{macrocode} +\group_begin: + \char_set_catcode_letter:N \| + \char_set_catcode_letter:N \& + \cs_new:Npn \@@_parse_infix_|:N #1#2 + { + \if:w | #2 + \exp_after:wN \@@_parse_infix_|:N + \exp_after:wN #1 + \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w + \else: + \exp_after:wN \@@_parse_infix_or:N + \exp_after:wN #1 + \exp_after:wN #2 + \fi: + } + \cs_new:Npn \@@_parse_infix_&:N #1#2 + { + \if:w & #2 + \exp_after:wN \@@_parse_infix_&:N + \exp_after:wN #1 + \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w + \else: + \exp_after:wN \@@_parse_infix_and:N + \exp_after:wN #1 + \exp_after:wN #2 + \fi: + } +\group_end: +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int, EXP] +% { +% \@@_parse_infix_<:N, \@@_parse_infix_=:N, +% \@@_parse_infix_>:N, \@@_parse_infix_!:N +% } +% \begin{macro}[aux, EXP] +% { +% \@@_parse_infix_excl_aux:NN, +% \@@_parse_infix_excl_error:, +% \@@_infix_compare:N, +% \@@_parse_compare:NNNNNw, +% \@@_parse_compare_expand:NNNNNw, +% \@@_parse_compare_end:NNNN, +% \@@_compare:wNNNNw, +% } +% \begin{macrocode} +\cs_new:cpn { @@_parse_infix_<:N } #1 + { + \@@_infix_compare:N #1 \c_one_fp + \c_zero_fp \c_zero_fp \c_zero_fp \c_zero_fp < + } +\cs_new:cpn { @@_parse_infix_=:N } #1 + { + \@@_infix_compare:N #1 \c_one_fp + \c_zero_fp \c_zero_fp \c_zero_fp \c_zero_fp = + } +\cs_new:cpn { @@_parse_infix_>:N } #1 + { + \@@_infix_compare:N #1 \c_one_fp + \c_zero_fp \c_zero_fp \c_zero_fp \c_zero_fp > + } +\cs_new:cpn { @@_parse_infix_!:N } #1 + { + \exp_after:wN \@@_parse_infix_excl_aux:NN + \exp_after:wN #1 \tex_romannumeral:D \@@_parse_expand:w + } +\cs_new:Npn \@@_parse_infix_excl_aux:NN #1#2 + { + \if_catcode:w \tex_relax:D #2 + \@@_parse_infix_excl_error: + \else: + \if_int_compare:w `#2 > `? \exp_stop_f: + \@@_parse_infix_excl_error: + \else: + \if_int_compare:w `#2 < `< \exp_stop_f: + \@@_parse_infix_excl_error: + \fi: + \fi: + \fi: + \@@_infix_compare:N #1 \c_zero_fp + \c_one_fp \c_one_fp \c_one_fp \c_one_fp #2 + } +\cs_new:Npn \@@_parse_infix_excl_error: + { \__msg_expandable_error:n { Missing~relation~symbol~after~'!'. } } +\cs_new:Npn \@@_infix_compare:N #1 + { + \if_int_compare:w #1 < \c_seven + \exp_after:wN \@@_parse_compare:NNNNNw + \else: + \exp_after:wN @ + \exp_after:wN \@@_parse_stop_until:N + \exp_after:wN \@@_infix_compare:N + \fi: + } +\cs_new:Npn \@@_parse_compare:NNNNNw #1#2#3#4#5#6 + { + \if_case:w + \if_catcode:w \tex_relax:D #6 + \c_minus_one + \else: + \__int_eval:w `#6 - `< \__int_eval_end: + \fi: + \@@_parse_compare_expand:NNNNNw #1#1#3#4#5 + \or: \@@_parse_compare_expand:NNNNNw #1#2#1#4#5 + \or: \@@_parse_compare_expand:NNNNNw #1#2#3#1#5 + \or: \@@_parse_compare_expand:NNNNNw #1#2#3#4#1 + \else: \@@_parse_compare_end:NNNN #2#3#4#5#6 + \fi: + } +\cs_new:Npn \@@_parse_compare_expand:NNNNNw #1#2#3#4#5 + { + \exp_after:wN \@@_parse_compare:NNNNNw + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN #3 + \exp_after:wN #4 + \exp_after:wN #5 + \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w + } +\cs_new:Npn \@@_parse_compare_end:NNNN #1#2#3#4#5 \fi: + { + \fi: + \exp_after:wN @ + \exp_after:wN \@@_parse_apply_compare:NwNNNNwN + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN #3 + \exp_after:wN #4 + \tex_romannumeral:D + \@@_parse_until:Nw \c_seven \@@_parse_expand:w #5 + } +\cs_new:Npn \@@_parse_apply_compare:NwNNNNwN #1 #2@ #3#4#5#6 #7@ #8 + { + \exp_after:wN \@@_parse_until_test:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN + \if_case:w \@@_compare:ww #2 #7 \exp_stop_f: + #4 + \or: #5 + \or: #6 + \else: #3 + \fi: + \tex_romannumeral:D -`0 #8 #1 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_parse_infix_?:N, \@@_parse_infix_::N} +% \begin{macrocode} +\group_begin: + \char_set_catcode_letter:N \? + \cs_new:Npn \@@_parse_infix_?:N #1 + { + \if_int_compare:w #1 < \c_three + \exp_after:wN @ + \exp_after:wN \@@_ternary:NwwN + \tex_romannumeral:D + \@@_parse_until:Nw \c_three + \exp_after:wN \@@_parse_expand:w + \else: + \exp_after:wN @ + \exp_after:wN \@@_parse_stop_until:N + \exp_after:wN \@@_parse_infix_?:N + \fi: + } + \cs_new:Npn \@@_parse_infix_::N #1 + { + \if_int_compare:w #1 < \c_three + \__msg_expandable_error:n { Missing~'?'~inserted~for~'?:'. } + \exp_after:wN @ + \exp_after:wN \@@_ternary_ii:NwwN + \tex_romannumeral:D + \@@_parse_until:Nw \c_two + \exp_after:wN \@@_parse_expand:w + \else: + \exp_after:wN @ + \exp_after:wN \@@_parse_stop_until:N + \exp_after:wN \@@_parse_infix_::N + \fi: + } +\group_end: +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]+\@@_parse_infix_):N+ +% This one is a little bit odd: force every previous operator to end, +% regardless of the precedence. This is very similar to +% \cs{@@_parse_infix_end:N}. +% \begin{macrocode} +\group_begin: + \char_set_catcode_letter:N \) + \cs_new:Npn \@@_parse_infix_):N #1 + { + \if_int_compare:w #1 < \c_zero + \@@_error:n { Extra~')'~ignored. } + \exp_after:wN \@@_parse_infix:NN + \exp_after:wN #1 + \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w + \else: + \exp_after:wN @ + \exp_after:wN \@@_parse_stop_until:N + \exp_after:wN \@@_parse_infix_):N + \fi: + } +\group_end: +\cs_new:Npn \@@_parse_infix_end:N #1 + { @ \@@_parse_stop_until:N \@@_parse_infix_end:N } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]+\@@_parse_infix_,:N+ +% \begin{macrocode} +\group_begin: + \char_set_catcode_letter:N \, + \cs_new:Npn \@@_parse_infix_,:N #1 + { + \if_int_compare:w #1 > \c_one + \exp_after:wN @ + \exp_after:wN \@@_parse_stop_until:N + \exp_after:wN \@@_parse_infix_,:N + \else: + \if_int_compare:w #1 = \c_one + \exp_after:wN \@@_parse_infix_comma:w + \tex_romannumeral:D + \else: + \exp_after:wN \@@_parse_infix_comma_gobble:w + \tex_romannumeral:D + \fi: + \@@_parse_until:Nw \c_one + \exp_after:wN \@@_parse_expand:w + \fi: + } + \cs_new:Npn \@@_parse_infix_comma:w #1 @ + { #1 @ \@@_parse_stop_until:N } + \cs_new:Npn \@@_parse_infix_comma_gobble:w #1 @ + { + \@@_error:n { Unexpected~comma:~extra~arguments~ignored. } + @ \@@_parse_stop_until:N + } +\group_end: +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx new file mode 100644 index 00000000000..68df5e1ac17 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx @@ -0,0 +1,424 @@ +% \iffalse meta-comment +% +%% File: l3fp-round.dtx Copyright(C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-round.dtx 3549 2012-03-13 20:54:30Z bruno $ + {L3 Floating-point rounding} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \textsf{l3fp-round} package\\ Rounding floating points^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-round} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% ^^A todo: provide an interface for rounding modes. +% ^^A todo: provide a \l_@@_rounding_mode_int giving the current mode. +% ^^A todo: make transcendental function obey the correct rounding mode. +% ^^A todo: optimize all rounding functions for various rounding modes. +% ^^A todo: reduce the number of almost identical functions. +% +% \subsection{Rounding tools} +% +% Floating point operations often yield a result that cannot be exactly +% represented in a mantissa with $16$ digits. In that case, we need to +% round the exact result to a representable number. The \textsc{ieee} +% standard defines four rounding modes: +% \begin{itemize} +% \item Round to nearest: round to the representable floating point +% number whose absolute difference with the exact result is the +% smallest. If the exact result lies exactly at the mid-point +% between two consecutive representable floating point numbers, +% round to the floating point number whose last digit is even. +% \item Round towards negative infinity: round to the greatest +% floating point number not larger than the exact result. +% \item Round towards zero: round to a floating point number with the +% same sign as the exact result, with the largest absolute value not +% larger than the absolute value of the exact result. +% \item Round towards positive infinity: round to the least floating +% point number not smaller than the exact result. +% \end{itemize} +% This is not fully implemented in \pkg{l3fp} yet, and transcendental +% functions fall back on the \enquote{round to nearest} mode. All +% rounding for basic algebra is done through the functions defined in +% this module, which can be redefined to change their rounding behaviour +% (but there is not interface for that yet). +% +% The rounding tools available in this module are many variations on a +% base function \cs{@@_round:NNN}, which expands to \cs{c_zero} or +% \cs{c_one} depending on whether the final result should be rounded up +% or down. +% \begin{itemize} +% \item \cs{@@_round:NNN} \meta{sign} \meta{digit_1} \meta{digit_2} +% can expand to \cs{c_zero} or \cs{c_one}. +% \item \cs{@@_round:NNNN} \meta{sign} \meta{digit_1} \meta{digit_2} +% \meta{digit_3} can expand to \cs{c_zero} or \cs{c_one}. +% \item \cs{@@_round_s:NNNw} \meta{sign} \meta{digit_1} \meta{digit_2} +% \meta{more digits} |;| can expand to |\c_zero ;| or |\c_one ;|. +% \item \cs{@@_round_neg:NNN} \meta{sign} \meta{digit_1} \meta{digit_2} +% can expand to \cs{c_zero} or \cs{c_one}. +% \end{itemize} +% See implementation comments for details on the syntax. +% +% \begin{macro}[int, rEXP]{\@@_round:NNN} +% \begin{macro}[aux, rEXP] +% { +% \@@_round_to_nearest:NNN, +% \@@_round_to_ninf:NNN, +% \@@_round_to_zero:NNN, +% \@@_round_to_pinf:NNN +% } +% \begin{syntax} +% \cs{@@_round:NNN} \meta{final sign} \meta{digit_1} \meta{digit_2} +% \end{syntax} +% If rounding the number $\meta{final sign} +% \meta{digit_1}.\meta{digit_2}$ to an integer rounds it towards zero +% (truncates it), this function expands to \cs{c_zero}, and otherwise +% to \cs{c_one}. Typically used within the scope of an +% \cs{__int_eval:w}, to add~$1$ if needed, and thereby round +% correctly. The result depends on the rounding mode. +% +% It is very important that \meta{final sign} be the final sign of the +% result. Otherwise, the result will be incorrect in the case of +% rounding towards~$-\infty$ or towards~$+\infty$. Also recall that +% \meta{final sign} is~$0$ for positive, and~$2$ for negative. +% +% By default, the functions below return \cs{c_zero}, but this is +% superseded by \cs{@@_round_return_one:}, which instead returns +% \cs{c_one}, expanding everything and removing \cs{c_zero} in the +% process. In the case of rounding towards~$\pm\infty$ or +% towards~$0$, this is not really useful, but it prepares us for the +% \enquote{round to nearest, ties to even} mode. +% +% The \enquote{round to nearest} mode is the default. If the +% \meta{digit_2} is larger than~$5$, then round up. If it is less +% than~$5$, round down. If it is exactly $5$, then round such that +% \meta{digit_1} plus the result is even. In other words, round up if +% \meta{digit_1} is odd. +% \begin{macrocode} +\cs_new:Npn \@@_round_return_one: + { \exp_after:wN \c_one \tex_romannumeral:D } +\cs_new:Npn \@@_round_to_ninf:NNN #1 #2 #3 + { + \if_meaning:w 2 #1 + \if_int_compare:w #3 > \c_zero + \@@_round_return_one: + \fi: + \fi: + \c_zero + } +\cs_new:Npn \@@_round_to_zero:NNN #1 #2 #3 { \c_zero } +\cs_new:Npn \@@_round_to_pinf:NNN #1 #2 #3 + { + \if_meaning:w 0 #1 + \if_int_compare:w #3 > \c_zero + \@@_round_return_one: + \fi: + \fi: + \c_zero + } +\cs_new:Npn \@@_round_to_nearest:NNN #1 #2 #3 + { + \if_int_compare:w #3 > \c_five + \@@_round_return_one: + \else: + \if_meaning:w 5 #3 + \if_int_odd:w #2 \exp_stop_f: + \@@_round_return_one: + \fi: + \fi: + \fi: + \c_zero + } +\cs_new_eq:NN \@@_round:NNN \@@_round_to_nearest:NNN +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP, int]{\@@_round_s:NNNw} +% \begin{syntax} +% \cs{@@_round_s:NNNw} \meta{final sign} \meta{digit} \meta{more digits} |;| +% \end{syntax} +% Similar to \cs{@@_round:NNN}, but with an extra semicolon, this +% function expands to |\c_zero ;| if rounding $\meta{final sign} +% \meta{digit}.\meta{more digits}$ to an integer truncates, and to +% |\c_one ;| otherwise. The \meta{more digits} part must be a digit, +% followed by something that does not overflow a \cs{int_use:N} +% \cs{__int_eval:w} construction. The only relevant information about +% this piece is whether it is zero or not. +% \begin{macrocode} +\cs_new:Npn \@@_round_s:NNNw #1 #2 #3 #4; + { + \exp_after:wN \@@_round:NNN + \exp_after:wN #1 + \exp_after:wN #2 + \int_use:N \__int_eval:w + \if_int_odd:w 0 \if_meaning:w 0 #3 1 \fi: + \if_meaning:w 5 #3 1 \fi: + \exp_stop_f: + \if_int_compare:w \__int_eval:w #4 > \c_zero + 1 + + \fi: + \fi: + #3 + ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_round:NNNN} +% \begin{syntax} +% \cs{@@_round:NNNN} \meta{final sign} \meta{digit} \meta{2d} +% \end{syntax} +% Identical to \cs{@@_round_s:NNNw} except for a trailing semicolon. +% \begin{macrocode} +\cs_new:Npn \@@_round:NNNN #1 #2 #3 #4 + { + \exp_after:wN \@@_round:NNN + \exp_after:wN #1 + \exp_after:wN #2 + \int_use:N \__int_eval:w + \if_int_odd:w 0 \if_meaning:w 0 #3 1 \fi: + \if_meaning:w 5 #3 1 \fi: + \exp_stop_f: + \if_int_compare:w #4 > \c_zero + 1 + + \fi: + \fi: + #3 + \__int_eval_end: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_round_neg:NNN} +% \begin{macro}[aux, EXP] +% { +% \@@_round_to_nearest_neg:NNN, +% \@@_round_to_ninf_neg:NNN, +% \@@_round_to_zero_neg:NNN, +% \@@_round_to_pinf_neg:NNN +% } +% \begin{syntax} +% \cs{@@_round_neg:NNN} \meta{final sign} \meta{digit_1} \meta{digit_2} +% \end{syntax} +% This expands to \cs{c_zero} or \cs{c_one}. Consider a number of +% the form $ \meta{final sign}.X\ldots X\meta{digit_1} $ with exactly +% $15$ (non-all-zero) digits before \meta{digit_1}, and subtract from it +% $\meta{final sign}.0\ldots0\meta{digit_2}$, where there are $16$ zeros. +% If in the current rounding mode the result should be rounded down, +% then this function returns \cs{c_one}. Otherwise, \emph{i.e.}, +% if the result is rounded back to the first operand, then this function +% returns \cs{c_zero}. +% +% It turns out that this negative \enquote{round to nearest} +% is identical to the positive one. And this is the default mode. +% \begin{macrocode} +\cs_new:Npn \@@_round_to_ninf_neg:NNN #1 #2 #3 + { + \if_meaning:w 0 #1 + \if_int_compare:w #3 > \c_zero + \@@_round_return_one: + \fi: + \fi: + \c_zero + } +\cs_new:Npn \@@_round_to_zero_neg:NNN #1 #2 #3 + { + \if_int_compare:w #3 > \c_zero + \@@_round_return_one: + \fi: + \c_zero + } +\cs_new:Npn \@@_round_to_pinf_neg:NNN #1 #2 #3 + { + \if_meaning:w 2 #1 + \if_int_compare:w #3 > \c_zero + \@@_round_return_one: + \fi: + \fi: + \c_zero + } +\cs_new_eq:NN \@@_round_to_nearest_neg:NNN \@@_round_to_nearest:NNN +\cs_new_eq:NN \@@_round_neg:NNN \@@_round_to_nearest_neg:NNN +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{The \texttt{round} function} +% +% ^^A todo: This macro is intermingled with l3fp-parse. +% ^^A todo: Add explanations. +% \begin{macro}[int, EXP]{\@@_round:Nww, \@@_round:Nwn} +% \begin{macro}[aux, EXP] +% { +% \@@_round_normal:NwNNnw , +% \@@_round_normal_ii:NnnwNNnn , +% \@@_round_pack:Nw , +% \@@_round_normal_iii:NNwNnn , +% \@@_round_normal_end:wwNnn , +% \@@_round_special:NwwNnn , +% \@@_round_special_aux:Nw +% } +% \begin{macrocode} +\cs_new:Npn \@@_round:Nww #1#2 ; #3 ; + { + \@@_small_int:wTF #3; { \@@_round:Nwn #1#2; } + { + \@@_error:x { {round(x,n)~with~n=} \@@_to_tl:w #3; } + \exp_after:wN \c_nan_fp + } + } +\cs_new:Npn \@@_round:Nwn #1 \s_@@ \@@_chk:w #2#3#4; #5 + { + \if_meaning:w 1 #2 + \exp_after:wN \@@_round_normal:NwNNnw + \exp_after:wN #1 + \__int_value:w #5 + \else: + \exp_after:wN \@@_exp_after_o:w + \fi: + \s_@@ \@@_chk:w #2#3#4; + } +\cs_new:Npn \@@_round_normal:NwNNnw #1#2 \s_@@ \@@_chk:w 1#3#4#5; + { + \@@_decimate:nNnnnn { \c_sixteen - #4 - #2 } + \@@_round_normal_ii:NnnwNNnn #5 #1 #3 {#4} {#2} + } +\cs_new:Npn \@@_round_normal_ii:NnnwNNnn #1#2#3#4; #5#6 + { + \exp_after:wN \@@_round_normal_iii:NNwNnn + \int_use:N \__int_eval:w + \if_int_compare:w #2 > \c_zero + 1 \__int_value:w #2 + \exp_after:wN \@@_round_pack:Nw + \int_use:N \__int_eval:w 1#3 + + \else: + \if_int_compare:w #3 > \c_zero + 1 \__int_value:w #3 + + \fi: + \fi: + \exp_after:wN #5 + \exp_after:wN #6 + \use_none:nnnnnnn #3 + #1 + \__int_eval_end: + 0000 0000 0000 0000 ; #6 + } +\cs_new:Npn \@@_round_pack:Nw #1 + { \if_meaning:w 2 #1 + \c_one \fi: \__int_eval_end: } +\cs_new:Npn \@@_round_normal_iii:NNwNnn #1 #2 + { + \if_meaning:w 0 #2 + \exp_after:wN \@@_round_special:NwwNnn + \exp_after:wN #1 + \fi: + \@@_pack_twice_four:wNNNNNNNN + \@@_pack_twice_four:wNNNNNNNN + \@@_round_normal_end:wwNnn + ; #2 + } +\cs_new:Npn \@@_round_normal_end:wwNnn #1;#2;#3#4#5 + { + \exp_after:wN \@@_exp_after_o:w \tex_romannumeral:D -`0 + \@@_sanitize:Nw #3 #4 ; #1 ; + } +\cs_new:Npn \@@_round_special:NwwNnn #1#2;#3;#4#5#6 + { + \if_meaning:w 0 #1 + \@@_case_return:nw + { \exp_after:wN \@@_zero_fp:N \exp_after:wN #4 } + \else: + \exp_after:wN \@@_round_special_aux:Nw + \exp_after:wN #4 + \int_use:N \__int_eval:w \c_one + \if_meaning:w 1 #1 -#6 \else: +#5 \fi: + \fi: + ; + } +\cs_new:Npn \@@_round_special_aux:Nw #1#2; + { + \exp_after:wN \@@_exp_after_o:w \tex_romannumeral:D -`0 + \@@_sanitize:Nw #1#2; {1000}{0000}{0000}{0000}; + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx new file mode 100644 index 00000000000..2e3a5e262ba --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx @@ -0,0 +1,418 @@ +% \iffalse meta-comment +%% +%% File: l3fp-traps.dtx Copyright (C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-traps.dtx 2479 2011-06-19 21:57:25Z bruno $ + {L3 Floating-point exception trapping} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp-traps} package\thanks{This file +% has version number \ExplFileVersion, last +% revised \ExplFileDate.}\\ +% Trapping floating-point exceptions} +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% \date{Released \ExplFileDate} +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-traps} Implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% Exceptions should be accessed by an \texttt{n}-type argument, among +% \begin{itemize} +% \item \texttt{invalid_operation} +% \item \texttt{division_by_zero} +% \item \texttt{overflow} +% \item \texttt{underflow} +% \item \texttt{inexact} (actually never used). +% \end{itemize} +% +% \subsection{Flags} +% +% \begin{macro}{\@@_flag_off:n} +% Function to turn a flag off. Simply undefine it. +% \begin{macrocode} +\cs_new_protected:Npn \@@_flag_off:n #1 + { \cs_set_eq:cN { l_@@_ #1 _flag_token } \c_undefined:D } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_flag_on:n} +% Function to turn a flag on expandably: use \TeX{}'s automatic +% assignment to \cs{scan_stop:}. +% \begin{macrocode} +\cs_new:Npn \@@_flag_on:n #1 + { \exp_args:Nc \use_none:n { l_@@_ #1 _flag_token } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP,pTF]{\@@_if_flag_on:n} +% Returns true if the flag is on, false otherwise. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_if_flag_on:n #1 { p , T , F , TF } + { + \if_cs_exist:w l_@@_ #1 _flag_token \cs_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{variable} +% { +% \l_@@_invalid_operation_flag_token , +% \l_@@_division_by_zero_flag_token , +% \l_@@_overflow_flag_token , +% \l_@@_underflow_flag_token , +% } +% The \textsc{ieee} standard defines five exceptions. We currently +% don't support the \enquote{inexact} exception. +% \begin{macrocode} +\cs_new_eq:NN \l_@@_invalid_operation_flag_token \c_undefined:D +\cs_new_eq:NN \l_@@_division_by_zero_flag_token \c_undefined:D +\cs_new_eq:NN \l_@@_overflow_flag_token \c_undefined:D +\cs_new_eq:NN \l_@@_underflow_flag_token \c_undefined:D +% \end{macrocode} +% \end{variable} +% +% \subsection{Traps} +% +% Exceptions can be trapped to obtain custom behaviour. When an invalid +% operation or a division by zero is trapped, the trap receives as +% arguments the result as an $N$-type floating point number, the +% function name (multiple letters for prefix operations, or a single +% symbol for infix operations), and the operand(s). When an overflow or +% underflow is trapped, the trap receives the resulting overly large or +% small floating point number if it is not too big, otherwise it +% receives $+\infty$. Currently, the inexact exception is entirely +% ignored. +% +% The behaviour when an exception occurs is controlled by the +% definitions of the functions +% \begin{itemize} +% \item \cs{@@_invalid_operation:Nnw}, +% \item \cs{@@_invalid_operation:Nnww}, +% \item \cs{@@_division_by_zero:Nnw}, +% \item \cs{@@_division_by_zero:Nnww}, +% \item \cs{@@_overflow:w}, +% \item \cs{@@_underflow:w}. +% \end{itemize} +% Rather than changing them directly, we provide a user interface as +% \cs{@@_trap:nn} \Arg{exception} \Arg{way of trapping}, where the +% \meta{way of trapping} is one of \texttt{error}, \texttt{flag}, or +% \texttt{none}. +% +% \begin{macro}{\@@_trap:nn} %^^A todo: user command => document +% \begin{macrocode} +\cs_new_protected:Npn \@@_trap:nn #1#2 + { + \cs_if_exist_use:cF { @@_trap_#1_set_#2: } + { + \clist_if_in:nnTF + { invalid_operation , division_by_zero , overflow , underflow } + {#1} + { + \__msg_kernel_error:nnxx { kernel } + { unknown-fpu-trap-type } {#1} {#2} + } + { \__msg_kernel_error:nnx { kernel } { unknown-fpu-exception } {#1} } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux] +% { +% \@@_trap_invalid_operation_set_error: , +% \@@_trap_invalid_operation_set_flag: , +% \@@_trap_invalid_operation_set_none: , +% \@@_trap_invalid_operation_set:N , +% } +% \begin{macro}[aux] +% { +% \@@_trap_division_by_zero_set_error: , +% \@@_trap_division_by_zero_set_flag: , +% \@@_trap_division_by_zero_set_none: , +% \@@_trap_division_by_zero_set:N , +% } +% \begin{macro}[aux]{\@@_trap_invalid_operation_set:Nnn} +% We provide three types of trapping for invalid operations and +% division by zero: either produce an error and raise the relevant +% flag; or only raise the flag; or don't even raise the flag. In all +% cases, the function must produce a result, namely its first +% argument, $\pm\infty$ or \nan{}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_trap_invalid_operation_set_error: + { \@@_trap_invalid_operation_set:N \prg_do_nothing: } +\cs_new_protected_nopar:Npn \@@_trap_invalid_operation_set_flag: + { \@@_trap_invalid_operation_set:N \use_none:nn } +\cs_new_protected_nopar:Npn \@@_trap_invalid_operation_set_none: + { \@@_trap_invalid_operation_set:N \use_none:nnnn } +\cs_new_protected:Npn \@@_trap_invalid_operation_set:N #1 + { + \@@_trap_invalid_operation_set:Nnn #1 + { invalid_operation } { Invalid~operation~ } + } +\cs_new_protected_nopar:Npn \@@_trap_division_by_zero_set_error: + { \@@_trap_division_by_zero_set:N \prg_do_nothing: } +\cs_new_protected_nopar:Npn \@@_trap_division_by_zero_set_flag: + { \@@_trap_division_by_zero_set:N \use_none:nn } +\cs_new_protected_nopar:Npn \@@_trap_division_by_zero_set_none: + { \@@_trap_division_by_zero_set:N \use_none:nnnn } +\cs_new_protected:Npn \@@_trap_division_by_zero_set:N #1 + { + \@@_trap_invalid_operation_set:Nnn #1 + { division_by_zero } { Division~by~zero~in~ } + } +\cs_new_protected:Npn \@@_trap_invalid_operation_set:Nnn #1#2#3 + { + \exp_args:Nno \use:n + { \cs_set:cpn { @@_ #2 :Nnw } ##1##2##3; } + { + #1 + \@@_error:x { { #3 ##2 } ( \@@_to_tl:w ##3; ) } + \@@_flag_on:n {#2} + \exp_after:wN ##1 + } + \exp_args:Nno \use:n + { \cs_set:cpn { @@_ #2 :Nnww } ##1##2##3; ##4; } + { + #1 + \@@_error:x + { + {#3} + \tl_if_single:nTF {##2} + { ( \@@_to_tl:w ##3; ) ##2 ( \@@_to_tl:w ##4; ) } + { { ##2 ( } \@@_to_tl:w ##3; { , ~ } \@@_to_tl:w ##4; ) } + } + \@@_flag_on:n {#2} + \exp_after:wN ##1 + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux] +% { +% \@@_trap_overflow_set_error: , +% \@@_trap_overflow_set_flag: , +% \@@_trap_overflow_set_none: , +% \@@_trap_overflow_set:N , +% } +% \begin{macro}[aux] +% { +% \@@_trap_underflow_set_error: , +% \@@_trap_underflow_set_flag: , +% \@@_trap_underflow_set_none: , +% \@@_trap_underflow_set:N , +% } +% \begin{macro}[aux]{\@@_trap_overflow_set:NnNn} +% Just as for invalid operations and division by zero, the three +% different behaviours are obtained by feeding \cs{prg_do_nothing:}, +% \cs{use_none:nn} or \cs{use_none:nnnn} to an auxiliary, with a +% further auxiliary common to overflow and underflow functions. In +% most cases, the argument of the \cs{@@_overflow:w} and +% \cs{@@_underflow:w} functions will be an (almost) normal number +% (with an exponent outside the allowed range), and the error message +% thus displays that number together with the result to which it +% overflowed or underflowed. For extreme cases such as \texttt{10 ** +% 1e9999}, the exponent would be too large for \TeX{}, and +% \cs{@@_overflow:w} receives $\pm \infty$ (\cs{@@_underflow:w} would +% receive $\pm 0$); then we cannot do better than simply say an +% overflow or underflow occurred. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_trap_overflow_set_error: + { \@@_trap_overflow_set:N \prg_do_nothing: } +\cs_new_protected_nopar:Npn \@@_trap_overflow_set_flag: + { \@@_trap_overflow_set:N \use_none:nn } +\cs_new_protected_nopar:Npn \@@_trap_overflow_set_none: + { \@@_trap_overflow_set:N \use_none:nnnn } +\cs_new_protected:Npn \@@_trap_overflow_set:N #1 + { \@@_trap_overflow_set:NnNn #1 { overflow } \@@_inf_fp:N { inf } } +\cs_new_protected_nopar:Npn \@@_trap_underflow_set_error: + { \@@_trap_underflow_set:N \prg_do_nothing: } +\cs_new_protected_nopar:Npn \@@_trap_underflow_set_flag: + { \@@_trap_underflow_set:N \use_none:nn } +\cs_new_protected_nopar:Npn \@@_trap_underflow_set_none: + { \@@_trap_underflow_set:N \use_none:nnnn } +\cs_new_protected:Npn \@@_trap_underflow_set:N #1 + { \@@_trap_overflow_set:NnNn #1 { underflow } \@@_zero_fp:N { 0 } } +\cs_new_protected:Npn \@@_trap_overflow_set:NnNn #1#2#3#4 + { + \exp_args:Nno \use:n + { \cs_set:cpn { @@_ #2 :w } \s_@@ \@@_chk:w ##1##2##3; } + { + #1 + \@@_error:x + { + \token_if_eq_meaning:NNTF 1 ##1 + { + \@@_to_tl:w \s_@@ \@@_chk:w ##1##2##3; ~ #2 ed ~ to ~ + \token_if_eq_meaning:NNF 0 ##2 { - } #4 . + } + { An~#2~occurred. } + } + \@@_flag_on:n {#2} + #3 ##2 + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int] +% { +% \@@_invalid_operation:Nnw, \@@_invalid_operation:Nnww, +% \@@_division_by_zero:Nnw, \@@_division_by_zero:Nnww, +% \@@_overflow:w , \@@_underflow:w +% } +% Initialize the two control sequences (to log properly their +% existence). Then set invalid operations to trigger an error, and +% division by zero, overflow, and underflow to act silently on their +% flag. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_invalid_operation:Nnw { } +\cs_new_protected_nopar:Npn \@@_invalid_operation:Nnww { } +\cs_new_protected_nopar:Npn \@@_division_by_zero:Nnw { } +\cs_new_protected_nopar:Npn \@@_division_by_zero:Nnww { } +\cs_new_protected_nopar:Npn \@@_overflow:w { } +\cs_new_protected_nopar:Npn \@@_underflow:w { } +\@@_trap:nn { invalid_operation } { error } +\@@_trap:nn { division_by_zero } { flag } +\@@_trap:nn { overflow } { flag } +\@@_trap:nn { underflow } { flag } +% \end{macrocode} +% \end{macro} +% +%^^A todo: first arg of @@_invalid_operation:Nnw(w) should be an 'invalid' nan. +% +% \subsection{Errors} +% +%^^A begin[todo] +% \begin{macro}[int, EXP]{\@@_error:n, \@@_error:x} +% The argument is fully expanded in a way similar to \texttt{x}-type +% expansion, but braced groups are simply copied, \cs{exp_not:n} does +% not work, spaces are ignored unless braced. The result of that +% weird (but useful) expansion is fed to \cs{__msg_expandable_error:n}. +% \begin{macrocode} +\cs_new_eq:NN \@@_error:n \__msg_expandable_error:n +\cs_new:Npn \@@_error:x #1 + { + \exp_args:Nf \__msg_expandable_error:n + { + \@@_error_loop:nwnN { \exp_stop_f: } #1 \prg_do_nothing: + \s_@@_mark { } \@@_error_loop:nwnN \s_@@_mark { } \@@_error_end:nw + } + } +\cs_new:Npn \@@_error_end:nw #1#2 \@@_error_end:nw { #1 } +\cs_new:Npn \@@_error_loop:nwnN #1#2 \s_@@_mark #3 #4 + { + \exp_after:wN #4 \tex_romannumeral:D -`0 + #2 + \s_@@_mark { #3 #1 } #4 + } +% \end{macrocode} +% \end{macro} +% ^^A end[todo] +% +% \subsection{Messages} +% +% Some messages. +% \begin{macrocode} +\msg_new:nnnn { kernel } { unknown-fpu-exception } + { The~FPU~exception~'#1'~is~not~known:~that~trap~will~never~be~triggered. } + { + The~only~exceptions~to~which~traps~can~be~attached~are \\ + \iow_indent:n + { + * ~ invalid_operation \\ + * ~ division_by_zero \\ + * ~ overflow \\ + * ~ underflow + } + } +\msg_new:nnnn { kernel } { unknown-fpu-trap-type } + { The~FPU~trap~type~'#2'~is~not~known. } + { + The~trap~type~must~be~one~of \\ + \iow_indent:n + { + * ~ error \\ + * ~ flag \\ + * ~ none + } + } +% \end{macrocode} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx new file mode 100644 index 00000000000..16a3fb465f6 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx @@ -0,0 +1,581 @@ +% \iffalse meta-comment +% +%% File: l3fp-trig.dtx Copyright (C) 2011-2012 The LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "l3kernel bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +% +%<*driver> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-trig.dtx 3514 2012-03-08 06:14:48Z bruno $ + {L3 Floating-point trigonometric functions} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp-trig} package\thanks{This file +% has version number \ExplFileVersion, last +% revised \ExplFileDate.}\\ +% Floating point trigonometric functions} +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{Implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +%^^A todo: check EXP/rEXP everywhere. +% +% \subsection{Inverting a floating point number} +% +% \begin{macro}[int, EXP]{\@@_one_over:w} +% Expects a floating point of the form \cs{s_@@} \ldots{} |;| and +% computes its multiplicative inverse. This is used to compute the +% cotangent function very near $0$. +% \begin{macrocode} +\cs_new_nopar:Npx \@@_one_over:w + { + \exp_not:N \exp_after:wN + \exp_not:c { @@_/_o:ww } + \exp_not:N \c_one_fp + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Direct trigonometric functions} +% +% The approach for all trigonometric functions (sine, cosine, tangent, +% and cotangent) is the same. +% \begin{itemize} +% \item Filter out special cases ($\pm 0$, $\pm\inf$ and \nan{}). +% \item Keep the sign for later, and work with the absolute value $|x|$ +% of the argument. +% \item For numbers less than $1$, shift the mantissa to convert them to +% fixed point numbers. Very small numbers take a slightly different +% route. +% \item For numbers $\geq 1$, subtract a multiple of $\pi/2$ to bring +% them to the range to $[0, \pi/2]$. +% \item Reduce further to $[0, \pi/4]$ using $\sin x = \cos (\pi/2-x)$. +% \item Use the appropriate power series depending on the octant +% $\lfloor\frac{|x|}{\pi/4}\rfloor \mod 8$, the sign, and the function +% to compute. +% \end{itemize} +% +% \subsubsection{Sign and special numbers} +% +% \begin{macro}[int, EXP]{\@@_sin:w} +% The sine of $\pm 0$ or \nan{} is the same floating point number. +% The sine of $\pm\infty$ raises an invalid operation exception. +% Otherwise, check the exponent, preparing to use +% \cs{@@_sin_series:NNwww} for the calculation, with a sign |#2|, and +% an initial octant of $0$. The question mark is an argument which is +% not used in this case. +% \begin{macrocode} +\cs_new:Npn \@@_sin:w \s_@@ \@@_chk:w #1#2 + { + \if_case:w #1 \exp_stop_f: + \@@_case_return_same_o:w + \or: + \exp_after:wN \@@_trig_exponent:NNNNwn + \exp_after:wN \@@_sin_series:NNwww + \exp_after:wN ? + \exp_after:wN #2 + \exp_after:wN \c_zero + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw \c_nan_fp { sin } } + \else: \@@_case_return_same_o:w + \fi: + \s_@@ \@@_chk:w #1#2 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_cos:w} +% The cosine of $\pm 0$ is $1$. The cosine of $\pm\infty$ raises an +% invalid operation exception. The cosine of \nan{} is itself. +% Otherwise, check the exponent, preparing to use +% \cs{@@_sin_series:NNwww} for the calculation, with a positive sign +% ($0$), and an initial octant of $2$, because $\cos x = \sin ( \pi/2 +% + |x|)$. The question mark is an argument which is not used in this +% case. +% \begin{macrocode} +\cs_new:Npn \@@_cos:w \s_@@ \@@_chk:w #1#2 + { + \if_case:w #1 \exp_stop_f: + \@@_case_return_o:Nw \c_one_fp + \or: + \@@_case_use:nw %^^A todo: is that faster than the exp_after route? + { + \@@_trig_exponent:NNNNwn + \@@_sin_series:NNwww + ? + 0 + \c_two + } + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw \c_nan_fp { cos } } + \else: \@@_case_return_same_o:w + \fi: + \s_@@ \@@_chk:w #1#2 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_tan:w} +% The tangent of $\pm 0$ or \nan{} is the same floating point number. +% The tangent of $\pm\infty$ raises an invalid operation exception. +% Otherwise, check the exponent, preparing to use +% \cs{@@_tan_series:NNwww} for the calculation, with a positive sign +% ($0$), and an initial octant of $1$, chosen to be distinct from the +% octants for sine and cosine. See \cs{@@_cot:w} for an +% explanation of the $0$ argument. +% \begin{macrocode} +\cs_new:Npn \@@_tan:w \s_@@ \@@_chk:w #1#2 + { + \if_case:w #1 \exp_stop_f: + \@@_case_return_same_o:w + \or: + \exp_after:wN \@@_trig_exponent:NNNNwn + \exp_after:wN \@@_tan_series:NNwww + \exp_after:wN 0 + \exp_after:wN #2 + \exp_after:wN \c_one + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw \c_nan_fp { tan } } + \else: \@@_case_return_same_o:w + \fi: + \s_@@ \@@_chk:w #1#2 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_cot:w} +% The cotangent of $\pm 0$ is $\pm \infty$ with the same sign, +% produced by \cs{@@_one_over:w}. The cotangent of $\pm\infty$ raises +% an invalid operation exception. The cotangent of \nan{} is itself. +% We use $\cot x = - \tan (\pi/2 + x)$, and the initial octant for the +% tangent was chosen to be $1$, so the octant here starts at $3$. The +% change in sign is obtained by feeding \cs{@@_tan_series:NNwww} two +% signs rather than just the sign of the argument: the first of those +% indicates whether we compute tangent or cotangent. Those signs are +% eventually combined. +% \begin{macrocode} +\cs_new:Npn \@@_cot:w \s_@@ \@@_chk:w #1#2 + { + \if_case:w #1 \exp_stop_f: + \exp_after:wN \@@_one_over:w + \or: + \exp_after:wN \@@_trig_exponent:NNNNwn + \exp_after:wN \@@_tan_series:NNwww + \exp_after:wN 2 + \exp_after:wN #2 + \exp_after:wN \c_three + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw \c_nan_fp { cot } } + \else: \@@_case_return_same_o:w + \fi: + \s_@@ \@@_chk:w #1#2 + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Small and tiny arguments} +% +% \begin{macro}[aux, EXP]{\@@_trig_exponent:NNNNwn} +% The first four arguments control what trigonometric function we +% compute, then follows a normal floating point number. If the +% floating point is smaller than $10^{-8}$, then call the appropriate +% \texttt{_epsilon} auxiliary. Otherwise, call the function |#1|, +% with arguments |#2|, |#3|, the octant, computed in an integer +% expression starting with |#4|, and a fixed point number obtained +% from the floating point number by argument reduction. Numbers less +% than $1$ are converted using \cs{@@_trig_small:w} which simply +% shifts the mantissa, while large numbers need argument reduction. +% \begin{macrocode} +\cs_new:Npn \@@_trig_exponent:NNNNwn #1#2#3#4 \s_@@ \@@_chk:w 1#5#6 + { + \if_int_compare:w #6 > - \c_eight + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN #3 + \int_use:N \__int_eval:w #4 + \if_int_compare:w #6 > \c_zero + \exp_after:wN \@@_trig_large:w \__int_value:w + \else: + \exp_after:wN \@@_trig_small:w \__int_value:w + \fi: + \else: + \if_case:w #4 + \@@_sin_epsilon:w + \or: \@@_sin_epsilon:w + \or: \@@_cos_epsilon:w + \else: \@@_cot_epsilon:w + \fi: + #5 + \fi: + #6 ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP] +% {\@@_sin_epsilon:w, \@@_cos_epsilon:w, \@@_cot_epsilon:w} +% Sine and tangent of tiny numbers give the number itself: the +% relative error is less than $5 \cdot 10^{-17}$, which is +% appropriate. Cosine simply gives $1$. Cotangent computes the +% inverse. This is actually slightly wrong because further terms in +% the power series could affect the rounding for cotangent. +% \begin{macrocode} +\cs_new:Npn \@@_sin_epsilon:w #1 \fi: #2 \fi: #3 ; + { \fi: \fi: \@@_exp_after_o:w \s_@@ \@@_chk:w 1 #2 {#3} } +\cs_new:Npn \@@_cos_epsilon:w #1 \fi: #2 \fi: #3 ; #4 ; + { \fi: \fi: \exp_after:wN \c_one_fp } +\cs_new:Npn \@@_cot_epsilon:w \fi: #1 \fi: #2 ; + { \fi: \fi: \@@_one_over:w \s_@@ \@@_chk:w 1 #1 {#2} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_trig_small:w, \@@_trig_small_aux:wwNN} +% Floating point numbers less than $1$ are converted to fixed point +% numbers by shifting the mantissa. Since we have already filtered +% out numbers less than $10^{-8}$, no digit is lost in converting to +% a fixed point number. +% \begin{macrocode} +\cs_new:Npn \@@_trig_small:w #1; + { + \exp_after:wN \exp_after:wN \exp_after:wN \@@_trig_small_aux:wwNN + \prg_replicate:nn { - #1 } { 0 } ; + } +\cs_new:Npn \@@_trig_small_aux:wwNN #1; #2#3#4#5; + { + \@@_pack_twice_four:wNNNNNNNN + \@@_pack_twice_four:wNNNNNNNN + \@@_pack_twice_four:wNNNNNNNN + . + ; + #1#2#3#4#5 0000 0000; + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Reduction of large arguments} +% +% In the case of a floating point argument greater or equal to $1$, we +% need to perform argument reduction. +% +% \begin{macro}[aux, rEXP] +% { +% \@@_trig_large:w, \@@_trig_large_i:www, +% \@@_trig_large_ii:wnnnnnn, \@@_trig_large_break:w +% } +% We shift the mantissa by one digit at a time, subtracting a multiple +% of $2\pi$ at each step. We use a value of $2\pi$ rounded up, +% consistent with the choice of \cs{c_pi_fp}. This is not quite +% correct from an accuracy perspective, but has the nice property that +% $\sin(180\mathrm{deg}) = 0$ exactly. The arguments of +% \cs{@@_trig_large_i:www} are a leading block of up to $5$ digits, +% three brace groups of $4$ digits each, and the exponent, decremented +% at each step. The multiple of $2\pi$ to subtract is estimated as +% $\lfloor |#1| / 6283\rfloor$ (the formula chosen always gives a +% non-negative integer). The subtraction has a form similar to our +% usual multiplications (see \pkg{l3fp-basics} or +% \pkg{l3fp-extended}). Once the exponent reaches $0$, we are done +% subtracting $2\pi$, and we call \cs{@@_trig_octant_loop:nw} to do +% the reduction by $\pi/2$. +% \begin{macrocode} +\cs_new:Npn \@@_trig_large:w #1; #2#3; + { \@@_trig_large_i:www #2; #3 ; #1; } +\cs_new:Npn \@@_trig_large_i:www #1; #2; #3; + { + \if_meaning:w 0 #3 \@@_trig_large_break:w \fi: + \exp_after:wN \@@_trig_large_ii:wnnnnnn + \int_use:N \__int_eval:w ( #1 - 3141 ) / 6283 ; + {#1} #2; + \int_use:N \__int_eval:w \c_minus_one + #3; + } +\cs_new:Npn \@@_trig_large_ii:wnnnnnn #1; #2#3#4#5; + { + \exp_after:wN \@@_trig_large_i:www + \int_use:N \__int_eval:w -5 0000 + #20 - #1*62831 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 4 9995 0000 + #30 - #1*8530 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 4 9995 0000 + #40 - #1*7179 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 5 0000 0000 + #50 - #1*5880 + \exp_after:wN ; + \exp_after:wN ; + } +\cs_new:Npn \@@_trig_large_break:w \fi: #1; #2; + { \fi: \@@_trig_octant_loop:nw #2 {0000} {0000} ; } +% \end{macrocode} +% \end{macro} +% +%^^A todo: optimize: we don't need 6x4 digits here, only 4x4. +% +% \begin{macro}[aux, rEXP] +% { +% \@@_trig_octant_loop:nw, \@@_trig_octant_break:w, +% \@@_trig_octant_neg:w +% } +% We receive a fixed point number as argument. As long as it is +% greater than $1.5707$ (a slight underestimate of $\pi/2$), subtract +% $\pi/2$, and leave |+ \c_two| in the integer expression for the +% octant. Once it becomes smaller, if it is greater than $0.7854$ +% (overestimate of $\pi/4$), then compute $\pi/2 - x$ and increment +% the octant. If it is negative, correct this by changing the sign +% and decrementing the octant (by adding $7$). The result is in all +% cases in the range $[0, 0.7854]$, appropriate for a series +% expansion. +% \begin{macrocode} +\cs_new:Npn \@@_trig_octant_loop:nw #1#2; + { + \if_int_compare:w #1 < 15707 \exp_stop_f: + \@@_trig_octant_break:w + \fi: + + \c_two + \@@_fixed_sub_back:wwN + {15707} {9632} {6794} {8970} {0000} {0000} ; + {#1} #2; + \@@_trig_octant_loop:nw + } +\cs_new:Npn \@@_trig_octant_break:w #1 \fi: + #2#3 #4; #5#6; #7; + { + \fi: + \if_int_compare:w #5 < 7854 \exp_stop_f: + \if_int_compare:w #5 < \c_zero + \exp_after:wN \@@_trig_octant_neg:w + \fi: + \exp_after:wN \@@_use_i_until_s:nw + \exp_after:wN . + \fi: + + \c_one + \@@_fixed_sub:wwN + {15707} {9632} {6794} {8970} {0000} {0000} ; + {#5} #6 ; . ; + } +\cs_new:Npn \@@_trig_octant_neg:w #1\fi: #2; #3#4#5#6#7#8; #9 + { + \fi: + + \c_seven + \exp_after:wN \@@_fixed_add_after:NNNNNwN + \int_use:N \__int_eval:w 1 9999 9998 - #30000 - #4 + \exp_after:wN \@@_fixed_add_pack:NNNNNwN + \int_use:N \__int_eval:w 1 9999 9998 - #5#6 + \exp_after:wN \@@_fixed_add_pack:NNNNNwN + \int_use:N \__int_eval:w 2 0000 0000 - #7#8 ; {#9} ; + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Computing the power series} +% +% \begin{macro}[aux, EXP]{\@@_sin_series:NNwww, \@@_sin_series_aux:Nnww} +% Here we receive an unused |?|, a \meta{sign} ($0$ or $2$), a +% (non-negative) \meta{octant} delimited by a dot, a \meta{fixed +% point} number, and junk delimited by a semicolon. The auxiliary +% receives: +% \begin{itemize} +% \item The final sign, which depends on the octant |#3| and the +% original sign |#2|, +% \item The octant |#3|, which will control the series we use. +% \item The square |#4 * #4| of the argument, computed with +% \cs{@@_fixed_mul:wwn}. +% \item The number itself. +% \end{itemize} +% If the octant is in $\{1,2,5,6,\ldots{}\}$, we are near an extremum +% of the function and we use the series +% \[ +% \cos(x) = 1 - x^2 \bigg( \frac{1}{2!} - x^2 \bigg( \frac{1}{4!} +% - x^2 \bigg( \cdots \bigg) \bigg) \bigg) . +% \] +% Otherwise, the series +% \[ +% \sin(x) = x \bigg( 1 - x^2 \bigg( \frac{1}{3!} - x^2 \bigg( +% \frac{1}{5!} - x^2 \bigg( \cdots \bigg) \bigg) \bigg) \bigg) +% \] +% is used. Finally, the fixed point number is converted to a floating +% point number with the given sign, and we check for overflow or +% underflow. %^^A todo: can over/underflow really happen?? +% \begin{macrocode} +\cs_new:Npn \@@_sin_series:NNwww #1#2#3 . #4; #5; + { + \@@_fixed_mul:wwn #4; #4; + { + \exp_after:wN \@@_sin_series_aux:Nnww + \__int_value:w + \if_int_odd:w \__int_eval:w ( #3 + \c_two ) / \c_four \__int_eval_end: + #2 + \else: + \if_meaning:w #2 0 2 \else: 0 \fi: + \fi: + {#3} + } + #4 ; + } +\cs_new:Npn \@@_sin_series_aux:Nnww #1#2 #3; #4; + { + \if_int_odd:w \__int_eval:w #2 / \c_two \__int_eval_end: + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { + \@@_fixed_continue:wn {0000}{0000}{0000}{0001}{5619}{2070}; % 1/18! + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0000}{0000}{0477}{9477}{3324}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0000}{0011}{4707}{4559}{7730}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0000}{2087}{6756}{9878}{6810}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0027}{5573}{1922}{3985}{8907}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{2480}{1587}{3015}{8730}{1587}; + \@@_fixed_mul_sub_back:wwwn #3; {0013}{8888}{8888}{8888}{8888}{8889}; + \@@_fixed_mul_sub_back:wwwn #3; {0416}{6666}{6666}{6666}{6666}{6667}; + \@@_fixed_mul_sub_back:wwwn #3; {5000}{0000}{0000}{0000}{0000}{0000}; + \@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000}; + } + { + \@@_fixed_continue:wn {0000}{0000}{0000}{0028}{1145}{7254}; % 1/17! + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0000}{0000}{7647}{1637}{3182}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0000}{0160}{5904}{3836}{8216}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0002}{5052}{1083}{8544}{1719}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0275}{5731}{9223}{9858}{9065}; + \@@_fixed_mul_sub_back:wwwn #3; {0001}{9841}{2698}{4126}{9841}{2698}; + \@@_fixed_mul_sub_back:wwwn #3; {0083}{3333}{3333}{3333}{3333}{3333}; + \@@_fixed_mul_sub_back:wwwn #3; {1666}{6666}{6666}{6666}{6666}{6667}; + \@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000}; + \@@_fixed_mul:wwn #4; + } + { + \exp_after:wN \@@_sanitize:Nw + \exp_after:wN #1 + \int_use:N \__int_eval:w \@@_fixed_to_float:wN + } + #1 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_tan_series:NNwww, \@@_tan_series_aux:Nnww} +% Similar to \cs{@@_sin_series:NNwww}, but with slightly different +% rules to find the sign. The result is expressed as a ratio of +% polynomials, of the form +% \[ +% \tan(x) \simeq +% \frac{x (1 - x^2 (a_1 - x^2 (a_2 - x^2 (a_3 - x^2 (a_4 - x^2 a_5)))))} +% {1 - x^2 (b_1 - x^2 (b_2 - x^2 (b_3 - x^2 (b_4 - x^2 b_5))))} . +% \] +% The ratio of the two fixed point numbers is converted to a floating +% point number directly to avoid rounding issues. The two fixed +% points may be exchanged before computing the ratio, depending on the +% quadrant. +% \begin{macrocode} +\cs_new:Npn \@@_tan_series:NNwww #1#2#3. #4; #5; + { + \@@_fixed_mul:wwn #4; #4; + { + \exp_after:wN \@@_tan_series_aux:Nnww + \__int_value:w + \if_int_odd:w \__int_eval:w #3 / \c_two \__int_eval_end: + \exp_after:wN \reverse_if:N + \fi: + \if_meaning:w #1#2 2 \else: 0 \fi: + {#3} + } + #4 ; + } +\cs_new:Npn \@@_tan_series_aux:Nnww #1 #2 #3; #4; + { + \@@_fixed_continue:wn {0000}{0000}{1527}{3493}{0856}{7059}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0159}{6080}{0274}{5257}{6472}; + \@@_fixed_mul_sub_back:wwwn #3; {0002}{4571}{2320}{0157}{2558}{8481}; + \@@_fixed_mul_sub_back:wwwn #3; {0115}{5830}{7533}{5397}{3168}{2147}; + \@@_fixed_mul_sub_back:wwwn #3; {1929}{8245}{6140}{3508}{7719}{2982}; + \@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000}; + \@@_fixed_mul:wwn #4; + { + \@@_fixed_continue:wn {0000}{0007}{0258}{0681}{9408}{4706}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{2343}{7175}{1399}{6151}{7670}; + \@@_fixed_mul_sub_back:wwwn #3; {0019}{2638}{4588}{9232}{8861}{3691}; + \@@_fixed_mul_sub_back:wwwn #3; {0536}{6357}{0691}{4344}{6852}{4252}; + \@@_fixed_mul_sub_back:wwwn #3; {5263}{1578}{9473}{6842}{1052}{6315}; + \@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000}; + { + \exp_after:wN \@@_sanitize:Nw + \exp_after:wN #1 + \int_use:N \__int_eval:w + \reverse_if:N \if_int_odd:w + \__int_eval:w (#2 - \c_one) / \c_two \__int_eval_end: + \exp_after:wN \@@_reverse_args:Nww + \fi: + \@@_fixed_div_to_float:ww + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx index 64a6b39252f..68f71f540cc 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3fp.dtx Copyright (C) 2010-2012 The LaTeX3 Project +%% File: l3fp.dtx Copyright (C) 2011-2012 The LaTeX3 Project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -29,27 +29,31 @@ %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without -%% prior consultation with the LaTeX3 Project. +%% prior consultation with the LaTeX3 Project Team. %% %% ----------------------------------------------------------------------- +%% % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3fp.dtx 3490 2012-03-04 01:00:53Z bruno $ - {L3 Experimental floating-point operations} +\GetIdInfo$Id: l3fp.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Floating points} %</driver|package> %<*driver> \documentclass[full]{l3doc} +\usepackage{amsmath} +\providecommand\nan{\texttt{NaN}} \begin{document} \DocInput{\jobname.dtx} \end{document} %</driver> % \fi % +% % \title{^^A -% The \pkg{l3fp} package\\ Floating-point operations^^A +% The \textsf{l3fp} package: floating points^^A % \thanks{This file describes v\ExplFileVersion, -% last revised \ExplFileDate.}^^A +% last revised \ExplFileDate.}^^A % } % % \author{^^A @@ -67,5497 +71,868 @@ % % \begin{documentation} % -% A floating point number is one which is stored as a mantissa and -% a separate exponent. This module implements arithmetic using radix -% $10$ floating point numbers. This means that the mantissa should -% be a real number in the range $1 \le \expandafter\mathopen\string| -% x \expandafter\mathclose\string| < 10$, with the -% exponent given as an integer between $-99$ and $99$. In the -% input, the exponent part is represented starting with an \texttt{e}. -% As this is a low-level module, error-checking is minimal. Numbers -% which are too large for the floating point unit to handle will result -% in errors, either from \TeX{} or from \LaTeX{}. The \LaTeX{} code does not -% check that the input will not overflow, hence the possibility of a -% \TeX{} error. On the other hand, numbers which are too small will be -% dropped, which will mean that extra decimal digits will simply be -% lost. -% -% When parsing numbers, any missing parts will be interpreted as -% zero. So for example -%\begin{verbatim} -% \fp_set:Nn \l_my_fp { } -% \fp_set:Nn \l_my_fp { . } -% \fp_set:Nn \l_my_fp { - } +% A floating point number is one which is stored as a mantissa and a +% separate exponent. The module implements expandably a wide set of +% arithmetic, trigonometric, and other operations on floating point +% numbers, to be used within floating point expressions. Floating point +% expressions support the following operations with their usual +% precedence. +% \begin{itemize} +% \item Basic arithmetic: addition $x+y$, subtraction $x-y$, +% multiplication $x*y$, division $x/y$, and parentheses. +% \item Trigonometry: $\sin x$, $\cos x$, $\tan x$, $\cot x$. +% \item Exponentials: $\exp x$, $\ln x$, $x^y$. +% \item Comparison operators: $x<y$, $x<=y$, $x>?y$, $x!=y$ \emph{etc.} +% \item Boolean logic: negation $!x$, conjunction $\&\&$, disjunction +% $\vert\vert$, ternary operator $x?y:z$. +% \item [\emph{not yet}] Inverse trigonometric functions: +% $\operatorname{asin} x$, $\operatorname{acos} x$, +% $\operatorname{atan} x$, $\operatorname{acot} x$. +% \item [\emph{not yet}] Hyperbolic functions and their inverse +% functions: $\sinh x$, $\cosh x$, $\tanh x$, $\coth x$, and +% $\operatorname{asinh} x$, $\operatorname{acosh} x$, +% $\operatorname{atanh} x$, $\operatorname{acoth} x$. +% \item Extrema: $\max(x,y,\ldots)$, $\min(x,y,\ldots)$, +% $\operatorname{abs}(x)$. +% \item Rounding functions: $\operatorname{round}(x,n)$ round to +% closest, $\operatorname{round} 0(x,n)$ round towards zero, +% $\operatorname{round}\pm(x,n)$ round towards $\pm\infty$. And +% (\emph{not yet}) modulo, and \enquote{quantize}. +% \item Constants: \texttt{pi}, \texttt{deg} (one degree in radians). +% \item Dimensions, automatically expressed in points, \emph{e.g.}, +% \texttt{pc} is $12$. +% \item Automatic conversion (no need for \cs{\meta{type}_use:N}) of +% integer, dimension, and skip variables to floating points, +% expressing dimensions in points and ignoring the stretch and +% shrink components of skips. +% \end{itemize} +% Floating point numbers can be given either explicitly (in a form such +% as |1.234e-34|, or |-.0001|), or as a stored floating point variable, +% which is automatically replaced by its current value. See +% section~\ref{sec:fp-floats} for a description of what a floating point is, +% section~\ref{sec:fp-precedence} for details about how an expression is +% parsed, and section~\ref{sec:fp-operations} to know what the various +% operations do. Some operations may raise exceptions (error messages), +% described in section~\ref{sec:fp-exceptions}. +% +% An example of use could be the following. +% \begin{verbatim} +% \LaTeX{} can now compute: $ \frac{\sin (3.5)}{2} + 2\cdot 10^{-3} +% = \ExplSyntaxOn \fp_to_decimal:n {sin 3.5 /2 + 2e-3} $. +% \end{verbatim} +% But in all fairness, this module is mostly meant as an underlying tool +% for higher-level commands. For example, one could provide a function +% to typeset nicely the result of floating point computations. +% \begin{verbatim} +% \usepackage{xparse, siunitx} +% \ExplSyntaxOn +% \NewDocumentCommand { \calcnum } { m } +% { \num { \fp_to_scientific:n {#1} } } +% \ExplSyntaxOff +% \calcnum { 2 pi * sin ( 2.3 ^ 5 ) } % \end{verbatim} -% will all be interpreted as zero values without raising an error. -% -% Operations which give an undefined result (such as division by -% $0$) will not lead to errors. Instead special marker values are -% returned, which can be tested for using for example -% \cs{fp_if_undefined:N(TF)}. In this way it is possible to work with -% asymptotic functions without first checking the input. If these -% special values are carried forward in calculations they will be -% treated as $0$. -% -% Floating point numbers are stored in the \texttt{fp} floating point -% variable type. This has a standard range of functions for -% variable management. -% -% \section{Floating-point variables} % -% \begin{function}{\fp_new:N, \fp_new:c} -% \begin{syntax} -% \cs{fp_new:N} \meta{floating point variable} -% \end{syntax} -% Creates a new \meta{floating point variable} or raises an error if -% the name is already taken. The declaration is global. The -% \meta{floating point} will initially be set to |+0.000000000e0| -% (the zero floating point). -% \end{function} +% \section{Creating and initialising floating point variables} % -% \begin{function}{\fp_const:Nn, \fp_const:cn} +% \begin{function}[updated = 2012-05-08]{\fp_new:N, \fp_new:c} % \begin{syntax} -% \cs{fp_const:Nn} \meta{floating point variable} \Arg{value} +% \cs{fp_new:N} \meta{fp~var} % \end{syntax} -% Creates a new constant \meta{floating point variable} or raises an -% error if the name is already taken. The value of the -% \meta{floating point variable} will be set globally to the -% \meta{value}. +% Creates a new \meta{fp~var} or raises an error if the name is +% already taken. The declaration is global. The \meta{fp~var} will +% initially be $+0$. % \end{function} % -% \begin{function} -% { -% \fp_set_eq:NN, \fp_set_eq:cN, \fp_set_eq:Nc, \fp_set_eq:cc, -% \fp_gset_eq:NN, \fp_gset_eq:cN, \fp_gset_eq:Nc, \fp_gset_eq:cc -% } +% \begin{function}[updated = 2012-05-08]{\fp_const:Nn, \fp_const:cn} % \begin{syntax} -% \cs{fp_set_eq:NN} \meta{fp var1} \meta{fp var2} +% \cs{fp_const:Nn} \meta{fp~var} \Arg{floating point expression} % \end{syntax} -% Sets the value of \meta{floating point variable1} equal to that of -% \meta{floating point variable2}. +% Creates a new constant \meta{fp~var} or raises an error if the name +% is already taken. The \meta{fp~var} will be set globally equal to +% the result of evaluating the \meta{floating point expression}. % \end{function} % -% \begin{function}{\fp_zero:N, \fp_zero:c, \fp_gzero:N, \fp_gzero:c} +% \begin{function}[updated = 2012-05-08] +% {\fp_zero:N, \fp_zero:c, \fp_gzero:N, \fp_gzero:c} % \begin{syntax} -% \cs{fp_zero:N} \meta{floating point variable} +% \cs{fp_zero:N} \meta{fp~var} % \end{syntax} -% Sets the \meta{floating point variable} to |+0.000000000e0|. +% Sets the \meta{fp~var} to~$+0$. % \end{function} % -% \begin{function}[added = 2012-01-07] +% \begin{function}[updated = 2012-05-08] % {\fp_zero_new:N, \fp_zero_new:c, \fp_gzero_new:N, \fp_gzero_new:c} % \begin{syntax} -% \cs{fp_zero_new:N} \meta{floating point variable} +% \cs{fp_zero_new:N} \meta{fp~var} % \end{syntax} -% Ensures that the \meta{floating point variable} exists globally +% Ensures that the \meta{fp~var} exists globally % by applying \cs{fp_new:N} if necessary, then applies -% \cs{fp_(g)zero:N} to leave the \meta{floating point variable} -% set to zero. +% \cs{fp_(g)zero:N} to leave the \meta{fp~var} set to zero. % \end{function} % -% \begin{function}{\fp_set:Nn, \fp_set:cn, \fp_gset:Nn, \fp_gset:cn} +% \section{Setting floating point variables} +% +% \begin{function}[updated = 2012-05-08] +% {\fp_set:Nn, \fp_set:cn, \fp_gset:Nn, \fp_gset:cn} % \begin{syntax} -% \cs{fp_set:Nn} \meta{floating point variable} \Arg{value} +% \cs{fp_set:Nn} \meta{fp~var} \Arg{floating point expression} % \end{syntax} -% Sets the \meta{floating point variable} variable to \meta{value}. +% Sets \meta{fp~var} equal to the result of computing the +% \meta{floating point expression}. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-05-08] % { -% \fp_set_from_dim:Nn, \fp_set_from_dim:cn, -% \fp_gset_from_dim:Nn, \fp_gset_from_dim:cn +% \fp_set_eq:NN , \fp_set_eq:cN , \fp_set_eq:Nc , \fp_set_eq:cc , +% \fp_gset_eq:NN, \fp_gset_eq:cN, \fp_gset_eq:Nc, \fp_gset_eq:cc % } % \begin{syntax} -% \cs{fp_set_from_dim:Nn} \meta{floating point variable} \Arg{dimexpr} +% \cs{fp_set_eq:NN} \meta{fp~var_1} \meta{fp~var_2} % \end{syntax} -% Sets the \meta{floating point variable} to the distance represented -% by the \meta{dimension expression} in the units points. This means -% that distances given in other units are first converted to points -% before being assigned to the \meta{floating point variable}. +% Sets the floating point variable \meta{fp~var_1} equal to the current +% value of \meta{fp~var_2}. % \end{function} % -% \begin{function}[rEXP]{\fp_use:N, \fp_use:c} +% \begin{function}[updated = 2012-05-08] +% {\fp_add:Nn, \fp_add:cn, \fp_gadd:Nn, \fp_gadd:cn} % \begin{syntax} -% \cs{fp_use:N} \meta{floating point variable} +% \cs{fp_add:Nn} \meta{fp~var} \Arg{floating point expression} % \end{syntax} -% Inserts the value of the \meta{floating point variable} into the -% input stream. The value will be given as a real number without any -% exponent part, and will always include a decimal point. For example, -% \begin{verbatim} -% \fp_new:Nn \test -% \fp_set:Nn \test { 1.234 e 5 } -% \fp_use:N \test -% \end{verbatim} -% will insert |12345.00000| into the input stream. -% As illustrated, a floating point will always be inserted with ten -% significant digits given. Very large and very small values will -% include additional zeros for place value. +% Adds the result of computing the \meta{floating point expression} to +% the \meta{fp~var}. % \end{function} % -% \begin{function}{\fp_show:N, \fp_show:c} +% \begin{function}[updated = 2012-05-08] +% {\fp_sub:Nn, \fp_sub:cn, \fp_gsub:Nn, \fp_gsub:cn} % \begin{syntax} -% \cs{fp_show:N} \meta{floating point variable} +% \cs{fp_sub:Nn} \meta{fp~var} \Arg{floating point expression} % \end{syntax} -% Displays the content of the \meta{floating point variable} on the -% terminal. +% Subtracts the result of computing the \meta{floating point +% expression} from the \meta{fp~var}. % \end{function} % -% \begin{function}[EXP, pTF, added=2012-03-03]{\fp_if_exist:N, \fp_if_exist:c} +% \section{Using floating point numbers} +% +% \begin{function}[EXP, added = 2012-05-08, updated = 2012-07-08]{\fp_eval:n} % \begin{syntax} -% \cs{fp_if_exist_p:N} \meta{fp~var} -% \cs{fp_if_exist:NTF} \meta{fp~var} \Arg{true code} \Arg{false code} +% \cs{fp_eval:n} \Arg{floating point expression} % \end{syntax} -% Tests whether the \meta{fp~var} is currently defined. This does not -% check that the \meta{fp~var} really is a floating point variable. +% Evaluates the \meta{floating point expression} and expresses the +% result as a decimal number with~$16$ significant figures and no +% exponent. Leading or trailing zeros may be inserted to compensate +% for the exponent. Non-significant trailing zeros are trimmed, and +% integers are expressed without a decimal separator. The values +% $\pm\infty$ and \texttt{nan} trigger an \enquote{invalid operation} +% exception. This function is identical to \cs{fp_to_decimal:n}. % \end{function} % -% \section{Conversion of floating point values to other formats} -% -% It is useful to be able to convert floating point variables to -% other forms. These functions are expandable, so that the material -% can be used in a variety of contexts. The \cs{fp_use:N} function -% should also be consulted in this context, as it will insert the -% value of the floating point variable as a real number. -% -% \begin{function}[rEXP]{\fp_to_dim:N, \fp_to_dim:c} +% \begin{function}[EXP, added = 2012-05-08, updated = 2012-07-08] +% {\fp_to_decimal:N, \fp_to_decimal:c, \fp_to_decimal:n} % \begin{syntax} -% \cs{fp_to_dim:N} \meta{floating point variable} +% \cs{fp_to_decimal:N} \meta{fp~var} +% \cs{fp_to_decimal:n} \Arg{floating point expression} % \end{syntax} -% Inserts the value of the \meta{floating point variable} -% into the input stream converted into a dimension in points. +% Evaluates the \meta{floating point expression} and expresses the +% result as a decimal number with $16$ significant figures and no +% exponent. Leading or trailing zeros may be inserted to compensate +% for the exponent. Non-significant trailing zeros are trimmed, and +% integers are expressed without a decimal separator. The values +% $\pm\infty$ and \texttt{nan} trigger an \enquote{invalid operation} +% exception. % \end{function} % -% \begin{function}[rEXP]{\fp_to_int:N, \fp_to_int:c} +% \begin{function}[EXP, updated = 2012-07-08] +% {\fp_to_dim:N, \fp_to_dim:c, \fp_to_dim:n} % \begin{syntax} -% \cs{fp_to_int:N} \meta{floating point variable} +% \cs{fp_to_dim:N} \meta{fp~var} +% \cs{fp_to_dim:n} \Arg{floating point expression} % \end{syntax} -% Inserts the integer value of the \meta{floating point variable} -% into the input stream. The decimal part of the number will not be -% included, but will be used to round the integer. +% Evaluates the \meta{floating point expression} and expresses the +% result as a dimension (in \texttt{pt}) suitable for use in dimension +% expressions. The output is identical to \cs{fp_to_decimal:n}, with +% an additional trailing \texttt{pt}. In particular, floating point +% numbers outside the range $[- 2^{14} + 2^{-17}, 2^{14} - 2^{-17}]$ +% overflow \TeX{}'s maximum dimension. The values $\pm\infty$ and +% \texttt{nan} trigger an \enquote{invalid operation} exception. % \end{function} % -% \begin{function}[rEXP]{\fp_to_tl:N, \fp_to_tl:c} +% \begin{function}[EXP, updated = 2012-07-08] +% {\fp_to_int:N, \fp_to_int:c, \fp_to_int:n} % \begin{syntax} -% \cs{fp_to_tl:N} \meta{floating point variable} +% \cs{fp_to_int:N} \meta{fp~var} +% \cs{fp_to_int:n} \Arg{floating point expression} % \end{syntax} -% Inserts a representation of the \meta{floating point variable} into -% the input stream as a token list. The representation follows the -% conventions of a pocket calculator: -% \begin{center} -% \ttfamily -% \begin{tabular}{r@{.}lr@{.}l} -% \toprule -% \multicolumn{2}{l}{\rmfamily{Floating point value}} & -% \multicolumn{2}{l}{\rmfamily{Representation}} \\ -% \midrule -% 1 & 234000000000e0 & 1 & 234 \\ -% -1 & 234000000000e0 & -1 & 234 \\ -% 1 & 234000000000e3 & \multicolumn{2}{l}{1234} \\ -% 1 & 234000000000e13 & \multicolumn{2}{l}{1234e13} \\ -% 1 & 234000000000e-1 & 0 & 1234 \\ -% 1 & 234000000000e-2 & 0 & 01234 \\ -% 1 & 234000000000e-3 & 1 & 234e-3 \\ -% \bottomrule -% \end{tabular} -% \end{center} -% Notice that trailing zeros are removed in this process, and that -% numbers which do not require a decimal part do \emph{not} include -% a decimal marker. +% Evaluates the \meta{floating point expression}, and rounds the +% result to the closest integer, with ties rounded to an even integer. +% The result may be outside the range $[- 2^{31} + 1, 2^{31} - 1]$ of +% valid \TeX{} integers, triggering \TeX{} errors if used in an +% integer expression. The values $\pm\infty$ and \texttt{nan} trigger +% an \enquote{invalid operation} exception. % \end{function} % -% \section{Rounding floating point values} -% -% The module can round floating point values to either decimal places -% or significant figures using the usual method in which exact halves -% are rounded up. +% \begin{function}[EXP, added = 2012-05-08, updated = 2012-07-08] +% {\fp_to_scientific:N, \fp_to_scientific:c, \fp_to_scientific:n} +% \begin{syntax} +% \cs{fp_to_scientific:N} \meta{fp~var} +% \cs{fp_to_scientific:n} \Arg{floating point expression} +% \end{syntax} +% Evaluates the \meta{floating point expression} and expresses the +% result in scientific notation with $16$ significant figures: +% \begin{quote} +% \meta{optional \texttt{-}}\meta{digit}\texttt{.}\meta{15 digits}\texttt{e}\meta{optional sign}\meta{exponent} +% \end{quote} +% The leading \meta{digit} is non-zero except in the case of $\pm 0$. +% The values $\pm\infty$ and \texttt{nan} trigger an \enquote{invalid +% operation} exception. +% \end{function} % -% \begin{function} -% { -% \fp_round_figures:Nn, \fp_round_figures:cn, -% \fp_ground_figures:Nn, \fp_ground_figures:cn -% } +% \begin{function}[EXP, updated = 2012-07-08] +% {\fp_to_tl:N, \fp_to_tl:c, \fp_to_tl:n} % \begin{syntax} -% \cs{fp_round_figures:Nn} \meta{floating point variable} \Arg{target} +% \cs{fp_to_tl:N} \meta{fp~var} +% \cs{fp_to_tl:n} \Arg{floating point expression} % \end{syntax} -% Rounds the \meta{floating point variable} to the \meta{target} number -% of significant figures (an integer expression). +% Evaluates the \meta{floating point expression} and expresses the +% result in (almost) the shortest possible form. Numbers greater or +% equal to $10^{16}$, or less than $10^{-3}$ are expressed in +% scientific notation with trailing zeros trimmed (see +% \cs{fp_to_scientific:n}). Numbers in the range $[10^{-3},10^{16})$ +% are expressed in a decimal notation without exponent, with trailing +% zeros trimmed, and no decimal separator for integer values (see +% \cs{fp_to_decimal:n}. The special values $\pm 0$, $\pm \inf$ and +% \texttt{nan} are rendered as |0|, |-0|, \texttt{inf}, \texttt{-inf}, +% and \texttt{nan} respectively. % \end{function} % -% \begin{function} -% { -% \fp_round_places:Nn, \fp_round_places:cn, -% \fp_ground_places:Nn, \fp_ground_places:cn -% } +% \begin{function}[EXP, updated = 2012-07-08]{\fp_use:N, \fp_use:c} % \begin{syntax} -% \cs{fp_round_places:Nn} \meta{floating point variable} \Arg{target} +% \cs{fp_use:N} \meta{fp~var} % \end{syntax} -% Rounds the \meta{floating point variable} to the \meta{target} number -% of decimal places (an integer expression). +% Inserts the value of the \meta{fp~var} into the input stream as a +% decimal number with $16$ significant figures and no exponent. +% Leading or trailing zeros may be inserted to compensate for the +% exponent. Non-significant trailing zeros are trimmed. Integers are +% expressed without a decimal separator. The values $\pm\infty$ and +% \texttt{nan} trigger an \enquote{invalid operation} exception. This +% function is identical to \cs{fp_to_decimal:N}. % \end{function} % -% \section{Floating-point conditionals} +% \section{Floating point conditionals} % -% \begin{function}[EXP,pTF]{\fp_if_undefined:N} +% \begin{function}[EXP, pTF, updated = 2012-05-08] +% {\fp_if_exist:N, \fp_if_exist:c} % \begin{syntax} -% \cs{fp_if_undefined_p:N} \meta{fixed-point} \\ -% \cs{fp_if_undefined:NTF} \meta{fixed-point} \Arg{true code} \Arg{false code} +% \cs{fp_if_exist_p:N} \meta{fp~var} +% \cs{fp_if_exist:NTF} \meta{fp~var} \Arg{true code} \Arg{false code} % \end{syntax} -% Tests if \meta{floating point} is undefined (\emph{i.e.}~equal to the -% special \cs{c_undefined_fp} variable). +% Tests whether the \meta{fp~var} is currently defined. This does not +% check that the \meta{fp~var} really is a floating point variable. % \end{function} % -% \begin{function}[EXP,pTF]{\fp_if_zero:N} +% \begin{function}[EXP, pTF, updated = 2012-05-08] +% {\fp_compare:nNn, \fp_compare:n} % \begin{syntax} -% \cs{fp_if_zero_p:N} \meta{fixed-point} -% \cs{fp_if_zero:NTF} \meta{fixed-point} \Arg{true code} \Arg{false code} +% \cs{fp_compare_p:nNn} \Arg{fpexpr_1} \meta{relation} \Arg{fpexpr_2} +% \cs{fp_compare:nNnTF} \Arg{fpexpr_1} \meta{relation} \Arg{fpexpr_2} \Arg{true code} \Arg{false code} +% \cs{fp_compare_p:n} \{ \meta{fpexpr_1} \meta{relation} \meta{fpexpr_2} \} +% \cs{fp_compare:nTF} \{ \meta{fpexpr_1} \meta{relation} \meta{fpexpr_2} \} \Arg{true code} \Arg{false code} % \end{syntax} -% Tests if \meta{floating point} is equal to zero (\emph{i.e.}~equal to -% the special \cs{c_zero_fp} variable). +% Compares the \meta{fpexpr_1} and the \meta{fpexpr_2}, and returns +% \texttt{true} if the \meta{relation} is obeyed. Two floating point +% numbers $x$ and $y$ may obey four mutually exclusive relations: +% $x<y$, $x=y$, $x>y$, or $x$ and $y$ are not ordered. The latter +% case occurs exactly when one of the operands is \texttt{nan}, and +% this relations is denoted by the symbol |?|. The \texttt{nNn} +% functions support the \meta{relations} |<|, |=|, |>|, and |?|. The +% \texttt{n} functions support as a \meta{relation} any combination of +% those four symbols, plus an optional leading |!| (which negates the +% \meta{relation}), with the restriction that the \meta{relation} may +% not start with |?|. Common choices of \meta{relation} include |>=| +% (greater or equal), |!=| (not equal), |!?| (comparable). Note that +% a \texttt{nan} is distinct from any value, even another +% \texttt{nan}, hence $x=x$ is not true for a \texttt{nan}. Thus to +% test if a value is \texttt{nan}, use +% \begin{verbatim} +% \fp_compare:nNnTF { <value> } != { <value> } +% { } % <value> is nan +% { } % <value> is not nan +% \end{verbatim} % \end{function} % -% \begin{function}[TF]{\fp_compare:nNn} +% \section{Some useful constants, and scratch variables} +% +% \begin{variable}[added = 2012-05-08]{\c_zero_fp, \c_minus_zero_fp} +% Zero, with either sign. +% \end{variable} +% +% \begin{variable}[added = 2012-05-08]{\c_inf_fp, \c_minus_inf_fp} +% Infinity, with either sign. These can be input directly in a +% floating point expression as \texttt{inf} and \texttt{-inf}. +% \end{variable} +% +% \begin{variable}[updated = 2012-05-08]{\c_e_fp} +% The value of the base of the natural logarithm, $\mathrm{e} = \exp(1)$. +% \end{variable} +% +% \begin{variable}[updated = 2012-05-08]{\c_pi_fp} +% The value of $\pi$. This can be input directly in a floating point +% expression as \texttt{pi}. The value is rounded in a slightly odd +% way, to ensure for instance that \texttt{sin(pi)} yields an exact $0$. +% \end{variable} +% +% \begin{variable}[added = 2012-05-08]{\c_one_degree_fp} +% The value of $1^{\circ}$ in radians. Multiply an angle given in +% degrees by this value to obtain a result in radians, suitable to be +% used for trigonometric functions. Within floating point +% expressions, this can be accessed by \texttt{deg}. +% \end{variable} +% +% \begin{variable}{\l_tmpa_fp, \l_tmpb_fp} +% Scratch floating points for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \begin{variable}{\g_tmpa_fp, \g_tmpb_fp} +% Scratch floating points for global assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \section{Floating point exceptions} +% \label{sec:fp-exceptions} +%^^A todo: redoc +% +% \enquote{Exceptions} may occur when performing some floating point +% operations, such as \texttt{0 / 0}, or \texttt{10 ** 1e9999}. The +% \textsc{IEEE} standard defines $5$ types of exceptions. +% \begin{itemize} +% \item \emph{Overflow} occurs whenever the result of an operation is +% too large to be represented as a normal floating point number. This +% results in $\pm \infty$. +% \item \emph{Underflow} occurs whenever the result of an operation is +% too close to $0$ to be represented as a normal floating point +% number. This results in $\pm 0$. +% \item \emph{Invalid operation} occurs for operations with no defined +% outcome, for instance $0/0$, or $\sin(\infty)$, and almost any +% operation involving a \nan{}. This results in a \nan{}. +% \item \emph{Division by zero} occurs when dividing a non-zero number +% by $0$, or when evaluating \emph{e.g.}, $\ln(0)$ or $\cot(0)$. This +% results in $\pm\infty$. +% \item \emph{Inexact} occurs whenever the result of a computation is +% not exact, in other words, almost always. This exception is +% entirely ignored in \LaTeX3. +% \end{itemize} +% To each exception is associated a \enquote{flag}, which can be either +% \emph{on} or \emph{off}. By default, when an exception occurs, the +% corresponding flag is turned on. The state of the flag can be tested +% and modified. The behaviour when an exception occurs can be modified +% (using \cs{fp_trap:nn}) to either produce an error and turn the flag +% on, or only turn the flag on, or do nothing at all. +% +% \begin{function}[EXP, pTF, added = 2012-05-28]{\fp_if_flag_on:n} % \begin{syntax} -% \cs{fp_compare:nNnTF} -% ~~\Arg{floating point1} \meta{relation} \Arg{floating point2} -% ~~\Arg{true code} \Arg{false code} +% \cs{fp_if_flag_on_p:n} \Arg{exception} +% \cs{fp_if_flag_on:nTF} \Arg{exception} \Arg{true code} \Arg{false code} % \end{syntax} -% This function compared the two \meta{floating point} values, which -% may be stored as \texttt{fp} variables, using the \meta{relation}: -% \begin{center} -% \begin{tabular}{ll} -% Equal & |=| \\ -% Greater than & |>| \\ -% Less than & |<| \\ -% \end{tabular} -% \end{center} -% The tests treat undefined floating points as -% zero as the comparison is intended for real numbers only. +% Tests if the flag for the \meta{exception} is on, which normally +% means the given \meta{exception} has occurred. % \end{function} % -% \begin{function}[TF]{\fp_compare:n} +% \begin{function}[added = 2012-05-28]{\fp_flag_off:n} % \begin{syntax} -% \cs{fp_compare:nTF} -% ~~\{ \meta{floating point1} \meta{relation} \meta{floating point2} \} -% ~~\Arg{true code} \Arg{false code} +% \cs{fp_flag_off:n} \Arg{exception} % \end{syntax} -% This function compared the two \meta{floating point} values, which -% may be stored as \texttt{fp} variables, using the \meta{relation}: -% \begin{center} -% \begin{tabular}{ll} -% Equal & |=| or |==| \\ -% Greater than & |>| \\ -% Greater than or equal & |>=| \\ -% Less than & |<| \\ -% Less than or equal & |<=| \\ -% Not equal & |!=| \\ -% \end{tabular} -% \end{center} -% The tests treat undefined floating points as -% zero as the comparison is intended for real numbers only. +% Locally turns off the flag which indicates whether the +% \meta{exception} has occurred. % \end{function} % -% \section{Unary floating-point operations} -% -% The unary operations alter the value stored within an \texttt{fp} -% variable. +% \begin{function}[EXP, added = 2012-05-28]{\fp_flag_on:n} +% \begin{syntax} +% \cs{fp_flag_on:n} \Arg{exception} +% \end{syntax} +% Locally turns on the flag to indicate (or pretend) that the +% \meta{exception} has occurred. Note that this function is +% expandable: it is used internally by \pkg{l3fp} to signal when +% exceptions do occur. +% \end{function} % -% \begin{function}{\fp_abs:N, \fp_abs:c, \fp_gabs:N, \fp_gabs:c} +% \begin{function}[added = 2012-05-28]{\fp_trap:nn} % \begin{syntax} -% \cs{fp_abs:N} \meta{floating point variable} +% \cs{fp_trap:nn} \Arg{exception} \Arg{trap type} % \end{syntax} -% Converts the \meta{floating point variable} to its absolute value. +% All occurrences of the \meta{exception} (\texttt{invalid_operation}, +% \texttt{division_by_zero}, \texttt{overflow}, or \texttt{underflow}) +% within the current group are treated as \meta{trap type}, which can +% be +% \begin{itemize} +% \item \texttt{none}: the \meta{exception} will be entirely +% ignored, and leave no trace; +% \item \texttt{flag}: the \meta{exception} will turn the +% corresponding flag on when it occurs; +% \item \texttt{error}: additionally, the \meta{exception} will halt +% the \TeX{} run and display some information about the current +% operation in the terminal. +% \end{itemize} % \end{function} % -% \begin{function}{\fp_neg:N, \fp_neg:c, \fp_gneg:N, \fp_gneg:c} +% \section{Floating point expressions} +% +% \begin{function}[added = 2012-05-08, updated = 2012-05-27] +% {\fp_show:N, \fp_show:c, \fp_show:n} % \begin{syntax} -% \cs{fp_neg:N} \meta{floating point variable} +% \cs{fp_show:N} \meta{fp~var} +% \cs{fp_show:n} \Arg{floating point expression} % \end{syntax} -% Reverse the sign of the \meta{floating point variable}. +% Evaluates the \meta{floating point expression} and displays the +% result in the terminal. % \end{function} % -% \section{Floating-point arithmetic} +% \subsection{Input of floating point numbers} \label{sec:fp-floats} % -% Binary arithmetic operations act on the value stored in an -% \texttt{fp}, so for example -% \begin{verbatim} -% \fp_set:Nn \l_my_fp { 1.234 } -% \fp_sub:Nn \l_my_fp { 5.678 } -% \end{verbatim} -% sets \cs{l_my_fp} to the result of $1.234 - 5.678$ -% (\emph{i.e.}~$-4.444$). +%^^A todo: write a grammar +%^^A todo: clarify what has changed compared to the previous l3fp +% +% We support four types of floating point numbers: +% \begin{itemize} +% \item $\pm 0.d_1d_2\ldots{}d_{16} \cdot 10^{n}$, a normal floating +% point number, with $d_i\in [0,9]$, $d_1\neq 0$, and $\lvert n\rvert +% \leq \ExplSyntaxOn \int_use:N \c__fp_max_exponent_int$; +% \item $\pm 0$, zero, with a given sign; +% \item $\pm \infty$, infinity, with a given sign; +% \item \texttt{nan}, is \enquote{not a number}, and can be either quiet +% or signalling (\emph{not yet}: this distinction is currently +% unsupported); +% \item [\emph{not yet}] subnormal numbers $\pm 0.d_1d_2\ldots{}d_{16} +% \cdot 10^{-\ExplSyntaxOn\int_use:N \c__fp_max_exponent_int}$ with +% $d_1=0$. +% \end{itemize} +% Normal floating point numbers are stored in base $10$, with $16$ +% significant figures. +% +% On input, a normal floating point number consists of: +% \begin{itemize} +% \item \meta{sign}: a possibly empty string of |+| and |-| characters; +% \item \meta{mantissa}: a non-empty string of digits together with zero +% or one dot; +% \item \meta{exponent} optionally: the character |e|, followed by a +% possibly empty string of |+|~and~|-| tokens, and a non-empty string +% of digits. +% \end{itemize} +% The sign of the resulting number is |+| if \meta{sign} contains an +% even number of |-|, and |-| otherwise, hence, an empty \meta{sign} +% denotes a non-negative input. The stored mantissa is obtained from +% \meta{mantissa} by omitting the decimal separator and leading zeros, +% and rounding to $16$ significant digits, filling with trailing zeros +% if necessary. In particular, the value stored is exact if the input +% \meta{mantissa} has at most $16$ digits. The stored \meta{exponent} +% is obtained by combining the input \meta{exponent} ($0$ if absent) +% with a shift depending on the position of the mantissa and the number +% of leading zeros. +% +% A special case arises if the resulting \meta{exponent} is either +% too large or too small to be represented. This results either in an +% overflow (the number is then replaced by $\pm\infty$), or an +% underflow (resulting in $\pm 0$). +% +% The result is thus $\pm 0$ if and only if \meta{mantissa} contains no +% non-zero digit (\emph{i.e.}, consists only in~|0| characters, and an +% optional |.| character), or there is an underflow. Note that a single +% dot is currently a valid floating point number, equal to~$+0$, but +% that is not guaranteed to remain the case. +% +% Special numbers are input as follows: +% \begin{itemize} +% \item \texttt{inf} represents $+\infty$, and can be preceded by any +% \meta{sign}. +% \item \texttt{nan} represents a (quiet) non-number. It can be preceded +% by any sign, but that will be ignored. +% \item Any unrecognisable string will yield a signalling \texttt{nan}. +% \end{itemize} +% +% Note that~|e-1| is not a representation of $10^{-1}$, because it +% could be mistaken with the difference of \enquote{\texttt{e}} and +% $1$. This is consistent with several other programming languages. +% However, in order to avoid confusions, |e-1| is not considered to +% be this difference either. To input the base of natural logarithms, +% use \texttt{exp(1)} or \cs{c_e_fp}. +% +% \subsection{Precedence of operators} +% \label{sec:fp-precedence} +% +% ^^A List "juxtaposition" somewhere in the list. % -% \begin{function}{\fp_add:Nn, \fp_add:cn, \fp_gadd:Nn, \fp_gadd:cn} +% We list here all the operations supported in floating point +% expressions, in order of decreasing precedence: operations listed +% earlier bind more tightly than operations listed below them. +% \begin{itemize} +% \item Implicit multiplication by juxtaposition (\texttt{2pi}, \emph{etc}). +% \item Function calls (\texttt{sin}, \texttt{ln}, \emph{etc}). +% \item Binary |**| and |^| (right associative). +% \item Unary |+|, |-|, |!|. +% \item Binary |*|, |/| and |%|. +% \item Binary |+| and |-|. +% \item Comparisons |>=|, |!=|, |<?|, \emph{etc}. +% \item Logical \texttt{and}, denoted by |&&|. +% \item Logical \texttt{or}, denoted by \verb*+||+. +% \item Ternary operator |?:| (right associative). +% \end{itemize} +% The precedence of operations can be overridden using parentheses. +% In particular, those precedences imply that +% \begin{align*} +% \mathtt{sin 2pi} & = \sin(2\pi) = 0, \\ +% \mathtt{2\char`\^2max(3,4)} & = 2^{2 \max(3,4)} = 256. +% \end{align*} +% Functions are called on the value of their argument, contrarily to +% \TeX{} macros. +% +% \subsection{Operations} \label{sec:fp-operations} +% +% We now present the various operations allowed in floating point +% expressions. When used as a truth value, a floating point expression +% is \texttt{false} if it is $\pm 0$, and \texttt{false} otherwise. +% +% The exceptions listed below are mostly not implemented yet. ^^A todo: +% +% \begin{function}{?:} % \begin{syntax} -% \cs{fp_add:Nn} \meta{floating point} \Arg{value} +% \cs{fp_eval:n} \{ \meta{operand_1} |?| \meta{operand_2} |:| \meta{operand_3} \} % \end{syntax} -% Adds the \meta{value} to the \meta{floating point}. +% The ternary operator |?:| results in \meta{operand_2} if +% \meta{operand_1} is true, and \meta{operand_3} if it is false (equal to +% $\pm 0$). All three \meta{operands} are evaluated in all cases. The +% operator is right associative, hence +% \begin{verbatim} +% \fp_eval:n +% { +% 1 + 3 > 4 ? 1 : +% 2 + 4 > 5 ? 2 : +% 3 + 5 > 6 ? 3 : 4 +% } +% \end{verbatim} +% first tests whether $1 + 3 > 4$; since this isn't true, the branch +% following |:| is taken, and $2 + 4 > 5$ is compared; since this is +% true, the branch before |:| is taken, and everything else is +% (evaluated then) ignored. That allows testing for various cases in +% a concise manner, with the drawback that all computations are made +% in all cases. % \end{function} % -% \begin{function}{\fp_sub:Nn, \fp_sub:cn, \fp_gsub:Nn, \fp_gsub:cn} +% \begingroup \catcode`\|=12 +% \begin{function}{TWO BARS} ^^A To fix % \begin{syntax} -% \cs{fp_sub:Nn} \meta{floating point} \Arg{value} +% \cs{fp_eval:n} \{ \meta{operand_1} \texttt{||} \meta{operand_2} \} % \end{syntax} -% Subtracts the \meta{value} from the \meta{floating point}. +% If \meta{operand_1} is true (non-zero), use that value, otherwise the +% value of \meta{operand_2}. Both \meta{operands} are evaluated in all +% cases. % \end{function} +% \endgroup % -% \begin{function}{\fp_mul:Nn, \fp_mul:cn, \fp_gmul:Nn, \fp_gmul:cn} +% \begingroup \catcode`\&=12 +% \begin{function}{&&} % \begin{syntax} -% \cs{fp_mul:Nn} \meta{floating point} \Arg{value} +% \cs{fp_eval:n} \{ \meta{operand_1} \texttt{&&} \meta{operand_2} \} % \end{syntax} -% Multiples the \meta{floating point} by the \meta{value}. +% If \meta{operand_1} is false (equal to $\pm 0$), use that value, +% otherwise the value of \meta{operand_2}. Both \meta{operands} are +% evaluated in all cases. % \end{function} +% \endgroup % -% \begin{function}{\fp_div:Nn, \fp_div:cn, \fp_gdiv:Nn, \fp_gdiv:cn} +% \begin{function}{\<, =, >, ?} % \begin{syntax} -% \cs{fp_div:Nn} \meta{floating point} \Arg{value} +% \cs{fp_eval:n} \{ \meta{operand_1} \meta{comparison} \meta{operand_2} \} % \end{syntax} -% Divides the \meta{floating point} by the \meta{value}, making the -% assignment within the current \TeX{} group level. If the \meta{value} -% is zero, the \meta{floating point} will be set to -% \cs{c_undefined_fp}. +% The \meta{comparison} consists of a non-empty string of |<|, |=|, +% |>|, and |?|, optionally preceeded by |!|. It may not start with +% |?|. This evaluates to $+1$ if the \meta{comparison} between the +% \meta{operand_1} and \meta{operand_2} is true, and $+0$ otherwise. % \end{function} % -% \section{Floating-point power operations} -% -% \begin{function}{\fp_pow:Nn, \fp_pow:cn, \fp_gpow:Nn, \fp_gpow:cn} +% \begin{function}{+, -} % \begin{syntax} -% \cs{fp_pow:Nn} \meta{floating point} \Arg{value} +% \cs{fp_eval:n} \{ \meta{operand_1} |+| \meta{operand_2} \} +% \cs{fp_eval:n} \{ \meta{operand_1} |-| \meta{operand_2} \} % \end{syntax} -% Raises the \meta{floating point} to the given \meta{value}. If the -% \meta{floating point} is negative, then the \meta{value} should be -% either a positive real number or a negative integer. If the -% \meta{floating point} is positive, then the \meta{value} may be any -% real value. Mathematically invalid operations such as $0^{0}$ -% will give set the \meta{floating point} to to \cs{c_undefined_fp}. +% Computes the sum or the difference of its two \meta{operands}. The +% \enquote{invalid operation} exception occurs for $\infty-\infty$. +% \enquote{Inexact}, \enquote{underflow} and \enquote{overflow} occur +% when appropriate. % \end{function} % -% \section{Exponential and logarithm functions} -% -% \begin{function}{\fp_exp:Nn, \fp_exp:cn, \fp_gexp:Nn, \fp_gexp:cn} +% \begin{function}{*, /} % \begin{syntax} -% \cs{fp_exp:Nn} \meta{floating point} \Arg{value} +% \cs{fp_eval:n} \{ \meta{operand_1} |*| \meta{operand_2} \} +% \cs{fp_eval:n} \{ \meta{operand_1} |/| \meta{operand_2} \} % \end{syntax} -% Calculates the exponential of the \meta{value} and assigns this -% to the \meta{floating point}. +% Computes the product or the ratio of its two \meta{operands}. The +% \enquote{invalid operation} exception occurs for $\infty/\infty$, +% $0/0$, or $0*\infty$. \enquote{Division by zero} occurs when +% dividing a finite non-zero number by $\pm 0$. The +% \enquote{inexact}, \enquote{underflow} and \enquote{overflow} +% exceptions occur when appropriate. % \end{function} % -% \begin{function}{\fp_ln:Nn, \fp_ln:cn, \fp_gln:Nn, \fp_gln:cn} +% \begin{function}{+, -, !} % \begin{syntax} -% \cs{fp_ln:Nn} \meta{floating point} \Arg{value} +% \cs{fp_eval:n} \{ |+| \meta{operand} \} +% \cs{fp_eval:n} \{ |-| \meta{operand} \} +% \cs{fp_eval:n} \{ |!| \meta{operand} \} % \end{syntax} -% Calculates the natural logarithm of the \meta{value} and assigns -% this to the \meta{floating point}. +% The unary |+| does nothing, the unary |-| changes the sign of the +% \meta{operand}, and |!| \meta{operand} evaluates to $1$ if +% \meta{operand} is false and $0$ otherwise (this is the \texttt{not} +% boolean function). % \end{function} % -% \section{Trigonometric functions} -% -% The trigonometric functions all work in radians. They accept a maximum -% input value of $100\,000\,000$, as there are issues with range -% reduction and very large input values. -% -% \begin{function}{\fp_sin:Nn, \fp_sin:cn, \fp_gsin:Nn, \fp_gsin:cn} +% \begingroup\catcode`\^=12 +% \begin{function}{**, ^} % \begin{syntax} -% \cs{fp_sin:Nn} \meta{floating point} \Arg{value} +% \cs{fp_eval:n} \{ \meta{operand_1} |**| \meta{operand_2} \} +% \cs{fp_eval:n} \{ \meta{operand_1} |^| \meta{operand_2} \} % \end{syntax} -% Assigns the sine of the \meta{value} to the \meta{floating point}. -% The \meta{value} should be given in radians. +% Raises \meta{operand_1} to the power \meta{operand_2}. This operation +% is right associative, hence \texttt{2 ** 2 ** 3} equals +% $2\sp{2\sp{3}} = 256$. The \enquote{invalid operation} exception +% occurs if \meta{operand_1} is negative or $-0$, \meta{operand_2} is +% not an integer, and the result is non-zero. \enquote{Division by +% zero} occurs \emph{not yet}. The \enquote{inexact}, +% \enquote{underflow} and \enquote{overflow} exceptions occur when +% appropriate. % \end{function} +% \endgroup % -% \begin{function}{\fp_cos:Nn, \fp_cos:cn, \fp_gcos:Nn, \fp_gcos:cn} +% \begin{function}{abs} % \begin{syntax} -% \cs{fp_cos:Nn} \meta{floating point} \Arg{value} +% \cs{fp_eval:n} \{ |abs(| \meta{fpexpr} |)| \} % \end{syntax} -% Assigns the cosine of the \meta{value} to the \meta{floating point}. -% The \meta{value} should be given in radians. +% Computes the absolute value of the \meta{fpexpr}. This function +% never raises an exception when \meta{fpexpr} is a number. % \end{function} % -% \begin{function}{\fp_tan:Nn, \fp_tan:cn, \fp_gtan:Nn, \fp_gtan:cn} +% \begin{function}{exp} % \begin{syntax} -% \cs{fp_tan:Nn} \meta{floating point} \Arg{value} +% \cs{fp_eval:n} \{ |exp(| \meta{fpexpr} |)| \} % \end{syntax} -% Assigns the tangent of the \meta{value} to the \meta{floating point}. -% The \meta{value} should be given in radians. +% Computes the exponential of the \meta{fpexpr}. The +% \enquote{inexact}, \enquote{underflow} and \enquote{overflow} +% exceptions occur when appropriate. % \end{function} % -% \section{Constant floating point values} -% -% \begin{variable}{\c_e_fp} -% The value of the base of natural numbers, $\mathrm{e}$. -% \end{variable} -% -% \begin{variable}{\c_one_fp} -% A floating point variable with permanent value $1$: used for -% speeding up some comparisons. -% \end{variable} -% -% \begin{variable}{\c_pi_fp} -% The value of $\pi$. -% \end{variable} -% -% \begin{variable}{\c_undefined_fp} -% A special marker floating point variable representing the result of -% an operation which does not give a defined result (such as division -% by $0$). -% \end{variable} -% -% \begin{variable}{\c_zero_fp} -% A permanently zero floating point variable. -% \end{variable} -% -% \section{Notes on the floating point unit} -% -% As calculation of the elemental transcendental functions is -% computationally expensive compared to storage of results, after -% calculating a trigonometric function, exponent, \emph{etc.}~the module -% stored the result for reuse. Thus the performance of the module for -% repeated operations, most probably trigonometric functions, should be -% much higher than if the values were re-calculated every time they -% were needed. -% -% Anyone with experience of programming floating point calculations will -% know that this is a complex area. The aim of the unit is to be -% accurate enough for the likely applications in a typesetting context. -% The arithmetic operations are therefore intended to provide ten digit -% accuracy with the last digit accurate to $\pm 1$. The elemental -% transcendental functions may not provide such high accuracy in every -% case, although the design aim has been to provide $10$ digit -% accuracy for cases likely to be relevant in typesetting situations. -% A good overview of the challenges in this area can be found in -% J.-M.~Muller, \emph{Elementary functions: algorithms and -% implementation}, 2nd edition, Birkh{\"{a}}uer Boston, New York, USA, -% 2006. -% -% The internal representation of numbers is tuned to the needs of the -% underlying \TeX{} system. This means that the format is somewhat -% different from that used in, for example, computer floating point -% units. Programming in \TeX{} makes it most convenient to use a -% radix $10$ system, using \TeX{} \texttt{count} registers for -% storage and taking advantage where possible of delimited arguments. -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3fp} Implementation} -% -% \TestFiles{m3fp003.lvt} -% -% \begin{macrocode} -%<*initex|package> -% \end{macrocode} -% -% \begin{macrocode} -%<*package> -\ProvidesExplPackage - {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: -%</package> -% \end{macrocode} -% -% \subsection{Constants} -% -% \begin{variable}{\c_forty_four} -% \begin{variable}{\c_one_million} -% \begin{variable}{\c_one_hundred_million} -% \begin{variable}{\c_five_hundred_million} -% \begin{variable}{\c_one_thousand_million} -% There is some speed to gain by moving numbers into fixed positions. -% \begin{macrocode} -\int_const:Nn \c_forty_four { 44 } -\int_const:Nn \c_one_million { 1 000 000 } -\int_const:Nn \c_one_hundred_million { 100 000 000 } -\int_const:Nn \c_five_hundred_million { 500 000 000 } -\int_const:Nn \c_one_thousand_million { 1 000 000 000 } -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\c_fp_pi_by_four_decimal_int} -% \begin{variable}{\c_fp_pi_by_four_extended_int} -% \begin{variable}{\c_fp_pi_decimal_int} -% \begin{variable}{\c_fp_pi_extended_int} -% \begin{variable}{\c_fp_two_pi_decimal_int} -% \begin{variable}{\c_fp_two_pi_extended_int} -% Parts of $\pi$ for trigonometric range reduction, implemented -% as \texttt{int} variables for speed. -% \begin{macrocode} -\int_new:N \c_fp_pi_by_four_decimal_int -\int_set:Nn \c_fp_pi_by_four_decimal_int { 785 398 158 } -\int_new:N \c_fp_pi_by_four_extended_int -\int_set:Nn \c_fp_pi_by_four_extended_int { 897 448 310 } -\int_new:N \c_fp_pi_decimal_int -\int_set:Nn \c_fp_pi_decimal_int { 141 592 653 } -\int_new:N \c_fp_pi_extended_int -\int_set:Nn \c_fp_pi_extended_int { 589 793 238 } -\int_new:N \c_fp_two_pi_decimal_int -\int_set:Nn \c_fp_two_pi_decimal_int { 283 185 307 } -\int_new:N \c_fp_two_pi_extended_int -\int_set:Nn \c_fp_two_pi_extended_int { 179 586 477 } -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\c_e_fp} -% The value $\mathrm{e}$ as a \enquote{machine number}. -% \begin{macrocode} -\tl_const:Nn \c_e_fp { + 2.718281828 e 0 } -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_one_fp} -% The constant value $1$: used for fast comparisons. -% \begin{macrocode} -\tl_const:Nn \c_one_fp { + 1.000000000 e 0 } -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_pi_fp} -% The value $\pi$ as a \enquote{machine number}. -% \begin{macrocode} -\tl_const:Nn \c_pi_fp { + 3.141592654 e 0 } -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_undefined_fp} -% A marker for undefined values. -% \begin{macrocode} -\tl_const:Nn \c_undefined_fp { X 0.000000000 e 0 } -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_zero_fp} -% The constant zero value. -% \begin{macrocode} -\tl_const:Nn \c_zero_fp { + 0.000000000 e 0 } -% \end{macrocode} -% \end{variable} -% -% \subsection{Variables} -% -% \begin{variable}{\l_fp_arg_tl} -% A token list to store the formalised representation of the input -% for transcendental functions. -% \begin{macrocode} -\tl_new:N \l_fp_arg_tl -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_fp_count_int} -% A counter for things like the number of divisions possible. -% \begin{macrocode} -\int_new:N \l_fp_count_int -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_fp_div_offset_int} -% When carrying out division, an offset is used for the results to -% get the decimal part correct. -% \begin{macrocode} -\int_new:N \l_fp_div_offset_int -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_fp_exp_integer_int} -% \begin{variable}{\l_fp_exp_decimal_int} -% \begin{variable}{\l_fp_exp_extended_int} -% \begin{variable}{\l_fp_exp_exponent_int} -% Used for the calculation of exponent values. -% \begin{macrocode} -\int_new:N \l_fp_exp_integer_int -\int_new:N \l_fp_exp_decimal_int -\int_new:N \l_fp_exp_extended_int -\int_new:N \l_fp_exp_exponent_int -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\l_fp_input_a_sign_int} -% \begin{variable}{\l_fp_input_a_integer_int} -% \begin{variable}{\l_fp_input_a_decimal_int} -% \begin{variable}{\l_fp_input_a_exponent_int} -% \begin{variable}{\l_fp_input_b_sign_int} -% \begin{variable}{\l_fp_input_b_integer_int} -% \begin{variable}{\l_fp_input_b_decimal_int} -% \begin{variable}{\l_fp_input_b_exponent_int} -% Storage for the input: two storage areas as there are at most two -% inputs. -% \begin{macrocode} -\int_new:N \l_fp_input_a_sign_int -\int_new:N \l_fp_input_a_integer_int -\int_new:N \l_fp_input_a_decimal_int -\int_new:N \l_fp_input_a_exponent_int -\int_new:N \l_fp_input_b_sign_int -\int_new:N \l_fp_input_b_integer_int -\int_new:N \l_fp_input_b_decimal_int -\int_new:N \l_fp_input_b_exponent_int -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\l_fp_input_a_extended_int} -% \begin{variable}{\l_fp_input_b_extended_int} -% For internal use, \enquote{extended} floating point numbers are -% needed. -% \begin{macrocode} -\int_new:N \l_fp_input_a_extended_int -\int_new:N \l_fp_input_b_extended_int -% \end{macrocode} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\l_fp_mul_a_i_int} -% \begin{variable}{\l_fp_mul_a_ii_int} -% \begin{variable}{\l_fp_mul_a_iii_int} -% \begin{variable}{\l_fp_mul_a_iv_int} -% \begin{variable}{\l_fp_mul_a_v_int} -% \begin{variable}{\l_fp_mul_a_vi_int} -% \begin{variable}{\l_fp_mul_b_i_int} -% \begin{variable}{\l_fp_mul_b_ii_int} -% \begin{variable}{\l_fp_mul_b_iii_int} -% \begin{variable}{\l_fp_mul_b_iv_int} -% \begin{variable}{\l_fp_mul_b_v_int} -% \begin{variable}{\l_fp_mul_b_vi_int} -% Multiplication requires that the decimal part is split into parts -% so that there are no overflows. -% \begin{macrocode} -\int_new:N \l_fp_mul_a_i_int -\int_new:N \l_fp_mul_a_ii_int -\int_new:N \l_fp_mul_a_iii_int -\int_new:N \l_fp_mul_a_iv_int -\int_new:N \l_fp_mul_a_v_int -\int_new:N \l_fp_mul_a_vi_int -\int_new:N \l_fp_mul_b_i_int -\int_new:N \l_fp_mul_b_ii_int -\int_new:N \l_fp_mul_b_iii_int -\int_new:N \l_fp_mul_b_iv_int -\int_new:N \l_fp_mul_b_v_int -\int_new:N \l_fp_mul_b_vi_int -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\l_fp_mul_output_int} -% \begin{variable}{\l_fp_mul_output_tl} -% Space for multiplication results. -% \begin{macrocode} -\int_new:N \l_fp_mul_output_int -\tl_new:N \l_fp_mul_output_tl -% \end{macrocode} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\l_fp_output_sign_int} -% \begin{variable}{\l_fp_output_integer_int} -% \begin{variable}{\l_fp_output_decimal_int} -% \begin{variable}{\l_fp_output_exponent_int} -% Output is stored in the same way as input. -% \begin{macrocode} -\int_new:N \l_fp_output_sign_int -\int_new:N \l_fp_output_integer_int -\int_new:N \l_fp_output_decimal_int -\int_new:N \l_fp_output_exponent_int -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\l_fp_output_extended_int} -% Again, for calculations an extended part. -% \begin{macrocode} -\int_new:N \l_fp_output_extended_int -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_fp_round_carry_bool} -% To indicate that a digit needs to be carried forward. -% \begin{macrocode} -\bool_new:N \l_fp_round_carry_bool -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_fp_round_decimal_tl} -% A temporary store when rounding, to build up the decimal part without -% needing to do any maths. -% \begin{macrocode} -\tl_new:N \l_fp_round_decimal_tl -% \end{macrocode} -% \end{variable} +% \begin{function}{ln} +% \begin{syntax} +% \cs{fp_eval:n} \{ |ln(| \meta{fpexpr} |)| \} +% \end{syntax} +% Computes the natural logarithm of the \meta{fpexpr}. Negative +% numbers have no (real) logarithm, hence the \enquote{invalid +% operation} is raised in that case. \enquote{Division by zero} +% occurs when evaluating the logarithm of $\pm 0$. The +% \enquote{inexact}, \enquote{underflow} and \enquote{overflow} +% exceptions occur when appropriate. +% \end{function} % -% \begin{variable}{\l_fp_round_position_int} -% \begin{variable}{\l_fp_round_target_int} -% Used to check the position for rounding. -% \begin{macrocode} -\int_new:N \l_fp_round_position_int -\int_new:N \l_fp_round_target_int -% \end{macrocode} -% \end{variable} -% \end{variable} +% \begin{function}{max, min} +% \begin{syntax} +% \cs{fp_eval:n} \{ |max(| \meta{fpexpr_1} |,| \meta{fpexpr_2} |,| \ldots{} |)| \} +% \cs{fp_eval:n} \{ |min(| \meta{fpexpr_1} |,| \meta{fpexpr_2} |,| \ldots{} |)| \} +% \end{syntax} +% Evalutes each \meta{fpexpr} and computes the largest (smallest) of +% those. If any of the \meta{fpexpr} is a \nan{}, the result is +% \nan{}. +% \end{function} % -% \begin{variable}{\l_fp_sign_tl} -% There are places where the sign needs to be set up \enquote{early}, -% so that the registers can be re-used. -% \begin{macrocode} -\tl_new:N \l_fp_sign_tl -% \end{macrocode} -% \end{variable} +% \begin{function}{round, round0, round+, round-} +% \begin{syntax} +% \cs{fp_eval:n} \{ |round| \meta{option} |(| \meta{fpexpr} |)| \} +% \cs{fp_eval:n} \{ |round| \meta{option} |(| \meta{fpexpr_1} , \meta{fpexpr_2} |)| \} +% \end{syntax} +% Rounds \meta{fpexpr_1} to \meta{fpexpr_2} places (this must be an +% integer). When \meta{fpexpr_2} is missing, it is assumed to be $0$, +% \emph{i.e.}, \meta{fpexpr_1} is rounded to an integer. The +% \meta{option} controls the rounding direction: +% \begin{itemize} +% \item by default, the function rounds to the closest allowed number +% (rounding ties to even); +% \item with |0|, the function rounds towards $0$, \emph{i.e.}, truncates; +% \item with |+|, the function rounds towards $+\infty$; +% \item with |-|, the function rounds towards $-\infty$. +% \end{itemize} +% \end{function} % -% \begin{variable}{\l_fp_split_sign_int} -% When splitting the input it is fastest to use a fixed name for the -% sign part, and to transfer it after the split is complete. -% \begin{macrocode} -\int_new:N \l_fp_split_sign_int -% \end{macrocode} -% \end{variable} +% \begin{function}{sin, cos, tan, cot} +% \begin{syntax} +% \cs{fp_eval:n} \{ |sin(| \meta{fpexpr} |)| \} +% \cs{fp_eval:n} \{ |cos(| \meta{fpexpr} |)| \} +% \cs{fp_eval:n} \{ |tan(| \meta{fpexpr} |)| \} +% \cs{fp_eval:n} \{ |cot(| \meta{fpexpr} |)| \} +% \end{syntax} +% Computes the sine, cosine, tangent or cotangent of the +% \meta{fpexpr}. The trigonometric functions are undefined for an +% argument of $\pm\infty$, leading to the \enquote{invalid operation} +% exception. Additionally, evaluating tangent or cotangent at one of +% their poles leads to a \enquote{division by zero} exception. Other +% exceptions occur when appropriate. +% \end{function} % -% \begin{variable}{\l_fp_internal_int} -% A scratch \texttt{int}: used only where the value is not carried -% forward. -% \begin{macrocode} -\int_new:N \l_fp_internal_int -% \end{macrocode} +% \begin{variable}{inf, nan} +% The special values $+\infty$, $-\infty$, and \nan{} are represented +% as \texttt{inf}, \texttt{-inf} and \texttt{nan} (see \cs{c_inf_fp}, +% \cs{c_minus_inf_fp} and \cs{c_nan_fp}). % \end{variable} % -% \begin{variable}{\l_fp_internal_tl} -% A scratch token list variable for expanding material. -% \begin{macrocode} -\tl_new:N \l_fp_internal_tl -% \end{macrocode} +% \begin{variable}{pi} +% The value of $\pi$ (see \cs{c_pi_fp}). % \end{variable} % -% \begin{variable}{\l_fp_trig_octant_int} -% To track which octant the trigonometric input is in. -% \begin{macrocode} -\int_new:N \l_fp_trig_octant_int -% \end{macrocode} +% \begin{variable}{deg} +% The value of $1^{\circ}$ in radians (see \cs{c_one_degree_fp}). % \end{variable} % -% \begin{variable}{\l_fp_trig_sign_int} -% \begin{variable}{\l_fp_trig_decimal_int} -% \begin{variable}{\l_fp_trig_extended_int} -% Used for the calculation of trigonometric values. -% \begin{macrocode} -\int_new:N \l_fp_trig_sign_int -\int_new:N \l_fp_trig_decimal_int -\int_new:N \l_fp_trig_extended_int -% \end{macrocode} -% \end{variable} -% \end{variable} +% \begin{variable}{em, ex, in, pt, pc, cm, mm, dd, cc, nd, nc, bp, sp} +% \newcommand{\unit}[1]{\text{\texttt{#1}}} +% Those units of measurement are equal to their values in \texttt{pt}, +% namely +% \begin{align*} +% 1 \unit{in} & = 72.27 \unit{pt} \\ +% 1 \unit{pt} & = 1 \unit{pt} \\ +% 1 \unit{pc} & = 12 \unit{pt} \\ +% 1 \unit{cm} & = \frac{1}{2.54} \unit{in} = 28.45275590551181 \unit{pt} \\ +% 1 \unit{mm} & = \frac{1}{25.4} \unit{in} = 2.845275590551181 \unit{pt} \\ +% 1 \unit{dd} & = 0.376065 \unit{mm} = 1.07000856496063 \unit{pt} \\ +% 1 \unit{cc} & = 12 \unit{dd} = 12.84010277952756 \unit{pt} \\ +% 1 \unit{nd} & = 0.375 \unit{mm} = 1.066978346456693 \unit{pt} \\ +% 1 \unit{nc} & = 12 \unit{nd} = 12.80374015748031 \unit{pt} \\ +% 1 \unit{bp} & = \frac{1}{72} \unit{in} = 1.00375 \unit{pt} \\ +% 1 \unit{sp} & = 2^{-16} \unit{pt} = 1.52587890625e-5 \unit{pt}. +% \end{align*} +% The values of the (font-dependent) units \texttt{em} and \texttt{ex} +% are gathered from \TeX{} when the surrounding floating point +% expression is evaluated. % \end{variable} % -% \subsection{Parsing numbers} -% -% \begin{macro}{\fp_read:N} -% \begin{macro}[aux]{\fp_read_aux:w} -% Reading a stored value is made easier as the format is designed to -% match the delimited function. This is always used to read the first -% value (register |a|). -% \begin{macrocode} -\cs_new_protected:Npn \fp_read:N #1 - { \exp_after:wN \fp_read_aux:w #1 \q_stop } -\cs_new_protected:Npn \fp_read_aux:w #1#2 . #3 e #4 \q_stop - { - \if:w #1 - - \l_fp_input_a_sign_int \c_minus_one - \else: - \l_fp_input_a_sign_int \c_one - \fi: - \l_fp_input_a_integer_int #2 \scan_stop: - \l_fp_input_a_decimal_int #3 \scan_stop: - \l_fp_input_a_exponent_int #4 \scan_stop: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_split:Nn} -% \begin{macro}[aux]{\fp_split_sign:} -% \begin{macro}[aux]{\fp_split_exponent:} -% \begin{macro}[aux]{\fp_split_aux_i:w} -% \begin{macro}[aux]{\fp_split_aux_ii:w} -% \begin{macro}[aux]{\fp_split_aux_iii:w} -% \begin{macro}[aux]{\fp_split_decimal:w} -% \begin{macro}[aux]{\fp_split_decimal_aux:w} -% The aim here is to use as much of \TeX{}'s mechanism as possible to pick -% up the numerical input without any mistakes. In particular, negative -% numbers have to be filtered out first in case the integer part is -% $0$ (in which case \TeX{} would drop the |-| sign). That process -% has to be done in a loop for cases where the sign is repeated. -% Finding an exponent is relatively easy, after which the next phase is -% to find the integer part, which will terminate with a |.|, and trigger -% the decimal-finding code. The later will allow the decimal to be too -% long, truncating the result. -% \begin{macrocode} -\cs_new_protected:Npn \fp_split:Nn #1#2 - { - \tl_set:Nx \l_fp_internal_tl {#2} - \tl_set_rescan:Nno \l_fp_internal_tl { \char_set_catcode_ignore:n { 32 } } - { \l_fp_internal_tl } - \l_fp_split_sign_int \c_one - \fp_split_sign: - \use:c { l_fp_input_ #1 _sign_int } \l_fp_split_sign_int - \exp_after:wN \fp_split_exponent:w \l_fp_internal_tl e e \q_stop #1 - } -\cs_new_protected_nopar:Npn \fp_split_sign: - { - \if_int_compare:w \pdftex_strcmp:D - { \exp_after:wN \tl_head:w \l_fp_internal_tl ? \q_stop } { - } - = \c_zero - \tl_set:Nx \l_fp_internal_tl - { - \exp_after:wN - \tl_tail:w \l_fp_internal_tl \prg_do_nothing: \q_stop - } - \l_fp_split_sign_int -\l_fp_split_sign_int - \exp_after:wN \fp_split_sign: - \else: - \if_int_compare:w \pdftex_strcmp:D - { \exp_after:wN \tl_head:w \l_fp_internal_tl ? \q_stop } { + } - = \c_zero - \tl_set:Nx \l_fp_internal_tl - { - \exp_after:wN - \tl_tail:w \l_fp_internal_tl \prg_do_nothing: \q_stop - } - \exp_after:wN \exp_after:wN \exp_after:wN \fp_split_sign: - \fi: - \fi: - } -\cs_new_protected:Npn \fp_split_exponent:w #1 e #2 e #3 \q_stop #4 - { - \use:c { l_fp_input_ #4 _exponent_int } - \int_eval:w 0 #2 \scan_stop: - \tex_afterassignment:D \fp_split_aux_i:w - \use:c { l_fp_input_ #4 _integer_int } - \int_eval:w 0 #1 . . \q_stop #4 - } -\cs_new_protected:Npn \fp_split_aux_i:w #1 . #2 . #3 \q_stop - { \fp_split_aux_ii:w #2 000000000 \q_stop } -\cs_new_protected:Npn \fp_split_aux_ii:w #1#2#3#4#5#6#7#8#9 - { \fp_split_aux_iii:w {#1#2#3#4#5#6#7#8#9} } -\cs_new_protected:Npn \fp_split_aux_iii:w #1#2 \q_stop - { - \l_fp_internal_int 1 #1 \scan_stop: - \exp_after:wN \fp_split_decimal:w - \int_use:N \l_fp_internal_int 000000000 \q_stop - } -\cs_new_protected:Npn \fp_split_decimal:w #1#2#3#4#5#6#7#8#9 - { \fp_split_decimal_aux:w {#2#3#4#5#6#7#8#9} } -\cs_new_protected:Npn \fp_split_decimal_aux:w #1#2#3 \q_stop #4 - { - \use:c { l_fp_input_ #4 _decimal_int } #1#2 \scan_stop: - \if_int_compare:w - \int_eval:w - \use:c { l_fp_input_ #4 _integer_int } + - \use:c { l_fp_input_ #4 _decimal_int } - \scan_stop: - = \c_zero - \use:c { l_fp_input_ #4 _sign_int } \c_one - \fi: - \if_int_compare:w - \use:c { l_fp_input_ #4 _integer_int } < \c_one_thousand_million - \else: - \exp_after:wN \fp_overflow_msg: - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_standardise:NNNN} -% \begin{macro}[aux]{\fp_standardise_aux:NNNN} -% \begin{macro}[aux]{\fp_standardise_aux:} -% \begin{macro}[aux]{\fp_standardise_aux:w} -% The idea here is to shift the input into a known exponent range. This -% is done using \TeX{} tokens where possible, as this is faster than -% arithmetic. -% \begin{macrocode} -\cs_new_protected:Npn \fp_standardise:NNNN #1#2#3#4 - { - \if_int_compare:w - \int_eval:w #2 + #3 = \c_zero - #1 \c_one - #4 \c_zero - \exp_after:wN \use_none:nnnn - \else: - \exp_after:wN \fp_standardise_aux:NNNN - \fi: - #1#2#3#4 - } -\cs_new_protected:Npn \fp_standardise_aux:NNNN #1#2#3#4 - { - \cs_set_protected_nopar:Npn \fp_standardise_aux: - { - \if_int_compare:w #2 = \c_zero - \tex_advance:D #3 \c_one_thousand_million - \exp_after:wN \fp_standardise_aux:w - \int_use:N #3 \q_stop - \exp_after:wN \fp_standardise_aux: - \fi: - } - \cs_set_protected:Npn - \fp_standardise_aux:w ##1##2##3##4##5##6##7##8##9 \q_stop - { - #2 ##2 \scan_stop: - #3 ##3##4##5##6##7##8##9 0 \scan_stop: - \tex_advance:D #4 \c_minus_one - } - \fp_standardise_aux: - \cs_set_protected_nopar:Npn \fp_standardise_aux: - { - \if_int_compare:w #2 > \c_nine - \tex_advance:D #2 \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_standardise_aux:w \int_use:N #2 - \exp_after:wN \fp_standardise_aux: - \fi: - } - \cs_set_protected:Npn - \fp_standardise_aux:w ##1##2##3##4##5##6##7##8##9 - { - #2 ##1##2##3##4##5##6##7##8 \scan_stop: - \tex_advance:D #3 \c_one_thousand_million - \tex_divide:D #3 \c_ten - \tl_set:Nx \l_fp_internal_tl - { - ##9 - \exp_after:wN \use_none:n \int_use:N #3 - } - #3 \l_fp_internal_tl \scan_stop: - \tex_advance:D #4 \c_one - } - \fp_standardise_aux: - \if_int_compare:w #4 < \c_one_hundred - \if_int_compare:w #4 > -\c_one_hundred - \else: - #1 \c_one - #2 \c_zero - #3 \c_zero - #4 \c_zero - \fi: - \else: - \exp_after:wN \fp_overflow_msg: - \fi: - } -\cs_new_protected_nopar:Npn \fp_standardise_aux: { } -\cs_new_protected_nopar:Npn \fp_standardise_aux:w { } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Internal utilities} -% -% \begin{macro}{\fp_level_input_exponents:} -% \begin{macro}[aux]{\fp_level_input_exponents_a:} -% \begin{macro}[aux]{\fp_level_input_exponents_a:NNNNNNNNN} -% \begin{macro}[aux]{\fp_level_input_exponents_b:} -% \begin{macro}[aux]{\fp_level_input_exponents_b:NNNNNNNNN} -% The routines here are similar to those used to standardise the -% exponent. However, the aim here is different: the two exponents need -% to end up the same. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_level_input_exponents: - { - \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int - \exp_after:wN \fp_level_input_exponents_a: - \else: - \exp_after:wN \fp_level_input_exponents_b: - \fi: - } -\cs_new_protected_nopar:Npn \fp_level_input_exponents_a: - { - \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int - \tex_advance:D \l_fp_input_b_integer_int \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_level_input_exponents_a:NNNNNNNNN - \int_use:N \l_fp_input_b_integer_int - \exp_after:wN \fp_level_input_exponents_a: - \fi: - } -\cs_new_protected:Npn \fp_level_input_exponents_a:NNNNNNNNN - #1#2#3#4#5#6#7#8#9 - { - \l_fp_input_b_integer_int #1#2#3#4#5#6#7#8 \scan_stop: - \tex_advance:D \l_fp_input_b_decimal_int \c_one_thousand_million - \tex_divide:D \l_fp_input_b_decimal_int \c_ten - \tl_set:Nx \l_fp_internal_tl - { - #9 - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_b_decimal_int - } - \l_fp_input_b_decimal_int \l_fp_internal_tl \scan_stop: - \tex_advance:D \l_fp_input_b_exponent_int \c_one - } -\cs_new_protected_nopar:Npn \fp_level_input_exponents_b: - { - \if_int_compare:w \l_fp_input_b_exponent_int > \l_fp_input_a_exponent_int - \tex_advance:D \l_fp_input_a_integer_int \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_level_input_exponents_b:NNNNNNNNN - \int_use:N \l_fp_input_a_integer_int - \exp_after:wN \fp_level_input_exponents_b: - \fi: - } -\cs_new_protected:Npn \fp_level_input_exponents_b:NNNNNNNNN - #1#2#3#4#5#6#7#8#9 - { - \l_fp_input_a_integer_int #1#2#3#4#5#6#7#8 \scan_stop: - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \tex_divide:D \l_fp_input_a_decimal_int \c_ten - \tl_set:Nx \l_fp_internal_tl - { - #9 - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_a_decimal_int - } - \l_fp_input_a_decimal_int \l_fp_internal_tl \scan_stop: - \tex_advance:D \l_fp_input_a_exponent_int \c_one - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}[aux]{\fp_tmp:w} -% Used for output of results, cutting down on \cs{exp_after:wN}. -% This is just a place holder definition. -% \begin{macrocode} -\cs_new_protected:Npn \fp_tmp:w #1#2 { } -% \end{macrocode} -% \end{macro} -% -% \subsection{Operations for \texttt{fp} variables} -% -% The format of \texttt{fp} variables is tightly defined, so that -% they can be read quickly by the internal code. The format is a single -% sign token, a single number, the decimal point, nine decimal numbers, -% an |e| and finally the exponent. This final part may vary in length. -% When stored, floating points will always be stored with a value in -% the integer position unless the number is zero. -% -% \begin{macro}{\fp_new:N, \fp_new:c} -% \UnitTested -% Fixed-points always have a value, and of course this has to be -% initialised globally. -% \begin{macrocode} -\cs_new_protected:Npn \fp_new:N #1 - { - \tl_new:N #1 - \tl_gset_eq:NN #1 \c_zero_fp - } -\cs_generate_variant:Nn \fp_new:N { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\fp_const:Nn, \fp_const:cn} -% A simple wrapper. -% \begin{macrocode} -\cs_new_protected:Npn \fp_const:Nn #1#2 - { - \fp_new:N #1 - \fp_gset:Nn #1 {#2} - } -\cs_generate_variant:Nn \fp_const:Nn { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\fp_zero:N, \fp_zero:c} -% \UnitTested -% \begin{macro}{\fp_gzero:N, \fp_gzero:c} -% \UnitTested -% Zeroing fixed-points is pretty obvious. -% \begin{macrocode} -\cs_new_protected:Npn \fp_zero:N #1 - { \tl_set_eq:NN #1 \c_zero_fp } -\cs_new_protected:Npn \fp_gzero:N #1 - { \tl_gset_eq:NN #1 \c_zero_fp } -\cs_generate_variant:Nn \fp_zero:N { c } -\cs_generate_variant:Nn \fp_gzero:N { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% {\fp_zero_new:N, \fp_zero_new:c, \fp_gzero_new:N, \fp_gzero_new:c} -% Create a floating point if needed, otherwise clear it. -% \begin{macrocode} -\cs_new_protected:Npn \fp_zero_new:N #1 - { \fp_if_exist:NTF #1 { \fp_zero:N #1 } { \fp_new:N #1 } } -\cs_new_protected:Npn \fp_gzero_new:N #1 - { \fp_if_exist:NTF #1 { \fp_gzero:N #1 } { \fp_new:N #1 } } -\cs_generate_variant:Nn \fp_zero_new:N { c } -\cs_generate_variant:Nn \fp_gzero_new:N { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\fp_set:Nn, \fp_set:cn} -% \UnitTested -% \begin{macro}{\fp_gset:Nn, \fp_gset:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_set_aux:NNn} -% To trap any input errors, a very simple version of the parser is run -% here. This will pick up any invalid characters at this stage, saving -% issues later. The splitting approach is the same as the more -% advanced function later. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_set:Nn { \fp_set_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gset:Nn { \fp_set_aux:NNn \tl_gset:Nn } -\cs_new_protected:Npn \fp_set_aux:NNn #1#2#3 - { - \group_begin: - \fp_split:Nn a {#3} - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_input_a_integer_int - \l_fp_input_a_decimal_int - \l_fp_input_a_exponent_int - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 - { - \if_int_compare:w \l_fp_input_a_sign_int < \c_zero - - - \else: - + - \fi: - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_a_decimal_int - e - \int_use:N \l_fp_input_a_exponent_int - } - } - \fp_tmp:w - } -\cs_generate_variant:Nn \fp_set:Nn { c } -\cs_generate_variant:Nn \fp_gset:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% -% -% \begin{macro}{\fp_set_from_dim:Nn, \fp_set_from_dim:cn} -% \UnitTested -% \begin{macro}{\fp_gset_from_dim:Nn, \fp_gset_from_dim:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_set_from_dim_aux:NNn} -% \begin{macro}[aux]{\fp_set_from_dim_aux:w} -% \begin{variable}{\l_fp_internal_dim} -% \begin{variable}{\l_fp_internal_skip} -% Here, dimensions are converted to fixed-points \emph{via} a -% temporary variable. This ensures that they always convert as points. -% The code is then essentially the same as for \cs{fp_set:Nn}, but with -% the dimension passed so that it will be striped of the |pt| on the -% way through. The passage through a skip is used to remove any rubber -% part. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_set_from_dim:Nn - { \fp_set_from_dim_aux:NNn \tl_set:Nx } -\cs_new_protected_nopar:Npn \fp_gset_from_dim:Nn - { \fp_set_from_dim_aux:NNn \tl_gset:Nx } -\cs_new_protected:Npn \fp_set_from_dim_aux:NNn #1#2#3 - { - \group_begin: - \l_fp_internal_skip \etex_glueexpr:D #3 \scan_stop: - \l_fp_internal_dim \l_fp_internal_skip - \fp_split:Nn a - { - \exp_after:wN \fp_set_from_dim_aux:w - \dim_use:N \l_fp_internal_dim - } - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_input_a_integer_int - \l_fp_input_a_decimal_int - \l_fp_input_a_exponent_int - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 - { - \if_int_compare:w \l_fp_input_a_sign_int < \c_zero - - - \else: - + - \fi: - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_a_decimal_int - e - \int_use:N \l_fp_input_a_exponent_int - } - } - \fp_tmp:w - } -\cs_set_protected_nopar:Npx \fp_set_from_dim_aux:w - { - \cs_set:Npn \exp_not:N \fp_set_from_dim_aux:w - ##1 \tl_to_str:n { pt } {##1} - } -\fp_set_from_dim_aux:w -\cs_generate_variant:Nn \fp_set_from_dim:Nn { c } -\cs_generate_variant:Nn \fp_gset_from_dim:Nn { c } -\dim_new:N \l_fp_internal_dim -\skip_new:N \l_fp_internal_skip -% \end{macrocode} -% \end{variable} +% \begin{variable}{true, false} +% Other names for $1$ and $+0$. % \end{variable} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % -% \begin{macro}{\fp_set_eq:NN, \fp_set_eq:cN, \fp_set_eq:Nc, \fp_set_eq:cc} -% \UnitTested -% \begin{macro}{\fp_gset_eq:NN, \fp_gset_eq:cN, \fp_gset_eq:Nc, \fp_gset_eq:cc} -% \UnitTested -% Pretty simple, really. -% \begin{macrocode} -\cs_new_eq:NN \fp_set_eq:NN \tl_set_eq:NN -\cs_new_eq:NN \fp_set_eq:cN \tl_set_eq:cN -\cs_new_eq:NN \fp_set_eq:Nc \tl_set_eq:Nc -\cs_new_eq:NN \fp_set_eq:cc \tl_set_eq:cc -\cs_new_eq:NN \fp_gset_eq:NN \tl_gset_eq:NN -\cs_new_eq:NN \fp_gset_eq:cN \tl_gset_eq:cN -\cs_new_eq:NN \fp_gset_eq:Nc \tl_gset_eq:Nc -\cs_new_eq:NN \fp_gset_eq:cc \tl_gset_eq:cc -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_show:N, \fp_show:c} -% \UnitTested -% Simple showing of the underlying variable. -% \begin{macrocode} -\cs_new_eq:NN \fp_show:N \tl_show:N -\cs_new_eq:NN \fp_show:c \tl_show:c -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\fp_use:N, \fp_use:c} -% \UnitTested -% \begin{macro}[aux]{\fp_use_aux:w} -% \begin{macro}[aux]{\fp_use_none:w} -% \begin{macro}[aux]{\fp_use_small:w} -% \begin{macro}[aux]{\fp_use_large:w} -% \begin{macro}[aux]{\fp_use_large_aux_i:w} -% \begin{macro}[aux]{\fp_use_large_aux_1:w} -% \begin{macro}[aux]{\fp_use_large_aux_2:w} -% \begin{macro}[aux]{\fp_use_large_aux_3:w} -% \begin{macro}[aux]{\fp_use_large_aux_4:w} -% \begin{macro}[aux]{\fp_use_large_aux_5:w} -% \begin{macro}[aux]{\fp_use_large_aux_6:w} -% \begin{macro}[aux]{\fp_use_large_aux_7:w} -% \begin{macro}[aux]{\fp_use_large_aux_8:w} -% \begin{macro}[aux]{\fp_use_large_aux_i:w} -% \begin{macro}[aux]{\fp_use_large_aux_ii:w} -% The idea of the \cs{fp_use:N} function to convert the stored -% value into something suitable for \TeX{} to use as a number in an -% expandable manner. The first step is to deal with the sign, then -% work out how big the input is. -% \begin{macrocode} -\cs_new:Npn \fp_use:N #1 - { \exp_after:wN \fp_use_aux:w #1 \q_stop } -\cs_generate_variant:Nn \fp_use:N { c } -\cs_new:Npn \fp_use_aux:w #1#2 e #3 \q_stop - { - \if:w #1 - - - - \fi: - \if_int_compare:w #3 > \c_zero - \exp_after:wN \fp_use_large:w - \else: - \if_int_compare:w #3 < \c_zero - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_use_small:w - \else: - \exp_after:wN \exp_after:wN \exp_after:wN \fp_use_none:w - \fi: - \fi: - #2 e #3 \q_stop - } -% \end{macrocode} -% When the exponent is zero, the input is simply returned as output. -% \begin{macrocode} -\cs_new:Npn \fp_use_none:w #1 e #2 \q_stop {#1} -% \end{macrocode} -% For small numbers (less than $1$) the correct number of zeros -% have to be inserted, but the decimal point is easy. -% \begin{macrocode} -\cs_new:Npn \fp_use_small:w #1 . #2 e #3 \q_stop - { - 0 . - \prg_replicate:nn { -#3 - 1 } { 0 } - #1#2 - } -% \end{macrocode} -% Life is more complex for large numbers. The decimal point needs to -% be shuffled, with potentially some zero-filling for very large values. -% \begin{macrocode} -\cs_new:Npn \fp_use_large:w #1 . #2 e #3 \q_stop - { - \if_int_compare:w #3 < \c_ten - \exp_after:wN \fp_use_large_aux_i:w - \else: - \exp_after:wN \fp_use_large_aux_ii:w - \fi: - #1#2 e #3 \q_stop - } -\cs_new:Npn \fp_use_large_aux_i:w #1#2 e #3 \q_stop - { - #1 - \use:c { fp_use_large_aux_ #3 :w } #2 \q_stop - } -\cs_new:cpn { fp_use_large_aux_1:w } #1#2 \q_stop { #1 . #2 } -\cs_new:cpn { fp_use_large_aux_2:w } #1#2#3 \q_stop - { #1#2 . #3 } -\cs_new:cpn { fp_use_large_aux_3:w } #1#2#3#4 \q_stop - { #1#2#3 . #4 } -\cs_new:cpn { fp_use_large_aux_4:w } #1#2#3#4#5 \q_stop - { #1#2#3#4 . #5 } -\cs_new:cpn { fp_use_large_aux_5:w } #1#2#3#4#5#6 \q_stop - { #1#2#3#4#5 . #6 } -\cs_new:cpn { fp_use_large_aux_6:w } #1#2#3#4#5#6#7 \q_stop - { #1#2#3#4#5#6 . #7 } -\cs_new:cpn { fp_use_large_aux_7:w } #1#2#3#4#5#6#7#8 \q_stop - { #1#2#3#4#6#7 . #8 } -\cs_new:cpn { fp_use_large_aux_8:w } #1#2#3#4#5#6#7#8#9 \q_stop - { #1#2#3#4#5#6#7#8 . #9 } -\cs_new:cpn { fp_use_large_aux_9:w } #1 \q_stop { #1 . } -\cs_new:Npn \fp_use_large_aux_ii:w #1 e #2 \q_stop - { - #1 - \prg_replicate:nn { #2 - 9 } { 0 } - . - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}[pTF]{\fp_if_exist:N, \fp_if_exist:c} -% Copies of the \texttt{cs} functions defined in \pkg{l3basics}. -% \begin{macrocode} -\cs_new_eq:NN \fp_if_exist:NTF \cs_if_exist:NTF -\cs_new_eq:NN \fp_if_exist:NT \cs_if_exist:NT -\cs_new_eq:NN \fp_if_exist:NF \cs_if_exist:NF -\cs_new_eq:NN \fp_if_exist_p:N \cs_if_exist_p:N -\cs_new_eq:NN \fp_if_exist:cTF \cs_if_exist:cTF -\cs_new_eq:NN \fp_if_exist:cT \cs_if_exist:cT -\cs_new_eq:NN \fp_if_exist:cF \cs_if_exist:cF -\cs_new_eq:NN \fp_if_exist_p:c \cs_if_exist_p:c -% \end{macrocode} -% \end{macro} -% -% \subsection{Transferring to other types} -% -% The \cs{fp_use:N} function converts a floating point variable to -% a form that can be used by \TeX{}. Here, the functions are slightly -% different, as some information may be discarded. -% -% \begin{macro}{\fp_to_dim:N, \fp_to_dim:c} -% A very simple wrapper. -% \begin{macrocode} -\cs_new:Npn \fp_to_dim:N #1 { \fp_use:N #1 pt } -\cs_generate_variant:Nn \fp_to_dim:N { c } -% \end{macrocode} -% \end{macro} -% -% -% \begin{macro}{\fp_to_int:N, \fp_to_int:c} -% \UnitTested -% \begin{macro}[aux]{\fp_to_int_aux:w} -% \begin{macro}[aux]{\fp_to_int_none:w} -% \begin{macro}[aux]{\fp_to_int_small:w} -% \begin{macro}[aux]{\fp_to_int_large:w} -% \begin{macro}[aux]{\fp_to_int_large_aux_i:w} -% \begin{macro}[aux]{\fp_to_int_large_aux_1:w} -% \begin{macro}[aux]{\fp_to_int_large_aux_2:w} -% \begin{macro}[aux]{\fp_to_int_large_aux_3:w} -% \begin{macro}[aux]{\fp_to_int_large_aux_4:w} -% \begin{macro}[aux]{\fp_to_int_large_aux_5:w} -% \begin{macro}[aux]{\fp_to_int_large_aux_6:w} -% \begin{macro}[aux]{\fp_to_int_large_aux_7:w} -% \begin{macro}[aux]{\fp_to_int_large_aux_8:w} -% \begin{macro}[aux]{\fp_to_int_large_aux_i:w} -% \begin{macro}[aux]{\fp_to_int_large_aux:nnn} -% \begin{macro}[aux]{\fp_to_int_large_aux_ii:w} -% Converting to integers in an expandable manner is very similar to -% simply using floating point variables, particularly in the lead-off. -% \begin{macrocode} -\cs_new:Npn \fp_to_int:N #1 - { \exp_after:wN \fp_to_int_aux:w #1 \q_stop } -\cs_generate_variant:Nn \fp_to_int:N { c } -\cs_new:Npn \fp_to_int_aux:w #1#2 e #3 \q_stop - { - \if:w #1 - - - - \fi: - \if_int_compare:w #3 < \c_zero - \exp_after:wN \fp_to_int_small:w - \else: - \exp_after:wN \fp_to_int_large:w - \fi: - #2 e #3 \q_stop - } -% \end{macrocode} -% For small numbers, if the decimal part is greater than a half then -% there is rounding up to do. -% \begin{macrocode} -\cs_new:Npn \fp_to_int_small:w #1 . #2 e #3 \q_stop - { - \if_int_compare:w #3 > \c_one - \else: - \if_int_compare:w #1 < \c_five - 0 - \else: - 1 - \fi: - \fi: - } -% \end{macrocode} -% For large numbers, the idea is to split off the part for rounding, -% do the rounding and fill if needed. -% \begin{macrocode} -\cs_new:Npn \fp_to_int_large:w #1 . #2 e #3 \q_stop - { - \if_int_compare:w #3 < \c_ten - \exp_after:wN \fp_to_int_large_aux_i:w - \else: - \exp_after:wN \fp_to_int_large_aux_ii:w - \fi: - #1#2 e #3 \q_stop - } -\cs_new:Npn \fp_to_int_large_aux_i:w #1#2 e #3 \q_stop - { \use:c { fp_to_int_large_aux_ #3 :w } #2 \q_stop {#1} } -\cs_new:cpn { fp_to_int_large_aux_1:w } #1#2 \q_stop - { \fp_to_int_large_aux:nnn { #2 0 } {#1} } -\cs_new:cpn { fp_to_int_large_aux_2:w } #1#2#3 \q_stop - { \fp_to_int_large_aux:nnn { #3 00 } {#1#2} } -\cs_new:cpn { fp_to_int_large_aux_3:w } #1#2#3#4 \q_stop - { \fp_to_int_large_aux:nnn { #4 000 } {#1#2#3} } -\cs_new:cpn { fp_to_int_large_aux_4:w } #1#2#3#4#5 \q_stop - { \fp_to_int_large_aux:nnn { #5 0000 } {#1#2#3#4} } -\cs_new:cpn { fp_to_int_large_aux_5:w } #1#2#3#4#5#6 \q_stop - { \fp_to_int_large_aux:nnn { #6 00000 } {#1#2#3#4#5} } -\cs_new:cpn { fp_to_int_large_aux_6:w } #1#2#3#4#5#6#7 \q_stop - { \fp_to_int_large_aux:nnn { #7 000000 } {#1#2#3#4#5#6} } -\cs_new:cpn { fp_to_int_large_aux_7:w } #1#2#3#4#5#6#7#8 \q_stop - { \fp_to_int_large_aux:nnn { #8 0000000 } {#1#2#3#4#5#6#7} } -\cs_new:cpn { fp_to_int_large_aux_8:w } #1#2#3#4#5#6#7#8#9 \q_stop - { \fp_to_int_large_aux:nnn { #9 00000000 } {#1#2#3#4#5#6#7#8} } -\cs_new:cpn { fp_to_int_large_aux_9:w } #1 \q_stop {#1} -\cs_new:Npn \fp_to_int_large_aux:nnn #1#2#3 - { - \if_int_compare:w #1 < \c_five_hundred_million - #3#2 - \else: - \int_value:w \int_eval:w #3#2 + 1 \int_eval_end: - \fi: - } -\cs_new:Npn \fp_to_int_large_aux_ii:w #1 e #2 \q_stop - { - #1 - \prg_replicate:nn { #2 - 9 } { 0 } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_to_tl:N, \fp_to_tl:c} -% \UnitTested -% \begin{macro}[aux]{\fp_to_tl_aux:w} -% \begin{macro}[aux]{\fp_to_tl_large:w} -% \begin{macro}[aux]{\fp_to_tl_large_aux_i:w} -% \begin{macro}[aux]{\fp_to_tl_large_aux_ii:w} -% \begin{macro}[aux]{\fp_to_tl_large_0:w} -% \begin{macro}[aux]{\fp_to_tl_large_1:w} -% \begin{macro}[aux]{\fp_to_tl_large_2:w} -% \begin{macro}[aux]{\fp_to_tl_large_3:w} -% \begin{macro}[aux]{\fp_to_tl_large_4:w} -% \begin{macro}[aux]{\fp_to_tl_large_5:w} -% \begin{macro}[aux]{\fp_to_tl_large_6:w} -% \begin{macro}[aux]{\fp_to_tl_large_7:w} -% \begin{macro}[aux]{\fp_to_tl_large_8:w} -% \begin{macro}[aux]{\fp_to_tl_large_8_aux:w} -% \begin{macro}[aux]{\fp_to_tl_large_9:w} -% \begin{macro}[aux]{\fp_to_tl_small:w} -% \begin{macro}[aux]{\fp_to_tl_small_one:w} -% \begin{macro}[aux]{\fp_to_tl_small_two:w} -% \begin{macro}[aux]{\fp_to_tl_small_aux:w} -% \begin{macro}[aux]{\fp_to_tl_large_zeros:NNNNNNNNN} -% \begin{macro}[aux]{\fp_to_tl_small_zeros:NNNNNNNNN} -% \begin{macro}[aux]{\fp_use_iix_ix:NNNNNNNNN} -% \begin{macro}[aux]{\fp_use_ix:NNNNNNNNN} -% \begin{macro}[aux]{\fp_use_i_to_vii:NNNNNNNNN} -% \begin{macro}[aux]{\fp_use_i_to_iix:NNNNNNNNN} -% Converting to integers in an expandable manner is very similar to -% simply using floating point variables, particularly in the lead-off. -% \begin{macrocode} -\cs_new:Npn \fp_to_tl:N #1 - { \exp_after:wN \fp_to_tl_aux:w #1 \q_stop } -\cs_generate_variant:Nn \fp_to_tl:N { c } -\cs_new:Npn \fp_to_tl_aux:w #1#2 e #3 \q_stop - { - \if:w #1 - - - - \fi: - \if_int_compare:w #3 < \c_zero - \exp_after:wN \fp_to_tl_small:w - \else: - \exp_after:wN \fp_to_tl_large:w - \fi: - #2 e #3 \q_stop - } -% \end{macrocode} -% For \enquote{large} numbers (exponent $\ge 0$) there are two -% cases. For very large exponents ($ \ge 10 $) life is easy: apart -% from dropping extra zeros there is no work to do. On the other hand, -% for intermediate exponent values the decimal needs to be moved, then -% zeros can be dropped. -% \begin{macrocode} -\cs_new:Npn \fp_to_tl_large:w #1 e #2 \q_stop - { - \if_int_compare:w #2 < \c_ten - \exp_after:wN \fp_to_tl_large_aux_i:w - \else: - \exp_after:wN \fp_to_tl_large_aux_ii:w - \fi: - #1 e #2 \q_stop - } -\cs_new:Npn \fp_to_tl_large_aux_i:w #1 e #2 \q_stop - { \use:c { fp_to_tl_large_ #2 :w } #1 \q_stop } -\cs_new:Npn \fp_to_tl_large_aux_ii:w #1 . #2 e #3 \q_stop - { - #1 - \fp_to_tl_large_zeros:NNNNNNNNN #2 - e #3 - } -\cs_new:cpn { fp_to_tl_large_0:w } #1 . #2 \q_stop - { - #1 - \fp_to_tl_large_zeros:NNNNNNNNN #2 - } -\cs_new:cpn { fp_to_tl_large_1:w } #1 . #2#3 \q_stop - { - #1#2 - \fp_to_tl_large_zeros:NNNNNNNNN #3 0 - } -\cs_new:cpn { fp_to_tl_large_2:w } #1 . #2#3#4 \q_stop - { - #1#2#3 - \fp_to_tl_large_zeros:NNNNNNNNN #4 00 - } -\cs_new:cpn { fp_to_tl_large_3:w } #1 . #2#3#4#5 \q_stop - { - #1#2#3#4 - \fp_to_tl_large_zeros:NNNNNNNNN #5 000 - } -\cs_new:cpn { fp_to_tl_large_4:w } #1 . #2#3#4#5#6 \q_stop - { - #1#2#3#4#5 - \fp_to_tl_large_zeros:NNNNNNNNN #6 0000 - } -\cs_new:cpn { fp_to_tl_large_5:w } #1 . #2#3#4#5#6#7 \q_stop - { - #1#2#3#4#5#6 - \fp_to_tl_large_zeros:NNNNNNNNN #7 00000 - } -\cs_new:cpn { fp_to_tl_large_6:w } #1 . #2#3#4#5#6#7#8 \q_stop - { - #1#2#3#4#5#6#7 - \fp_to_tl_large_zeros:NNNNNNNNN #8 000000 - } -\cs_new:cpn { fp_to_tl_large_7:w } #1 . #2#3#4#5#6#7#8#9 \q_stop - { - #1#2#3#4#5#6#7#8 - \fp_to_tl_large_zeros:NNNNNNNNN #9 0000000 - } -\cs_new:cpn { fp_to_tl_large_8:w } #1 . - { - #1 - \use:c { fp_to_tl_large_8_aux:w } - } -\cs_new:cpn { fp_to_tl_large_8_aux:w } #1#2#3#4#5#6#7#8#9 \q_stop - { - #1#2#3#4#5#6#7#8 - \fp_to_tl_large_zeros:NNNNNNNNN #9 00000000 - } -\cs_new:cpn { fp_to_tl_large_9:w } #1 . #2 \q_stop {#1#2} -% \end{macrocode} -% Dealing with small numbers is a bit more complex as there has to be -% rounding. This makes life rather awkward, as there need to be a series -% of tests and calculations, as things cannot be stored in an -% expandable system. -% \begin{macrocode} -\cs_new:Npn \fp_to_tl_small:w #1 e #2 \q_stop - { - \if_int_compare:w #2 = \c_minus_one - \exp_after:wN \fp_to_tl_small_one:w - \else: - \if_int_compare:w #2 = -\c_two - \exp_after:wN \exp_after:wN \exp_after:wN \fp_to_tl_small_two:w - \else: - \exp_after:wN \exp_after:wN \exp_after:wN \fp_to_tl_small_aux:w - \fi: - \fi: - #1 e #2 \q_stop - } -\cs_new:Npn \fp_to_tl_small_one:w #1 . #2 e #3 \q_stop - { - \if_int_compare:w \fp_use_ix:NNNNNNNNN #2 > \c_four - \if_int_compare:w - \int_eval:w #1 \fp_use_i_to_iix:NNNNNNNNN #2 + 1 - < \c_one_thousand_million - 0. - \exp_after:wN \fp_to_tl_small_zeros:NNNNNNNNN - \int_value:w \int_eval:w - #1 \fp_use_i_to_iix:NNNNNNNNN #2 + 1 - \int_eval_end: - \else: - 1 - \fi: - \else: - 0. #1 - \fp_to_tl_small_zeros:NNNNNNNNN #2 - \fi: - } -\cs_new:Npn \fp_to_tl_small_two:w #1 . #2 e #3 \q_stop - { - \if_int_compare:w \fp_use_iix_ix:NNNNNNNNN #2 > \c_forty_four - \if_int_compare:w - \int_eval:w #1 \fp_use_i_to_vii:NNNNNNNNN #2 0 + \c_ten - < \c_one_thousand_million - 0.0 - \exp_after:wN \fp_to_tl_small_zeros:NNNNNNNNN - \int_value:w \int_eval:w - #1 \fp_use_i_to_vii:NNNNNNNNN #2 0 + \c_ten - \int_eval_end: - \else: - 0.1 - \fi: - \else: - 0.0 - #1 - \fp_to_tl_small_zeros:NNNNNNNNN #2 - \fi: - } -\cs_new:Npn \fp_to_tl_small_aux:w #1 . #2 e #3 \q_stop - { - #1 - \fp_to_tl_large_zeros:NNNNNNNNN #2 - e #3 - } -% \end{macrocode} -% Rather than a complex recursion, the tests for finding trailing zeros -% are written out long-hand. The difference between the two is only the -% need for a decimal marker. -% \begin{macrocode} -\cs_new:Npn \fp_to_tl_large_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - { - \if_int_compare:w #9 = \c_zero - \if_int_compare:w #8 = \c_zero - \if_int_compare:w #7 = \c_zero - \if_int_compare:w #6 = \c_zero - \if_int_compare:w #5 = \c_zero - \if_int_compare:w #4 = \c_zero - \if_int_compare:w #3 = \c_zero - \if_int_compare:w #2 = \c_zero - \if_int_compare:w #1 = \c_zero - \else: - . #1 - \fi: - \else: - . #1#2 - \fi: - \else: - . #1#2#3 - \fi: - \else: - . #1#2#3#4 - \fi: - \else: - . #1#2#3#4#5 - \fi: - \else: - . #1#2#3#4#5#6 - \fi: - \else: - . #1#2#3#4#5#6#7 - \fi: - \else: - . #1#2#3#4#5#6#7#8 - \fi: - \else: - . #1#2#3#4#5#6#7#8#9 - \fi: - } -\cs_new:Npn \fp_to_tl_small_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - { - \if_int_compare:w #9 = \c_zero - \if_int_compare:w #8 = \c_zero - \if_int_compare:w #7 = \c_zero - \if_int_compare:w #6 = \c_zero - \if_int_compare:w #5 = \c_zero - \if_int_compare:w #4 = \c_zero - \if_int_compare:w #3 = \c_zero - \if_int_compare:w #2 = \c_zero - \if_int_compare:w #1 = \c_zero - \else: - #1 - \fi: - \else: - #1#2 - \fi: - \else: - #1#2#3 - \fi: - \else: - #1#2#3#4 - \fi: - \else: - #1#2#3#4#5 - \fi: - \else: - #1#2#3#4#5#6 - \fi: - \else: - #1#2#3#4#5#6#7 - \fi: - \else: - #1#2#3#4#5#6#7#8 - \fi: - \else: - #1#2#3#4#5#6#7#8#9 - \fi: - } -% \end{macrocode} -% Some quick \enquote{return a few} functions. -% \begin{macrocode} -\cs_new:Npn \fp_use_iix_ix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 {#8#9} -\cs_new:Npn \fp_use_ix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 {#9} -\cs_new:Npn \fp_use_i_to_vii:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - {#1#2#3#4#5#6#7} -\cs_new:Npn \fp_use_i_to_iix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - {#1#2#3#4#5#6#7#8} -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Rounding numbers} -% -% The results may well need to be rounded. A couple of related functions -% to do this for a stored value. -% -% \begin{macro}{\fp_round_figures:Nn, \fp_round_figures:cn} -% \UnitTested -% \begin{macro}{\fp_ground_figures:Nn, \fp_ground_figures:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_round_figures_aux:NNn} -% Rounding to figures needs only an adjustment to the target by one -% (as the target is in decimal places). -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_round_figures:Nn - { \fp_round_figures_aux:NNn \tl_set:Nn } -\cs_generate_variant:Nn \fp_round_figures:Nn { c } -\cs_new_protected_nopar:Npn \fp_ground_figures:Nn - { \fp_round_figures_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_ground_figures:Nn { c } -\cs_new_protected:Npn \fp_round_figures_aux:NNn #1#2#3 - { - \group_begin: - \fp_read:N #2 - \int_set:Nn \l_fp_round_target_int { #3 - 1 } - \if_int_compare:w \l_fp_round_target_int < \c_ten - \exp_after:wN \fp_round: - \fi: - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 - { - \if_int_compare:w \l_fp_input_a_sign_int < \c_zero - - - \else: - + - \fi: - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_a_decimal_int - e - \int_use:N \l_fp_input_a_exponent_int - } - } - \fp_tmp:w - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_round_places:Nn, \fp_round_places:cn} -% \UnitTested -% \begin{macro}{\fp_ground_places:Nn, \fp_ground_places:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_round_places_aux:NNn} -% Rounding to places needs an adjustment for the exponent value, which -% will mean that everything should be correct. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_round_places:Nn - { \fp_round_places_aux:NNn \tl_set:Nn } -\cs_generate_variant:Nn \fp_round_places:Nn { c } -\cs_new_protected_nopar:Npn \fp_ground_places:Nn - { \fp_round_places_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_ground_places:Nn { c } -\cs_new_protected:Npn \fp_round_places_aux:NNn #1#2#3 - { - \group_begin: - \fp_read:N #2 - \int_set:Nn \l_fp_round_target_int - { #3 + \l_fp_input_a_exponent_int } - \if_int_compare:w \l_fp_round_target_int < \c_ten - \exp_after:wN \fp_round: - \fi: - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 - { - \if_int_compare:w \l_fp_input_a_sign_int < \c_zero - - - \else: - + - \fi: - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_a_decimal_int - e - \int_use:N \l_fp_input_a_exponent_int - } - } - \fp_tmp:w - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_round:} -% \begin{macro}[aux]{\fp_round_aux:NNNNNNNNN} -% \begin{macro}{\fp_round_loop:N} -% The rounding approach is the same for decimal places and significant -% figures. There are always nine decimal digits to round, so the code -% can be written to account for this. The basic logic is simply to -% find the rounding, track any carry digit and move along. At the end -% of the loop there is a possible shuffle if the integer part has -% become $10$. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_round: - { - \bool_set_false:N \l_fp_round_carry_bool - \l_fp_round_position_int \c_eight - \tl_clear:N \l_fp_round_decimal_tl - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_round_aux:NNNNNNNNN \int_use:N \l_fp_input_a_decimal_int - } -\cs_new_protected:Npn \fp_round_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - { - \fp_round_loop:N #9#8#7#6#5#4#3#2#1 - \bool_if:NT \l_fp_round_carry_bool - { \tex_advance:D \l_fp_input_a_integer_int \c_one } - \l_fp_input_a_decimal_int \l_fp_round_decimal_tl \scan_stop: - \if_int_compare:w \l_fp_input_a_integer_int < \c_ten - \else: - \l_fp_input_a_integer_int \c_one - \tex_divide:D \l_fp_input_a_decimal_int \c_ten - \tex_advance:D \l_fp_input_a_exponent_int \c_one - \fi: - } -\cs_new_protected:Npn \fp_round_loop:N #1 - { - \if_int_compare:w \l_fp_round_position_int < \l_fp_round_target_int - \bool_if:NTF \l_fp_round_carry_bool - { \l_fp_internal_int \int_eval:w #1 + \c_one \scan_stop: } - { \l_fp_internal_int \int_eval:w #1 \scan_stop: } - \if_int_compare:w \l_fp_internal_int = \c_ten - \l_fp_internal_int \c_zero - \else: - \bool_set_false:N \l_fp_round_carry_bool - \fi: - \tl_set:Nx \l_fp_round_decimal_tl - { \int_use:N \l_fp_internal_int \l_fp_round_decimal_tl } - \else: - \tl_set:Nx \l_fp_round_decimal_tl { 0 \l_fp_round_decimal_tl } - \if_int_compare:w \l_fp_round_position_int = \l_fp_round_target_int - \if_int_compare:w #1 > \c_four - \bool_set_true:N \l_fp_round_carry_bool - \fi: - \fi: - \fi: - \tex_advance:D \l_fp_round_position_int \c_minus_one - \if_int_compare:w \l_fp_round_position_int > \c_minus_one - \exp_after:wN \fp_round_loop:N - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Unary functions} -% -% \begin{macro}{\fp_abs:N, \fp_abs:c} -% \UnitTested -% \begin{macro}{\fp_gabs:N, \fp_gabs:c} -% \UnitTested -% \begin{macro}[aux]{\fp_abs_aux:NN} -% Setting the absolute value is easy: read the value, ignore the sign, -% return the result. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_abs:N { \fp_abs_aux:NN \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gabs:N { \fp_abs_aux:NN \tl_gset:Nn } -\cs_generate_variant:Nn \fp_abs:N { c } -\cs_generate_variant:Nn \fp_gabs:N { c } -\cs_new_protected:Npn \fp_abs_aux:NN #1#2 - { - \group_begin: - \fp_read:N #2 - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 - { - + - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_a_decimal_int - e - \int_use:N \l_fp_input_a_exponent_int - } - } - \fp_tmp:w - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_neg:N, \fp_neg:c} -% \UnitTested -% \begin{macro}{\fp_gneg:N, \fp_gneg:c} -% \UnitTested -% \begin{macro}[aux]{\fp_neg:NN} -% Just a bit more complex: read the input, reverse the sign and -% output the result. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_neg:N { \fp_neg_aux:NN \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gneg:N { \fp_neg_aux:NN \tl_gset:Nn } -\cs_generate_variant:Nn \fp_neg:N { c } -\cs_generate_variant:Nn \fp_gneg:N { c } -\cs_new_protected:Npn \fp_neg_aux:NN #1#2 - { - \group_begin: - \fp_read:N #2 - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \tl_set:Nx \l_fp_internal_tl - { - \if_int_compare:w \l_fp_input_a_sign_int < \c_zero - + - \else: - - - \fi: - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_a_decimal_int - e - \int_use:N \l_fp_input_a_exponent_int - } - \exp_after:wN \group_end: \exp_after:wN - #1 \exp_after:wN #2 \exp_after:wN { \l_fp_internal_tl } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Basic arithmetic} -% -% \begin{macro}{\fp_add:Nn, \fp_add:cn} -% \UnitTested -% \begin{macro}{\fp_gadd:Nn,\fp_gadd:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_add_aux:NNn} -% \begin{macro}[aux]{\fp_add_core:} -% \begin{macro}[aux]{\fp_add_sum:} -% \begin{macro}[aux]{\fp_add_difference:} -% The various addition functions are simply different ways to call the -% single master function below. This pattern is repeated for the -% other arithmetic functions. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_add:Nn { \fp_add_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gadd:Nn { \fp_add_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_add:Nn { c } -\cs_generate_variant:Nn \fp_gadd:Nn { c } -% \end{macrocode} -% Addition takes place using one of two paths. If the signs of the -% two parts are the same, they are simply combined. On the other -% hand, if the signs are different the calculation finds this -% difference. -% \begin{macrocode} -\cs_new_protected:Npn \fp_add_aux:NNn #1#2#3 - { - \group_begin: - \fp_read:N #2 - \fp_split:Nn b {#3} - \fp_standardise:NNNN - \l_fp_input_b_sign_int - \l_fp_input_b_integer_int - \l_fp_input_b_decimal_int - \l_fp_input_b_exponent_int - \fp_add_core: - \fp_tmp:w #1#2 - } -\cs_new_protected_nopar:Npn \fp_add_core: - { - \fp_level_input_exponents: - \if_int_compare:w - \int_eval:w - \l_fp_input_a_sign_int * \l_fp_input_b_sign_int - > \c_zero - \exp_after:wN \fp_add_sum: - \else: - \exp_after:wN \fp_add_difference: - \fi: - \l_fp_output_exponent_int \l_fp_input_a_exponent_int - \fp_standardise:NNNN - \l_fp_output_sign_int - \l_fp_output_integer_int - \l_fp_output_decimal_int - \l_fp_output_exponent_int - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 ##2 - { - \if_int_compare:w \l_fp_output_sign_int < \c_zero - - - \else: - + - \fi: - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_output_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_output_exponent_int - } - } - } -% \end{macrocode} -% Finding the sum of two numbers is trivially easy. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_add_sum: - { - \l_fp_output_sign_int \l_fp_input_a_sign_int - \l_fp_output_integer_int - \int_eval:w - \l_fp_input_a_integer_int + \l_fp_input_b_integer_int - \scan_stop: - \l_fp_output_decimal_int - \int_eval:w - \l_fp_input_a_decimal_int + \l_fp_input_b_decimal_int - \scan_stop: - \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million - \else: - \tex_advance:D \l_fp_output_integer_int \c_one - \tex_advance:D \l_fp_output_decimal_int -\c_one_thousand_million - \fi: - } -% \end{macrocode} -% When the signs of the two parts of the input are different, the -% absolute difference is worked out first. There is then a calculation -% to see which way around everything has worked out, so that the final -% sign is correct. The difference might also give a zero result with -% a negative sign, which is reversed as zero is regarded as positive. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_add_difference: - { - \l_fp_output_integer_int - \int_eval:w - \l_fp_input_a_integer_int - \l_fp_input_b_integer_int - \scan_stop: - \l_fp_output_decimal_int - \int_eval:w - \l_fp_input_a_decimal_int - \l_fp_input_b_decimal_int - \scan_stop: - \if_int_compare:w \l_fp_output_decimal_int < \c_zero - \tex_advance:D \l_fp_output_integer_int \c_minus_one - \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million - \fi: - \if_int_compare:w \l_fp_output_integer_int < \c_zero - \l_fp_output_sign_int \l_fp_input_b_sign_int - \if_int_compare:w \l_fp_output_decimal_int = \c_zero - \l_fp_output_integer_int -\l_fp_output_integer_int - \else: - \l_fp_output_decimal_int - \int_eval:w - \c_one_thousand_million - \l_fp_output_decimal_int - \scan_stop: - \l_fp_output_integer_int - \int_eval:w - - \l_fp_output_integer_int - \c_one - \scan_stop: - \fi: - \else: - \l_fp_output_sign_int \l_fp_input_a_sign_int - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} +% \begin{function}[EXP, added = 2012-05-08]{\dim_to_fp:n} +% \begin{syntax} +% \cs{dim_to_fp:n} \Arg{dimexpr} +% \end{syntax} +% Expands to an internal floating point number equal to the value of +% the \meta{dimexpr} in \texttt{pt}. +% \end{function} % -% \begin{macro}{\fp_sub:Nn, \fp_sub:cn} -% \UnitTested -% \begin{macro}{\fp_gsub:Nn,\fp_gsub:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_sub_aux:NNn} -% Subtraction is essentially the same as addition, but with the sign -% of the second component reversed. Thus the core of the two function -% groups is the same, with just a little set up here. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_sub:Nn { \fp_sub_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gsub:Nn { \fp_sub_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_sub:Nn { c } -\cs_generate_variant:Nn \fp_gsub:Nn { c } -\cs_new_protected:Npn \fp_sub_aux:NNn #1#2#3 - { - \group_begin: - \fp_read:N #2 - \fp_split:Nn b {#3} - \fp_standardise:NNNN - \l_fp_input_b_sign_int - \l_fp_input_b_integer_int - \l_fp_input_b_decimal_int - \l_fp_input_b_exponent_int - \tex_multiply:D \l_fp_input_b_sign_int \c_minus_one - \fp_add_core: - \fp_tmp:w #1#2 - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} +% \begin{function}[EXP, added = 2012-05-14, updated = 2012-07-08]{\fp_abs:n} +% \begin{syntax} +% \cs{fp_abs:n} \Arg{floating point expression} +% \end{syntax} +% Evaluates the \meta{floating point expression} as described for +% \cs{fp_eval:n} and leaves the absolute value of the result in +% the input stream. +% \end{function} % -% \begin{macro}{\fp_mul:Nn, \fp_mul:cn} -% \UnitTested -% \begin{macro}{\fp_gmul:Nn,\fp_gmul:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_mul_aux:NNn} -% \begin{macro}[aux]{\fp_mul_internal:} -% \begin{macro}[aux]{\fp_mul_split:NNNN} -% \begin{macro}[aux]{\fp_mul_split:w} -% \begin{macro}[aux]{\fp_mul_end_level:} -% \begin{macro}[aux]{\fp_mul_end_level:NNNNNNNNN} -% The pattern is much the same for multiplication. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_mul:Nn { \fp_mul_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gmul:Nn { \fp_mul_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_mul:Nn { c } -\cs_generate_variant:Nn \fp_gmul:Nn { c } -% \end{macrocode} -% The approach to multiplication is as follows. First, the two numbers -% are split into blocks of three digits. These are then multiplied -% together to find products for each group of three output digits. This -% is al written out in full for speed reasons. Between each block of -% three digits in the output, there is a carry step. The very lowest -% digits are not calculated, while -% \begin{macrocode} -\cs_new_protected:Npn \fp_mul_aux:NNn #1#2#3 - { - \group_begin: - \fp_read:N #2 - \fp_split:Nn b {#3} - \fp_standardise:NNNN - \l_fp_input_b_sign_int - \l_fp_input_b_integer_int - \l_fp_input_b_decimal_int - \l_fp_input_b_exponent_int - \fp_mul_internal: - \l_fp_output_exponent_int - \int_eval:w - \l_fp_input_a_exponent_int + \l_fp_input_b_exponent_int - \scan_stop: - \fp_standardise:NNNN - \l_fp_output_sign_int - \l_fp_output_integer_int - \l_fp_output_decimal_int - \l_fp_output_exponent_int - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 - { - \if_int_compare:w - \int_eval:w - \l_fp_input_a_sign_int * \l_fp_input_b_sign_int - < \c_zero - \if_int_compare:w - \int_eval:w - \l_fp_output_integer_int + \l_fp_output_decimal_int - = \c_zero - + - \else: - - - \fi: - \else: - + - \fi: - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_output_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_output_exponent_int - } - } - \fp_tmp:w - } -% \end{macrocode} -% Done separately so that the internal use is a bit easier. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_mul_internal: - { - \fp_mul_split:NNNN \l_fp_input_a_decimal_int - \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int - \fp_mul_split:NNNN \l_fp_input_b_decimal_int - \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int - \l_fp_mul_output_int \c_zero - \tl_clear:N \l_fp_mul_output_tl - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int - \tex_divide:D \l_fp_mul_output_int \c_one_thousand - \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_input_b_integer_int - \fp_mul_end_level: - \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_input_b_integer_int - \fp_mul_end_level: - \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_i_int - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_input_b_integer_int - \fp_mul_end_level: - \l_fp_output_decimal_int 0 \l_fp_mul_output_tl \scan_stop: - \tl_clear:N \l_fp_mul_output_tl - \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_input_b_integer_int - \fp_mul_end_level: - \l_fp_output_integer_int 0 \l_fp_mul_output_tl \scan_stop: - } -% \end{macrocode} -% The split works by making a $10$ digit number, from which -% the first digit can then be dropped using a delimited argument. The -% groups of three digits are then assigned to the various parts of -% the input: notice that |##9| contains the last two digits of the -% smallest part of the input. -% \begin{macrocode} -\cs_new_protected:Npn \fp_mul_split:NNNN #1#2#3#4 - { - \tex_advance:D #1 \c_one_thousand_million - \cs_set_protected:Npn \fp_mul_split_aux:w - ##1##2##3##4##5##6##7##8##9 \q_stop { - #2 ##2##3##4 \scan_stop: - #3 ##5##6##7 \scan_stop: - #4 ##8##9 \scan_stop: - } - \exp_after:wN \fp_mul_split_aux:w \int_use:N #1 \q_stop - \tex_advance:D #1 -\c_one_thousand_million - } -\cs_new_protected:Npn \fp_mul_product:NN #1#2 - { - \l_fp_mul_output_int - \int_eval:w \l_fp_mul_output_int + #1 * #2 \scan_stop: - } -% \end{macrocode} -% At the end of each output group of three, there is a transfer of -% information so that there is no danger of an overflow. This is done by -% expansion to keep the number of calculations down. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_mul_end_level: - { - \tex_advance:D \l_fp_mul_output_int \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_mul_end_level:NNNNNNNNN \int_use:N \l_fp_mul_output_int - } -\cs_new_protected:Npn \fp_mul_end_level:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - { - \tl_set:Nx \l_fp_mul_output_tl { #7#8#9 \l_fp_mul_output_tl } - \l_fp_mul_output_int #1#2#3#4#5#6 \scan_stop: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} +% ^^A todo +% ^^A \section{Rounding} +% ^^A +% ^^A This explains how to go from a floating point number to a +% ^^A rounded value for various applications. Perhaps worth coding +% ^^A functionalities up to what siunitx can do on this matter. % -% \begin{macro}{\fp_div:Nn, \fp_div:cn} -% \UnitTested -% \begin{macro}{\fp_gdiv:Nn,\fp_gdiv:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_div_aux:NNn} -% \begin{macro}{\fp_div_internal:} -% \begin{macro}[aux]{\fp_div_loop:} -% \begin{macro}[aux]{\fp_div_divide:} -% \begin{macro}[aux]{\fp_div_divide_aux:} -% \begin{macro}[aux]{\fp_div_store:} -% \begin{macro}[aux]{\fp_div_store_integer:} -% \begin{macro}[aux]{\fp_div_store_decimal:} -% The pattern is much the same for multiplication. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_div:Nn { \fp_div_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gdiv:Nn { \fp_div_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_div:Nn { c } -\cs_generate_variant:Nn \fp_gdiv:Nn { c } -% \end{macrocode} -% Division proper starts with a couple of tests. If the denominator is -% zero then a error is issued. On the other hand, if the numerator is -% zero then the result must be $0.0$ and can be given with no -% further work. -% \begin{macrocode} -\cs_new_protected:Npn \fp_div_aux:NNn #1#2#3 - { - \group_begin: - \fp_read:N #2 - \fp_split:Nn b {#3} - \fp_standardise:NNNN - \l_fp_input_b_sign_int - \l_fp_input_b_integer_int - \l_fp_input_b_decimal_int - \l_fp_input_b_exponent_int - \if_int_compare:w - \int_eval:w - \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int - = \c_zero - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - #1 \exp_not:N #2 { \c_undefined_fp } - } - \else: - \if_int_compare:w - \int_eval:w - \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int - = \c_zero - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - #1 \exp_not:N #2 { \c_zero_fp } - } - \else: - \exp_after:wN \exp_after:wN \exp_after:wN \fp_div_internal: - \fi: - \fi: - \fp_tmp:w #1#2 - } -% \end{macrocode} -% The main division algorithm works by finding how many times |b| can -% be removed from |a|, storing the result and doing the subtraction. -% Input |a| is then multiplied by $10$, and the process is repeated. -% The looping ends either when there is nothing left of |a| -% (\emph{i.e.}~an exact result) or when the code reaches the ninth -% decimal place. Most of the process takes place in the loop function -% below. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_div_internal: { - \l_fp_output_integer_int \c_zero - \l_fp_output_decimal_int \c_zero - \cs_set_eq:NN \fp_div_store: \fp_div_store_integer: - \l_fp_div_offset_int \c_one_hundred_million - \fp_div_loop: - \l_fp_output_exponent_int - \int_eval:w - \l_fp_input_a_exponent_int - \l_fp_input_b_exponent_int - \scan_stop: - \fp_standardise:NNNN - \l_fp_output_sign_int - \l_fp_output_integer_int - \l_fp_output_decimal_int - \l_fp_output_exponent_int - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 ##2 - { - \if_int_compare:w - \int_eval:w - \l_fp_input_a_sign_int * \l_fp_input_b_sign_int - < \c_zero - \if_int_compare:w - \int_eval:w - \l_fp_output_integer_int + \l_fp_output_decimal_int - = \c_zero - + - \else: - - - \fi: - \else: - + - \fi: - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_output_decimal_int + \c_one_thousand_million - \int_eval_end: - e - \int_use:N \l_fp_output_exponent_int - } - } -} -% \end{macrocode} -% The main loop implements the approach described above. The storing -% function is done as a function so that the integer and decimal parts -% can be done separately but rapidly. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_div_loop: - { - \l_fp_count_int \c_zero - \fp_div_divide: - \fp_div_store: - \tex_multiply:D \l_fp_input_a_integer_int \c_ten - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \exp_after:wN \fp_div_loop_step:w - \int_use:N \l_fp_input_a_decimal_int \q_stop - \if_int_compare:w - \int_eval:w \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int - > \c_zero - \if_int_compare:w \l_fp_div_offset_int > \c_zero - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_div_loop: - \fi: - \fi: - } -% \end{macrocode} -% Checking to see if the numerator can be divides needs quite an -% involved check. Either the integer part has to be bigger for the -% numerator or, if it is not smaller then the decimal part of the -% numerator must not be smaller than that of the denominator. Once -% the test is right the rest is much as elsewhere. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_div_divide: - { - \if_int_compare:w \l_fp_input_a_integer_int > \l_fp_input_b_integer_int - \exp_after:wN \fp_div_divide_aux: - \else: - \if_int_compare:w \l_fp_input_a_integer_int < \l_fp_input_b_integer_int - \else: - \if_int_compare:w - \l_fp_input_a_decimal_int < \l_fp_input_b_decimal_int - \else: - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \fp_div_divide_aux: - \fi: - \fi: - \fi: - } -\cs_new_protected_nopar:Npn \fp_div_divide_aux: - { - \tex_advance:D \l_fp_count_int \c_one - \tex_advance:D \l_fp_input_a_integer_int -\l_fp_input_b_integer_int - \tex_advance:D \l_fp_input_a_decimal_int -\l_fp_input_b_decimal_int - \if_int_compare:w \l_fp_input_a_decimal_int < \c_zero - \tex_advance:D \l_fp_input_a_integer_int \c_minus_one - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \fi: - \fp_div_divide: - } -% \end{macrocode} -% Storing the number of each division is done differently for the -% integer and decimal. The integer is easy and a one-off, while the -% decimal also needs to account for the position of the digit to store. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_div_store: { } -\cs_new_protected_nopar:Npn \fp_div_store_integer: - { - \l_fp_output_integer_int \l_fp_count_int - \cs_set_eq:NN \fp_div_store: \fp_div_store_decimal: - } -\cs_new_protected_nopar:Npn \fp_div_store_decimal: - { - \l_fp_output_decimal_int - \int_eval:w - \l_fp_output_decimal_int + - \l_fp_count_int * \l_fp_div_offset_int - \int_eval_end: - \tex_divide:D \l_fp_div_offset_int \c_ten - } -\cs_new_protected:Npn \fp_div_loop_step:w #1#2#3#4#5#6#7#8#9 \q_stop - { - \l_fp_input_a_integer_int - \int_eval:w #2 + \l_fp_input_a_integer_int \int_eval_end: - \l_fp_input_a_decimal_int #3#4#5#6#7#8#9 0 \scan_stop: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} +% ^^A todo +% ^^A \section{Floating points} +% ^^A +% ^^A Here, there may be a discussion of what floating point numbers +% ^^A are, and a list of relevant resources (\emph{e.g.}, some of +% ^^A Kahan's articles), and previous \TeX{} packages. % -% \subsection{Arithmetic for internal use} +% \section{Disclaimer and roadmap} % -% For the more complex functions, it is only possible to deliver -% reliable $10$ digit accuracy if the internal calculations are -% carried out to a higher degree of precision. This is done using a -% second set of functions so that the `user' versions are not -% slowed down. These versions are also focussed on the needs of internal -% calculations. No error checking, sign checking or exponent levelling -% is done. For addition and subtraction, the arguments are: +% The package may break down if: % \begin{itemize} -% \item Integer part of input |a|. -% \item Decimal part of input |a|. -% \item Additional decimal part of input |a|. -% \item Integer part of input |b|. -% \item Decimal part of input |b|. -% \item Additional decimal part of input |b|. -% \item Integer part of output. -% \item Decimal part of output. -% \item Additional decimal part of output. +% \item the escape character is either a digit, or an underscore, +% \item the \tn{uccodes} are changed: the test for whether a character +% is a letter actually tests if the upper-case code of the character +% is between A and Z. % \end{itemize} -% The situation for multiplication and division is a little different as -% they only deal with the decimal part. -% -% \begin{macro}{\fp_add:NNNNNNNNN} -% The internal sum is always exactly that: it is always a sum and there -% is no sign check. -% \begin{macrocode} -\cs_new_protected:Npn \fp_add:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - { - #7 \int_eval:w #1 + #4 \int_eval_end: - #8 \int_eval:w #2 + #5 \int_eval_end: - #9 \int_eval:w #3 + #6 \int_eval_end: - \if_int_compare:w #9 < \c_one_thousand_million - \else: - \tex_advance:D #8 \c_one - \tex_advance:D #9 -\c_one_thousand_million - \fi: - \if_int_compare:w #8 < \c_one_thousand_million - \else: - \tex_advance:D #7 \c_one - \tex_advance:D #8 -\c_one_thousand_million - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\fp_sub:NNNNNNNNN} -% Internal subtraction is needed only when the first number is bigger -% than the second, so there is no need to worry about the sign. This is -% a good job as there are no arguments left. The flipping flag is -% used in the rare case where a sign change is possible. -% \begin{macrocode} -\cs_new_protected:Npn \fp_sub:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - { - #7 \int_eval:w #1 - #4 \int_eval_end: - #8 \int_eval:w #2 - #5 \int_eval_end: - #9 \int_eval:w #3 - #6 \int_eval_end: - \if_int_compare:w #9 < \c_zero - \tex_advance:D #8 \c_minus_one - \tex_advance:D #9 \c_one_thousand_million - \fi: - \if_int_compare:w #8 < \c_zero - \tex_advance:D #7 \c_minus_one - \tex_advance:D #8 \c_one_thousand_million - \fi: - \if_int_compare:w #7 < \c_zero - \if_int_compare:w \int_eval:w #8 + #9 = \c_zero - #7 -#7 - \else: - \tex_advance:D #7 \c_one - #8 \int_eval:w \c_one_thousand_million - #8 \int_eval_end: - #9 \int_eval:w \c_one_thousand_million - #9 \int_eval_end: - \fi: - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\fp_mul:NNNNNN} -% Decimal-part only multiplication but with higher accuracy than the -% user version. -% \begin{macrocode} -\cs_new_protected:Npn \fp_mul:NNNNNN #1#2#3#4#5#6 - { - \fp_mul_split:NNNN #1 - \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int - \fp_mul_split:NNNN #2 - \l_fp_mul_a_iv_int \l_fp_mul_a_v_int \l_fp_mul_a_vi_int - \fp_mul_split:NNNN #3 - \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int - \fp_mul_split:NNNN #4 - \l_fp_mul_b_iv_int \l_fp_mul_b_v_int \l_fp_mul_b_vi_int - \l_fp_mul_output_int \c_zero - \tl_clear:N \l_fp_mul_output_tl - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_vi_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_v_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_i_int - \tex_divide:D \l_fp_mul_output_int \c_one_thousand - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_v_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_i_int - \fp_mul_end_level: - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_i_int - \fp_mul_end_level: - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int - \fp_mul_end_level: - #6 0 \l_fp_mul_output_tl \scan_stop: - \tl_clear:N \l_fp_mul_output_tl - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int - \fp_mul_end_level: - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int - \fp_mul_end_level: - \fp_mul_end_level: - #5 0 \l_fp_mul_output_tl \scan_stop: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\fp_mul:NNNNNNNNN} -% For internal multiplication where the integer does need to be -% retained. This means of course that this code is quite slow, and so -% is only used when necessary. -% \begin{macrocode} -\cs_new_protected:Npn \fp_mul:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - { - \fp_mul_split:NNNN #2 - \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int - \fp_mul_split:NNNN #3 - \l_fp_mul_a_iv_int \l_fp_mul_a_v_int \l_fp_mul_a_vi_int - \fp_mul_split:NNNN #5 - \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int - \fp_mul_split:NNNN #6 - \l_fp_mul_b_iv_int \l_fp_mul_b_v_int \l_fp_mul_b_vi_int - \l_fp_mul_output_int \c_zero - \tl_clear:N \l_fp_mul_output_tl - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_vi_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_v_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_i_int - \tex_divide:D \l_fp_mul_output_int \c_one_thousand - \fp_mul_product:NN #1 \l_fp_mul_b_vi_int - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_v_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_i_int - \fp_mul_product:NN \l_fp_mul_a_vi_int #4 - \fp_mul_end_level: - \fp_mul_product:NN #1 \l_fp_mul_b_v_int - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_i_int - \fp_mul_product:NN \l_fp_mul_a_v_int #4 - \fp_mul_end_level: - \fp_mul_product:NN #1 \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int - \fp_mul_product:NN \l_fp_mul_a_iv_int #4 - \fp_mul_end_level: - #9 0 \l_fp_mul_output_tl \scan_stop: - \tl_clear:N \l_fp_mul_output_tl - \fp_mul_product:NN #1 \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int - \fp_mul_product:NN \l_fp_mul_a_iii_int #4 - \fp_mul_end_level: - \fp_mul_product:NN #1 \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int - \fp_mul_product:NN \l_fp_mul_a_ii_int #4 - \fp_mul_end_level: - \fp_mul_product:NN #1 \l_fp_mul_b_i_int - \fp_mul_product:NN \l_fp_mul_a_i_int #4 - \fp_mul_end_level: - #8 0 \l_fp_mul_output_tl \scan_stop: - \tl_clear:N \l_fp_mul_output_tl - \fp_mul_product:NN #1 #4 - \fp_mul_end_level: - #7 0 \l_fp_mul_output_tl \scan_stop: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\fp_div_integer:NNNNN} -% Here, division is always by an integer, and so it is possible to -% use \TeX{}'s native calculations rather than doing it in macros. -% The idea here is to divide the decimal part, find any remainder, -% then do the real division of the two parts before adding in what -% is needed for the remainder. -% \begin{macrocode} -\cs_new_protected:Npn \fp_div_integer:NNNNN #1#2#3#4#5 - { - \l_fp_internal_int #1 - \tex_divide:D \l_fp_internal_int #3 - \l_fp_internal_int \int_eval:w #1 - \l_fp_internal_int * #3 \int_eval_end: - #4 #1 - \tex_divide:D #4 #3 - #5 #2 - \tex_divide:D #5 #3 - \tex_multiply:D \l_fp_internal_int \c_one_thousand - \tex_divide:D \l_fp_internal_int #3 - #5 \int_eval:w #5 + \l_fp_internal_int * \c_one_million \int_eval_end: - \if_int_compare:w #5 > \c_one_thousand_million - \tex_advance:D #4 \c_one - \tex_advance:D #5 -\c_one_thousand_million - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\fp_extended_normalise:} -% \begin{macro}[aux]{\fp_extended_normalise_aux_i:} -% \begin{macro}[aux]{\fp_extended_normalise_aux_i:w} -% \begin{macro}[aux]{\fp_extended_normalise_aux_ii:w} -% \begin{macro}[aux]{\fp_extended_normalise_aux_ii:} -% \begin{macro}[aux]{\fp_extended_normalise_aux:NNNNNNNNN} -% The \enquote{extended} integers for internal use are mainly used in -% fixed-point mode. This comes up in a few places, so a generalised -% utility is made available to carry out the change. This function -% simply calls the two loops to shift the input to the point of -% having a zero exponent. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_extended_normalise: - { - \fp_extended_normalise_aux_i: - \fp_extended_normalise_aux_ii: - } -\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_i: - { - \if_int_compare:w \l_fp_input_a_exponent_int > \c_zero - \tex_multiply:D \l_fp_input_a_integer_int \c_ten - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \exp_after:wN \fp_extended_normalise_aux_i:w - \int_use:N \l_fp_input_a_decimal_int \q_stop - \exp_after:wN \fp_extended_normalise_aux_i: - \fi: - } -\cs_new_protected:Npn \fp_extended_normalise_aux_i:w - #1#2#3#4#5#6#7#8#9 \q_stop - { - \l_fp_input_a_integer_int - \int_eval:w \l_fp_input_a_integer_int + #2 \scan_stop: - \l_fp_input_a_decimal_int #3#4#5#6#7#8#9 0 \scan_stop: - \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million - \exp_after:wN \fp_extended_normalise_aux_ii:w - \int_use:N \l_fp_input_a_extended_int \q_stop - } -\cs_new_protected:Npn \fp_extended_normalise_aux_ii:w - #1#2#3#4#5#6#7#8#9 \q_stop - { - \l_fp_input_a_decimal_int - \int_eval:w \l_fp_input_a_decimal_int + #2 \scan_stop: - \l_fp_input_a_extended_int #3#4#5#6#7#8#9 0 \scan_stop: - \tex_advance:D \l_fp_input_a_exponent_int \c_minus_one - } -\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_ii: - { - \if_int_compare:w \l_fp_input_a_exponent_int < \c_zero - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_extended_normalise_ii_aux:NNNNNNNNN - \int_use:N \l_fp_input_a_decimal_int - \exp_after:wN \fp_extended_normalise_aux_ii: - \fi: - } -\cs_new_protected:Npn \fp_extended_normalise_ii_aux:NNNNNNNNN - #1#2#3#4#5#6#7#8#9 - { - \if_int_compare:w \l_fp_input_a_integer_int = \c_zero - \l_fp_input_a_decimal_int #1#2#3#4#5#6#7#8 \scan_stop: - \else: - \tl_set:Nx \l_fp_internal_tl - { - \int_use:N \l_fp_input_a_integer_int - #1#2#3#4#5#6#7#8 - } - \l_fp_input_a_integer_int \c_zero - \l_fp_input_a_decimal_int \l_fp_internal_tl \scan_stop: - \fi: - \tex_divide:D \l_fp_input_a_extended_int \c_ten - \tl_set:Nx \l_fp_internal_tl - { - #9 - \int_use:N \l_fp_input_a_extended_int - } - \l_fp_input_a_extended_int \l_fp_internal_tl \scan_stop: - \tex_advance:D \l_fp_input_a_exponent_int \c_one - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_extended_normalise_output:} -% \begin{macro}[aux]{\fp_extended_normalise_output_aux_i:NNNNNNNNN} -% \begin{macro}[aux]{\fp_extended_normalise_output_aux_ii:NNNNNNNNN} -% \begin{macro}[aux]{\fp_extended_normalise_output_aux:N} -% At some stages in working out extended output, it is possible for the -% value to need shifting to keep the integer part in range. This only -% ever happens such that the integer needs to be made smaller. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_extended_normalise_output: - { - \if_int_compare:w \l_fp_output_integer_int > \c_nine - \tex_advance:D \l_fp_output_integer_int \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_extended_normalise_output_aux_i:NNNNNNNNN - \int_use:N \l_fp_output_integer_int - \exp_after:wN \fp_extended_normalise_output: - \fi: - } -\cs_new_protected:Npn \fp_extended_normalise_output_aux_i:NNNNNNNNN - #1#2#3#4#5#6#7#8#9 - { - \l_fp_output_integer_int #1#2#3#4#5#6#7#8 \scan_stop: - \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million - \tl_set:Nx \l_fp_internal_tl - { - #9 - \exp_after:wN \use_none:n - \int_use:N \l_fp_output_decimal_int - } - \exp_after:wN \fp_extended_normalise_output_aux_ii:NNNNNNNNN - \l_fp_internal_tl - } -\cs_new_protected:Npn \fp_extended_normalise_output_aux_ii:NNNNNNNNN - #1#2#3#4#5#6#7#8#9 - { - \l_fp_output_decimal_int #1#2#3#4#5#6#7#8#9 \scan_stop: - \fp_extended_normalise_output_aux:N - } -\cs_new_protected:Npn \fp_extended_normalise_output_aux:N #1 - { - \tex_advance:D \l_fp_output_extended_int \c_one_thousand_million - \tex_divide:D \l_fp_output_extended_int \c_ten - \tl_set:Nx \l_fp_internal_tl - { - #1 - \exp_after:wN \use_none:n - \int_use:N \l_fp_output_extended_int - } - \l_fp_output_extended_int \l_fp_internal_tl \scan_stop: - \tex_advance:D \l_fp_output_exponent_int \c_one - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Trigonometric functions} -% -% \begin{macro}{\fp_trig_normalise:} -% \begin{macro}[aux]{\fp_trig_normalise_aux:} -% \begin{macro}[aux]{\fp_trig_sub:NNN} -% For normalisation, the code essentially switches to fixed-point -% arithmetic. There is a shift of the exponent, then repeated -% subtractions. The end result is a number in the range -% $ -\pi < x \le \pi $. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_trig_normalise: - { - \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten - \l_fp_input_a_extended_int \c_zero - \fp_extended_normalise: - \fp_trig_normalise_aux: - \if_int_compare:w \l_fp_input_a_integer_int < \c_zero - \l_fp_input_a_sign_int -\l_fp_input_a_sign_int - \l_fp_input_a_integer_int -\l_fp_input_a_integer_int - \fi: - \exp_after:wN \fp_trig_octant: - \else: - \l_fp_input_a_sign_int \c_one - \l_fp_output_integer_int \c_zero - \l_fp_output_decimal_int \c_zero - \l_fp_output_exponent_int \c_zero - \exp_after:wN \fp_trig_overflow_msg: - \fi: - } -\cs_new_protected_nopar:Npn \fp_trig_normalise_aux: - { - \if_int_compare:w \l_fp_input_a_integer_int > \c_three - \fp_trig_sub:NNN - \c_six \c_fp_two_pi_decimal_int \c_fp_two_pi_extended_int - \exp_after:wN \fp_trig_normalise_aux: - \else: - \if_int_compare:w \l_fp_input_a_integer_int > \c_two - \if_int_compare:w \l_fp_input_a_decimal_int > \c_fp_pi_decimal_int - \fp_trig_sub:NNN - \c_six \c_fp_two_pi_decimal_int \c_fp_two_pi_extended_int - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \fp_trig_normalise_aux: - \fi: - \fi: - \fi: - } -% \end{macrocode} -% Here, there may be a sign change but there will never be any -% variation in the input. So a dedicated function can be used. -% \begin{macrocode} -\cs_new_protected:Npn \fp_trig_sub:NNN #1#2#3 - { - \l_fp_input_a_integer_int - \int_eval:w \l_fp_input_a_integer_int - #1 \int_eval_end: - \l_fp_input_a_decimal_int - \int_eval:w \l_fp_input_a_decimal_int - #2 \int_eval_end: - \l_fp_input_a_extended_int - \int_eval:w \l_fp_input_a_extended_int - #3 \int_eval_end: - \if_int_compare:w \l_fp_input_a_extended_int < \c_zero - \tex_advance:D \l_fp_input_a_decimal_int \c_minus_one - \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million - \fi: - \if_int_compare:w \l_fp_input_a_decimal_int < \c_zero - \tex_advance:D \l_fp_input_a_integer_int \c_minus_one - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \fi: - \if_int_compare:w \l_fp_input_a_integer_int < \c_zero - \l_fp_input_a_sign_int -\l_fp_input_a_sign_int - \if_int_compare:w - \int_eval:w - \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int - = \c_zero - \l_fp_input_a_integer_int -\l_fp_input_a_integer_int - \else: - \l_fp_input_a_integer_int - \int_eval:w - - \l_fp_input_a_integer_int - \c_one - \int_eval_end: - \l_fp_input_a_decimal_int - \int_eval:w - \c_one_thousand_million - \l_fp_input_a_decimal_int - \int_eval_end: - \l_fp_input_a_extended_int - \int_eval:w - \c_one_thousand_million - \l_fp_input_a_extended_int - \int_eval_end: - \fi: - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_trig_octant:} -% \begin{macro}[aux] -% {\fp_trig_octant_aux_i:, \fp_trig_octant_aux_ii:} -% Here, the input is further reduced into the range -% $ 0 < x \le \pi / 4 $. This is pretty simple: check if -% $ \pi / 4 $ can be taken off and if it can do it and loop. The -% check at the end is to \enquote{mop up} values which are so close to -% $ \pi / 4 $ that they should be treated as such. The test for -% an even octant is needed as the `remainder' needed is from -% the nearest $ \pi / 2 $. The check for octant $4$ is needed as an exact -% $\pi$ input will otherwise end up in the wrong place! -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_trig_octant: - { - \l_fp_trig_octant_int \c_one - \fp_trig_octant_aux_i: - \if_int_compare:w \l_fp_input_a_decimal_int < \c_ten - \l_fp_input_a_decimal_int \c_zero - \l_fp_input_a_extended_int \c_zero - \fi: - \if_int_odd:w \l_fp_trig_octant_int - \else: - \fp_sub:NNNNNNNNN - \c_zero \c_fp_pi_by_four_decimal_int \c_fp_pi_by_four_extended_int - \l_fp_input_a_integer_int \l_fp_input_a_decimal_int - \l_fp_input_a_extended_int - \l_fp_input_a_integer_int \l_fp_input_a_decimal_int - \l_fp_input_a_extended_int - \fi: - } -\cs_new_protected_nopar:Npn \fp_trig_octant_aux_i: - { - \if_int_compare:w \l_fp_trig_octant_int > \c_four - \l_fp_trig_octant_int \c_four - \l_fp_input_a_decimal_int \c_fp_pi_by_four_decimal_int - \l_fp_input_a_extended_int \c_fp_pi_by_four_extended_int - \else: - \exp_after:wN \fp_trig_octant_aux_ii: - \fi: - } -\cs_new_protected_nopar:Npn \fp_trig_octant_aux_ii: - { - \if_int_compare:w \l_fp_input_a_integer_int > \c_zero - \fp_sub:NNNNNNNNN - \l_fp_input_a_integer_int \l_fp_input_a_decimal_int - \l_fp_input_a_extended_int - \c_zero \c_fp_pi_by_four_decimal_int \c_fp_pi_by_four_extended_int - \l_fp_input_a_integer_int \l_fp_input_a_decimal_int - \l_fp_input_a_extended_int - \tex_advance:D \l_fp_trig_octant_int \c_one - \exp_after:wN \fp_trig_octant_aux_i: - \else: - \if_int_compare:w - \l_fp_input_a_decimal_int > \c_fp_pi_by_four_decimal_int - \fp_sub:NNNNNNNNN - \l_fp_input_a_integer_int \l_fp_input_a_decimal_int - \l_fp_input_a_extended_int - \c_zero \c_fp_pi_by_four_decimal_int - \c_fp_pi_by_four_extended_int - \l_fp_input_a_integer_int \l_fp_input_a_decimal_int - \l_fp_input_a_extended_int - \tex_advance:D \l_fp_trig_octant_int \c_one - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_trig_octant_aux_i: - \fi: - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_sin:Nn, \fp_sin:cn} -% \UnitTested -% \begin{macro}{\fp_gsin:Nn,\fp_gsin:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_sin_aux:NNn} -% \begin{macro}[aux]{\fp_sin_aux_i:} -% \begin{macro}[aux]{\fp_sin_aux_ii:} -% Calculating the sine starts off in the usual way. There is a check -% to see if the value has already been worked out before proceeding -% further. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_sin:Nn { \fp_sin_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gsin:Nn { \fp_sin_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_sin:Nn { c } -\cs_generate_variant:Nn \fp_gsin:Nn { c } -% \end{macrocode} -% The internal routine for sines does a check to see if the value is -% already known. This saves a lot of repetition when doing rotations. -% For very small values it is best to simply return the input as the -% sine: the cut-off is $ 1 \times 10^{-5} $. -% \begin{macrocode} -\cs_new_protected:Npn \fp_sin_aux:NNn #1#2#3 - { - \group_begin: - \fp_split:Nn a {#3} - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_input_a_integer_int - \l_fp_input_a_decimal_int - \l_fp_input_a_exponent_int - \tl_set:Nx \l_fp_arg_tl - { - \if_int_compare:w \l_fp_input_a_sign_int < \c_zero - - - \else: - + - \fi: - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_input_a_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_input_a_exponent_int - } - \if_int_compare:w \l_fp_input_a_exponent_int < -\c_five - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 { \l_fp_arg_tl } - } - \else: - \if_cs_exist:w - c_fp_sin ( \l_fp_arg_tl ) _fp - \cs_end: - \else: - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_sin_aux_i: - \fi: - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 - { \use:c { c_fp_sin ( \l_fp_arg_tl ) _fp } } - } - \fi: - \fp_tmp:w - } -% \end{macrocode} -% The internals for sine first normalise the input into an octant, then -% choose the correct set up for the Taylor series. The sign for the sine -% function is easy, so there is no worry about it. So the only thing to -% do is to get the output standardised. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_sin_aux_i: - { - \fp_trig_normalise: - \fp_sin_aux_ii: - \if_int_compare:w \l_fp_output_integer_int = \c_one - \l_fp_output_exponent_int \c_zero - \else: - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_decimal_int \l_fp_output_extended_int - \l_fp_output_exponent_int -\c_nine - \fi: - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_output_integer_int - \l_fp_output_decimal_int - \l_fp_output_exponent_int - \tl_new:c { c_fp_sin ( \l_fp_arg_tl ) _fp } - \tl_gset:cx { c_fp_sin ( \l_fp_arg_tl ) _fp } - { - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - + - \else: - - - \fi: - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_output_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_output_exponent_int - } - } -\cs_new_protected_nopar:Npn \fp_sin_aux_ii: - { - \if_case:w \l_fp_trig_octant_int - \or: - \exp_after:wN \fp_trig_calc_sin: - \or: - \exp_after:wN \fp_trig_calc_cos: - \or: - \exp_after:wN \fp_trig_calc_cos: - \or: - \exp_after:wN \fp_trig_calc_sin: - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_cos:Nn, \fp_cos:cn} -% \UnitTested -% \begin{macro}{\fp_gcos:Nn,\fp_gcos:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_cos_aux:NNn} -% \begin{macro}[aux]{\fp_cos_aux_i:} -% \begin{macro}[aux]{\fp_cos_aux_ii:} -% Cosine is almost identical, but there is no short cut code here. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_cos:Nn { \fp_cos_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gcos:Nn { \fp_cos_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_cos:Nn { c } -\cs_generate_variant:Nn \fp_gcos:Nn { c } -\cs_new_protected:Npn \fp_cos_aux:NNn #1#2#3 - { - \group_begin: - \fp_split:Nn a {#3} - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_input_a_integer_int - \l_fp_input_a_decimal_int - \l_fp_input_a_exponent_int - \tl_set:Nx \l_fp_arg_tl - { - \if_int_compare:w \l_fp_input_a_sign_int < \c_zero - - - \else: - + - \fi: - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_input_a_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_input_a_exponent_int - } - \if_cs_exist:w c_fp_cos ( \l_fp_arg_tl ) _fp \cs_end: - \else: - \exp_after:wN \fp_cos_aux_i: - \fi: - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 - { \use:c { c_fp_cos ( \l_fp_arg_tl ) _fp } } - } - \fp_tmp:w - } -% \end{macrocode} -% Almost the same as for sine: just a bit of correction for the sign -% of the output. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_cos_aux_i: - { - \fp_trig_normalise: - \fp_cos_aux_ii: - \if_int_compare:w \l_fp_output_integer_int = \c_one - \l_fp_output_exponent_int \c_zero - \else: - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_decimal_int \l_fp_output_extended_int - \l_fp_output_exponent_int -\c_nine - \fi: - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_output_integer_int - \l_fp_output_decimal_int - \l_fp_output_exponent_int - \tl_new:c { c_fp_cos ( \l_fp_arg_tl ) _fp } - \tl_gset:cx { c_fp_cos ( \l_fp_arg_tl ) _fp } - { - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - + - \else: - - - \fi: - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_output_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_output_exponent_int - } - } -\cs_new_protected_nopar:Npn \fp_cos_aux_ii: - { - \if_case:w \l_fp_trig_octant_int - \or: - \exp_after:wN \fp_trig_calc_cos: - \or: - \exp_after:wN \fp_trig_calc_sin: - \or: - \exp_after:wN \fp_trig_calc_sin: - \or: - \exp_after:wN \fp_trig_calc_cos: - \fi: - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - \if_int_compare:w \l_fp_trig_octant_int > \c_two - \l_fp_input_a_sign_int \c_minus_one - \fi: - \else: - \if_int_compare:w \l_fp_trig_octant_int > \c_two - \else: - \l_fp_input_a_sign_int \c_one - \fi: - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_trig_calc_cos:} -% \begin{macro}{\fp_trig_calc_sin:} -% \begin{macro}[aux]{\fp_trig_calc_Taylor:} -% These functions actually do the calculation for sine and cosine. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_trig_calc_cos: - { - \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero - \l_fp_output_integer_int \c_one - \l_fp_output_decimal_int \c_zero - \else: - \l_fp_trig_sign_int \c_minus_one - \fp_mul:NNNNNN - \l_fp_input_a_decimal_int \l_fp_input_a_extended_int - \l_fp_input_a_decimal_int \l_fp_input_a_extended_int - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \fp_div_integer:NNNNN - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \c_two - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \l_fp_count_int \c_three - \if_int_compare:w \l_fp_trig_extended_int = \c_zero - \if_int_compare:w \l_fp_trig_decimal_int = \c_zero - \l_fp_output_integer_int \c_one - \l_fp_output_decimal_int \c_zero - \l_fp_output_extended_int \c_zero - \else: - \l_fp_output_integer_int \c_zero - \l_fp_output_decimal_int \c_one_thousand_million - \l_fp_output_extended_int \c_zero - \fi: - \else: - \l_fp_output_integer_int \c_zero - \l_fp_output_decimal_int 999999999 \scan_stop: - \l_fp_output_extended_int \c_one_thousand_million - \fi: - \tex_advance:D \l_fp_output_extended_int -\l_fp_trig_extended_int - \tex_advance:D \l_fp_output_decimal_int -\l_fp_trig_decimal_int - \exp_after:wN \fp_trig_calc_Taylor: - \fi: - } -\cs_new_protected_nopar:Npn \fp_trig_calc_sin: - { - \l_fp_output_integer_int \c_zero - \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero - \l_fp_output_decimal_int \c_zero - \else: - \l_fp_output_decimal_int \l_fp_input_a_decimal_int - \l_fp_output_extended_int \l_fp_input_a_extended_int - \l_fp_trig_sign_int \c_one - \l_fp_trig_decimal_int \l_fp_input_a_decimal_int - \l_fp_trig_extended_int \l_fp_input_a_extended_int - \l_fp_count_int \c_two - \exp_after:wN \fp_trig_calc_Taylor: - \fi: - } -% \end{macrocode} -% This implements a Taylor series calculation for the trigonometric -% functions. Lots of shuffling about as \TeX\ is not exactly a natural -% choice for this sort of thing. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_trig_calc_Taylor: - { - \l_fp_trig_sign_int -\l_fp_trig_sign_int - \fp_mul:NNNNNN - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \l_fp_input_a_decimal_int \l_fp_input_a_extended_int - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \fp_mul:NNNNNN - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \l_fp_input_a_decimal_int \l_fp_input_a_extended_int - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \fp_div_integer:NNNNN - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \l_fp_count_int - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \tex_advance:D \l_fp_count_int \c_one - \fp_div_integer:NNNNN - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \l_fp_count_int - \l_fp_trig_decimal_int \l_fp_trig_extended_int - \tex_advance:D \l_fp_count_int \c_one - \if_int_compare:w \l_fp_trig_decimal_int > \c_zero - \if_int_compare:w \l_fp_trig_sign_int > \c_zero - \tex_advance:D \l_fp_output_decimal_int \l_fp_trig_decimal_int - \tex_advance:D \l_fp_output_extended_int - \l_fp_trig_extended_int - \if_int_compare:w \l_fp_output_extended_int < \c_one_thousand_million - \else: - \tex_advance:D \l_fp_output_decimal_int \c_one - \tex_advance:D \l_fp_output_extended_int - -\c_one_thousand_million - \fi: - \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million - \else: - \tex_advance:D \l_fp_output_integer_int \c_one - \tex_advance:D \l_fp_output_decimal_int - -\c_one_thousand_million - \fi: - \else: - \tex_advance:D \l_fp_output_decimal_int -\l_fp_trig_decimal_int - \tex_advance:D \l_fp_output_extended_int - -\l_fp_input_a_extended_int - \if_int_compare:w \l_fp_output_extended_int < \c_zero - \tex_advance:D \l_fp_output_decimal_int \c_minus_one - \tex_advance:D \l_fp_output_extended_int \c_one_thousand_million - \fi: - \if_int_compare:w \l_fp_output_decimal_int < \c_zero - \tex_advance:D \l_fp_output_integer_int \c_minus_one - \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million - \fi: - \fi: - \exp_after:wN \fp_trig_calc_Taylor: - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_tan:Nn, \fp_tan:cn} -% \UnitTested -% \begin{macro}{\fp_gtan:Nn,\fp_gtan:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_tan_aux:NNn} -% \begin{macro}[aux]{\fp_tan_aux_i:} -% \begin{macro}[aux]{\fp_tan_aux_ii:} -% \begin{macro}[aux]{\fp_tan_aux_iii:} -% \begin{macro}[aux]{\fp_tan_aux_iv:} -% As might be expected, tangents are calculated from the sine and cosine -% by division. So there is a bit of set up, the two subsidiary pieces -% of work are done and then a division takes place. For small numbers, -% the same approach is used as for sines, with the input value simply -% returned as is. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_tan:Nn { \fp_tan_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gtan:Nn { \fp_tan_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_tan:Nn { c } -\cs_generate_variant:Nn \fp_gtan:Nn { c } -\cs_new_protected:Npn \fp_tan_aux:NNn #1#2#3 - { - \group_begin: - \fp_split:Nn a {#3} - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_input_a_integer_int - \l_fp_input_a_decimal_int - \l_fp_input_a_exponent_int - \tl_set:Nx \l_fp_arg_tl - { - \if_int_compare:w \l_fp_input_a_sign_int < \c_zero - - - \else: - + - \fi: - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_input_a_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_input_a_exponent_int - } - \if_int_compare:w \l_fp_input_a_exponent_int < -\c_five - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 { \l_fp_arg_tl } - } - \else: - \if_cs_exist:w - c_fp_tan ( \l_fp_arg_tl ) _fp - \cs_end: - \else: - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_tan_aux_i: - \fi: - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 - { \use:c { c_fp_tan ( \l_fp_arg_tl ) _fp } } - } - \fi: - \fp_tmp:w - } -% \end{macrocode} -% The business of the calculation does not check for stored sines or -% cosines as there would then be an overhead to reading them back in. -% There is also no need to worry about \enquote{small} sine values as -% these will have been dealt with earlier. There is a two-step lead off -% so that undefined division is not even attempted. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_tan_aux_i: - { - \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten - \exp_after:wN \fp_tan_aux_ii: - \else: - \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp } - \c_zero_fp - \exp_after:wN \fp_trig_overflow_msg: - \fi: - } -\cs_new_protected_nopar:Npn \fp_tan_aux_ii: - { - \fp_trig_normalise: - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - \if_int_compare:w \l_fp_trig_octant_int > \c_two - \l_fp_output_sign_int \c_minus_one - \else: - \l_fp_output_sign_int \c_one - \fi: - \else: - \if_int_compare:w \l_fp_trig_octant_int > \c_two - \l_fp_output_sign_int \c_one - \else: - \l_fp_output_sign_int \c_minus_one - \fi: - \fi: - \fp_cos_aux_ii: - \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero - \if_int_compare:w \l_fp_input_a_integer_int = \c_zero - \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp } - \c_undefined_fp - \else: - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_tan_aux_iii: - \fi: - \else: - \exp_after:wN \fp_tan_aux_iii: - \fi: - } -% \end{macrocode} -% The division is done here using the same code as the standard division -% unit, shifting the digits in the calculated sine and cosine to -% maintain accuracy. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_tan_aux_iii: - { - \l_fp_input_b_integer_int \l_fp_output_decimal_int - \l_fp_input_b_decimal_int \l_fp_output_extended_int - \l_fp_input_b_exponent_int -\c_nine - \fp_standardise:NNNN - \l_fp_input_b_sign_int - \l_fp_input_b_integer_int - \l_fp_input_b_decimal_int - \l_fp_input_b_exponent_int - \fp_sin_aux_ii: - \l_fp_input_a_integer_int \l_fp_output_decimal_int - \l_fp_input_a_decimal_int \l_fp_output_extended_int - \l_fp_input_a_exponent_int -\c_nine - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_input_a_integer_int - \l_fp_input_a_decimal_int - \l_fp_input_a_exponent_int - \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero - \if_int_compare:w \l_fp_input_a_integer_int = \c_zero - \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp } - \c_zero_fp - \else: - \exp_after:wN \exp_after:wN \exp_after:wN \fp_tan_aux_iv: - \fi: - \else: - \exp_after:wN \fp_tan_aux_iv: - \fi: - } -\cs_new_protected_nopar:Npn \fp_tan_aux_iv: - { - \l_fp_output_integer_int \c_zero - \l_fp_output_decimal_int \c_zero - \cs_set_eq:NN \fp_div_store: \fp_div_store_integer: - \l_fp_div_offset_int \c_one_hundred_million - \fp_div_loop: - \l_fp_output_exponent_int - \int_eval:w - \l_fp_input_a_exponent_int - \l_fp_input_b_exponent_int - \int_eval_end: - \fp_standardise:NNNN - \l_fp_output_sign_int - \l_fp_output_integer_int - \l_fp_output_decimal_int - \l_fp_output_exponent_int - \tl_new:c { c_fp_tan ( \l_fp_arg_tl ) _fp } - \tl_gset:cx { c_fp_tan ( \l_fp_arg_tl ) _fp } - { - \if_int_compare:w \l_fp_output_sign_int > \c_zero - + - \else: - - - \fi: - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_output_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_output_exponent_int - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Exponent and logarithm functions} -% -% \begin{variable}{\c_fp_exp_1_tl} -% \begin{variable}{\c_fp_exp_2_tl} -% \begin{variable}{\c_fp_exp_3_tl} -% \begin{variable}{\c_fp_exp_4_tl} -% \begin{variable}{\c_fp_exp_5_tl} -% \begin{variable}{\c_fp_exp_6_tl} -% \begin{variable}{\c_fp_exp_7_tl} -% \begin{variable}{\c_fp_exp_8_tl} -% \begin{variable}{\c_fp_exp_9_tl} -% \begin{variable}{\c_fp_exp_10_tl} -% \begin{variable}{\c_fp_exp_20_tl} -% \begin{variable}{\c_fp_exp_30_tl} -% \begin{variable}{\c_fp_exp_40_tl} -% \begin{variable}{\c_fp_exp_50_tl} -% \begin{variable}{\c_fp_exp_60_tl} -% \begin{variable}{\c_fp_exp_70_tl} -% \begin{variable}{\c_fp_exp_80_tl} -% \begin{variable}{\c_fp_exp_90_tl} -% \begin{variable}{\c_fp_exp_100_tl} -% \begin{variable}{\c_fp_exp_200_tl} -% Calculation of exponentials requires a number of precomputed values: -% first the positive integers. -% \begin{macrocode} -\tl_const:cn { c_fp_exp_1_tl } { { 2 } { 718281828 } { 459045235 } { 0 } } -\tl_const:cn { c_fp_exp_2_tl } { { 7 } { 389056098 } { 930650227 } { 0 } } -\tl_const:cn { c_fp_exp_3_tl } { { 2 } { 008553692 } { 318766774 } { 1 } } -\tl_const:cn { c_fp_exp_4_tl } { { 5 } { 459815003 } { 314423908 } { 1 } } -\tl_const:cn { c_fp_exp_5_tl } { { 1 } { 484131591 } { 025766034 } { 2 } } -\tl_const:cn { c_fp_exp_6_tl } { { 4 } { 034287934 } { 927351226 } { 2 } } -\tl_const:cn { c_fp_exp_7_tl } { { 1 } { 096633158 } { 428458599 } { 3 } } -\tl_const:cn { c_fp_exp_8_tl } { { 2 } { 980957987 } { 041728275 } { 3 } } -\tl_const:cn { c_fp_exp_9_tl } { { 8 } { 103083927 } { 575384008 } { 3 } } -\tl_const:cn { c_fp_exp_10_tl } { { 2 } { 202646579 } { 480671652 } { 4 } } -\tl_const:cn { c_fp_exp_20_tl } { { 4 } { 851651954 } { 097902280 } { 8 } } -\tl_const:cn { c_fp_exp_30_tl } { { 1 } { 068647458 } { 152446215 } { 13 } } -\tl_const:cn { c_fp_exp_40_tl } { { 2 } { 353852668 } { 370199854 } { 17 } } -\tl_const:cn { c_fp_exp_50_tl } { { 5 } { 184705528 } { 587072464 } { 21 } } -\tl_const:cn { c_fp_exp_60_tl } { { 1 } { 142007389 } { 815684284 } { 26 } } -\tl_const:cn { c_fp_exp_70_tl } { { 2 } { 515438670 } { 919167006 } { 30 } } -\tl_const:cn { c_fp_exp_80_tl } { { 5 } { 540622384 } { 393510053 } { 34 } } -\tl_const:cn { c_fp_exp_90_tl } { { 1 } { 220403294 } { 317840802 } { 39 } } -\tl_const:cn { c_fp_exp_100_tl } { { 2 } { 688117141 } { 816135448 } { 43 } } -\tl_const:cn { c_fp_exp_200_tl } { { 7 } { 225973768 } { 125749258 } { 86 } } -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{variable}{\c_fp_exp_-1_tl} -% \begin{variable}{\c_fp_exp_-2_tl} -% \begin{variable}{\c_fp_exp_-3_tl} -% \begin{variable}{\c_fp_exp_-4_tl} -% \begin{variable}{\c_fp_exp_-5_tl} -% \begin{variable}{\c_fp_exp_-6_tl} -% \begin{variable}{\c_fp_exp_-7_tl} -% \begin{variable}{\c_fp_exp_-8_tl} -% \begin{variable}{\c_fp_exp_-9_tl} -% \begin{variable}{\c_fp_exp_-10_tl} -% \begin{variable}{\c_fp_exp_-20_tl} -% \begin{variable}{\c_fp_exp_-30_tl} -% \begin{variable}{\c_fp_exp_-40_tl} -% \begin{variable}{\c_fp_exp_-50_tl} -% \begin{variable}{\c_fp_exp_-60_tl} -% \begin{variable}{\c_fp_exp_-70_tl} -% \begin{variable}{\c_fp_exp_-80_tl} -% \begin{variable}{\c_fp_exp_-90_tl} -% \begin{variable}{\c_fp_exp_-100_tl} -% \begin{variable}{\c_fp_exp_-200_tl} -% Now the negative integers. -% \begin{macrocode} -\tl_const:cn { c_fp_exp_-1_tl } { { 3 } { 678794411 } { 71442322 } { -1 } } -\tl_const:cn { c_fp_exp_-2_tl } { { 1 } { 353352832 } { 366132692 } { -1 } } -\tl_const:cn { c_fp_exp_-3_tl } { { 4 } { 978706836 } { 786394298 } { -2 } } -\tl_const:cn { c_fp_exp_-4_tl } { { 1 } { 831563888 } { 873418029 } { -2 } } -\tl_const:cn { c_fp_exp_-5_tl } { { 6 } { 737946999 } { 085467097 } { -3 } } -\tl_const:cn { c_fp_exp_-6_tl } { { 2 } { 478752176 } { 666358423 } { -3 } } -\tl_const:cn { c_fp_exp_-7_tl } { { 9 } { 118819655 } { 545162080 } { -4 } } -\tl_const:cn { c_fp_exp_-8_tl } { { 3 } { 354626279 } { 025118388 } { -4 } } -\tl_const:cn { c_fp_exp_-9_tl } { { 1 } { 234098040 } { 866795495 } { -4 } } -\tl_const:cn { c_fp_exp_-10_tl } { { 4 } { 539992976 } { 248451536 } { -5 } } -\tl_const:cn { c_fp_exp_-20_tl } { { 2 } { 061153622 } { 438557828 } { -9 } } -\tl_const:cn { c_fp_exp_-30_tl } { { 9 } { 357622968 } { 840174605 } { -14 } } -\tl_const:cn { c_fp_exp_-40_tl } { { 4 } { 248354255 } { 291588995 } { -18 } } -\tl_const:cn { c_fp_exp_-50_tl } { { 1 } { 928749847 } { 963917783 } { -22 } } -\tl_const:cn { c_fp_exp_-60_tl } { { 8 } { 756510762 } { 696520338 } { -27 } } -\tl_const:cn { c_fp_exp_-70_tl } { { 3 } { 975449735 } { 908646808 } { -31 } } -\tl_const:cn { c_fp_exp_-80_tl } { { 1 } { 804851387 } { 845415172 } { -35 } } -\tl_const:cn { c_fp_exp_-90_tl } { { 8 } { 194012623 } { 990515430 } { -40 } } -\tl_const:cn { c_fp_exp_-100_tl } { { 3 } { 720075976 } { 020835963 } { -44 } } -\tl_const:cn { c_fp_exp_-200_tl } { { 1 } { 383896526 } { 736737530 } { -87 } } -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{macro}{\fp_exp:Nn, \fp_exp:cn} -% \UnitTested -% \begin{macro}{\fp_gexp:Nn,\fp_gexp:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_exp_aux:NNn} -% \begin{macro}[aux]{\fp_exp_internal:} -% \begin{macro}[aux]{\fp_exp_aux:} -% \begin{macro}[aux]{\fp_exp_integer:} -% \begin{macro}[aux]{\fp_exp_integer_tens:} -% \begin{macro}[aux]{\fp_exp_integer_units:} -% \begin{macro}[aux]{\fp_exp_integer_const:n} -% \begin{macro}[aux]{\fp_exp_integer_const:nnnn} -% \begin{macro}[aux]{\fp_exp_decimal:} -% \begin{macro}[aux]{\fp_exp_Taylor:} -% \begin{macro}[aux]{\fp_exp_const:Nx} -% \begin{macro}[aux]{\fp_exp_const:cx} -% The calculation of an exponent starts off starts in much the same -% way as the trigonometric functions: normalise the input, look for -% a pre-defined value and if one is not found hand off to the real -% workhorse function. The test for a definition of the result is used -% so that overflows do not result in any outcome being defined. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_exp:Nn { \fp_exp_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gexp:Nn { \fp_exp_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_exp:Nn { c } -\cs_generate_variant:Nn \fp_gexp:Nn { c } -\cs_new_protected:Npn \fp_exp_aux:NNn #1#2#3 - { - \group_begin: - \fp_split:Nn a {#3} - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_input_a_integer_int - \l_fp_input_a_decimal_int - \l_fp_input_a_exponent_int - \l_fp_input_a_extended_int \c_zero - \tl_set:Nx \l_fp_arg_tl - { - \if_int_compare:w \l_fp_input_a_sign_int < \c_zero - - - \else: - + - \fi: - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_input_a_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_input_a_exponent_int - } - \if_cs_exist:w c_fp_exp ( \l_fp_arg_tl ) _fp \cs_end: - \else: - \exp_after:wN \fp_exp_internal: - \fi: - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - #1 \exp_not:N #2 - { - \if_cs_exist:w c_fp_exp ( \l_fp_arg_tl ) _fp - \cs_end: - \use:c { c_fp_exp ( \l_fp_arg_tl ) _fp } - \else: - \c_zero_fp - \fi: - } - } - \fp_tmp:w - } -% \end{macrocode} -% The first real step is to convert the input into a fixed-point -% representation for further calculation: anything which is dropped -% here as too small would not influence the output in any case. There -% are a couple of overflow tests: the maximum -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_exp_internal: - { - \if_int_compare:w \l_fp_input_a_exponent_int < \c_three - \fp_extended_normalise: - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - \if_int_compare:w \l_fp_input_a_integer_int < 230 \scan_stop: - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \fp_exp_aux: - \else: - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \fp_exp_overflow_msg: - \fi: - \else: - \if_int_compare:w \l_fp_input_a_integer_int < 230 \scan_stop: - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \fp_exp_aux: - \else: - \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp } - { \c_zero_fp } - \fi: - \fi: - \else: - \exp_after:wN \fp_exp_overflow_msg: - \fi: - } -% \end{macrocode} -% The main algorithm makes use of the fact that -% \[ -% \mathrm{e}^{nmp.q} = -% \mathrm{e}^{n} -% \mathrm{e}^{m} -% \mathrm{e}^{p} -% \mathrm{e}^{0.q} -% \] -% and that there is a Taylor series that can be used to calculate -% $ \mathrm{e}^{0.q} $. Thus the approach needed is in three parts. -% First, the exponent of the integer part of the input is found -% using the pre-calculated constants. Second, the Taylor series is -% used to find the exponent for the decimal part of the input. Finally, -% the two parts are multiplied together to give the result. As the -% normalisation code will already have dealt with any overflowing -% values, there are no further checks needed. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_exp_aux: - { - \if_int_compare:w \l_fp_input_a_integer_int > \c_zero - \exp_after:wN \fp_exp_integer: - \else: - \l_fp_output_integer_int \c_one - \l_fp_output_decimal_int \c_zero - \l_fp_output_extended_int \c_zero - \l_fp_output_exponent_int \c_zero - \exp_after:wN \fp_exp_decimal: - \fi: - } -% \end{macrocode} -% The integer part calculation starts with the hundreds. This is -% set up such that very large negative numbers can short-cut the entire -% procedure and simply return zero. In other cases, the code either -% recovers the exponent of the hundreds value or sets the appropriate -% storage to one (so that multiplication works correctly). -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_exp_integer: - { - \if_int_compare:w \l_fp_input_a_integer_int < \c_one_hundred - \l_fp_exp_integer_int \c_one - \l_fp_exp_decimal_int \c_zero - \l_fp_exp_extended_int \c_zero - \l_fp_exp_exponent_int \c_zero - \exp_after:wN \fp_exp_integer_tens: - \else: - \tl_set:Nx \l_fp_internal_tl - { - \exp_after:wN \use_i:nnn - \int_use:N \l_fp_input_a_integer_int - } - \l_fp_input_a_integer_int - \int_eval:w - \l_fp_input_a_integer_int - \l_fp_internal_tl 00 - \int_eval_end: - \if_int_compare:w \l_fp_input_a_sign_int < \c_zero - \if_int_compare:w \l_fp_output_integer_int > 200 \scan_stop: - \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp } - { \c_zero_fp } - \else: - \fp_exp_integer_const:n { - \l_fp_internal_tl 00 } - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \fp_exp_integer_tens: - \fi: - \else: - \fp_exp_integer_const:n { \l_fp_internal_tl 00 } - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \fp_exp_integer_tens: - \fi: - \fi: - } -% \end{macrocode} -% The tens and units parts are handled in a similar way, with a -% multiplication step to build up the final value. That also includes a -% correction step to avoid an overflow of the integer part. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_exp_integer_tens: - { - \l_fp_output_integer_int \l_fp_exp_integer_int - \l_fp_output_decimal_int \l_fp_exp_decimal_int - \l_fp_output_extended_int \l_fp_exp_extended_int - \l_fp_output_exponent_int \l_fp_exp_exponent_int - \if_int_compare:w \l_fp_input_a_integer_int > \c_nine - \tl_set:Nx \l_fp_internal_tl - { - \exp_after:wN \use_i:nn - \int_use:N \l_fp_input_a_integer_int - } - \l_fp_input_a_integer_int - \int_eval:w - \l_fp_input_a_integer_int - \l_fp_internal_tl 0 - \int_eval_end: - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - \fp_exp_integer_const:n { \l_fp_internal_tl 0 } - \else: - \fp_exp_integer_const:n { - \l_fp_internal_tl 0 } - \fi: - \fp_mul:NNNNNNNNN - \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \tex_advance:D \l_fp_output_exponent_int \l_fp_exp_exponent_int - \fp_extended_normalise_output: - \fi: - \fp_exp_integer_units: - } -\cs_new_protected_nopar:Npn \fp_exp_integer_units: - { - \if_int_compare:w \l_fp_input_a_integer_int > \c_zero - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - \fp_exp_integer_const:n { \int_use:N \l_fp_input_a_integer_int } - \else: - \fp_exp_integer_const:n - { - \int_use:N \l_fp_input_a_integer_int } - \fi: - \fp_mul:NNNNNNNNN - \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \tex_advance:D \l_fp_output_exponent_int \l_fp_exp_exponent_int - \fp_extended_normalise_output: - \fi: - \fp_exp_decimal: - } -% \end{macrocode} -% Recovery of the stored constant values into the separate registers -% is done with a simple expansion then assignment. -% \begin{macrocode} -\cs_new_protected:Npn \fp_exp_integer_const:n #1 - { - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_exp_integer_const:nnnn - \cs:w c_fp_exp_ #1 _tl \cs_end: - } -\cs_new_protected:Npn \fp_exp_integer_const:nnnn #1#2#3#4 - { - \l_fp_exp_integer_int #1 \scan_stop: - \l_fp_exp_decimal_int #2 \scan_stop: - \l_fp_exp_extended_int #3 \scan_stop: - \l_fp_exp_exponent_int #4 \scan_stop: - } -% \end{macrocode} -% Finding the exponential for the decimal part of the number requires -% a Taylor series calculation. The set up is done here with the loop -% itself a separate function. Once the decimal part is available this -% is multiplied by the integer part already worked out to give -% the final result. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_exp_decimal: - { - \if_int_compare:w \l_fp_input_a_decimal_int > \c_zero - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - \l_fp_exp_integer_int \c_one - \l_fp_exp_decimal_int \l_fp_input_a_decimal_int - \l_fp_exp_extended_int \l_fp_input_a_extended_int - \else: - \l_fp_exp_integer_int \c_zero - \if_int_compare:w \l_fp_exp_extended_int = \c_zero - \l_fp_exp_decimal_int - \int_eval:w - \c_one_thousand_million - \l_fp_input_a_decimal_int - \int_eval_end: - \l_fp_exp_extended_int \c_zero - \else: - \l_fp_exp_decimal_int - \int_eval:w - 999999999 - \l_fp_input_a_decimal_int - \scan_stop: - \l_fp_exp_extended_int - \int_eval:w - \c_one_thousand_million - \l_fp_input_a_extended_int - \int_eval_end: - \fi: - \fi: - \l_fp_input_b_sign_int \l_fp_input_a_sign_int - \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int - \l_fp_input_b_extended_int \l_fp_input_a_extended_int - \l_fp_count_int \c_one - \fp_exp_Taylor: - \fp_mul:NNNNNNNNN - \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \fi: - \if_int_compare:w \l_fp_output_extended_int < \c_five_hundred_million - \else: - \tex_advance:D \l_fp_output_decimal_int \c_one - \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million - \else: - \l_fp_output_decimal_int \c_zero - \tex_advance:D \l_fp_output_integer_int \c_one - \fi: - \fi: - \fp_standardise:NNNN - \l_fp_output_sign_int - \l_fp_output_integer_int - \l_fp_output_decimal_int - \l_fp_output_exponent_int - \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp } - { - + - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_output_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_output_exponent_int - } - } -% \end{macrocode} -% The Taylor series for $ \exp(x) $ is -% \[ -% 1 + x + \frac{x^2}{2!} + \frac{x^3}{3!} + \frac{x^4}{4!} + \cdots -% \] -% which converges for $ -1 < x < 1 $. The code above sets up -% the $ x $ part, leaving the loop to multiply the running -% value by $ x / n $ and add it onto the sum. The way that this is -% done is that the running total is stored in the \texttt{exp} set of -% registers, while the current item is stored as \texttt{input_b}. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_exp_Taylor: - { - \tex_advance:D \l_fp_count_int \c_one - \tex_multiply:D \l_fp_input_b_sign_int \l_fp_input_a_sign_int - \fp_mul:NNNNNN - \l_fp_input_a_decimal_int \l_fp_input_a_extended_int - \l_fp_input_b_decimal_int \l_fp_input_b_extended_int - \l_fp_input_b_decimal_int \l_fp_input_b_extended_int - \fp_div_integer:NNNNN - \l_fp_input_b_decimal_int \l_fp_input_b_extended_int - \l_fp_count_int - \l_fp_input_b_decimal_int \l_fp_input_b_extended_int - \if_int_compare:w - \int_eval:w - \l_fp_input_b_decimal_int + \l_fp_input_b_extended_int - > \c_zero - \if_int_compare:w \l_fp_input_b_sign_int > \c_zero - \tex_advance:D \l_fp_exp_decimal_int \l_fp_input_b_decimal_int - \tex_advance:D \l_fp_exp_extended_int - \l_fp_input_b_extended_int - \if_int_compare:w \l_fp_exp_extended_int < \c_one_thousand_million - \else: - \tex_advance:D \l_fp_exp_decimal_int \c_one - \tex_advance:D \l_fp_exp_extended_int - -\c_one_thousand_million - \fi: - \if_int_compare:w \l_fp_exp_decimal_int < \c_one_thousand_million - \else: - \tex_advance:D \l_fp_exp_integer_int \c_one - \tex_advance:D \l_fp_exp_decimal_int - -\c_one_thousand_million - \fi: - \else: - \tex_advance:D \l_fp_exp_decimal_int -\l_fp_input_b_decimal_int - \tex_advance:D \l_fp_exp_extended_int - -\l_fp_input_a_extended_int - \if_int_compare:w \l_fp_exp_extended_int < \c_zero - \tex_advance:D \l_fp_exp_decimal_int \c_minus_one - \tex_advance:D \l_fp_exp_extended_int \c_one_thousand_million - \fi: - \if_int_compare:w \l_fp_exp_decimal_int < \c_zero - \tex_advance:D \l_fp_exp_integer_int \c_minus_one - \tex_advance:D \l_fp_exp_decimal_int \c_one_thousand_million - \fi: - \fi: - \exp_after:wN \fp_exp_Taylor: - \fi: - } -% \end{macrocode} -% This is set up as a function so that the power code can redirect -% the effect. -% \begin{macrocode} -\cs_new_protected:Npn \fp_exp_const:Nx #1#2 - { - \tl_new:N #1 - \tl_gset:Nx #1 {#2} - } -\cs_generate_variant:Nn \fp_exp_const:Nx { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{variable}{\c_fp_ln_10_1_tl} -% \begin{variable}{\c_fp_ln_10_2_tl} -% \begin{variable}{\c_fp_ln_10_3_tl} -% \begin{variable}{\c_fp_ln_10_4_tl} -% \begin{variable}{\c_fp_ln_10_5_tl} -% \begin{variable}{\c_fp_ln_10_6_tl} -% \begin{variable}{\c_fp_ln_10_7_tl} -% \begin{variable}{\c_fp_ln_10_8_tl} -% \begin{variable}{\c_fp_ln_10_9_tl} -% Constants for working out logarithms: first those for the powers of -% ten. -% \begin{macrocode} -\tl_const:cn { c_fp_ln_10_1_tl } { { 2 } { 302585092 } { 994045684 } { 0 } } -\tl_const:cn { c_fp_ln_10_2_tl } { { 4 } { 605170185 } { 988091368 } { 0 } } -\tl_const:cn { c_fp_ln_10_3_tl } { { 6 } { 907755278 } { 982137052 } { 0 } } -\tl_const:cn { c_fp_ln_10_4_tl } { { 9 } { 210340371 } { 976182736 } { 0 } } -\tl_const:cn { c_fp_ln_10_5_tl } { { 1 } { 151292546 } { 497022842 } { 1 } } -\tl_const:cn { c_fp_ln_10_6_tl } { { 1 } { 381551055 } { 796427410 } { 1 } } -\tl_const:cn { c_fp_ln_10_7_tl } { { 1 } { 611809565 } { 095831979 } { 1 } } -\tl_const:cn { c_fp_ln_10_8_tl } { { 1 } { 842068074 } { 395226547 } { 1 } } -\tl_const:cn { c_fp_ln_10_9_tl } { { 2 } { 072326583 } { 694641116 } { 1 } } -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -% \end{variable} -%^^A 0.69...309 4. -% \begin{variable}{\c_fp_ln_2_1_tl } -% \begin{variable}{\c_fp_ln_2_2_tl } -% \begin{variable}{\c_fp_ln_2_3_tl } -% The smaller set for powers of two. -% \begin{macrocode} -\tl_const:cn { c_fp_ln_2_1_tl } { { 0 } { 693147180 } { 559945309 } { 0 } } -\tl_const:cn { c_fp_ln_2_2_tl } { { 1 } { 386294361 } { 119890618 } { 0 } } -\tl_const:cn { c_fp_ln_2_3_tl } { { 2 } { 079441541 } { 679835928 } { 0 } } -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{variable} -% -% \begin{macro}{\fp_ln:Nn, \fp_ln:cn} -% \UnitTested -% \begin{macro}{\fp_gln:Nn,\fp_gln:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_ln_aux:NNn} -% \begin{macro}[aux]{\fp_ln_aux:} -% \begin{macro}[aux]{\fp_ln_exponent:} -% \begin{macro}[aux]{\fp_ln_internal:} -% \begin{macro}[aux]{\fp_ln_exponent_tens:} -% \begin{macro}[aux]{\fp_ln_exponent_units:} -% \begin{macro}[aux]{\fp_ln_normalise:} -% \begin{macro}[aux]{\fp_ln_nornalise_aux:NNNNNNNNN} -% \begin{macro}[aux]{\fp_ln_mantissa:} -% \begin{macro}[aux]{\fp_ln_mantissa_aux:} -% \begin{macro}[aux]{\fp_ln_mantissa_divide_two:} -% \begin{macro}[aux]{\fp_ln_integer_const:nn} -% \begin{macro}[aux]{\fp_ln_Taylor:} -% \begin{macro}[aux]{\fp_ln_fixed:} -% \begin{macro}[aux]{\fp_ln_fixed_aux:NNNNNNNNN} -% \begin{macro}[aux]{\fp_ln_Taylor_aux:} -% The approach for logarithms is again based on a mix of tables and -% Taylor series. Here, the initial validation is a bit easier and so it -% is set up earlier, meaning less need to escape later on. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_ln:Nn { \fp_ln_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gln:Nn { \fp_ln_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_ln:Nn { c } -\cs_generate_variant:Nn \fp_gln:Nn { c } -\cs_new_protected:Npn \fp_ln_aux:NNn #1#2#3 - { - \group_begin: - \fp_split:Nn a {#3} - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_input_a_integer_int - \l_fp_input_a_decimal_int - \l_fp_input_a_exponent_int - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - \if_int_compare:w - \int_eval:w - \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int - > \c_zero - \exp_after:wN \exp_after:wN \exp_after:wN \fp_ln_aux: - \else: - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 \exp_not:N ##2 { \c_zero_fp } - } - \exp_after:wN \exp_after:wN \exp_after:wN \fp_ln_error_msg: - \fi: - \else: - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 \exp_not:N ##2 { \c_zero_fp } - } - \exp_after:wN \fp_ln_error_msg: - \fi: - \fp_tmp:w #1 #2 - } -% \end{macrocode} -% As the input at this stage meets the validity criteria above, the -% argument can now be saved for further processing. There is no need -% to look at the sign of the input as it must be positive. The function -% here simply sets up to either do the full calculation or recover -% the stored value, as appropriate. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_ln_aux: - { - \tl_set:Nx \l_fp_arg_tl - { - + - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_input_a_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_input_a_exponent_int - } - \if_cs_exist:w c_fp_ln ( \l_fp_arg_tl ) _fp \cs_end: - \else: - \exp_after:wN \fp_ln_exponent: - \fi: - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 \exp_not:N ##2 - { \use:c { c_fp_ln ( \l_fp_arg_tl ) _fp } } - } - } -% \end{macrocode} -% The main algorithm here uses the fact the logarithm can be divided -% up, first taking out the powers of ten, then powers of two and finally -% using a Taylor series for the remainder. -% \[ -% \ln ( 10^{n} \times 2^{m} \times x ) -% = \ln ( 10^{n} ) + \ln ( 2^{m} ) + \ln ( x ) -% \] -% The second point to remember is that -% \[ -% \ln ( x^{-1} ) = - \ln ( x ) -% \] -% which means that for the powers of $ 10 $ and $ 2 $ constants -% are only needed for positive powers. -% -% The first step is to set up the sign for the output functions and -% work out the powers of ten in the exponent. First the larger powers -% are sorted out. The values for the constants are the same as those -% for the smaller ones, just with a shift in the exponent. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_ln_exponent: - { - \fp_ln_internal: - \if_int_compare:w \l_fp_output_extended_int < \c_five_hundred_million - \else: - \tex_advance:D \l_fp_output_decimal_int \c_one - \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million - \else: - \l_fp_output_decimal_int \c_zero - \tex_advance:D \l_fp_output_integer_int \c_one - \fi: - \fi: - \fp_standardise:NNNN - \l_fp_output_sign_int - \l_fp_output_integer_int - \l_fp_output_decimal_int - \l_fp_output_exponent_int - \tl_const:cx { c_fp_ln ( \l_fp_arg_tl ) _fp } - { - \if_int_compare:w \l_fp_output_sign_int > \c_zero - + - \else: - - - \fi: - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_output_decimal_int + \c_one_thousand_million - \scan_stop: - e - \int_use:N \l_fp_output_exponent_int - } - } -\cs_new_protected_nopar:Npn \fp_ln_internal: - { - \if_int_compare:w \l_fp_input_a_exponent_int < \c_zero - \l_fp_input_a_exponent_int -\l_fp_input_a_exponent_int - \l_fp_output_sign_int \c_minus_one - \else: - \l_fp_output_sign_int \c_one - \fi: - \if_int_compare:w \l_fp_input_a_exponent_int > \c_nine - \exp_after:wN \fp_ln_exponent_tens:NN - \int_use:N \l_fp_input_a_exponent_int - \else: - \l_fp_output_integer_int \c_zero - \l_fp_output_decimal_int \c_zero - \l_fp_output_extended_int \c_zero - \l_fp_output_exponent_int \c_zero - \fi: - \fp_ln_exponent_units: - } -\cs_new_protected:Npn \fp_ln_exponent_tens:NN #1 #2 - { - \l_fp_input_a_exponent_int #2 \scan_stop: - \fp_ln_const:nn { 10 } { #1 } - \tex_advance:D \l_fp_exp_exponent_int \c_one - \l_fp_output_integer_int \l_fp_exp_integer_int - \l_fp_output_decimal_int \l_fp_exp_decimal_int - \l_fp_output_extended_int \l_fp_exp_extended_int - \l_fp_output_exponent_int \l_fp_exp_exponent_int - } -% \end{macrocode} -% Next the smaller powers of ten, which will need to be combined -% with the above: always an additive process. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_ln_exponent_units: - { - \if_int_compare:w \l_fp_input_a_exponent_int > \c_zero - \fp_ln_const:nn { 10 } { \int_use:N \l_fp_input_a_exponent_int } - \fp_ln_normalise: - \fp_add:NNNNNNNNN - \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \fi: - \fp_ln_mantissa: - } -% \end{macrocode} -% The smaller table-based parts may need to be exponent shifted so that -% they stay in line with the larger parts. This is similar to the -% approach in other places, but here there is a need to watch the -% extended part of the number. The only case where the new exponent is -% larger than the old is if there was no previous part. Then simply set -% the exponent. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_ln_normalise: - { - \if_int_compare:w \l_fp_exp_exponent_int < \l_fp_output_exponent_int - \tex_advance:D \l_fp_exp_decimal_int \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_ln_normalise_aux:NNNNNNNNN - \int_use:N \l_fp_exp_decimal_int - \exp_after:wN \fp_ln_normalise: - \else: - \l_fp_output_exponent_int \l_fp_exp_exponent_int - \fi: - } -\cs_new_protected:Npn \fp_ln_normalise_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - { - \if_int_compare:w \l_fp_exp_integer_int = \c_zero - \l_fp_exp_decimal_int #1#2#3#4#5#6#7#8 \scan_stop: - \else: - \tl_set:Nx \l_fp_internal_tl - { - \int_use:N \l_fp_exp_integer_int - #1#2#3#4#5#6#7#8 - } - \l_fp_exp_integer_int \c_zero - \l_fp_exp_decimal_int \l_fp_internal_tl \scan_stop: - \fi: - \tex_divide:D \l_fp_exp_extended_int \c_ten - \tl_set:Nx \l_fp_internal_tl - { - #9 - \int_use:N \l_fp_exp_extended_int - } - \l_fp_exp_extended_int \l_fp_internal_tl \scan_stop: - \tex_advance:D \l_fp_exp_exponent_int \c_one - } -% \end{macrocode} -% The next phase is to decompose the mantissa by division by two to -% leave a value which is in the range $ 1 \le x < 2 $. The sum of the -% two powers needs to take account of the sign of the output: if it -% is negative then the result gets \emph{smaller} as the mantissa gets -% \emph{bigger}. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_ln_mantissa: - { - \l_fp_count_int \c_zero - \l_fp_input_a_extended_int \c_zero - \fp_ln_mantissa_aux: - \if_int_compare:w \l_fp_count_int > \c_zero - \fp_ln_const:nn { 2 } { \int_use:N \l_fp_count_int } - \fp_ln_normalise: - \if_int_compare:w \l_fp_output_sign_int > \c_zero - \exp_after:wN \fp_add:NNNNNNNNN - \else: - \exp_after:wN \fp_sub:NNNNNNNNN - \fi: - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \fi: - \if_int_compare:w - \int_eval:w - \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int > \c_one - \exp_after:wN \fp_ln_Taylor: - \fi: - } -\cs_new_protected_nopar:Npn \fp_ln_mantissa_aux: - { - \if_int_compare:w \l_fp_input_a_integer_int > \c_one - \tex_advance:D \l_fp_count_int \c_one - \fp_ln_mantissa_divide_two: - \exp_after:wN \fp_ln_mantissa_aux: - \fi: - } -% \end{macrocode} -% A fast one-shot division by two. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_ln_mantissa_divide_two: - { - \if_int_odd:w \l_fp_input_a_decimal_int - \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million - \fi: - \if_int_odd:w \l_fp_input_a_integer_int - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \fi: - \tex_divide:D \l_fp_input_a_integer_int \c_two - \tex_divide:D \l_fp_input_a_decimal_int \c_two - \tex_divide:D \l_fp_input_a_extended_int \c_two - } -% \end{macrocode} -% Recovering constants makes use of the same auxiliary code as for -% exponents. -% \begin{macrocode} -\cs_new_protected:Npn \fp_ln_const:nn #1#2 - { - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_exp_integer_const:nnnn - \cs:w c_fp_ln_ #1 _ #2 _tl \cs_end: - } -% \end{macrocode} -% The Taylor series for the logarithm function is best implemented using -% the identity -% \[ -% \ln(x) = \ln\left( \frac{y + 1}{y - 1} \right) -% \] -% with -% \[ -% y = \frac{x - 1}{x + 1} -% \] -% This leads to the series -% \[ -% \ln(x) -% = 2y -% \left( -% 1 + y^{2} -% \left( -% \frac{1}{3} + y^{2} -% \left( -% \frac{1}{5} + y^{2} -% \left( -% \frac{1}{7} + y^{2} -% \left( -% \frac{1}{9} + \cdots -% \right) -% \right) -% \right) -% \right) -% \right) -% \] -% This expansion has the advantage that a lot of the work can be -% loaded up early by finding $ y^{2} $ before the loop itself starts. -% (In practice, the implementation does the multiplication by two at the -% end of the loop, and expands out the brackets as this is an overall -% more efficient approach.) -% -% At the implementation level, the code starts by calculating $ y $ -% and storing that in input \texttt{a} (which is no longer needed -% for other purposes). That is done using the full division system -% avoiding the parsing step. The value is then switched to a fixed-point -% representation. There is then some shuffling to get all of the working -% space set up. At this stage, a lot of registers are in use and so -% the Taylor series is calculated within a group so that the -% \texttt{output} variables can be used to hold the result. The value -% of $ y^{2} $ is held in input \texttt{b} (there are a few -% assignments saved by choosing this over \texttt{a}), while input -% \texttt{a} is used for the \enquote{loop value}. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_ln_Taylor: - { - \group_begin: - \l_fp_input_a_integer_int \c_zero - \l_fp_input_a_exponent_int \c_zero - \l_fp_input_b_integer_int \c_two - \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int - \l_fp_input_b_exponent_int \c_zero - \fp_div_internal: - \fp_ln_fixed: - \l_fp_input_a_integer_int \l_fp_output_integer_int - \l_fp_input_a_decimal_int \l_fp_output_decimal_int - \l_fp_input_a_extended_int \c_zero - \l_fp_input_a_exponent_int \l_fp_output_exponent_int - \l_fp_output_decimal_int \c_zero %^^A Bug? - \l_fp_output_decimal_int \l_fp_input_a_decimal_int - \l_fp_output_extended_int \l_fp_input_a_extended_int - \fp_mul:NNNNNN - \l_fp_input_a_decimal_int \l_fp_input_a_extended_int - \l_fp_input_a_decimal_int \l_fp_input_a_extended_int - \l_fp_input_b_decimal_int \l_fp_input_b_extended_int - \l_fp_count_int \c_one - \fp_ln_Taylor_aux: - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - \l_fp_exp_integer_int \c_zero - \exp_not:N \l_fp_exp_decimal_int - \int_use:N \l_fp_output_decimal_int \scan_stop: - \exp_not:N \l_fp_exp_extended_int - \int_use:N \l_fp_output_extended_int \scan_stop: - \exp_not:N \l_fp_exp_exponent_int - \int_use:N \l_fp_output_exponent_int \scan_stop: - } - \fp_tmp:w -% \end{macrocode} -% After the loop part of the Taylor series, the factor of $ 2 $ needs -% to be included. The total for the result can then be constructed. -% \begin{macrocode} - \tex_advance:D \l_fp_exp_decimal_int \l_fp_exp_decimal_int - \if_int_compare:w \l_fp_exp_extended_int < \c_five_hundred_million - \else: - \tex_advance:D \l_fp_exp_extended_int -\c_five_hundred_million - \tex_advance:D \l_fp_exp_decimal_int \c_one - \fi: - \tex_advance:D \l_fp_exp_extended_int \l_fp_exp_extended_int - \fp_ln_normalise: - \if_int_compare:w \l_fp_output_sign_int > \c_zero - \exp_after:wN \fp_add:NNNNNNNNN - \else: - \exp_after:wN \fp_sub:NNNNNNNNN - \fi: - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \c_zero \l_fp_exp_decimal_int \l_fp_exp_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - } -% \end{macrocode} -% The usual shifts to move to fixed-point working. This is done using -% the \texttt{output} registers as this saves a reassignment here. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_ln_fixed: - { - \if_int_compare:w \l_fp_output_exponent_int < \c_zero - \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_ln_fixed_aux:NNNNNNNNN - \int_use:N \l_fp_output_decimal_int - \exp_after:wN \fp_ln_fixed: - \fi: - } -\cs_new_protected:Npn \fp_ln_fixed_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 - { - \if_int_compare:w \l_fp_output_integer_int = \c_zero - \l_fp_output_decimal_int #1#2#3#4#5#6#7#8 \scan_stop: - \else: - \tl_set:Nx \l_fp_internal_tl - { - \int_use:N \l_fp_output_integer_int - #1#2#3#4#5#6#7#8 - } - \l_fp_output_integer_int \c_zero - \l_fp_output_decimal_int \l_fp_internal_tl \scan_stop: - \fi: - \tex_advance:D \l_fp_output_exponent_int \c_one - } -% \end{macrocode} -% The main loop for the Taylor series: unlike some of the other similar -% functions, the result here is not the final value and is therefore -% subject to further manipulation outside of the loop. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_ln_Taylor_aux: - { - \tex_advance:D \l_fp_count_int \c_two - \fp_mul:NNNNNN - \l_fp_input_a_decimal_int \l_fp_input_a_extended_int - \l_fp_input_b_decimal_int \l_fp_input_b_extended_int - \l_fp_input_a_decimal_int \l_fp_input_a_extended_int - \if_int_compare:w - \int_eval:w - \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int - > \c_zero - \fp_div_integer:NNNNN - \l_fp_input_a_decimal_int \l_fp_input_a_extended_int - \l_fp_count_int - \l_fp_exp_decimal_int \l_fp_exp_extended_int - \tex_advance:D \l_fp_output_decimal_int \l_fp_exp_decimal_int - \tex_advance:D \l_fp_output_extended_int \l_fp_exp_extended_int - \if_int_compare:w \l_fp_output_extended_int < \c_one_thousand_million - \else: - \tex_advance:D \l_fp_output_decimal_int \c_one - \tex_advance:D \l_fp_output_extended_int - -\c_one_thousand_million - \fi: - \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million - \else: - \tex_advance:D \l_fp_output_integer_int \c_one - \tex_advance:D \l_fp_output_decimal_int - -\c_one_thousand_million - \fi: - \exp_after:wN \fp_ln_Taylor_aux: - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fp_pow:Nn, \fp_pow:cn} -% \UnitTested -% \begin{macro}{\fp_gpow:Nn,\fp_gpow:cn} -% \UnitTested -% \begin{macro}[aux]{\fp_pow_aux:NNn} -% \begin{macro}[aux]{\fp_pow_aux_i:} -% \begin{macro}[aux]{\fp_pow_positive:} -% \begin{macro}[aux]{\fp_pow_negative:} -% \begin{macro}[aux]{\fp_pow_aux_ii:} -% \begin{macro}[aux]{\fp_pow_aux_iii:} -% \begin{macro}[aux]{\fp_pow_aux_iv:} -% The approach used for working out powers is to first filter out the -% various special cases and then do most of the work using the -% logarithm and exponent functions. The two storage areas are used -% in the reverse of the `natural' logic as this avoids some -% re-assignment in the sanity checking code. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_pow:Nn { \fp_pow_aux:NNn \tl_set:Nn } -\cs_new_protected_nopar:Npn \fp_gpow:Nn { \fp_pow_aux:NNn \tl_gset:Nn } -\cs_generate_variant:Nn \fp_pow:Nn { c } -\cs_generate_variant:Nn \fp_gpow:Nn { c } -\cs_new_protected:Npn \fp_pow_aux:NNn #1#2#3 - { - \group_begin: - \fp_read:N #2 - \l_fp_input_b_sign_int \l_fp_input_a_sign_int - \l_fp_input_b_integer_int \l_fp_input_a_integer_int - \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int - \l_fp_input_b_exponent_int \l_fp_input_a_exponent_int - \fp_split:Nn a {#3} - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_input_a_integer_int - \l_fp_input_a_decimal_int - \l_fp_input_a_exponent_int - \if_int_compare:w - \int_eval:w - \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int - = \c_zero - \if_int_compare:w - \int_eval:w - \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int - = \c_zero - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 ##2 { \c_undefined_fp } - } - \else: - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 ##2 { \c_zero_fp } - } - \fi: - \else: - \if_int_compare:w - \int_eval:w - \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int - = \c_zero - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 ##2 { \c_one_fp } - } - \else: - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_pow_aux_i: - \fi: - \fi: - \fp_tmp:w #1 #2 -} -% \end{macrocode} -% Simply using the logarithm function directly will fail when negative -% numbers are raised to integer powers, which is a mathematically valid -% operation. So there are some more tests to make, after forcing the -% power into an integer and decimal parts, if necessary. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_pow_aux_i: - { - \if_int_compare:w \l_fp_input_b_sign_int > \c_zero - \tl_set:Nn \l_fp_sign_tl { + } - \exp_after:wN \fp_pow_aux_ii: - \else: - \l_fp_input_a_extended_int \c_zero - \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten - \group_begin: - \fp_extended_normalise: - \if_int_compare:w - \int_eval:w - \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int - = \c_zero - \group_end: - \tl_set:Nn \l_fp_sign_tl { - } - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \fp_pow_aux_ii: - \else: - \group_end: - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 ##2 { \c_undefined_fp } - } - \fi: - \else: - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 ##2 { \c_undefined_fp } - } - \fi: - \fi: - } -% \end{macrocode} -% The approach used here for powers works well in most cases but gives -% poorer results for negative integer powers, which often have exact -% values. So there is some filtering to do. For negative powers where -% the power is small, an alternative approach is used in which the -% positive value is worked out and the reciprocal is then taken. The -% filtering is unfortunately rather long. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_pow_aux_ii: - { - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - \exp_after:wN \fp_pow_aux_iv: - \else: - \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten - \group_begin: - \l_fp_input_a_extended_int \c_zero - \fp_extended_normalise: - \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero - \if_int_compare:w \l_fp_input_a_integer_int > \c_ten - \group_end: - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_pow_aux_iv: - \else: - \group_end: - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \fp_pow_aux_iii: - \fi: - \else: - \group_end: - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \exp_after:wN \exp_after:wN - \exp_after:wN \fp_pow_aux_iv: - \fi: - \else: - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_pow_aux_iv: - \fi: - \fi: - \cs_set_protected:Npx \fp_tmp:w ##1##2 - { - \group_end: - ##1 ##2 - { - \l_fp_sign_tl - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_value:w \int_eval:w - \l_fp_output_decimal_int + \c_one_thousand_million - e - \int_use:N \l_fp_output_exponent_int - } - } - } -% \end{macrocode} -% For the small negative integer powers, the calculation is done for -% the positive power and the reciprocal is then taken. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_pow_aux_iii: - { - \l_fp_input_a_sign_int \c_one - \fp_pow_aux_iv: - \l_fp_input_a_integer_int \c_one - \l_fp_input_a_decimal_int \c_zero - \l_fp_input_a_exponent_int \c_zero - \l_fp_input_b_integer_int \l_fp_output_integer_int - \l_fp_input_b_decimal_int \l_fp_output_decimal_int - \l_fp_input_b_exponent_int \l_fp_output_exponent_int - \fp_div_internal: - } -% \end{macrocode} -% The business end of the code starts by finding the logarithm of the -% given base. There is a bit of a shuffle so that this does not have -% to be re-parsed and so that the output ends up in the correct place. -% There is also a need to enable using the short-cut for a -% pre-calculated result. The internal part of the multiplication -% function can then be used to do the second part of the calculation -% directly. There is some more set up before doing the exponential: -% the idea here is to deactivate some internals so that everything works -% smoothly. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_pow_aux_iv: - { - \group_begin: - \l_fp_input_a_integer_int \l_fp_input_b_integer_int - \l_fp_input_a_decimal_int \l_fp_input_b_decimal_int - \l_fp_input_a_exponent_int \l_fp_input_b_exponent_int - \fp_ln_internal: - \cs_set_protected_nopar:Npx \fp_tmp:w - { - \group_end: - \exp_not:N \l_fp_input_b_sign_int - \int_use:N \l_fp_output_sign_int \scan_stop: - \exp_not:N \l_fp_input_b_integer_int - \int_use:N \l_fp_output_integer_int \scan_stop: - \exp_not:N \l_fp_input_b_decimal_int - \int_use:N \l_fp_output_decimal_int \scan_stop: - \exp_not:N \l_fp_input_b_extended_int - \int_use:N \l_fp_output_extended_int \scan_stop: - \exp_not:N \l_fp_input_b_exponent_int - \int_use:N \l_fp_output_exponent_int \scan_stop: - } - \fp_tmp:w - \l_fp_input_a_extended_int \c_zero - \fp_mul:NNNNNNNNN - \l_fp_input_a_integer_int \l_fp_input_a_decimal_int - \l_fp_input_a_extended_int - \l_fp_input_b_integer_int \l_fp_input_b_decimal_int - \l_fp_input_b_extended_int - \l_fp_output_integer_int \l_fp_output_decimal_int - \l_fp_output_extended_int - \l_fp_output_exponent_int - \int_eval:w - \l_fp_input_a_exponent_int + \l_fp_input_b_exponent_int - \scan_stop: - \fp_extended_normalise_output: - \tex_multiply:D \l_fp_input_a_sign_int \l_fp_input_b_sign_int - \l_fp_input_a_integer_int \l_fp_output_integer_int - \l_fp_input_a_decimal_int \l_fp_output_decimal_int - \l_fp_input_a_extended_int \l_fp_output_extended_int - \l_fp_input_a_exponent_int \l_fp_output_exponent_int - \l_fp_output_integer_int \c_zero - \l_fp_output_decimal_int \c_zero - \l_fp_output_extended_int \c_zero - \l_fp_output_exponent_int \c_zero - \cs_set_eq:NN \fp_exp_const:Nx \use_none:nn - \fp_exp_internal: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % -% \subsection{Tests for special values} -% -% \begin{macro}[pTF]{\fp_if_undefined:N} -% \UnitTested -% Testing for an undefined value is easy. -% \begin{macrocode} -\prg_new_conditional:Npnn \fp_if_undefined:N #1 { p , T , F , TF } - { - \if_meaning:w #1 \c_undefined_fp - \prg_return_true: - \else: - \prg_return_false: - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[pTF]{\fp_if_zero:N} -% \UnitTested -% Testing for a zero fixed-point is also easy. -% \begin{macrocode} -\prg_new_conditional:Npnn \fp_if_zero:N #1 { p , T , F , TF } - { - \if_meaning:w #1 \c_zero_fp - \prg_return_true: - \else: - \prg_return_false: - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \subsection{Floating-point conditionals} -% -% \begin{macro}[TF]{\fp_compare:nNn} -% \begin{macro}[TF]{\fp_compare:NNN} -% \UnitTested -% \begin{macro}[aux]{\fp_compare_aux:N} -% \begin{macro}[aux]{\fp_compare_=:} -% \begin{macro}[aux]{\fp_compare_<:} -% \begin{macro}[aux]{\fp_compare_<_aux:} -% \begin{macro}[aux]{\fp_compare_absolute_a>b:} -% \begin{macro}[aux]{\fp_compare_absolute_a<b:} -% \begin{macro}[aux]{\fp_compare_>:} -% The idea for the comparisons is to provide two versions: slower and -% faster. The lead off for both is the same: get the two numbers -% read and then look for a function to handle the comparison. -% \begin{macrocode} -\prg_new_protected_conditional:Npnn \fp_compare:nNn #1#2#3 { T , F , TF } - { - \group_begin: - \fp_split:Nn a {#1} - \fp_standardise:NNNN - \l_fp_input_a_sign_int - \l_fp_input_a_integer_int - \l_fp_input_a_decimal_int - \l_fp_input_a_exponent_int - \fp_split:Nn b {#3} - \fp_standardise:NNNN - \l_fp_input_b_sign_int - \l_fp_input_b_integer_int - \l_fp_input_b_decimal_int - \l_fp_input_b_exponent_int - \fp_compare_aux:N #2 - } -\prg_new_protected_conditional:Npnn \fp_compare:NNN #1#2#3 { T , F , TF } - { - \group_begin: - \fp_read:N #3 - \l_fp_input_b_sign_int \l_fp_input_a_sign_int - \l_fp_input_b_integer_int \l_fp_input_a_integer_int - \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int - \l_fp_input_b_exponent_int \l_fp_input_a_exponent_int - \fp_read:N #1 - \fp_compare_aux:N #2 - } -\cs_new_protected:Npn \fp_compare_aux:N #1 - { - \cs_if_exist:cTF { fp_compare_#1: } - { \use:c { fp_compare_#1: } } - { - \group_end: - \prg_return_false: - } - } -% \end{macrocode} -% For equality, the test is pretty easy as things are either equal or -% they are not. -% \begin{macrocode} -\cs_new_protected_nopar:cpn { fp_compare_=: } - { - \if_int_compare:w \l_fp_input_a_sign_int = \l_fp_input_b_sign_int - \if_int_compare:w \l_fp_input_a_integer_int = \l_fp_input_b_integer_int - \if_int_compare:w \l_fp_input_a_decimal_int = \l_fp_input_b_decimal_int - \if_int_compare:w - \l_fp_input_a_exponent_int = \l_fp_input_b_exponent_int - \group_end: - \prg_return_true: - \else: - \group_end: - \prg_return_false: - \fi: - \else: - \group_end: - \prg_return_false: - \fi: - \else: - \group_end: - \prg_return_false: - \fi: - \else: - \group_end: - \prg_return_false: - \fi: - } -% \end{macrocode} -% Comparing two values is quite complex. First, there is a filter step -% to check if one or other of the given values is zero. If it is then -% the result is relatively easy to determine. -% \begin{macrocode} -\cs_new_protected_nopar:cpn { fp_compare_>: } - { - \if_int_compare:w \int_eval:w - \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int - = \c_zero - \if_int_compare:w \int_eval:w - \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int - = \c_zero - \group_end: - \prg_return_false: - \else: - \if_int_compare:w \l_fp_input_b_sign_int > \c_zero - \group_end: - \prg_return_false: - \else: - \group_end: - \prg_return_true: - \fi: - \fi: - \else: - \if_int_compare:w \int_eval:w - \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int - = \c_zero - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - \group_end: - \prg_return_true: - \else: - \group_end: - \prg_return_false: - \fi: - \else: - \use:c { fp_compare_>_aux: } - \fi: - \fi: - } -% \end{macrocode} -% Next, check the sign of the input: this again may give an obvious -% result. If both signs are the same, then hand off to comparing the -% absolute values. -% \begin{macrocode} -\cs_new_protected_nopar:cpn { fp_compare_>_aux: } - { - \if_int_compare:w \l_fp_input_a_sign_int > \l_fp_input_b_sign_int - \group_end: - \prg_return_true: - \else: - \if_int_compare:w \l_fp_input_a_sign_int < \l_fp_input_b_sign_int - \group_end: - \prg_return_false: - \else: - \if_int_compare:w \l_fp_input_a_sign_int > \c_zero - \use:c { fp_compare_absolute_a>b: } - \else: - \use:c { fp_compare_absolute_a<b: } - \fi: - \fi: - \fi: - } -% \end{macrocode} -% Rather long runs of checks, as there is the need to go through each -% layer of the input and do the comparison. There is also the need to -% avoid messing up with equal inputs at each stage. -% \begin{macrocode} -\cs_new_protected_nopar:cpn { fp_compare_absolute_a>b: } - { - \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int - \group_end: - \prg_return_true: - \else: - \if_int_compare:w \l_fp_input_a_exponent_int < \l_fp_input_b_exponent_int - \group_end: - \prg_return_false: - \else: - \if_int_compare:w \l_fp_input_a_integer_int > \l_fp_input_b_integer_int - \group_end: - \prg_return_true: - \else: - \if_int_compare:w - \l_fp_input_a_integer_int < \l_fp_input_b_integer_int - \group_end: - \prg_return_false: - \else: - \if_int_compare:w - \l_fp_input_a_decimal_int > \l_fp_input_b_decimal_int - \group_end: - \prg_return_true: - \else: - \group_end: - \prg_return_false: - \fi: - \fi: - \fi: - \fi: - \fi: - } -\cs_new_protected_nopar:cpn { fp_compare_absolute_a<b: } - { - \if_int_compare:w \l_fp_input_b_exponent_int > \l_fp_input_a_exponent_int - \group_end: - \prg_return_true: - \else: - \if_int_compare:w \l_fp_input_b_exponent_int < \l_fp_input_a_exponent_int - \group_end: - \prg_return_false: - \else: - \if_int_compare:w \l_fp_input_b_integer_int > \l_fp_input_a_integer_int - \group_end: - \prg_return_true: - \else: - \if_int_compare:w - \l_fp_input_b_integer_int < \l_fp_input_a_integer_int - \group_end: - \prg_return_false: - \else: - \if_int_compare:w - \l_fp_input_b_decimal_int > \l_fp_input_a_decimal_int - \group_end: - \prg_return_true: - \else: - \group_end: - \prg_return_false: - \fi: - \fi: - \fi: - \fi: - \fi: - } -% \end{macrocode} -% This is just a case of reversing the two input values and then -% running the tests already defined. -% \begin{macrocode} -\cs_new_protected_nopar:cpn { fp_compare_<: } - { - \tl_set:Nx \l_fp_internal_tl - { - \int_set:Nn \exp_not:N \l_fp_input_a_sign_int - { \int_use:N \l_fp_input_b_sign_int } - \int_set:Nn \exp_not:N \l_fp_input_a_integer_int - { \int_use:N \l_fp_input_b_integer_int } - \int_set:Nn \exp_not:N \l_fp_input_a_decimal_int - { \int_use:N \l_fp_input_b_decimal_int } - \int_set:Nn \exp_not:N \l_fp_input_a_exponent_int - { \int_use:N \l_fp_input_b_exponent_int } - \int_set:Nn \exp_not:N \l_fp_input_b_sign_int - { \int_use:N \l_fp_input_a_sign_int } - \int_set:Nn \exp_not:N \l_fp_input_b_integer_int - { \int_use:N \l_fp_input_a_integer_int } - \int_set:Nn \exp_not:N \l_fp_input_b_decimal_int - { \int_use:N \l_fp_input_a_decimal_int } - \int_set:Nn \exp_not:N \l_fp_input_b_exponent_int - { \int_use:N \l_fp_input_a_exponent_int } - } - \l_fp_internal_tl - \use:c { fp_compare_>: } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} +% The following need to be done. I'll try to time-order the items. +% \begin{itemize} +% \item Decide what exponent range to consider. +% \item Change the internal representation of fp, by replacing braced +% groups of $4$ digits by delimited arguments. +% \item Modulo and remainder, and rounding functions |quantize|, +% |quantize0|, |quantize+|, |quantize-|, |quantize=|, |round=|. +% Should the modulo also be provided as (catcode 12) |%|? +% \item \cs{fp_format:nn} \Arg{fpexpr} \Arg{format}, but what should +% \meta{format} be? More general pretty printing? +% \item Add |and|, |or|, |xor|? Perhaps under the names \texttt{all}, +% \texttt{any}, and \texttt{xor}? +% \item Add \texttt{csc} and \texttt{sec}. +% \item Add $\log(x,b)$ for logarithm of $x$ in base $b$. +% \item \texttt{hypot} (Euclidean length) and $\atan(x,y) = \atan(x/y)$, +% also called \texttt{atan2} in other math packages. +% Cartesian-to-polar transform. Other inverse trigonometric functions +% \texttt{acos}, \texttt{asin}, \texttt{atan} (one and two arguments). +% Also \texttt{asec}, \texttt{acsc}? +% \item Hyperbolic functions \texttt{cosh}, \texttt{sinh}, \texttt{tanh}. +% \item Inverse hyperbolics. +% \item Base conversion, input such as \texttt{0xAB.CDEF}. +% \item Random numbers (pgfmath provides |rnd|, |rand|, |random|), with +% seed reset at every \cs{fp_set:Nn}. +% \item Factorial (not with |!|), gamma function. +% \item Improve coefficients of \texttt{sin}, \texttt{cos} and +% \texttt{tan}. +% \item Treat upper and lower case letters identically in +% identifiers, and ignore underscores. +% \item Parse $-3<-2<-1$ as it should, not $(-3<-2)<-1$. +% \item Add an |array(1,2,3)| and |i=complex(0,1)|. +% \item Provide an experimental |map| function? Perhaps easier to +% implement if it is a single character, |@sin(1,2)|? +% \item Provide \cs{fp_if_nan:nTF}? +% \end{itemize} +% \pkg{Pgfmath} also provides box-measurements (depth, height, width), but +% boxes are not possible expandably. % -% \begin{macro}[TF]{\fp_compare:n} -% \begin{macro}[aux] -% { -% \fp_compare_aux_i:w, \fp_compare_aux_ii:w, \fp_compare_aux_iii:w, -% \fp_compare_aux_iv:w, \fp_compare_aux_v:w, \fp_compare_aux_vi:w, -% \fp_compare_aux_vii:w -% } -% As \TeX{} cannot help out here, a daisy-chain of delimited functions -% are used. This is very much a first-generation approach: revision will -% be needed if these functions are really useful. -% \begin{macrocode} -\prg_new_protected_conditional:Npnn \fp_compare:n #1 { T , F , TF } - { - \group_begin: - \tl_set:Nx \l_fp_internal_tl - { - \group_end: - \fp_compare_aux_i:w #1 \exp_not:n { == \q_nil == \q_stop } - } - \l_fp_internal_tl - } -\cs_new_protected:Npn \fp_compare_aux_i:w #1 == #2 == #3 \q_stop - { - \quark_if_nil:nTF {#2} - { \fp_compare_aux_ii:w #1 != \q_nil != \q_stop } - { \fp_compare:nNnTF {#1} = {#2} \prg_return_true: \prg_return_false: } - } -\cs_new_protected:Npn \fp_compare_aux_ii:w #1 != #2 != #3 \q_stop - { - \quark_if_nil:nTF {#2} - { \fp_compare_aux_iii:w #1 <= \q_nil <= \q_stop } - { \fp_compare:nNnTF {#1} = {#2} \prg_return_false: \prg_return_true: } - } -\cs_new_protected:Npn \fp_compare_aux_iii:w #1 <= #2 <= #3 \q_stop - { - \quark_if_nil:nTF {#2} - { \fp_compare_aux_iv:w #1 >= \q_nil >= \q_stop } - { \fp_compare:nNnTF {#1} > {#2} \prg_return_false: \prg_return_true: } - } -\cs_new_protected:Npn \fp_compare_aux_iv:w #1 >= #2 >= #3 \q_stop - { - \quark_if_nil:nTF {#2} - { \fp_compare_aux_v:w #1 = \q_nil \q_stop } - { \fp_compare:nNnTF {#1} < {#2} \prg_return_false: \prg_return_true: } - } -\cs_new_protected:Npn \fp_compare_aux_v:w #1 = #2 = #3 \q_stop - { - \quark_if_nil:nTF {#2} - { \fp_compare_aux_vi:w #1 < \q_nil < \q_stop } - { \fp_compare:nNnTF {#1} = {#2} \prg_return_true: \prg_return_false: } - } -\cs_new_protected:Npn \fp_compare_aux_vi:w #1 < #2 < #3 \q_stop - { - \quark_if_nil:nTF {#2} - { \fp_compare_aux_vii:w #1 > \q_nil > \q_stop } - { \fp_compare:nNnTF {#1} < {#2} \prg_return_true: \prg_return_false: } - } -\cs_new_protected:Npn \fp_compare_aux_vii:w #1 > #2 > #3 \q_stop - { - \quark_if_nil:nTF {#2} - { \prg_return_false: } - { \fp_compare:nNnTF {#1} > {#2} \prg_return_true: \prg_return_false: } - } -% \end{macrocode} -% \end{macro} -% \end{macro} +% Bugs. (Exclamation points mark important bugs.) +% \begin{itemize} +% \item[!] \cs{fp_eval:n} |{nan}| mustn't produce an error. +% \item $1-10^{-16}$ should not give $1$. +% \item When rounding towards $-\infty$, |\dim_to_fp:n {0pt}| should +% return $-0$, not $+0$. +% \item \texttt{0e9999999999} gives a \TeX{} \enquote{number too +% large} error. +% \item \texttt{tan} and \texttt{cot} give very slightly wrong results +% for arguments near $10^{-8}$. +% \item[!] Multiplying $0$ with $\infty$ doesn't trigger an invalid +% operation error. +% \item Conversion to integers with \cs{fp_to_int:n} does not check +% for overflow. +% \item Subnormals are not implemented. +% \end{itemize} % -% \subsection{Messages} +% \end{documentation} % -% \begin{macro}{\fp_overflow_msg:} -% A generic overflow message, used whenever there is a possible -% overflow. -% \begin{macrocode} -\msg_kernel_new:nnnn { fpu } { overflow } - { Number~too~big. } - { - The~input~given~is~too~big~for~the~LaTeX~floating~point~unit. \\ - Further~errors~may~well~occur! - } -\cs_new_protected_nopar:Npn \fp_overflow_msg: - { \msg_kernel_error:nn { fpu } { overflow } } -% \end{macrocode} -% \end{macro} +% \begin{implementation} % -% \begin{macro}{\fp_exp_overflow_msg:} -% A slightly more helpful message for exponent overflows. -% \begin{macrocode} -\msg_kernel_new:nnnn { fpu } { exponent-overflow } - { Number~too~big~for~exponent~unit. } - { - The~exponent~of~the~input~given~is~too~big~for~the~floating~point~ - unit:~the~maximum~input~value~for~an~exponent~is~230. - } -\cs_new_protected_nopar:Npn \fp_exp_overflow_msg: - { \msg_kernel_error:nn { fpu } { exponent-overflow } } -% \end{macrocode} -% \end{macro} +% \section{\pkg{l3fp} implementation} % -% \begin{macro}{\fp_ln_error_msg:} -% Logarithms are only valid for positive number % \begin{macrocode} -\msg_kernel_new:nnnn { fpu } { logarithm-input-error } - { Invalid~input~to~ln~function. } - { Logarithms~can~only~be~calculated~for~positive~numbers. } -\cs_new_protected_nopar:Npn \fp_ln_error_msg: { - \msg_kernel_error:nn { fpu } { logarithm-input-error } -} +%<*package> % \end{macrocode} -% \end{macro} % -% \begin{macro}{\fp_trig_overflow_msg:} -% A slightly more helpful message for trigonometric overflows. % \begin{macrocode} -\msg_kernel_new:nnnn { fpu } { trigonometric-overflow } - { Number~too~big~for~trigonometry~unit. } - { - The~trigonometry~code~can~only~work~with~numbers~smaller~ - than~1000000000. - } -\cs_new_protected_nopar:Npn \fp_trig_overflow_msg: - { \msg_kernel_error:nn { fpu } { trigonometric-overflow } } +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\__expl_package_check: % \end{macrocode} -% \end{macro} % % \begin{macrocode} -%</initex|package> +%</package> % \end{macrocode} % % \end{implementation} % -%\PrintIndex +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx index fdae7fa1046..a12b22a45fb 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3int.dtx 3490 2012-03-04 01:00:53Z bruno $ - {L3 Experimental integers} +\GetIdInfo$Id: l3int.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Integers} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -73,7 +73,7 @@ % \texttt{+}, \texttt{-}, \texttt{/} and \texttt{*} and % parentheses can be used within such expressions to carry % arithmetic operations. This module carries out these functions -% on \emph{integer expressions} (\enquote{\texttt{int expr}}). +% on \emph{integer expressions} (\enquote{\texttt{intexpr}}). % % \section{Integer expressions} % @@ -99,7 +99,7 @@ % both evaluate to \( -6 \). The \Arg{integer expression} may % contain the operators \texttt{+}, \texttt{-}, \texttt{*} and % \texttt{/}, along with parenthesis \texttt{(} and \texttt{)}. -% After two expansions, \cs{int_eval:n} yields a +% After two expansions, \cs{int_eval:n} yields an % \meta{integer denotation} which is left in the input stream. This is % \emph{not} an \meta{internal integer}, and therefore requires % suitable termination if used in a \TeX{}-style integer assignment. @@ -124,7 +124,7 @@ % second, rounding any remainder. Ties are rounded away from zero. % Note that this is identical to using % |/| directly in an \meta{integer expression}. The result is left in -% the input stream as a \meta{integer denotation} after two expansions. +% the input stream as an \meta{integer denotation} after two expansions. % \end{function} % % \begin{function}[EXP, updated = 2012-02-09]{\int_div_truncate:nn} @@ -134,7 +134,7 @@ % Evaluates the two \meta{integer expressions} as described earlier, % then calculates the result of dividing the first value by the % second, truncating any remainder. Note that division using |/| -% rounds the result. The result is left in the input stream as a +% rounds the result. The result is left in the input stream as an % \meta{integer denotation} after two expansions. % \end{function} % @@ -202,10 +202,10 @@ % \int_gset_eq:NN, \int_gset_eq:cN, \int_gset_eq:Nc, \int_gset_eq:cc % } % \begin{syntax} -% \cs{int_set_eq:NN} \meta{integer1} \meta{integer2} +% \cs{int_set_eq:NN} \meta{integer_1} \meta{integer_2} % \end{syntax} -% Sets the content of \meta{integer1} equal to that of -% \meta{integer2}. +% Sets the content of \meta{integer_1} equal to that of +% \meta{integer_2}. % \end{function} % % \begin{function}[EXP, pTF, added=2012-03-03] @@ -268,9 +268,9 @@ % \begin{syntax} % \cs{int_use:N} \meta{integer} % \end{syntax} -% Recovers the content of a \meta{integer} and places it directly +% Recovers the content of an \meta{integer} and places it directly % in the input stream. An error will be raised if the variable does -% not exist or if it is invalid. Can be omitted in places where a +% not exist or if it is invalid. Can be omitted in places where an % \meta{integer} is required (such as in the first and third arguments % of \cs{int_compare:nNnTF}). % \begin{texnote} @@ -302,9 +302,9 @@ % % \begin{function}[EXP,pTF]{\int_compare:n} % \begin{syntax} -% \cs{int_compare_p:n} \{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} \\ +% \cs{int_compare_p:n} \{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} \\ % \cs{int_compare:nTF} -% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} +% ~~\{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % This function first evaluates each of the \meta{integer expressions} @@ -322,6 +322,36 @@ % \end{center} % \end{function} % +% \begin{function}[added = 2012-06-03, EXP]{\int_case:nnn} +% \begin{syntax} +% \cs{int_case:nnn} \Arg{test integer expression} \\ +% ~~|{| \\ +% ~~~~\Arg{intexpr case_1} \Arg{code case_1} \\ +% ~~~~\Arg{intexpr case_2} \Arg{code case_2} \\ +% ~~~~\ldots \\ +% ~~~~\Arg{intexpr case_n} \Arg{code case_n} \\ +% ~~|}| \\ +% ~~\Arg{else code} +% \end{syntax} +% This function evaluates the \meta{test integer expression} and +% compares this in turn to each of the +% \meta{integer expression cases}. If the two are equal then the +% associated \meta{code} is left in the input stream. If none of +% the tests are \texttt{true} then the \texttt{else code} will be +% left in the input stream. For example +% \begin{verbatim} +% \int_case:nnn +% { 2 * 5 } +% { +% { 5 } { Small } +% { 4 + 6 } { Medium } +% { -2 * 10 } { Negative } +% } +% { No idea! } +% \end{verbatim} +% will leave \enquote{\texttt{Medium}} in the input stream. +% \end{function} +% % \begin{function}[EXP,pTF]{\int_if_even:n, \int_if_odd:n} % \begin{syntax} % \cs{int_if_odd_p:n} \Arg{integer expression} @@ -390,7 +420,7 @@ % \begin{function}[rEXP]{\int_do_while:nn} % \begin{syntax} % \cs{int_do_while:nn} -% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} \Arg{code} +% ~~\{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} \Arg{code} % \end{syntax} % Evaluates the relationship between the two \meta{integer expressions} % as described for \cs{int_compare:nTF}, and then places the @@ -403,7 +433,7 @@ % \begin{function}[rEXP]{\int_do_until:nn} % \begin{syntax} % \cs{int_do_until:nn} -% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} \Arg{code} +% ~~\{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} \Arg{code} % \end{syntax} % Evaluates the relationship between the two \meta{integer expressions} % as described for \cs{int_compare:nTF}, and then places the @@ -416,7 +446,7 @@ % \begin{function}[rEXP]{\int_until_do:nn} % \begin{syntax} % \cs{int_until_do:nn} -% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} \Arg{code} +% ~~\{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} \Arg{code} % \end{syntax} % Places the \meta{code} in the input stream for \TeX\ to process, and % then evaluates the relationship between the two @@ -429,7 +459,7 @@ % \begin{function}[rEXP]{\int_while_do:nn} % \begin{syntax} % \cs{int_while_do:nn} \ -% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} \Arg{code} +% ~~\{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} \Arg{code} % \end{syntax} % Places the \meta{code} in the input stream for \TeX{} to process, and % then evaluates the relationship between the two @@ -439,6 +469,59 @@ % \meta{relation} is \texttt{false}. % \end{function} % +% \section{Integer step functions} +% +% \begin{function}[added = 2012-06-04, updated = 2012-06-29, rEXP] +% {\int_step_function:nnnN} +% \begin{syntax} +% \cs{int_step_function:nnnN} \Arg{initial value} \Arg{step} \Arg{final value} \meta{function} +% \end{syntax} +% This function first evaluates the \meta{initial value}, \meta{step} +% and \meta{final value}, all of which should be integer expressions. +% The \meta{function} is then placed in front of each \meta{value} +% from the \meta{initial value} to the \meta{final value} in turn +% (using \meta{step} between each \meta{value}). Thus \meta{function} +% should absorb one numerical argument. For example +% \begin{verbatim} +% \cs_set:Npn \my_func:n #1 { [I~saw~#1] \quad } +% \int_step_function:nnnN { 1 } { 1 } { 5 } \my_func:n +% \end{verbatim} +% would print +% \begin{quote} +% [I saw 1] \quad +% [I saw 2] \quad +% [I saw 3] \quad +% [I saw 4] \quad +% [I saw 5] \quad +% \end{quote} +% \end{function} +% +% \begin{function}[added = 2012-06-04, updated = 2012-06-29] +% {\int_step_inline:nnnn} +% \begin{syntax} +% \cs{int_step_inline:nnnn} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code} +% \end{syntax} +% This function first evaluates the \meta{initial value}, \meta{step} +% and \meta{final value}, all of which should be integer expressions. +% The \meta{code} is then placed in front of each \meta{value} +% from the \meta{initial value} to the \meta{final value} in turn +% (using \meta{step} between each \meta{value}). Thus the \meta{code} +% should define a function of one argument (|#1|). +% \end{function} +% +% \begin{function}[added = 2012-06-04, updated = 2012-06-29] +% {\int_step_variable:nnnNn} +% \begin{syntax} +% \cs{int_step_variable:nnnNn} \\ +% ~~\Arg{initial value} \Arg{step} \Arg{final value} \meta{tl~var} \Arg{code} +% \end{syntax} +% This function first evaluates the \meta{initial value}, \meta{step} +% and \meta{final value}, all of which should be integer expressions. +% The \meta{code} is inserted into the input stream, with the +% \meta{tl~var} defined as the current \meta{value}. Thus the +% \meta{code} should make use of the \meta{tl~var}. +% \end{function} +% % \section{Formatting integers} % % Integers can be placed into the output stream with formatting. These @@ -626,7 +709,7 @@ % Displays the value of the \meta{integer} on the terminal. % \end{function} % -% \begin{function}[added = 2011-11-22]{\int_show:n} +% \begin{function}[added = 2011-11-22, updated = 2012-05-27]{\int_show:n} % \begin{syntax} % \cs{int_show:n} \meta{integer expression} % \end{syntax} @@ -678,7 +761,7 @@ % % \section{Scratch integers} % -% \begin{variable}{\l_tmpa_int, \l_tmpb_int, \l_tmpc_int} +% \begin{variable}{\l_tmpa_int, \l_tmpb_int} % Scratch integer for local assignment. These are never used by % the kernel code, and so are safe for use with any \LaTeX3-defined % function. However, they may be overwritten by other non-kernel @@ -692,57 +775,11 @@ % code and so should only be used for short-term storage. % \end{variable} % -% \section{Internal functions} -% -% \begin{function}[EXP]{\int_get_digits:n} -% \begin{syntax} -% \cs{int_get_digits:n} \meta{value} -% \end{syntax} -% Parses the \meta{value} to leave the absolute \meta{value} -% in the input stream. This may therefore be used -% to remove multiple sign tokens from the \meta{value} -% (which may be symbolic). -% \end{function} -% -% \begin{function}[rEXP]{\int_get_sign:n} -% \begin{syntax} -% \cs{int_get_sign:n} \meta{value} -% \end{syntax} -% Parses the \meta{value} to leave a single sign token -% (either |+| or |-|) in the input stream. This may therefore be used -% to sanitise sign tokens from the \meta{value} (which may be symbolic). -% \end{function} -% -% \begin{function}[updated = 2011-09-17, EXP]{\int_to_letter:n} -% \begin{syntax} -% \cs{int_to_letter:n} \meta{integer value} -% \end{syntax} -% For \meta{integer values} from $0$ to $9$, leaves the \meta{value} -% in the input stream unchanged. For \meta{integer values} from -% $10$ to $35$, leaves the appropriate upper case letter (from the -% standard English alphabet) in the input stream: for example, -% $10$ is converted to |A|, $11$ to |B|, \emph{etc.} -% \end{function} +% \section{Primitive conditionals} % -% \begin{function}[EXP]{\int_to_roman:w} +% \begin{function}[EXP]{\if_int_compare:w} % \begin{syntax} -% \cs{int_to_roman:w} \meta{integer} \meta{space} \textit{or} \meta{non-expandable token} -% \end{syntax} -% Converts \meta{integer} to it lower case Roman representation. Expansion -% ends when a space or non-expandable token is found. -% Note that this function produces a string of letters with category code -% $12$ and that protected functions \emph{are} expanded by this -% process. Negative \meta{integer} values result in no output, although -% the function does not terminate expansion until a suitable endpoint -% is found in the same way as for positive numbers. -% \begin{texnote} -% This is the \TeX{} primitive \tn{romannumeral} renamed. -% \end{texnote} -% \end{function} -% -% \begin{function}[EXP]{\if_num:w, \if_int_compare:w} -% \begin{syntax} -% \cs{if_num:w} \meta{integer1} \meta{relation} \meta{integer2} +% \cs{if_int_compare:w} \meta{integer_1} \meta{relation} \meta{integer_2} % ~~\meta{true code} % \cs{else:} % ~~\meta{false code} @@ -758,15 +795,15 @@ % % \begin{function}[EXP]{\if_case:w, \or:} % \begin{syntax} -% \cs{if_case:w} \meta{integer} \meta{case0} -% ~~\cs{or:} \meta{case1} +% \cs{if_case:w} \meta{integer} \meta{case_0} +% ~~\cs{or:} \meta{case_1} % ~~\cs{or:} |...| % ~~\cs{else:} \meta{default} % \cs{fi:} % \end{syntax} % Selects a case to execute based on the value of the \meta{integer}. The -% first case (\meta{case0}) is executed if \meta{integer} is $0$, the second -% (\meta{case1}) if the \meta{integer} is $1$, \emph{etc.} The +% first case (\meta{case_0}) is executed if \meta{integer} is $0$, the second +% (\meta{case_1}) if the \meta{integer} is $1$, \emph{etc.} The % \meta{integer} may be a literal, a constant or an integer % expression (\emph{e.g.}~using \cs{int_eval:n}). % \begin{texnote} @@ -774,10 +811,44 @@ % \end{texnote} % \end{function} % -% \begin{function}[EXP]{\int_value:w} +% \begin{function}[EXP]{\if_int_odd:w} +% \begin{syntax} +% \cs{if_int_odd:w} \meta{tokens} \meta{optional space} +% ~~\meta{true code} +% \cs{else:} +% ~~\meta{true code} +% \cs{fi:} +% \end{syntax} +% Expands \meta{tokens} until a non-numeric token or a space is found, and +% tests whether the resulting \meta{integer} is odd. If so, \meta{true code} +% is executed. The \cs{else:} branch is optional. +% \begin{texnote} +% This is the \TeX{} primitive \tn{ifodd}. +% \end{texnote} +% \end{function} +% +% \section{Internal functions} +% +% \begin{function}[EXP]{\__int_to_roman:w} +% \begin{syntax} +% \cs{__int_to_roman:w} \meta{integer} \meta{space} \textit{or} \meta{non-expandable token} +% \end{syntax} +% Converts \meta{integer} to it lower case Roman representation. Expansion +% ends when a space or non-expandable token is found. +% Note that this function produces a string of letters with category code +% $12$ and that protected functions \emph{are} expanded by this +% process. Negative \meta{integer} values result in no output, although +% the function does not terminate expansion until a suitable endpoint +% is found in the same way as for positive numbers. +% \begin{texnote} +% This is the \TeX{} primitive \tn{romannumeral} renamed. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\__int_value:w} % \begin{syntax} -% \cs{int_value:w} \meta{integer} -% \cs{int_value:w} \meta{tokens} \meta{optional space} +% \cs{__int_value:w} \meta{integer} +% \cs{__int_value:w} \meta{tokens} \meta{optional space} % \end{syntax} % Expands \meta{tokens} until an \meta{integer} is formed. One space may be % gobbled in the process. @@ -786,35 +857,29 @@ % \end{texnote} % \end{function} % -% \begin{function}[EXP]{\int_eval:w, \int_eval_end:} +% \begin{function}[EXP]{\__int_eval:w, \__int_eval_end:} % \begin{syntax} -% \cs{int_eval:w} \meta{intexpr} \cs{int_eval_end:} +% \cs{__int_eval:w} \meta{intexpr} \cs{__int_eval_end:} % \end{syntax} % Evaluates \meta{integer expression} as described for \cs{int_eval:n}. % The evaluation stops when an unexpandable token which is not a valid -% part of an integer is read or when \cs{int_eval_end:} is +% part of an integer is read or when \cs{__int_eval_end:} is % reached. The latter is gobbled by the scanner mechanism: -% \cs{int_eval_end:} itself is unexpandable but used correctly +% \cs{__int_eval_end:} itself is unexpandable but used correctly % the entire construct is expandable. % \begin{texnote} % This is the \eTeX{} primitive \tn{numexpr}. % \end{texnote} % \end{function} % -% \begin{function}[EXP]{\if_int_odd:w} +% \begin{function}{\__prg_compare_error:, \__prg_compare_error:Nw} % \begin{syntax} -% \cs{if_int_odd:w} \meta{tokens} \meta{optional space} -% ~~\meta{true code} -% \cs{else:} -% ~~\meta{true code} -% \cs{fi:} +% \cs{__prg_compare_error:} +% \cs{__prg_compare_error:Nw} \meta{token} % \end{syntax} -% Expands \meta{tokens} until a non-numeric token or a space is found, and -% tests whether the resulting \meta{integer} is odd. If so, \meta{true code} -% is executed. The \cs{else:} branch is optional. -% \begin{texnote} -% This is the \TeX{} primitive \tn{ifodd}. -% \end{texnote} +% These are used within \cs{int_compare:n(TF)}, \cs{dim_compare:n(TF)} +% and so on to recover correctly if the \texttt{n}-type argument does not +% contain a properly-formed relation. % \end{function} % % \end{documentation} @@ -827,58 +892,59 @@ %<*initex|package> % \end{macrocode} % +% \begin{macrocode} +%<@@=int> +% \end{macrocode} +% % \TestFiles{m3int001,m3int002,m3int03} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % -% \begin{macro}{\int_to_roman:w} +% \begin{macro}{\@@_to_roman:w} % \begin{macro}{\if_int_compare:w} % Done in \pkg{l3basics}. % \end{macro} % \end{macro} % -% \begin{macro}{\int_value:w} -% \begin{macro}{\int_eval:w} -% \begin{macro}{\int_eval_end:} -% \begin{macro}{\if_num:w} +% \begin{macro}{\@@_value:w} +% \begin{macro}{\@@_eval:w} +% \begin{macro}{\@@_eval_end:} % \begin{macro}{\if_int_odd:w} % \begin{macro}{\if_case:w} % Here are the remaining primitives for number comparisons and % expressions. % \begin{macrocode} -\cs_new_eq:NN \int_value:w \tex_number:D -\cs_new_eq:NN \int_eval:w \etex_numexpr:D -\cs_new_eq:NN \int_eval_end: \tex_relax:D -\cs_new_eq:NN \if_num:w \tex_ifnum:D -\cs_new_eq:NN \if_int_odd:w \tex_ifodd:D -\cs_new_eq:NN \if_case:w \tex_ifcase:D +\cs_new_eq:NN \@@_value:w \tex_number:D +\cs_new_eq:NN \@@_eval:w \etex_numexpr:D +\cs_new_eq:NN \@@_eval_end: \tex_relax:D +\cs_new_eq:NN \if_int_odd:w \tex_ifodd:D +\cs_new_eq:NN \if_case:w \tex_ifcase:D % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} -% \end{macro} % % \subsection{Integer expressions} % % \begin{macro}{\int_eval:n} -% Wrapper for \cs{int_eval:w}. Can be used in an integer expression +% Wrapper for \cs{@@_eval:w}. Can be used in an integer expression % or directly in the input stream. In format mode, there is already % a definition in \pkg{l3alloc} for bookstrapping, which is therefore % corrected to the \enquote{real} version here. % \begin{macrocode} %<*initex> -\cs_set:Npn \int_eval:n #1 { \int_value:w \int_eval:w #1 \int_eval_end: } +\cs_set:Npn \int_eval:n #1 { \@@_value:w \@@_eval:w #1 \@@_eval_end: } %</initex> %<*package> -\cs_new:Npn \int_eval:n #1 { \int_value:w \int_eval:w #1 \int_eval_end: } +\cs_new:Npn \int_eval:n #1 { \@@_value:w \@@_eval:w #1 \@@_eval_end: } %</package> % \end{macrocode} % \end{macro} @@ -893,33 +959,33 @@ % \begin{macrocode} \cs_new:Npn \int_abs:n #1 { - \int_value:w - \if_int_compare:w \int_eval:w #1 < \c_zero + \@@_value:w + \if_int_compare:w \@@_eval:w #1 < \c_zero - \fi: - \int_eval:w #1 \int_eval_end: + \@@_eval:w #1 \@@_eval_end: } \cs_new:Npn \int_max:nn #1#2 { - \int_value:w \int_eval:w + \@@_value:w \@@_eval:w \if_int_compare:w - \int_eval:w #1 > \int_eval:w #2 \int_eval_end: + \@@_eval:w #1 > \@@_eval:w #2 \@@_eval_end: #1 \else: #2 \fi: - \int_eval_end: + \@@_eval_end: } \cs_new:Npn \int_min:nn #1#2 { - \int_value:w \int_eval:w + \@@_value:w \@@_eval:w \if_int_compare:w - \int_eval:w #1 < \int_eval:w #2 \int_eval_end: + \@@_eval:w #1 < \@@_eval:w #2 \@@_eval_end: #1 \else: #2 \fi: - \int_eval_end: + \@@_eval_end: } % \end{macrocode} % \end{macro} @@ -932,12 +998,12 @@ % \UnitTested % \begin{macro}[EXP]{\int_mod:nn} % \UnitTested -% \begin{macro}[aux, EXP]{\int_div_truncate_aux:NwNw} -% As \cs{int_eval:w} rounds the result of a division we also provide a +% \begin{macro}[aux, EXP]{\@@_div_truncate:NwNw} +% As \cs{@@_eval:w} rounds the result of a division we also provide a % version that truncates the result. We use an auxiliary to make sure % numerator and denominator are only evaluated once: this comes in % handy when those are more expressions are expensive to evaluate -% (\emph{e.g.}, \cs{tl_length:n}). If the numerator |#1#2| is $0$, +% (\emph{e.g.}, \cs{tl_count:n}). If the numerator |#1#2| is $0$, % then we divide $0$ by the denominator (this ensures that $0/0$ is % correctly reported as an error). Otherwise, shift the numerator % |#1#2| towards $0$ by $(\left\vert\texttt{\#3\#4}\right\vert-1)/2$, which we @@ -948,13 +1014,13 @@ % \begin{macrocode} \cs_new:Npn \int_div_truncate:nn #1#2 { - \int_use:N \int_eval:w - \exp_after:wN \int_div_truncate_aux:NwNw - \int_use:N \int_eval:w #1 \exp_after:wN ; - \int_use:N \int_eval:w #2 ; - \int_eval_end: + \int_use:N \@@_eval:w + \exp_after:wN \@@_div_truncate:NwNw + \int_use:N \@@_eval:w #1 \exp_after:wN ; + \int_use:N \@@_eval:w #2 ; + \@@_eval_end: } -\cs_new:Npn \int_div_truncate_aux:NwNw #1#2; #3#4; +\cs_new:Npn \@@_div_truncate:NwNw #1#2; #3#4; { \if_meaning:w 0 #1 \c_zero @@ -976,9 +1042,9 @@ % \begin{macrocode} \cs_new:Npn \int_mod:nn #1#2 { - \int_value:w \int_eval:w + \@@_value:w \@@_eval:w #1 - \int_div_truncate:nn {#1} {#2} * ( #2 ) - \int_eval_end: + \@@_eval_end: } % \end{macrocode} % \end{macro} @@ -996,7 +1062,7 @@ %<*package> \cs_new_protected:Npn \int_new:N #1 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \newcount #1 } %</package> @@ -1005,8 +1071,8 @@ % \end{macro} % % \begin{macro}{\int_const:Nn, \int_const:cn} -% \begin{macro}[aux]{\int_constdef:Nw} -% \begin{variable}{\c_max_const_int} +% \begin{macro}[aux]{\@@_constdef:Nw} +% \begin{variable}{\c__max_constdef_int} % \UnitTested % As stated, most constants can be defined as \tn{chardef} or % \tn{mathchardef} but that's engine dependent. As a result, there is some @@ -1016,15 +1082,15 @@ { \int_compare:nNnTF {#2} > \c_minus_one { - \int_compare:nNnTF {#2} > \c_max_const_int + \int_compare:nNnTF {#2} > \c__max_constdef_int { \int_new:N #1 \int_gset:Nn #1 {#2} } { - \chk_if_free_cs:N #1 - \tex_global:D \int_constdef:Nw #1 = - \int_eval:w #2 \int_eval_end: + \__chk_if_free_cs:N #1 + \tex_global:D \@@_constdef:Nw #1 = + \@@_eval:w #2 \@@_eval_end: } } { @@ -1035,12 +1101,12 @@ \cs_generate_variant:Nn \int_const:Nn { c } \pdftex_if_engine:TF { - \cs_new_eq:NN \int_constdef:Nw \tex_mathchardef:D - \tex_mathchardef:D \c_max_const_int 32 767 ~ + \cs_new_eq:NN \@@_constdef:Nw \tex_mathchardef:D + \tex_mathchardef:D \c__max_constdef_int 32 767 ~ } { - \cs_new_eq:NN \int_constdef:Nw \tex_chardef:D - \tex_chardef:D \c_max_const_int 1 114 111 ~ + \cs_new_eq:NN \@@_constdef:Nw \tex_chardef:D + \tex_chardef:D \c__max_constdef_int 1 114 111 ~ } % \end{macrocode} % \end{variable} @@ -1119,9 +1185,9 @@ % Adding and subtracting to and from a counter \ldots % \begin{macrocode} \cs_new_protected:Npn \int_add:Nn #1#2 - { \tex_advance:D #1 by \int_eval:w #2 \int_eval_end: } + { \tex_advance:D #1 by \@@_eval:w #2 \@@_eval_end: } \cs_new_protected:Npn \int_sub:Nn #1#2 - { \tex_advance:D #1 by - \int_eval:w #2 \int_eval_end: } + { \tex_advance:D #1 by - \@@_eval:w #2 \@@_eval_end: } \cs_new_protected_nopar:Npn \int_gadd:Nn { \tex_global:D \int_add:Nn } \cs_new_protected_nopar:Npn \int_gsub:Nn @@ -1174,7 +1240,7 @@ % code seen with token list variables. % \begin{macrocode} \cs_new_protected:Npn \int_set:Nn #1#2 - { #1 ~ \int_eval:w #2\int_eval_end: } + { #1 ~ \@@_eval:w #2\@@_eval_end: } \cs_new_protected_nopar:Npn \int_gset:Nn { \tex_global:D \int_set:Nn } \cs_generate_variant:Nn \int_set:Nn { c } \cs_generate_variant:Nn \int_gset:Nn { c } @@ -1195,30 +1261,30 @@ % % \subsection{Integer expression conditionals} % -% \begin{macro}[aux, EXP]{\kernel_compare_error:, \kernel_compare_error:NNw} +% \begin{macro}[aux, EXP]{\__prg_compare_error:, \__prg_compare_error:NNw} % Those functions are used for comparison tests which use a simple % syntax where only one set of braces is required and additional % operators such as |!=| and |>=| are supported. The tests first % evaluate their left-hand side, with a trailing -% \cs{kernel_compare_error:}. This marker is normally not expanded, +% \cs{__prg_compare_error:}. This marker is normally not expanded, % but if the relation symbol is missing from the test's argument, then % the marker inserts |=| (and itself) after triggering the relevant % \TeX{} error. If the first token which appears after evaluating and % removing the left-hand side is not a known relation symbol, then a -% judiciously placed \cs{kernel_compare_error:Nw} gets expanded, +% judiciously placed \cs{__prg_compare_error:Nw} gets expanded, % cleaning up the end of the test and telling the user what the % problem was. % \begin{macrocode} -\cs_new_protected_nopar:Npn \kernel_compare_error: +\cs_new_protected_nopar:Npn \__prg_compare_error: { - \if_num:w \c_zero \c_zero \fi: + \if_int_compare:w \c_zero \c_zero \fi: = - \kernel_compare_error: + \__prg_compare_error: } -\cs_new:Npn \kernel_compare_error:Nw +\cs_new:Npn \__prg_compare_error:Nw #1#2 \prg_return_true: \else: \prg_return_false: \fi: { - \msg_expandable_kernel_error:nnn + \__msg_kernel_expandable_error:nnn { kernel } { unknown-comparison } {#1} \prg_return_false: } @@ -1226,31 +1292,31 @@ % \end{macro} % % \begin{macro}[pTF, EXP]{\int_compare:n} -% \begin{macro}[aux, EXP]{\int_compare_aux:Nw, \int_compare_aux:NNw} +% \begin{macro}[aux, EXP]{\@@_compare_aux:Nw, \@@_compare_aux:NNw} % \begin{macro}[aux, EXP] % { -% \int_compare_=:NNw, -% \int_compare_<:NNw, -% \int_compare_>:NNw, -% \int_compare_==:NNw, -% \int_compare_!=:NNw, -% \int_compare_<=:NNw, -% \int_compare_>=:NNw +% \@@_compare_=:NNw, +% \@@_compare_<:NNw, +% \@@_compare_>:NNw, +% \@@_compare_==:NNw, +% \@@_compare_!=:NNw, +% \@@_compare_<=:NNw, +% \@@_compare_>=:NNw % } % Comparison tests using a simple syntax where only one set of braces % is required and additional operators such as |!=| and |>=| are % supported. We can start evaluating from the left using -% \cs{int_eval:w}, and we know that since the relation symbols |<|, +% \cs{@@_eval:w}, and we know that since the relation symbols |<|, % |>|, |=| and |!| are not allowed in such expressions, they will % terminate the expression. Therefore, we first let \TeX{} evaluate % this left hand side of the (in)equality. We also insert at that -% stage the end of the test: \cs{int_eval_end:} will end the +% stage the end of the test: \cs{@@_eval_end:} will end the % evaluation of the right-hand side. % \begin{macrocode} \prg_new_conditional:Npnn \int_compare:n #1 { p , T , F , TF } { - \exp_after:wN \int_compare_aux:Nw \int_use:N \int_eval:w #1 - \kernel_compare_error: \int_eval_end: + \exp_after:wN \@@_compare_aux:Nw \int_use:N \@@_eval:w #1 + \__prg_compare_error: \@@_eval_end: \prg_return_true: \else: \prg_return_false: @@ -1258,47 +1324,47 @@ } % \end{macrocode} % We have just evaluated the left-hand side. To access the relation -% symbol, we remove the number by applying \cs{int_to_roman:w}, after +% symbol, we remove the number by applying \cs{@@_to_roman:w}, after % making sure that the argument becomes non-positive: its roman -% numeral representation is then empty. The \cs{int_compare_aux:NNw} +% numeral representation is then empty. The \cs{@@_compare_aux:NNw} % auxiliary then probes the first two tokens to determine the relation % symbol, building a control sequence from it. All the extended forms % have an extra |=| hence the test for that as a second token. If the % relation symbol is unknown, then the control sequence is turned by -% \TeX{} into \cs{scan_stop:}, and \cs{kernel_compare_error:Nw} +% \TeX{} into \cs{scan_stop:}, and \cs{__prg_compare_error:Nw} % raises an error. % \begin{macrocode} -\cs_new:Npn \int_compare_aux:Nw #1#2 \kernel_compare_error: +\cs_new:Npn \@@_compare_aux:Nw #1#2 \__prg_compare_error: { - \exp_after:wN \int_compare_aux:NNw - \int_to_roman:w - 0 #2 ?? \q_mark + \exp_after:wN \@@_compare_aux:NNw + \@@_to_roman:w - 0 #2 ?? \q_mark #1#2 } -\cs_new:Npn \int_compare_aux:NNw #1#2#3 \q_mark +\cs_new:Npn \@@_compare_aux:NNw #1#2#3 \q_mark { - \use:c { int_compare_ #1 \if_meaning:w = #2 = \fi: :NNw } - \kernel_compare_error:Nw #1 + \use:c { @@_compare_ #1 \if_meaning:w = #2 = \fi: :NNw } + \__prg_compare_error:Nw #1 } % \end{macrocode} % The actual comparisons are then simple function calls, using the % relation as delimiter for a delimited argument and discarding -% \cs{kernel_compare_error:Nw} \meta{token} responsible for error +% \cs{__prg_compare_error:Nw} \meta{token} responsible for error % detection. % \begin{macrocode} -\cs_new:cpn { int_compare_=:NNw } #1#2#3 = - { \if_int_compare:w #3 = \int_eval:w } -\cs_new:cpn { int_compare_<:NNw } #1#2#3 < - { \if_int_compare:w #3 < \int_eval:w } -\cs_new:cpn { int_compare_>:NNw } #1#2#3 > - { \if_int_compare:w #3 > \int_eval:w } -\cs_new:cpn { int_compare_==:NNw } #1#2#3 == - { \if_int_compare:w #3 = \int_eval:w } -\cs_new:cpn { int_compare_!=:NNw } #1#2#3 != - { \reverse_if:N \if_int_compare:w #3 = \int_eval:w } -\cs_new:cpn { int_compare_<=:NNw } #1#2#3 <= - { \reverse_if:N \if_int_compare:w #3 > \int_eval:w } -\cs_new:cpn { int_compare_>=:NNw } #1#2#3 >= - { \reverse_if:N \if_int_compare:w #3 < \int_eval:w } +\cs_new:cpn { @@_compare_=:NNw } #1#2#3 = + { \if_int_compare:w #3 = \@@_eval:w } +\cs_new:cpn { @@_compare_<:NNw } #1#2#3 < + { \if_int_compare:w #3 < \@@_eval:w } +\cs_new:cpn { @@_compare_>:NNw } #1#2#3 > + { \if_int_compare:w #3 > \@@_eval:w } +\cs_new:cpn { @@_compare_==:NNw } #1#2#3 == + { \if_int_compare:w #3 = \@@_eval:w } +\cs_new:cpn { @@_compare_!=:NNw } #1#2#3 != + { \reverse_if:N \if_int_compare:w #3 = \@@_eval:w } +\cs_new:cpn { @@_compare_<=:NNw } #1#2#3 <= + { \reverse_if:N \if_int_compare:w #3 > \@@_eval:w } +\cs_new:cpn { @@_compare_>=:NNw } #1#2#3 >= + { \reverse_if:N \if_int_compare:w #3 < \@@_eval:w } % \end{macrocode} % \end{macro} % \end{macro} @@ -1308,9 +1374,9 @@ % \UnitTested % More efficient but less natural in typing. % \begin{macrocode} -\prg_new_conditional:Npnn \int_compare:nNn #1#2#3 { p , T , F , TF} +\prg_new_conditional:Npnn \int_compare:nNn #1#2#3 { p , T , F , TF } { - \if_int_compare:w \int_eval:w #1 #2 \int_eval:w #3 \int_eval_end: + \if_int_compare:w \@@_eval:w #1 #2 \@@_eval:w #3 \@@_eval_end: \prg_return_true: \else: \prg_return_false: @@ -1319,6 +1385,35 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\int_case:nnn} +% \begin{macro}[aux]{\@@_case:nnn} +% \begin{macro}[aux]{\@@_case:nw, \@@_case_end:nw} +% For integer cases, the first task to fully expand the check +% condition. After that, a loop is started to compare each possible +% value and stop if the test is true. The tested value is put at the +% end to ensure that there is necessarily a match, which will fire the +% \enquote{else} pathway. The leading \tn{romannumeral} triggers an +% expansion which is then stopped in \cs{@@_case_end:nw}. +% \begin{macrocode} +\cs_new:Npn \int_case:nnn #1 + { + \tex_romannumeral:D + \exp_args:Nf \@@_case:nnn { \int_eval:n {#1} } + } +\cs_new:Npn \@@_case:nnn #1#2#3 + { \@@_case:nw {#1} #2 {#1} {#3} \q_recursion_stop } +\cs_new:Npn \@@_case:nw #1#2#3 + { + \int_compare:nNnTF {#1} = {#2} + { \@@_case_end:nw {#3} } + { \@@_case:nw {#1} } + } +\cs_new_eq:NN \@@_case_end:nw \__prg_case_end:nw +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% % \begin{macro}[pTF]{\int_if_odd:n} % \UnitTested % \begin{macro}[pTF]{\int_if_even:n} @@ -1327,7 +1422,7 @@ % \begin{macrocode} \prg_new_conditional:Npnn \int_if_odd:n #1 { p , T , F , TF} { - \if_int_odd:w \int_eval:w #1 \int_eval_end: + \if_int_odd:w \@@_eval:w #1 \@@_eval_end: \prg_return_true: \else: \prg_return_false: @@ -1335,7 +1430,7 @@ } \prg_new_conditional:Npnn \int_if_even:n #1 { p , T , F , TF} { - \if_int_odd:w \int_eval:w #1 \int_eval_end: + \if_int_odd:w \@@_eval:w #1 \@@_eval_end: \prg_return_false: \else: \prg_return_true: @@ -1437,6 +1532,86 @@ % \end{macro} % \end{macro} % +% \subsection{Integer step functions} +% +% \begin{macro}{\int_step_function:nnnN} +% \begin{macro}[aux]{\@@_step:NnnnN} +% Repeating a function by steps first needs a check on the direction +% of the steps. After that, do the function for the start value +% then step and loop around. It would be more symmetrical to test +% for a step size of zero before checking the sign, but we optimize +% for the most frequent case (positive step). +% \begin{macrocode} +\cs_new:Npn \int_step_function:nnnN #1#2#3#4 + { + \int_compare:nNnTF {#2} > \c_zero + { \exp_args:NNf \@@_step:NnnnN > } + { + \int_compare:nNnTF {#2} = \c_zero + { + \__msg_kernel_expandable_error:nnn { kernel } { zero-step } {#4} + \use_none:nnnn + } + { \exp_args:NNf \@@_step:NnnnN < } + } + { \int_eval:n {#1} } {#2} {#3} #4 + } +\cs_new:Npn \@@_step:NnnnN #1#2#3#4#5 + { + \int_compare:nNnF {#2} #1 {#4} + { + #5 {#2} + \exp_args:NNf \@@_step:NnnnN + #1 { \int_eval:n { #2 + #3 } } {#3} {#4} #5 + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_step_inline:nnnn} +% \begin{macro}{\int_step_variable:nnnNn} +% \UnitTested +% \begin{macro}[aux]{\@@_step:NNnnnn} +% The approach here is to build a function, with a global integer +% required to make the nesting safe (as seen in other in line +% functions), and map that function using \cs{int_step_function:nnnN}. +% We put a \cs{__prg_break_point:Nn} so that \texttt{map_break} +% functions from other modules correctly decrement \cs{g__prg_map_int} +% before looking for their own break point. The first argument is +% \cs{scan_stop:}, so no breaking function will recognize this break +% point as its own. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \int_step_inline:nnnn + { + \int_gincr:N \g__prg_map_int + \exp_args:NNc \@@_step:NNnnnn + \cs_gset_nopar:Npn + { __prg_map_ \int_use:N \g__prg_map_int :w } + } +\cs_new_protected:Npn \int_step_variable:nnnNn #1#2#3#4#5 + { + \int_gincr:N \g__prg_map_int + \exp_args:NNc \@@_step:NNnnnn + \cs_gset_nopar:Npx + { __prg_map_ \int_use:N \g__prg_map_int :w } + {#1}{#2}{#3} + { + \tl_set:Nn \exp_not:N #4 {##1} + \exp_not:n {#5} + } + } +\cs_new_protected:Npn \@@_step:NNnnnn #1#2#3#4#5#6 + { + #1 #2 ##1 {#6} + \int_step_function:nnnN {#3} {#4} {#5} #2 + \__prg_break_point:Nn \scan_stop: { \int_gdecr:N \g__prg_map_int } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% % \subsection{Formatting integers} % % \begin{macro}{\int_to_arabic:n} @@ -1449,6 +1624,7 @@ % % \begin{macro}{\int_to_symbols:nnn} % \UnitTested +% \begin{macro}[aux]{\@@_to_symbols:nnnn} % For conversion of integers to arbitrary symbols the method is in % general as follows. The input number (|#1|) is compared to the total % number of symbols available at each place (|#2|). If the input is larger @@ -1463,17 +1639,17 @@ { \int_compare:nNnTF {#1} > {#2} { - \exp_args:NNo \exp_args:No \int_to_symbols_aux:nnnn + \exp_args:NNo \exp_args:No \@@_to_symbols:nnnn { - \prg_case_int:nnn + \int_case:nnn { 1 + \int_mod:nn { #1 - 1 } {#2} } {#3} { } } {#1} {#2} {#3} } - { \prg_case_int:nnn {#1} {#3} { } } + { \int_case:nnn {#1} {#3} { } } } -\cs_new:Npn \int_to_symbols_aux:nnnn #1#2#3#4 +\cs_new:Npn \@@_to_symbols:nnnn #1#2#3#4 { \exp_args:Nf \int_to_symbols:nnn { \int_div_truncate:nn { #2 - 1 } {#3} } {#3} {#4} @@ -1481,6 +1657,7 @@ } % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro}{\int_to_alph:n,\int_to_Alph:n} % \UnitTested @@ -1556,9 +1733,9 @@ % % \begin{macro}{\int_to_base:nn} % \UnitTested -% \begin{macro}[aux]{\int_to_base_aux_i:nn, -% \int_to_base_aux_ii:nnN,\int_to_base_aux_iii:nnnN} -% \begin{macro}[int]{\int_to_letter:n} +% \begin{macro}[aux]{\@@_to_base:nn, +% \@@_to_base:nnN,\@@_to_base:nnnN} +% \begin{macro}[aux]{\@@_to_letter:n} % \UnitTested % Converting from base ten (|#1|) to a second base (|#2|) starts with % computing |#1|: if it is a complicated calculation, we shouldn't @@ -1567,12 +1744,12 @@ % function. % \begin{macrocode} \cs_new:Npn \int_to_base:nn #1 - { \exp_args:Nf \int_to_base_aux_i:nn { \int_eval:n {#1} } } -\cs_new:Npn \int_to_base_aux_i:nn #1#2 + { \exp_args:Nf \@@_to_base:nn { \int_eval:n {#1} } } +\cs_new:Npn \@@_to_base:nn #1#2 { \int_compare:nNnTF {#1} < \c_zero - { \exp_args:No \int_to_base_aux_ii:nnN { \use_none:n #1 } {#2} - } - { \int_to_base_aux_ii:nnN {#1} {#2} \c_empty_tl } + { \exp_args:No \@@_to_base:nnN { \use_none:n #1 } {#2} - } + { \@@_to_base:nnN {#1} {#2} \c_empty_tl } } % \end{macrocode} % Here, the idea is to provide a recursive system to deal with the @@ -1585,21 +1762,21 @@ % modulus is converted to a symbol and put on the right, % and the remainder is carried forward to the next round. % \begin{macrocode} -\cs_new:Npn \int_to_base_aux_ii:nnN #1#2#3 +\cs_new:Npn \@@_to_base:nnN #1#2#3 { \int_compare:nNnTF {#1} < {#2} - { \exp_last_unbraced:Nf #3 { \int_to_letter:n {#1} } } + { \exp_last_unbraced:Nf #3 { \@@_to_letter:n {#1} } } { - \exp_args:Nf \int_to_base_aux_iii:nnnN - { \int_to_letter:n { \int_mod:nn {#1} {#2} } } + \exp_args:Nf \@@_to_base:nnnN + { \@@_to_letter:n { \int_mod:nn {#1} {#2} } } {#1} {#2} #3 } } -\cs_new:Npn \int_to_base_aux_iii:nnnN #1#2#3#4 +\cs_new:Npn \@@_to_base:nnnN #1#2#3#4 { - \exp_args:Nf \int_to_base_aux_ii:nnN + \exp_args:Nf \@@_to_base:nnN { \int_div_truncate:nn {#2} {#3} } {#3} #4 @@ -1607,7 +1784,7 @@ } % \end{macrocode} % Convert to a letter only if necessary, otherwise simply return the -% value unchanged. It would be cleaner to use \cs{prg_case_int:nnn}, +% value unchanged. It would be cleaner to use \cs{int_case:nnn}, % but in our case, the cases are contiguous, so it is forty times faster % to use the \cs{if_case:w} primitive. The first \cs{exp_after:wN} % expands the conditional, jumping to the correct case, the second one @@ -1615,10 +1792,10 @@ % Since |#1| might be an expression, and not directly a single digit, % we need to evaluate it properly, and expand the trailing \cs{fi:}. % \begin{macrocode} -\cs_new:Npn \int_to_letter:n #1 +\cs_new:Npn \@@_to_letter:n #1 { \exp_after:wN \exp_after:wN - \if_case:w \int_eval:w #1 - \c_ten \int_eval_end: + \if_case:w \@@_eval:w #1 - \c_ten \@@_eval_end: A \or: B \or: C @@ -1645,7 +1822,7 @@ \or: X \or: Y \or: Z - \else: \int_value:w \int_eval:w #1 \exp_after:wN \int_eval_end: + \else: \@@_value:w \@@_eval:w #1 \exp_after:wN \@@_eval_end: \fi: } % \end{macrocode} @@ -1668,17 +1845,17 @@ % % \begin{macro}{\int_to_roman:n, \int_to_Roman:n} % \UnitTested -% \begin{macro}[aux]{\int_to_roman_aux:N, \int_to_roman_aux:N} +% \begin{macro}[aux]{\@@_to_roman:N, \@@_to_roman:N} % \begin{macro}[aux] % { -% \int_to_roman_i:w, \int_to_roman_v:w, \int_to_roman_x:w, -% \int_to_roman_l:w, \int_to_roman_c:w, \int_to_roman_d:w, -% \int_to_roman_m:w, \int_to_roman_Q:w, -% \int_to_Roman_i:w, \int_to_Roman_v:w, \int_to_Roman_x:w, -% \int_to_Roman_l:w, \int_to_Roman_c:w, \int_to_Roman_d:w, -% \int_to_Roman_m:w, \int_to_Roman_Q:w, +% \@@_to_roman_i:w, \@@_to_roman_v:w, \@@_to_roman_x:w, +% \@@_to_roman_l:w, \@@_to_roman_c:w, \@@_to_roman_d:w, +% \@@_to_roman_m:w, \@@_to_roman_Q:w, +% \@@_to_Roman_i:w, \@@_to_Roman_v:w, \@@_to_Roman_x:w, +% \@@_to_Roman_l:w, \@@_to_Roman_c:w, \@@_to_Roman_d:w, +% \@@_to_Roman_m:w, \@@_to_Roman_Q:w, % } -% The \cs{int_to_roman:w} primitive creates tokens of category +% The \cs{@@_to_roman:w} primitive creates tokens of category % code $12$ (other). Usually, what is actually wanted is letters. % The approach here is to convert the output of the primitive into % letters using appropriate control sequence names. That keeps @@ -1687,40 +1864,40 @@ % \begin{macrocode} \cs_new:Npn \int_to_roman:n #1 { - \exp_after:wN \int_to_roman_aux:N - \int_to_roman:w \int_eval:n {#1} Q + \exp_after:wN \@@_to_roman:N + \@@_to_roman:w \int_eval:n {#1} Q } -\cs_new:Npn \int_to_roman_aux:N #1 +\cs_new:Npn \@@_to_roman:N #1 { - \use:c { int_to_roman_ #1 :w } - \int_to_roman_aux:N + \use:c { @@_to_roman_ #1 :w } + \@@_to_roman:N } \cs_new:Npn \int_to_Roman:n #1 { - \exp_after:wN \int_to_Roman_aux:N - \int_to_roman:w \int_eval:n {#1} Q + \exp_after:wN \@@_to_Roman_aux:N + \@@_to_roman:w \int_eval:n {#1} Q } -\cs_new:Npn \int_to_Roman_aux:N #1 +\cs_new:Npn \@@_to_Roman_aux:N #1 { - \use:c { int_to_Roman_ #1 :w } - \int_to_Roman_aux:N + \use:c { @@_to_Roman_ #1 :w } + \@@_to_Roman_aux:N } -\cs_new_nopar:Npn \int_to_roman_i:w { i } -\cs_new_nopar:Npn \int_to_roman_v:w { v } -\cs_new_nopar:Npn \int_to_roman_x:w { x } -\cs_new_nopar:Npn \int_to_roman_l:w { l } -\cs_new_nopar:Npn \int_to_roman_c:w { c } -\cs_new_nopar:Npn \int_to_roman_d:w { d } -\cs_new_nopar:Npn \int_to_roman_m:w { m } -\cs_new_nopar:Npn \int_to_roman_Q:w #1 { } -\cs_new_nopar:Npn \int_to_Roman_i:w { I } -\cs_new_nopar:Npn \int_to_Roman_v:w { V } -\cs_new_nopar:Npn \int_to_Roman_x:w { X } -\cs_new_nopar:Npn \int_to_Roman_l:w { L } -\cs_new_nopar:Npn \int_to_Roman_c:w { C } -\cs_new_nopar:Npn \int_to_Roman_d:w { D } -\cs_new_nopar:Npn \int_to_Roman_m:w { M } -\cs_new:Npn \int_to_Roman_Q:w #1 { } +\cs_new_nopar:Npn \@@_to_roman_i:w { i } +\cs_new_nopar:Npn \@@_to_roman_v:w { v } +\cs_new_nopar:Npn \@@_to_roman_x:w { x } +\cs_new_nopar:Npn \@@_to_roman_l:w { l } +\cs_new_nopar:Npn \@@_to_roman_c:w { c } +\cs_new_nopar:Npn \@@_to_roman_d:w { d } +\cs_new_nopar:Npn \@@_to_roman_m:w { m } +\cs_new_nopar:Npn \@@_to_roman_Q:w #1 { } +\cs_new_nopar:Npn \@@_to_Roman_i:w { I } +\cs_new_nopar:Npn \@@_to_Roman_v:w { V } +\cs_new_nopar:Npn \@@_to_Roman_x:w { X } +\cs_new_nopar:Npn \@@_to_Roman_l:w { L } +\cs_new_nopar:Npn \@@_to_Roman_c:w { C } +\cs_new_nopar:Npn \@@_to_Roman_d:w { D } +\cs_new_nopar:Npn \@@_to_Roman_m:w { M } +\cs_new:Npn \@@_to_Roman_Q:w #1 { } % \end{macrocode} % \end{macro} % \end{macro} @@ -1728,54 +1905,54 @@ % % \subsection{Converting from other formats to integers} % -% \begin{macro}[int]{\int_get_sign:n} -% \begin{macro}[int]{\int_get_digits:n} +% \begin{macro}[int]{\@@_get_sign:n} +% \begin{macro}[int]{\@@_get_digits:n} % \begin{macro}[aux] -% {\int_get_sign_and_digits_aux:nNNN, \int_get_sign_and_digits_aux:oNNN} +% {\@@_get_sign_and_digits:nNNN, \@@_get_sign_and_digits:oNNN} % Finding a number and its sign requires dealing with an arbitrary % list of |+| and |-| symbols. This is done by working through token % by token until there is something else at the start of the input. % The sign of the input is tracked by the first Boolean used by the % auxiliary function. % \begin{macrocode} -\cs_new:Npn \int_get_sign:n #1 +\cs_new:Npn \@@_get_sign:n #1 { - \int_get_sign_and_digits_aux:nNNN {#1} + \@@_get_sign_and_digits:nNNN {#1} \c_true_bool \c_true_bool \c_false_bool } -\cs_new:Npn \int_get_digits:n #1 +\cs_new:Npn \@@_get_digits:n #1 { - \int_get_sign_and_digits_aux:nNNN {#1} + \@@_get_sign_and_digits:nNNN {#1} \c_true_bool \c_false_bool \c_true_bool } % \end{macrocode} % The auxiliary loops through, finding sign tokens and removing them. % The sign itself is carried through as a flag. % \begin{macrocode} -\cs_new:Npn \int_get_sign_and_digits_aux:nNNN #1#2#3#4 +\cs_new:Npn \@@_get_sign_and_digits:nNNN #1#2#3#4 { \exp_args:Nf \tl_if_head_eq_charcode:nNTF {#1} - { \bool_if:NTF #2 { - \int_get_sign_and_digits_aux:oNNN + \@@_get_sign_and_digits:oNNN { \use_none:n #1 } \c_false_bool #3#4 } { - \int_get_sign_and_digits_aux:oNNN + \@@_get_sign_and_digits:oNNN { \use_none:n #1 } \c_true_bool #3#4 } } { \exp_args:Nf \tl_if_head_eq_charcode:nNTF {#1} + - { \int_get_sign_and_digits_aux:oNNN { \use_none:n #1 } #2#3#4 } + { \@@_get_sign_and_digits:oNNN { \use_none:n #1 } #2#3#4 } { \bool_if:NT #3 { \bool_if:NF #2 - } \bool_if:NT #4 {#1} } } } -\cs_generate_variant:Nn \int_get_sign_and_digits_aux:nNNN { o } +\cs_generate_variant:Nn \@@_get_sign_and_digits:nNNN { o } % \end{macrocode} % \end{macro} % \end{macro} @@ -1783,9 +1960,9 @@ % % \begin{macro}{\int_from_alph:n} % \UnitTested -% \begin{macro}[aux]{\int_from_alph_aux:n} -% \begin{macro}[aux]{\int_from_alph_aux:nN} -% \begin{macro}[aux]{\int_from_alph_aux:N} +% \begin{macro}[aux]{\@@_from_alph:n} +% \begin{macro}[aux]{\@@_from_alph:nN} +% \begin{macro}[aux]{\@@_from_alph:N} % The aim here is to iterate through the input, converting one letter at % a time to a number. The same approach is also used for base % conversion, but this needs a different final auxiliary. @@ -1794,22 +1971,22 @@ { \int_eval:n { - \int_get_sign:n {#1} - \exp_args:Nf \int_from_alph_aux:n { \int_get_digits:n {#1} } + \@@_get_sign:n {#1} + \exp_args:Nf \@@_from_alph:n { \@@_get_digits:n {#1} } } } -\cs_new:Npn \int_from_alph_aux:n #1 - { \int_from_alph_aux:nN { 0 } #1 \q_nil } -\cs_new:Npn \int_from_alph_aux:nN #1#2 +\cs_new:Npn \@@_from_alph:n #1 + { \@@_from_alph:nN { 0 } #1 \q_nil } +\cs_new:Npn \@@_from_alph:nN #1#2 { \quark_if_nil:NTF #2 {#1} { - \exp_args:Nf \int_from_alph_aux:nN - { \int_eval:n { #1 * 26 + \int_from_alph_aux:N #2 } } + \exp_args:Nf \@@_from_alph:nN + { \int_eval:n { #1 * 26 + \@@_from_alph:N #2 } } } } -\cs_new:Npn \int_from_alph_aux:N #1 +\cs_new:Npn \@@_from_alph:N #1 { \int_eval:n { `#1 - \int_compare:nNnTF { `#1 } < { 91 } { 64 } { 96 } } } % \end{macrocode} % \end{macro} @@ -1819,9 +1996,9 @@ % % \begin{macro}{\int_from_base:nn} % \UnitTested -% \begin{macro}[aux]{\int_from_base_aux:nn} -% \begin{macro}[aux]{\int_from_base_aux:nnN} -% \begin{macro}[aux]{\int_from_base_aux:N} +% \begin{macro}[aux]{\@@_from_base:nn} +% \begin{macro}[aux]{\@@_from_base:nnN} +% \begin{macro}[aux]{\@@_from_base:N} % Conversion to base ten means stripping off the sign then iterating % through the input one token at a time. The total number is then added % up as the code loops. @@ -1830,20 +2007,20 @@ { \int_eval:n { - \int_get_sign:n {#1} - \exp_args:Nf \int_from_base_aux:nn - { \int_get_digits:n {#1} } {#2} + \@@_get_sign:n {#1} + \exp_args:Nf \@@_from_base:nn + { \@@_get_digits:n {#1} } {#2} } } -\cs_new:Npn \int_from_base_aux:nn #1#2 - { \int_from_base_aux:nnN { 0 } { #2 } #1 \q_nil } -\cs_new:Npn \int_from_base_aux:nnN #1#2#3 +\cs_new:Npn \@@_from_base:nn #1#2 + { \@@_from_base:nnN { 0 } { #2 } #1 \q_nil } +\cs_new:Npn \@@_from_base:nnN #1#2#3 { \quark_if_nil:NTF #3 {#1} { - \exp_args:Nf \int_from_base_aux:nnN - { \int_eval:n { #1 * #2 + \int_from_base_aux:N #3 } } + \exp_args:Nf \@@_from_base:nnN + { \int_eval:n { #1 * #2 + \@@_from_base:N #3 } } {#2} } } @@ -1852,7 +2029,7 @@ % them into the appropriate number, hence the two-part nature of the % function. % \begin{macrocode} -\cs_new:Npn \int_from_base_aux:N #1 +\cs_new:Npn \@@_from_base:N #1 { \int_compare:nNnTF { `#1 } < { 58 } {#1} @@ -1882,40 +2059,40 @@ % % \begin{variable} % { -% \c_int_from_roman_i_int, \c_int_from_roman_v_int, -% \c_int_from_roman_x_int, \c_int_from_roman_l_int, -% \c_int_from_roman_c_int, \c_int_from_roman_d_int, -% \c_int_from_roman_m_int, -% \c_int_from_roman_I_int, \c_int_from_roman_V_int, -% \c_int_from_roman_X_int, \c_int_from_roman_L_int, -% \c_int_from_roman_C_int, \c_int_from_roman_D_int, -% \c_int_from_roman_M_int +% \c_@@_from_roman_i_int, \c_@@_from_roman_v_int, +% \c_@@_from_roman_x_int, \c_@@_from_roman_l_int, +% \c_@@_from_roman_c_int, \c_@@_from_roman_d_int, +% \c_@@_from_roman_m_int, +% \c_@@_from_roman_I_int, \c_@@_from_roman_V_int, +% \c_@@_from_roman_X_int, \c_@@_from_roman_L_int, +% \c_@@_from_roman_C_int, \c_@@_from_roman_D_int, +% \c_@@_from_roman_M_int % } % Constants used to convert from Roman numerals to integers. % \begin{macrocode} -\int_const:cn { c_int_from_roman_i_int } { 1 } -\int_const:cn { c_int_from_roman_v_int } { 5 } -\int_const:cn { c_int_from_roman_x_int } { 10 } -\int_const:cn { c_int_from_roman_l_int } { 50 } -\int_const:cn { c_int_from_roman_c_int } { 100 } -\int_const:cn { c_int_from_roman_d_int } { 500 } -\int_const:cn { c_int_from_roman_m_int } { 1000 } -\int_const:cn { c_int_from_roman_I_int } { 1 } -\int_const:cn { c_int_from_roman_V_int } { 5 } -\int_const:cn { c_int_from_roman_X_int } { 10 } -\int_const:cn { c_int_from_roman_L_int } { 50 } -\int_const:cn { c_int_from_roman_C_int } { 100 } -\int_const:cn { c_int_from_roman_D_int } { 500 } -\int_const:cn { c_int_from_roman_M_int } { 1000 } +\int_const:cn { c_@@_from_roman_i_int } { 1 } +\int_const:cn { c_@@_from_roman_v_int } { 5 } +\int_const:cn { c_@@_from_roman_x_int } { 10 } +\int_const:cn { c_@@_from_roman_l_int } { 50 } +\int_const:cn { c_@@_from_roman_c_int } { 100 } +\int_const:cn { c_@@_from_roman_d_int } { 500 } +\int_const:cn { c_@@_from_roman_m_int } { 1000 } +\int_const:cn { c_@@_from_roman_I_int } { 1 } +\int_const:cn { c_@@_from_roman_V_int } { 5 } +\int_const:cn { c_@@_from_roman_X_int } { 10 } +\int_const:cn { c_@@_from_roman_L_int } { 50 } +\int_const:cn { c_@@_from_roman_C_int } { 100 } +\int_const:cn { c_@@_from_roman_D_int } { 500 } +\int_const:cn { c_@@_from_roman_M_int } { 1000 } % \end{macrocode} % \end{variable} % % \begin{macro}{\int_from_roman:n} % \UnitTested % \TestMissing{boundary cases / wrong input?} -% \begin{macro}[aux]{\int_from_roman_aux:NN} -% \begin{macro}[aux]{\int_from_roman_end:w} -% \begin{macro}[aux]{\int_from_roman_clean_up:w} +% \begin{macro}[aux]{\@@_from_roman:NN} +% \begin{macro}[aux]{\@@_from_roman_end:w} +% \begin{macro}[aux]{\@@_from_roman_clean_up:w} % The method here is to iterate through the input, finding the % appropriate value for each letter and building up a sum. This is % then evaluated by \TeX{}. @@ -1924,48 +2101,48 @@ { \tl_if_blank:nF {#1} { - \exp_after:wN \int_from_roman_end:w - \int_value:w \int_eval:w - \int_from_roman_aux:NN #1 Q \q_stop + \exp_after:wN \@@_from_roman_end:w + \@@_value:w \@@_eval:w + \@@_from_roman:NN #1 Q \q_stop } } -\cs_new:Npn \int_from_roman_aux:NN #1#2 +\cs_new:Npn \@@_from_roman:NN #1#2 { \str_if_eq:nnTF {#1} { Q } {#1#2} { \str_if_eq:nnTF {#2} { Q } { - \int_if_exist:cF { c_int_from_roman_ #1 _int } - { \int_from_roman_clean_up:w } + \int_if_exist:cF { c_@@_from_roman_ #1 _int } + { \@@_from_roman_clean_up:w } + - \use:c { c_int_from_roman_ #1 _int } + \use:c { c_@@_from_roman_ #1 _int } #2 } { - \int_if_exist:cF { c_int_from_roman_ #1 _int } - { \int_from_roman_clean_up:w } - \int_if_exist:cF { c_int_from_roman_ #2 _int } - { \int_from_roman_clean_up:w } + \int_if_exist:cF { c_@@_from_roman_ #1 _int } + { \@@_from_roman_clean_up:w } + \int_if_exist:cF { c_@@_from_roman_ #2 _int } + { \@@_from_roman_clean_up:w } \int_compare:nNnTF - { \use:c { c_int_from_roman_ #1 _int } } + { \use:c { c_@@_from_roman_ #1 _int } } < - { \use:c { c_int_from_roman_ #2 _int } } + { \use:c { c_@@_from_roman_ #2 _int } } { - + \use:c { c_int_from_roman_ #2 _int } - - \use:c { c_int_from_roman_ #1 _int } - \int_from_roman_aux:NN + + \use:c { c_@@_from_roman_ #2 _int } + - \use:c { c_@@_from_roman_ #1 _int } + \@@_from_roman:NN } { - + \use:c { c_int_from_roman_ #1 _int } - \int_from_roman_aux:NN #2 + + \use:c { c_@@_from_roman_ #1 _int } + \@@_from_roman:NN #2 } } } } -\cs_new:Npn \int_from_roman_end:w #1 Q #2 \q_stop +\cs_new:Npn \@@_from_roman_end:w #1 Q #2 \q_stop { \tl_if_empty:nTF {#2} {#1} {#2} } -\cs_new:Npn \int_from_roman_clean_up:w #1 Q { + 0 Q -1 } +\cs_new:Npn \@@_from_roman_clean_up:w #1 Q { + 0 Q -1 } % \end{macrocode} % \end{macro} % \end{macro} @@ -1977,16 +2154,19 @@ % \begin{macro}{\int_show:N,\int_show:c} % \UnitTested % \begin{macrocode} -\cs_new_eq:NN \int_show:N \kernel_register_show:N -\cs_new_eq:NN \int_show:c \kernel_register_show:c +\cs_new_eq:NN \int_show:N \__kernel_register_show:N +\cs_new_eq:NN \int_show:c \__kernel_register_show:c % \end{macrocode} % \end{macro} % % \begin{macro}{\int_show:n} % \UnitTested +% We don't use the \TeX{} primitive \tn{showthe} to show integer +% expressions: this gives a more unified output, since the closing +% brace is read by the integer expression in all cases. % \begin{macrocode} \cs_new_protected:Npn \int_show:n #1 - { \tex_showthe:D \int_eval:w #1 \int_eval_end: } + { \etex_showtokens:D \exp_after:wN { \int_use:N \@@_eval:w #1 } } % \end{macrocode} % \end{macro} % @@ -2064,14 +2244,13 @@ % % \subsection{Scratch integers} % -% \begin{variable}{\l_tmpa_int, \l_tmpb_int, \l_tmpc_int} +% \begin{variable}{\l_tmpa_int, \l_tmpb_int} % \begin{variable}{\g_tmpa_int, \g_tmpb_int} -% We provide three local and two global scratch counters, maybe we +% We provide two local and two global scratch counters, maybe we % need more or less. % \begin{macrocode} \int_new:N \l_tmpa_int \int_new:N \l_tmpb_int -\int_new:N \l_tmpc_int \int_new:N \g_tmpa_int \int_new:N \g_tmpb_int % \end{macrocode} @@ -2147,6 +2326,35 @@ % \end{macro} % \end{macro} % +% \begin{macro}{\if_num:w} +% Deprecated 2012-05-30 for removal after 2012-11-30. +% \begin{macrocode} +\cs_new_eq:NN \if_num:w \if_int_compare:w +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_tmpc_int} +% Deprecated 2012-07-04 for removal after 2012-12-31. +% \begin{macrocode} +\int_new:N \l_tmpc_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\int_eval:w, \int_eval_end:} +% Deprecated 2012-07-13 for removal after 2012-12-31. +% \begin{macrocode} +\cs_new_eq:NN \int_eval:w \@@_eval:w +\cs_new_eq:NN \int_eval_end: \@@_eval_end: +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\int_value:w} +% Deprecated 2012-07-14 for removal after 2012-12-31. +% \begin{macrocode} +\cs_new_eq:NN \int_value:w \@@_value:w +% \end{macrocode} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx index e0becb45696..7e3cc783af2 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3keys.dtx Copyright (C) 2006-2011 The LaTeX3 Project +%% File: l3keys.dtx Copyright (C) 2006-2012 The LaTeX3 Project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -35,7 +35,7 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3keys.dtx 3487 2012-03-03 19:36:51Z bruno $ +\GetIdInfo$Id: l3keys.dtx 3986 2012-07-15 19:23:51Z joseph $ {L3 Experimental key-value interfaces} %</driver|package> %<*driver> @@ -170,27 +170,18 @@ % arbitrary \meta{key}, which when used may be supplied with a % \meta{value}. All key \emph{definitions} are local. % -% \begin{function}{.bool_set:N} +% \begin{function}{.bool_set:N, .bool_gset:N} % \begin{syntax} % \meta{key} .bool_set:N = \meta{boolean} % \end{syntax} % Defines \meta{key} to set \meta{boolean} to \meta{value} (which % must be either \texttt{true} or \texttt{false}). If the variable % does not exist, it will be created at the point that the key is -% set up. The \meta{boolean} will be assigned locally. +% set up. % \end{function} % -% \begin{function}{.bool_gset:N} -% \begin{syntax} -% \meta{key} .bool_gset:N = \meta{boolean} -% \end{syntax} -% Defines \meta{key} to set \meta{boolean} to \meta{value} (which -% must be either \texttt{true} or \texttt{false}). If the variable -% does not exist, it will be created at the point that the key is -% set up. The \meta{boolean} will be assigned globally. -% \end{function} -% -% \begin{function}[added = 2011-08-28]{.bool_set_inverse:N} +% \begin{function}[added = 2011-08-28] +% {.bool_set_inverse:N, .bool_gset_inverse:N} % \begin{syntax} % \meta{key} .bool_set_inverse:N = \meta{boolean} % \end{syntax} @@ -198,22 +189,7 @@ % inverse of \meta{value} (which must be either \texttt{true} or % \texttt{false}). % If the \meta{boolean} does not exist, it will be created at the point -% that the key is set up. The \meta{boolean} will be assigned locally. -% -% \textbf{This property is experimental.} -% \end{function} -% -% \begin{function}{.bool_gset_inverse:N} -% \begin{syntax} -% \meta{key} .bool_gset_inverse:N = \meta{boolean} -% \end{syntax} -% Defines \meta{key} to set \meta{boolean} to the logical -% inverse of \meta{value} (which must be either \texttt{true} or -% \texttt{false}). -% If the \meta{boolean} does not exist, it will be created at the point -% that the key is set up. The \meta{boolean} will be assigned globally. -% -% \textbf{This property is experimental.} +% that the key is set up. % \end{function} % % \begin{function}{.choice:} @@ -233,10 +209,8 @@ % which are implemented using the \meta{code}. Inside \meta{code}, % \cs{l_keys_choice_tl} will be the name of the choice made, and % \cs{l_keys_choice_int} will be the position of the choice in the list -% of \meta{choices} (indexed from $0$). +% of \meta{choices} (indexed from~$1$). % Choices are discussed in detail in section~\ref{sec:choice}. -% -% \textbf{This property is experimental.} % \end{function} % % \begin{function}{.choice_code:n, .choice_code:x} @@ -251,21 +225,12 @@ % detail in section~\ref{sec:choice}. % \end{function} % -% \begin{function}[added=2011/09/11]{.clist_set:N, .clist_set:c} +% \begin{function}[added=2011/09/11] +% {.clist_set:N, .clist_set:c, .clist_gset:N, .clist_gset:c} % \begin{syntax} % \meta{key} .clist_set:N = \meta{comma list variable} % \end{syntax} -% Defines \meta{key} to locally set \meta{comma list variable} to \meta{value}. -% Spaces around commas and empty items will be stripped. -% If the variable does not exist, it -% will be created at the point that the key is set up. -% \end{function} -% -% \begin{function}[added=2011/09/11]{.clist_gset:N, .clist_gset:c} -% \begin{syntax} -% \meta{key} .clist_gset:N = \meta{comma list variable} -% \end{syntax} -% Defines \meta{key} to globally set \meta{comma list variable} to \meta{value}. +% Defines \meta{key} to set \meta{comma list variable} to \meta{value}. % Spaces around commas and empty items will be stripped. % If the variable does not exist, it % will be created at the point that the key is set up. @@ -304,44 +269,22 @@ % \end{verbatim} % \end{function} % -% \begin{function}{.dim_set:N, .dim_set:c} +% \begin{function}{.dim_set:N, .dim_set:c, .dim_gset:N, .dim_gset:c} % \begin{syntax} % \meta{key} .dim_set:N = \meta{dimension} % \end{syntax} % Defines \meta{key} to set \meta{dimension} to \meta{value} (which % must a dimension expression). If the variable does not exist, it -% will be created at the point that the key is set up. The -% \meta{dimension} will be assigned locally. -% \end{function} -% -% \begin{function}{.dim_gset:N, .dim_gset:c} -% \begin{syntax} -% \meta{key} .dim_gset:N = \meta{dimension} -% \end{syntax} -% Defines \meta{key} to set \meta{dimension} to \meta{value} (which -% must a dimension expression). If the variable does not exist, it -% will be created at the point that the key is set up. The -% \meta{dimension} will be assigned globally. +% will be created at the point that the key is set up. % \end{function} % -% \begin{function}{.fp_set:N, .fp_set:c} +% \begin{function}{.fp_set:N, .fp_set:c, .fp_gset:N, .fp_gset:c} % \begin{syntax} % \meta{key} .fp_set:N = \meta{floating point} % \end{syntax} % Defines \meta{key} to set \meta{floating point} to \meta{value} % (which must a floating point number). If the variable does not exist, -% it will be created at the point that the key is set up. The -% \meta{integer} will be assigned locally. -% \end{function} -% -% \begin{function}{.fp_gset:N, .fp_gset:c} -% \begin{syntax} -% \meta{key} .fp_gset:N = \meta{floating point} -% \end{syntax} -% Defines \meta{key} to set \meta{floating-point} to \meta{value} -% (which must a floating point number). If the variable does not exist, -% it will be created at the point that the key is set up. The -% \meta{integer} will be assigned globally. +% it will be created at the point that the key is set up. % \end{function} % % \begin{function}{.generate_choices:n} @@ -355,25 +298,24 @@ % \texttt{.choice_code:n} (or \texttt{.choice_code:x}). Choices are % discussed in detail in section~\ref{sec:choice}. % \end{function} -% -% \begin{function}{.int_set:N, .int_set:c} +% +% \begin{function}[added = 2012-06-02]{.initial:n, .initial:V} % \begin{syntax} -% \meta{key} .int_set:N = \meta{integer} +% \meta{key} .initial:n = \meta{value} % \end{syntax} -% Defines \meta{key} to set \meta{integer} to \meta{value} (which -% must be an integer expression). If the variable does not exist, it -% will be created at the point that the key is set up. The -% \meta{integer} will be assigned locally. +% Initialises the \meta{key} with the \meta{value}, equivalent to +% \begin{quote} +% \cs{keys_set:nn} \marg{module} \{ \meta{key} = \meta{value} \} +% \end{quote} % \end{function} % -% \begin{function}{.int_gset:N, .int_gset:c} +% \begin{function}{.int_set:N, .int_set:c, .int_gset:N, .int_gset:c} % \begin{syntax} -% \meta{key} .int_gset:N = \meta{integer} +% \meta{key} .int_set:N = \meta{integer} % \end{syntax} % Defines \meta{key} to set \meta{integer} to \meta{value} (which % must be an integer expression). If the variable does not exist, it -% will be created at the point that the key is set up. The -% \meta{integer} will be assigned globally. +% will be created at the point that the key is set up. % \end{function} % % \begin{function}{.meta:n, .meta:x} @@ -397,81 +339,47 @@ % \textbf{This property is experimental.} % \end{function} % -% \begin{function}[added = 2011-08-21]{.multichoice:nn} +% \begin{function}[added = 2011-08-21]{.multichoices:nn} % \begin{syntax} -% \meta{key} .multichoice:nn \meta{choices} \meta{code} +% \meta{key} .multichoices:nn \meta{choices} \meta{code} % \end{syntax} % Sets \meta{key} to act as a multiple choice key, and defines a series % \meta{choices} % which are implemented using the \meta{code}. Inside \meta{code}, % \cs{l_keys_choice_tl} will be the name of the choice made, and % \cs{l_keys_choice_int} will be the position of the choice in the list -% of \meta{choices} (indexed from $0$). +% of \meta{choices} (indexed from~$1$). % Choices are discussed in detail in section~\ref{sec:choice}. % % \textbf{This property is experimental.} % \end{function} % -% \begin{function}{.skip_set:N, .skip_set:c} +% \begin{function}{.skip_set:N, .skip_set:c, .skip_gset:N, .skip_gset:c} % \begin{syntax} % \meta{key} .skip_set:N = \meta{skip} % \end{syntax} % Defines \meta{key} to set \meta{skip} to \meta{value} (which % must be a skip expression). If the variable does not exist, it -% will be created at the point that the key is set up. The -% \meta{skip} will be assigned locally. -% \end{function} -% -% \begin{function}{.skip_gset:N, .skip_gset:c} -% \begin{syntax} -% \meta{key} .skip_gset:N = \meta{skip} -% \end{syntax} -% Defines \meta{key} to set \meta{skip} to \meta{value} (which -% must be a skip expression). If the variable does not exist, it -% will be created at the point that the key is set up. The -% \meta{skip} will be assigned globally. +% will be created at the point that the key is set up. % \end{function} % -% \begin{function}{.tl_set:N, .tl_set:c} +% \begin{function}{.tl_set:N, .tl_set:c, .tl_gset:N, .tl_gset:c} % \begin{syntax} % \meta{key} .tl_set:N = \meta{token list variable} % \end{syntax} % Defines \meta{key} to set \meta{token list variable} to \meta{value}. % If the variable does not exist, it will be created at the point that -% the key is set up. The \meta{token list variable} will be assigned -% locally. -% \end{function} -% -% \begin{function}{.tl_gset:N, .tl_gset:c} -% \begin{syntax} -% \meta{key} .tl_gset:N = \meta{token list variable} -% \end{syntax} -% Defines \meta{key} to set \meta{token list variable} to \meta{value}. -% If the variable does not exist, it will be created at the point that -% the key is set up. The \meta{token list variable} will be assigned -% globally. +% the key is set up. % \end{function} % -% \begin{function}{.tl_set_x:N, .tl_set_x:c} +% \begin{function}{.tl_set_x:N, .tl_set_x:c, .tl_gset_x:N, .tl_gset_x:c} % \begin{syntax} % \meta{key} .tl_set_x:N = \meta{token list variable} % \end{syntax} % Defines \meta{key} to set \meta{token list variable} to \meta{value}, % which will be subjected to an \texttt{x}-type expansion % (\emph{i.e.}~using \cs{tl_set:Nx}). If the variable does not exist, -% it will be created at the point that the key is set up. The -% \meta{token list variable} will be assigned locally. -% \end{function} -% -% \begin{function}{.tl_gset_x:N, .tl_gset_x:c} -% \begin{syntax} -% \meta{key} .tl_gset_x:N = \meta{token list variable} -% \end{syntax} -% Defines \meta{key} to set \meta{token list variable} to \meta{value}, -% which will be subjected to an \texttt{x}-type expansion -% (\emph{i.e.}~using \cs{tl_set:Nx}). If the variable does not exist, -% it will be created at the point that the key is set up. The -% \meta{token list variable} will be assigned globally. +% it will be created at the point that the key is set up. % \end{function} % % \begin{function}{.value_forbidden:} @@ -552,9 +460,7 @@ % } % \end{verbatim} % Following common computing practice, \cs{l_keys_choice_int} is -% indexed from $0$ (as an offset), so that the value of -% \cs{l_keys_choice_int} for the first choice in a list will be -% zero. +% indexed from~$1$. % % The same approach is also implemented by the \emph{experimental} % property \texttt{.choices:nn}. This combines the functionality of @@ -691,9 +597,6 @@ % % \section{Setting known keys only} % -% The functionality described in this section is experimental and may be -% altered or removed, depending on feedback. -% % \begin{function}[added = 2011-08-23] % { % \keys_set_known:nnN, \keys_set_known:nVN, @@ -720,7 +623,7 @@ % has been defined for \meta{key}. % \end{function} % -% \begin{function}[added = 2011-08-21,EXP,pTF]{\keys_if_choice_exist:nn} +% \begin{function}[added = 2011-08-21,EXP,pTF]{\keys_if_choice_exist:nnn} % \begin{syntax} % \cs{keys_if_choice_exist_p:nnn} \meta{module} \meta{key} \meta{choice} \\ % \cs{keys_if_choice_exist:nnnTF} \meta{module} \meta{key} \meta{choice} \Arg{true code} \Arg{false code} @@ -782,15 +685,15 @@ % % \begin{function}[updated = 2011-09-08]{\keyval_parse:NNn} % \begin{syntax} -% \cs{keyval_parse:NNn} \meta{function1} \meta{function2} \Arg{key--value list} +% \cs{keyval_parse:NNn} \meta{function_1} \meta{function_2} \Arg{key--value list} % \end{syntax} % Parses the \meta{key--value list} into a series of \meta{keys} and % associated \meta{values}, or keys alone (if no \meta{value} was -% given). \meta{function1} should take one argument, while -% \meta{function2} should absorb two arguments. After +% given). \meta{function_1} should take one argument, while +% \meta{function_2} should absorb two arguments. After % \cs{keyval_parse:NNn} has parsed the \meta{key--value list}, -% \meta{function1} will be used to process keys given with no value -% and \meta{function2} will be used to process keys given with a +% \meta{function_1} will be used to process keys given with no value +% and \meta{function_2} will be used to process keys given with a % value. The order of the \meta{keys} in the \meta{key--value list} % will be preserved. Thus % \begin{verbatim} @@ -825,41 +728,43 @@ %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % % \subsection{Low-level interface} +% +%<@@=keyval> % % For historical reasons this code uses the `keyval' module prefix. % -% \begin{variable}{\g_keyval_level_int} +% \begin{variable}{\g_@@_level_int} % For nesting purposes an integer is needed for the current level. % \begin{macrocode} -\int_new:N \g_keyval_level_int +\int_new:N \g_@@_level_int % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_keyval_key_tl, \l_keyval_value_tl} +% \begin{variable}{\l_@@_key_tl, \l_@@_value_tl} % The current key name and value. % \begin{macrocode} -\tl_new:N \l_keyval_key_tl -\tl_new:N \l_keyval_value_tl +\tl_new:N \l_@@_key_tl +\tl_new:N \l_@@_value_tl % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_keyval_sanitise_tl} -% \begin{variable}{\l_keyval_parse_tl} +% \begin{variable}{\l_@@_sanitise_tl} +% \begin{variable}{\l_@@_parse_tl} % Token list variables for dealing with awkward category codes in the % input. % \begin{macrocode} -\tl_new:N \l_keyval_sanitise_tl -\tl_new:N \l_keyval_parse_tl +\tl_new:N \l_@@_sanitise_tl +\tl_new:N \l_@@_parse_tl % \end{macrocode} %\end{variable} %\end{variable} % -% \begin{macro}{\keyval_parse:n} +% \begin{macro}{\@@_parse:n} % The parsing function first deals with the category codes for % |=| and |,|, so that there are no odd events. The input is then % handed off to the element by element system. @@ -872,49 +777,49 @@ \tl_to_lowercase:n { \group_end: - \cs_new_protected:Npn \keyval_parse:n #1 + \cs_new_protected:Npn \@@_parse:n #1 { \group_begin: - \tl_clear:N \l_keyval_sanitise_tl - \tl_set:Nn \l_keyval_sanitise_tl {#1} - \tl_replace_all:Nnn \l_keyval_sanitise_tl { = } { 8 } - \tl_replace_all:Nnn \l_keyval_sanitise_tl { , } { 9 } - \tl_clear:N \l_keyval_parse_tl - \exp_after:wN \keyval_parse_elt:w \exp_after:wN - \q_no_value \l_keyval_sanitise_tl 9 \q_nil 9 + \tl_clear:N \l_@@_sanitise_tl + \tl_set:Nn \l_@@_sanitise_tl {#1} + \tl_replace_all:Nnn \l_@@_sanitise_tl { = } { 8 } + \tl_replace_all:Nnn \l_@@_sanitise_tl { , } { 9 } + \tl_clear:N \l_@@_parse_tl + \exp_after:wN \@@_parse_elt:w \exp_after:wN + \q_no_value \l_@@_sanitise_tl 9 \q_nil 9 \exp_after:wN \group_end: - \l_keyval_parse_tl + \l_@@_parse_tl } } % \end{macrocode} % \end{macro} % -% \begin{macro}{\keyval_parse_elt:w} +% \begin{macro}{\@@_parse_elt:w} % Each item to be parsed will have \cs{q_no_value} added to the front. % Hence the blank test here can always be used to find a totally % empty argument. If this is the case, the system loops round. If there % is something to parse, there is a check for the \cs{q_nil} marker % and if not a hand-off. % \begin{macrocode} -\cs_new_protected:Npn \keyval_parse_elt:w #1 , +\cs_new_protected:Npn \@@_parse_elt:w #1 , { \tl_if_blank:oTF { \use_none:n #1 } - { \keyval_parse_elt:w \q_no_value } + { \@@_parse_elt:w \q_no_value } { \quark_if_nil:oF { \use_ii:nn #1 } { - \keyval_split_key_value:w #1 = = \q_stop - \keyval_parse_elt:w \q_no_value + \@@_split_key_value:w #1 = = \q_stop + \@@_parse_elt:w \q_no_value } } } % \end{macrocode} % \end{macro} % -% \begin{macro}{\keyval_split_key_value:w} -% \begin{macro}[aux]{\keyval_split_key_value_aux:wTF} +% \begin{macro}{\@@_split_key_value:w} +% \begin{macro}[aux]{\@@_split_key_value:wTF} % The key and value are handled separately. First the key is grabbed and -% saved as \cs{l_keyval_key_tl}. Then a check is need to see if there is +% saved as \cs{l_@@_key_tl}. Then a check is need to see if there is % a value at all: if not then the key name is simply added to the output. % If there is a value then there is a check to ensure that there was % only one |=| in the input (remembering some extra ones are around at @@ -922,84 +827,84 @@ % hand-off to find the value: the \cs{q_nil} is there to prevent loss % of braces. % \begin{macrocode} -\cs_new_protected:Npn \keyval_split_key_value:w #1 = #2 \q_stop +\cs_new_protected:Npn \@@_split_key_value:w #1 = #2 \q_stop { - \keyval_split_key:w #1 \q_stop + \@@_split_key:w #1 \q_stop \str_if_eq:nnTF {#2} { = } { - \tl_put_right:Nx \l_keyval_parse_tl + \tl_put_right:Nx \l_@@_parse_tl { \exp_not:c - { keyval_key_no_value_elt_ \int_use:N \g_keyval_level_int :n } - { \exp_not:o \l_keyval_key_tl } + { @@_key_no_value_elt_ \int_use:N \g_@@_level_int :n } + { \exp_not:o \l_@@_key_tl } } } { - \keyval_split_key_value_aux:wTF #2 \q_no_value \q_stop - { \keyval_split_value:w \q_nil #2 } - { \msg_kernel_error:nn { keyval } { misplaced-equals-sign } } + \@@_split_key_value:wTF #2 \q_no_value \q_stop + { \@@_split_value:w \q_nil #2 } + { \__msg_kernel_error:nn { kernel } { misplaced-equals-sign } } } } -\cs_new:Npn \keyval_split_key_value_aux:wTF #1 = #2#3 \q_stop +\cs_new:Npn \@@_split_key_value:wTF #1 = #2#3 \q_stop { \tl_if_head_eq_meaning:nNTF {#3} \q_no_value } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}{\keyval_split_key:w} +% \begin{macro}{\@@_split_key:w} % The aim here is to remove spaces and also exactly one set of braces. % There is also a quark to remove, hence the \cs{use_none:n} appearing before % application of \cs{tl_trim_spaces:n}. % \begin{macrocode} -\cs_new_protected:Npn \keyval_split_key:w #1 \q_stop +\cs_new_protected:Npn \@@_split_key:w #1 \q_stop { - \tl_set:Nx \l_keyval_key_tl + \tl_set:Nx \l_@@_key_tl { \exp_after:wN \tl_trim_spaces:n \exp_after:wN { \use_none:n #1 } } } % \end{macrocode} % \end{macro} % -% \begin{macro}{\keyval_split_value:w} +% \begin{macro}{\@@_split_value:w} % Here the value has to be separated from the equals signs and the % leading \cs{q_nil} added in to keep the brace levels. Fist the % processing function can be added to the output list. If there is no -% value, setting \cs{l_keyval_value_tl} with three groups removed will +% value, setting \cs{l_@@_value_tl} with three groups removed will % leave nothing at all, and so an empty group can be added to the % parsed list. On the other hand, if the value is entirely contained -% within a set of braces then \cs{l_keyval_value_tl} will contain +% within a set of braces then \cs{l_@@_value_tl} will contain % \cs{q_nil} only. In that case, strip off the leading quark using % \cs{use_ii:nnn}, which also deals with any spaces. % \begin{macrocode} -\cs_new_protected:Npn \keyval_split_value:w #1 = = +\cs_new_protected:Npn \@@_split_value:w #1 = = { - \tl_put_right:Nx \l_keyval_parse_tl + \tl_put_right:Nx \l_@@_parse_tl { \exp_not:c - { keyval_key_value_elt_ \int_use:N \g_keyval_level_int :nn } - { \exp_not:o \l_keyval_key_tl } + { @@_key_value_elt_ \int_use:N \g_@@_level_int :nn } + { \exp_not:o \l_@@_key_tl } } - \tl_set:Nx \l_keyval_value_tl + \tl_set:Nx \l_@@_value_tl { \exp_not:o { \use_none:nnn #1 \q_nil \q_nil } } - \tl_if_empty:NTF \l_keyval_value_tl - { \tl_put_right:Nn \l_keyval_parse_tl { { } } } + \tl_if_empty:NTF \l_@@_value_tl + { \tl_put_right:Nn \l_@@_parse_tl { { } } } { - \quark_if_nil:NTF \l_keyval_value_tl + \quark_if_nil:NTF \l_@@_value_tl { - \tl_put_right:Nx \l_keyval_parse_tl + \tl_put_right:Nx \l_@@_parse_tl { { \exp_not:o { \use_ii:nnn #1 \q_nil } } } } - { \keyval_split_value_aux:w #1 \q_stop } + { \@@_split_value_aux:w #1 \q_stop } } } % \end{macrocode} % A similar idea to the key code: remove the spaces from each end and % deal with one set of braces. % \begin{macrocode} -\cs_new_protected:Npn \keyval_split_value_aux:w \q_nil #1 \q_stop +\cs_new_protected:Npn \@@_split_value_aux:w \q_nil #1 \q_stop { - \tl_set:Nx \l_keyval_value_tl { \tl_trim_spaces:n {#1} } - \tl_put_right:Nx \l_keyval_parse_tl - { { \exp_not:o \l_keyval_value_tl } } + \tl_set:Nx \l_@@_value_tl { \tl_trim_spaces:n {#1} } + \tl_put_right:Nx \l_@@_parse_tl + { { \exp_not:o \l_@@_value_tl } } } % \end{macrocode} % \end{macro} @@ -1010,20 +915,20 @@ % \begin{macrocode} \cs_new_protected:Npn \keyval_parse:NNn #1#2#3 { - \int_gincr:N \g_keyval_level_int + \int_gincr:N \g_@@_level_int \cs_gset_eq:cN - { keyval_key_no_value_elt_ \int_use:N \g_keyval_level_int :n } #1 + { @@_key_no_value_elt_ \int_use:N \g_@@_level_int :n } #1 \cs_gset_eq:cN - { keyval_key_value_elt_ \int_use:N \g_keyval_level_int :nn } #2 - \keyval_parse:n {#3} - \int_gdecr:N \g_keyval_level_int + { @@_key_value_elt_ \int_use:N \g_@@_level_int :nn } #2 + \@@_parse:n {#3} + \int_gdecr:N \g_@@_level_int } % \end{macrocode} % \end{macro} % % One message for the low level parsing system. % \begin{macrocode} -\msg_kernel_new:nnnn { keyval } { misplaced-equals-sign } +\__msg_kernel_new:nnnn { kernel } { misplaced-equals-sign } { Misplaced~equals~sign~in~key-value~input~\msg_line_number: } { LaTeX~is~attempting~to~parse~some~key-value~input~but~found~ @@ -1032,36 +937,40 @@ % \end{macrocode} % % \subsection{Constants and variables} +% +% \begin{macrocode} +%<@@=keys> +% \end{macrocode} % -% \begin{variable}{\c_keys_code_root_tl, \c_keys_vars_root_tl} +% \begin{variable}{\c_@@_code_root_tl, \c_@@_vars_root_tl} % The prefixes for the code and variables of the keys themselves. % \begin{macrocode} -\tl_const:Nn \c_keys_code_root_tl { key~code~>~ } -\tl_const:Nn \c_keys_vars_root_tl { key~var~>~ } +\tl_const:Nn \c_@@_code_root_tl { key~code~>~ } +\tl_const:Nn \c_@@_vars_root_tl { key~var~>~ } % \end{macrocode} % \end{variable} % -% \begin{variable}{\c_keys_props_root_tl} +% \begin{variable}{\c_@@_props_root_tl} % The prefix for storing properties. % \begin{macrocode} -\tl_const:Nn \c_keys_props_root_tl { key~prop~>~ } +\tl_const:Nn \c_@@_props_root_tl { key~prop~>~ } % \end{macrocode} % \end{variable} % -% \begin{variable}{\c_keys_value_forbidden_tl, \c_keys_value_required_tl} +% \begin{variable}{\c_@@_value_forbidden_tl, \c_@@_value_required_tl} % Two marker token lists. % \begin{macrocode} -\tl_const:Nn \c_keys_value_forbidden_tl { forbidden } -\tl_const:Nn \c_keys_value_required_tl { required } +\tl_const:Nn \c_@@_value_forbidden_tl { forbidden } +\tl_const:Nn \c_@@_value_required_tl { required } % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_keys_choice_int, \l_keys_choices_tl} +% \begin{variable}{\l_keys_choice_int, \l_keys_choice_tl} % Publicly accessible data on which choice is being used when several % are generated as a set. % \begin{macrocode} \int_new:N \l_keys_choice_int -\tl_new:N \l_keys_choices_tl +\tl_new:N \l_keys_choice_tl % \end{macrocode} % \end{variable} % @@ -1072,18 +981,18 @@ % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_keys_module_tl} +% \begin{variable}{\l_@@_module_tl} % The module for an entire set of keys. % \begin{macrocode} -\tl_new:N \l_keys_module_tl +\tl_new:N \l_@@_module_tl % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_keys_no_value_bool} +% \begin{variable}{\l_@@_no_value_bool} % A marker is needed internally to show if only a key or a key plus a % value was seen: this is recorded here. % \begin{macrocode} -\bool_new:N \l_keys_no_value_bool +\bool_new:N \l_@@_no_value_bool % \end{macrocode} % \end{variable} % @@ -1095,18 +1004,18 @@ % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_keys_property_tl} +% \begin{variable}{\l_@@_property_tl} % The \enquote{property} begin set for a key at definition time is % stored here. % \begin{macrocode} -\tl_new:N \l_keys_property_tl +\tl_new:N \l_@@_property_tl % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_keys_unknown_clist} +% \begin{variable}{\l_@@_unknown_clist} % Used when setting only known keys to store those left over. % \begin{macrocode} -\tl_new:N \l_keys_unknown_clist +\tl_new:N \l_@@_unknown_clist % \end{macrocode} % \end{variable} % @@ -1120,51 +1029,51 @@ % \subsection{The key defining mechanism} % % \begin{macro}{\keys_define:nn} -% \begin{macro}[aux]{\keys_define_aux:nnn, \keys_define_aux:onn} +% \begin{macro}[aux]{\@@_define:nnn, \@@_define:onn} % The public function for definitions is just a wrapper for the lower % level mechanism, more or less. The outer function is designed to % keep a track of the current module, to allow safe nesting. The module is set % removing any leading |/| (which is not needed here). % \begin{macrocode} \cs_new_protected:Npn \keys_define:nn - { \keys_define_aux:onn \l_keys_module_tl } -\cs_new_protected:Npn \keys_define_aux:nnn #1#2#3 + { \@@_define:onn \l_@@_module_tl } +\cs_new_protected:Npn \@@_define:nnn #1#2#3 { - \tl_set:Nx \l_keys_module_tl { \tl_to_str:n {#2} } - \keyval_parse:NNn \keys_define_elt:n \keys_define_elt:nn {#3} - \tl_set:Nn \l_keys_module_tl {#1} + \tl_set:Nx \l_@@_module_tl { \tl_to_str:n {#2} } + \keyval_parse:NNn \@@_define_elt:n \@@_define_elt:nn {#3} + \tl_set:Nn \l_@@_module_tl {#1} } -\cs_generate_variant:Nn \keys_define_aux:nnn { o } +\cs_generate_variant:Nn \@@_define:nnn { o } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[int]{\keys_define_elt:n} -% \begin{macro}[int]{\keys_define_elt:nn} -% \begin{macro}[aux]{\keys_define_elt_aux:nn} +% \begin{macro}[int]{\@@_define_elt:n} +% \begin{macro}[int]{\@@_define_elt:nn} +% \begin{macro}[aux]{\@@_define_elt_aux:nn} % The outer functions here record whether a value was given and then % converge on a common internal mechanism. There is first a search for % a property in the current key name, then a check to make sure it is % known before the code hands off to the next step. % \begin{macrocode} -\cs_new_protected:Npn \keys_define_elt:n #1 +\cs_new_protected:Npn \@@_define_elt:n #1 { - \bool_set_true:N \l_keys_no_value_bool - \keys_define_elt_aux:nn {#1} { } + \bool_set_true:N \l_@@_no_value_bool + \@@_define_elt_aux:nn {#1} { } } -\cs_new_protected:Npn \keys_define_elt:nn #1#2 +\cs_new_protected:Npn \@@_define_elt:nn #1#2 { - \bool_set_false:N \l_keys_no_value_bool - \keys_define_elt_aux:nn {#1} {#2} + \bool_set_false:N \l_@@_no_value_bool + \@@_define_elt_aux:nn {#1} {#2} } -\cs_new_protected:Npn \keys_define_elt_aux:nn #1#2 +\cs_new_protected:Npn \@@_define_elt_aux:nn #1#2 { - \keys_property_find:n {#1} - \cs_if_exist:cTF { \c_keys_props_root_tl \l_keys_property_tl } - { \keys_define_key:n {#2} } + \@@_property_find:n {#1} + \cs_if_exist:cTF { \c_@@_props_root_tl \l_@@_property_tl } + { \@@_define_key:n {#2} } { - \msg_kernel_error:nnxx { keys } { property-unknown } - { \l_keys_property_tl } { \l_keys_path_tl } + \__msg_kernel_error:nnxx { kernel } { property-unknown } + { \l_@@_property_tl } { \l_keys_path_tl } } } % \end{macrocode} @@ -1172,57 +1081,57 @@ % \end{macro} % \end{macro} % -% \begin{macro}[int]{\keys_property_find:n} -% \begin{macro}[aux]{\keys_property_find_aux:w} +% \begin{macro}[int]{\@@_property_find:n} +% \begin{macro}[aux]{\@@_property_find:w} % Searching for a property means finding the last |.| in the input, % and storing the text before and after it. Everything is turned into % strings, so there is no problem using an \texttt{x}-type expansion. % \begin{macrocode} -\cs_new_protected:Npn \keys_property_find:n #1 +\cs_new_protected:Npn \@@_property_find:n #1 { - \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / } + \tl_set:Nx \l_keys_path_tl { \l_@@_module_tl / } \tl_if_in:nnTF {#1} { . } - { \keys_property_find_aux:w #1 \q_stop } - { \msg_kernel_error:nnx { keys } { key-no-property } {#1} } + { \@@_property_find:w #1 \q_stop } + { \__msg_kernel_error:nnx { kernel } { key-no-property } {#1} } } -\cs_new_protected:Npn \keys_property_find_aux:w #1 . #2 \q_stop +\cs_new_protected:Npn \@@_property_find:w #1 . #2 \q_stop { \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl \tl_to_str:n {#1} } \tl_if_in:nnTF {#2} { . } { \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl . } - \keys_property_find_aux:w #2 \q_stop + \@@_property_find:w #2 \q_stop } - { \tl_set:Nn \l_keys_property_tl { . #2 } } + { \tl_set:Nn \l_@@_property_tl { . #2 } } } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[int]{\keys_define_key:n} -% \begin{macro}[aux]{\keys_define_key_aux:w} +% \begin{macro}[int]{\@@_define_key:n} +% \begin{macro}[aux]{\@@_define_key:w} % Two possible cases. If there is a value for the key, then just use % the function. If not, then a check to make sure there is no need for % a value with the property. If there should be one then complain, % otherwise execute it. There is no need to check for a |:| as if it % is missing the earlier tests will have failed. % \begin{macrocode} -\cs_new_protected:Npn \keys_define_key:n #1 +\cs_new_protected:Npn \@@_define_key:n #1 { - \bool_if:NTF \l_keys_no_value_bool + \bool_if:NTF \l_@@_no_value_bool { - \exp_after:wN \keys_define_key_aux:w - \l_keys_property_tl \q_stop - { \use:c { \c_keys_props_root_tl \l_keys_property_tl } } + \exp_after:wN \@@_define_key:w + \l_@@_property_tl \q_stop + { \use:c { \c_@@_props_root_tl \l_@@_property_tl } } { - \msg_kernel_error:nnxx { keys } - { property-requires-value } { \l_keys_property_tl } + \__msg_kernel_error:nnxx { kernel } + { property-requires-value } { \l_@@_property_tl } { \l_keys_path_tl } } } - { \use:c { \c_keys_props_root_tl \l_keys_property_tl } {#1} } + { \use:c { \c_@@_props_root_tl \l_@@_property_tl } {#1} } } -\cs_new_protected:Npn \keys_define_key_aux:w #1 : #2 \q_stop +\cs_new_protected:Npn \@@_define_key:w #1 : #2 \q_stop { \tl_if_empty:nTF {#2} } % \end{macrocode} % \end{macro} @@ -1230,226 +1139,246 @@ % % \subsection{Turning properties into actions} % -% \begin{macro}[int]{\keys_bool_set:NN} +% \begin{macro}[int]{\@@_bool_set:NN} % Boolean keys are really just choices, but all done by hand. The % second argument here is the scope: either empty or \texttt{g} for % global. % \begin{macrocode} -\cs_new:Npn \keys_bool_set:NN #1#2 +\cs_new:Npn \@@_bool_set:NN #1#2 { \bool_if_exist:NF #1 { \bool_new:N #1 } - \keys_choice_make: - \keys_cmd_set:nx { \l_keys_path_tl / true } + \@@_choice_make: + \@@_cmd_set:nx { \l_keys_path_tl / true } { \exp_not:c { bool_ #2 set_true:N } \exp_not:N #1 } - \keys_cmd_set:nx { \l_keys_path_tl / false } + \@@_cmd_set:nx { \l_keys_path_tl / false } { \exp_not:c { bool_ #2 set_false:N } \exp_not:N #1 } - \keys_cmd_set:nn { \l_keys_path_tl / unknown } + \@@_cmd_set:nn { \l_keys_path_tl / unknown } { - \msg_kernel_error:nnx { keys } { boolean-values-only } + \__msg_kernel_error:nnx { kernel } { boolean-values-only } { \l_keys_key_tl } } - \keys_default_set:n { true } + \@@_default_set:n { true } } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\keys_bool_set_inverse:NN} +% \begin{macro}[int]{\@@_bool_set_inverse:NN} % Inverse boolean setting is much the same. % \begin{macrocode} -\cs_new:Npn \keys_bool_set_inverse:NN #1#2 +\cs_new:Npn \@@_bool_set_inverse:NN #1#2 { \bool_if_exist:NF #1 { \bool_new:N #1 } - \keys_choice_make: - \keys_cmd_set:nx { \l_keys_path_tl / true } + \@@_choice_make: + \@@_cmd_set:nx { \l_keys_path_tl / true } { \exp_not:c { bool_ #2 set_false:N } \exp_not:N #1 } - \keys_cmd_set:nx { \l_keys_path_tl / false } + \@@_cmd_set:nx { \l_keys_path_tl / false } { \exp_not:c { bool_ #2 set_true:N } \exp_not:N #1 } - \keys_cmd_set:nn { \l_keys_path_tl / unknown } + \@@_cmd_set:nn { \l_keys_path_tl / unknown } { - \msg_kernel_error:nnx { keys } { boolean-values-only } + \__msg_kernel_error:nnx { kernel } { boolean-values-only } { \l_keys_key_tl } } - \keys_default_set:n { true } + \@@_default_set:n { true } } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\keys_choice_make:} +% \begin{macro}[int]{\@@_choice_make:} % To make a choice from a key, two steps: set the code, and set the % unknown key. % \begin{macrocode} -\cs_new_protected_nopar:Npn \keys_choice_make: +\cs_new_protected_nopar:Npn \@@_choice_make: { - \keys_cmd_set:nn { \l_keys_path_tl } - { \keys_choice_find:n {##1} } - \keys_cmd_set:nn { \l_keys_path_tl / unknown } + \@@_cmd_set:nn { \l_keys_path_tl } + { \@@_choice_find:n {##1} } + \@@_cmd_set:nn { \l_keys_path_tl / unknown } { - \msg_kernel_error:nnxx { keys } { choice-unknown } + \__msg_kernel_error:nnxx { kernel } { key-choice-unknown } { \l_keys_path_tl } {##1} } } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\keys_choices_make:nn} +% \begin{macro}[int]{\@@_choices_make:nn} % Auto-generating choices means setting up the root key as a choice, then % defining each choice in turn. % \begin{macrocode} -\cs_new_protected:Npn \keys_choices_make:nn #1#2 +\cs_new_protected:Npn \@@_choices_make:nn #1#2 { - \keys_choice_make: + \@@_choice_make: \int_zero:N \l_keys_choice_int \clist_map_inline:nn {#1} { - \keys_cmd_set:nx { \l_keys_path_tl / ##1 } + \int_incr:N \l_keys_choice_int + \@@_cmd_set:nx { \l_keys_path_tl / ##1 } { \tl_set:Nn \exp_not:N \l_keys_choice_tl {##1} \int_set:Nn \exp_not:N \l_keys_choice_int { \int_use:N \l_keys_choice_int } \exp_not:n {#2} } - \int_incr:N \l_keys_choice_int } } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\keys_choices_generate:n} -% \begin{macro}[aux]{\keys_choices_generate_aux:n} +% \begin{macro}[int]{\@@_choices_generate:n} +% \begin{macro}[aux]{\@@_choices_generate_aux:n} % Creating multiple-choices means setting up the \enquote{indicator} % code, then applying whatever the user wanted. % \begin{macrocode} -\cs_new_protected:Npn \keys_choices_generate:n #1 +\cs_new_protected:Npn \@@_choices_generate:n #1 { \cs_if_exist:cTF - { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + { \c_@@_vars_root_tl \l_keys_path_tl .choice~code } { - \keys_choice_make: + \@@_choice_make: \int_zero:N \l_keys_choice_int - \clist_map_function:nN {#1} \keys_choices_generate_aux:n + \clist_map_function:nN {#1} \@@_choices_generate_aux:n } { - \msg_kernel_error:nnx { keys } + \__msg_kernel_error:nnx { kernel } { generate-choices-before-code } { \l_keys_path_tl } } } -\cs_new_protected:Npn \keys_choices_generate_aux:n #1 +\cs_new_protected:Npn \@@_choices_generate_aux:n #1 { - \keys_cmd_set:nx { \l_keys_path_tl / #1 } + \int_incr:N \l_keys_choice_int + \@@_cmd_set:nx { \l_keys_path_tl / #1 } { \tl_set:Nn \exp_not:N \l_keys_choice_tl {#1} \int_set:Nn \exp_not:N \l_keys_choice_int { \int_use:N \l_keys_choice_int } \exp_not:v - { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + { \c_@@_vars_root_tl \l_keys_path_tl .choice~code } } - \int_incr:N \l_keys_choice_int } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[int]{\keys_choice_code_store:x} +% \begin{macro}[int]{\@@_choice_code_store:n, \@@_choice_code_store:x} % The code for making multiple choices is stored in a token list. % \begin{macrocode} -\cs_new_protected:Npn \keys_choice_code_store:x #1 +\cs_new_protected:Npn \@@_choice_code_store:n #1 { \cs_if_exist:cF - { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + { \c_@@_vars_root_tl \l_keys_path_tl .choice~code } { \tl_new:c - { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + { \c_@@_vars_root_tl \l_keys_path_tl .choice~code } } - \tl_set:cx { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + \tl_set:cn { \c_@@_vars_root_tl \l_keys_path_tl .choice~code } {#1} } +\cs_generate_variant:Nn \@@_choice_code_store:n { x } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\keys_cmd_set:nn, \keys_cmd_set:nx} -% \begin{macro}[aux]{\keys_cmd_set_aux:n} +% \begin{macro}[int]{\@@_cmd_set:nn, \@@_cmd_set:nx, \@@_cmd_set:Vo} +% \begin{macro}[aux]{\@@_cmd_set:n} % Creating a new command means tidying up the properties and then making % the internal function which actually does the work. % \begin{macrocode} -\cs_new_protected:Npn \keys_cmd_set:nn #1#2 +\cs_new_protected:Npn \@@_cmd_set:nn #1#2 { - \keys_cmd_set_aux:n {#1} - \cs_set:cpn { \c_keys_code_root_tl #1 } ##1 {#2} + \@@_cmd_set:n {#1} + \cs_set:cpn { \c_@@_code_root_tl #1 } ##1 {#2} } -\cs_new_protected:Npn \keys_cmd_set:nx #1#2 +\cs_new_protected:Npn \@@_cmd_set:nx #1#2 { - \keys_cmd_set_aux:n {#1} - \cs_set:cpx { \c_keys_code_root_tl #1 } ##1 {#2} + \@@_cmd_set:n {#1} + \cs_set:cpx { \c_@@_code_root_tl #1 } ##1 {#2} } -\cs_new_protected:Npn \keys_cmd_set_aux:n #1 +\cs_generate_variant:Nn \@@_cmd_set:nn { Vo } +\cs_new_protected:Npn \@@_cmd_set:n #1 { - \tl_clear_new:c { \c_keys_vars_root_tl #1 .default } - \tl_set:cn { \c_keys_vars_root_tl #1 .default } { \q_no_value } - \tl_clear_new:c { \c_keys_vars_root_tl #1 .req } + \tl_clear_new:c { \c_@@_vars_root_tl #1 .default } + \tl_set:cn { \c_@@_vars_root_tl #1 .default } { \q_no_value } + \tl_clear_new:c { \c_@@_vars_root_tl #1 .req } } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[int]{\keys_default_set:n, \keys_default_set:V} +% \begin{macro}[int]{\@@_default_set:n, \@@_default_set:V} % Setting a default value is easy. % \begin{macrocode} -\cs_new_protected:Npn \keys_default_set:n #1 - { \tl_set:cn { \c_keys_vars_root_tl \l_keys_path_tl .default } {#1} } -\cs_generate_variant:Nn \keys_default_set:n { V } +\cs_new_protected:Npn \@@_default_set:n #1 + { \tl_set:cn { \c_@@_vars_root_tl \l_keys_path_tl .default } {#1} } +\cs_generate_variant:Nn \@@_default_set:n { V } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\@@_initialise:n, \@@_initialise:V} +% \begin{macro}[aux, EXP]{\@@_initialise:wn} +% A set up for initialisation from which the key system requires that +% the path is split up into a module and a key name. At this stage, +% \cs{l_keys_path_tl} will contain \texttt{/} so a split is easy to do. +% \begin{macrocode} +\cs_new_protected:Npn \@@_initialise:n #1 + { + \use:x + { \exp_after:wN \@@_initialise:wn \l_keys_path_tl \q_stop {#1} } + } +\cs_generate_variant:Nn \@@_initialise:n { V } +\cs_new:Npn \@@_initialise:wn #1 / #2 \q_stop #3 + { \keys_set:nn {#1} { #2 = \exp_not:n { {#3} } } } % \end{macrocode} % \end{macro} +% \end{macro} % -% \begin{macro}{\keys_meta_make:n, \keys_meta_make:x} +% \begin{macro}{\@@_meta_make:n, \@@_meta_make:x} % To create a meta-key, simply set up to pass data through. % \begin{macrocode} -\cs_new_protected:Npn \keys_meta_make:n #1 +\cs_new_protected:Npn \@@_meta_make:n #1 { - \exp_args:NNo \keys_cmd_set:nn \l_keys_path_tl - { \exp_after:wN \keys_set:nn \exp_after:wN { \l_keys_module_tl } {#1} } + \@@_cmd_set:Vo \l_keys_path_tl + { \exp_after:wN \keys_set:nn \exp_after:wN { \l_@@_module_tl } {#1} } } -\cs_new_protected:Npn \keys_meta_make:x #1 +\cs_new_protected:Npn \@@_meta_make:x #1 { - \keys_cmd_set:nx { \l_keys_path_tl } - { \exp_not:N \keys_set:nn { \l_keys_module_tl } {#1} } + \@@_cmd_set:nx { \l_keys_path_tl } + { \exp_not:N \keys_set:nn { \l_@@_module_tl } {#1} } } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\keys_multichoice_find:n} -% \begin{macro}[int]{\keys_multichoice_make:} -% \begin{macro}[int]{\keys_multichoices_make:nn} +% \begin{macro}[int]{\@@_multichoice_find:n} +% \begin{macro}[int]{\@@_multichoice_make:} +% \begin{macro}[int]{\@@_multichoices_make:nn} % Choices where several values can be selected are very similar to normal % exclusive choices. There is just a slight change in implementation to % map across a comma-separated list. This then requires that the appropriate % set up takes place elsewhere. % \begin{macrocode} -\cs_new:Npn \keys_multichoice_find:n #1 - { \clist_map_function:nN {#1} \keys_choice_find:n } -\cs_new_protected_nopar:Npn \keys_multichoice_make: +\cs_new:Npn \@@_multichoice_find:n #1 + { \clist_map_function:nN {#1} \@@_choice_find:n } +\cs_new_protected_nopar:Npn \@@_multichoice_make: { - \keys_cmd_set:nn { \l_keys_path_tl } - { \keys_multichoice_find:n {##1} } - \keys_cmd_set:nn { \l_keys_path_tl / unknown } + \@@_cmd_set:nn { \l_keys_path_tl } + { \@@_multichoice_find:n {##1} } + \@@_cmd_set:nn { \l_keys_path_tl / unknown } { - \msg_kernel_error:nnxx { keys } { choice-unknown } + \__msg_kernel_error:nnxx { kernel } { key-choice-unknown } { \l_keys_path_tl } {##1} } } -\cs_new_protected:Npn \keys_multichoices_make:nn #1#2 +\cs_new_protected:Npn \@@_multichoices_make:nn #1#2 { - \keys_multichoice_make: + \@@_multichoice_make: \int_zero:N \l_keys_choice_int \clist_map_inline:nn {#1} { - \keys_cmd_set:nx { \l_keys_path_tl / ##1 } + \int_incr:N \l_keys_choice_int + \@@_cmd_set:nx { \l_keys_path_tl / ##1 } { \tl_set:Nn \exp_not:N \l_keys_choice_tl {##1} \int_set:Nn \exp_not:N \l_keys_choice_int { \int_use:N \l_keys_choice_int } \exp_not:n {#2} } - \int_incr:N \l_keys_choice_int } } % \end{macrocode} @@ -1457,36 +1386,36 @@ % \end{macro} % \end{macro} % -% \begin{macro}[int]{\keys_value_requirement:n} +% \begin{macro}[int]{\@@_value_requirement:n} % Values can be required or forbidden by having the appropriate marker % set. % \begin{macrocode} -\cs_new_protected:Npn \keys_value_requirement:n #1 +\cs_new_protected:Npn \@@_value_requirement:n #1 { \tl_set_eq:cc - { \c_keys_vars_root_tl \l_keys_path_tl .req } - { c_keys_value_ #1 _tl } + { \c_@@_vars_root_tl \l_keys_path_tl .req } + { c_@@_value_ #1 _tl } } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\keys_variable_set:NnNN, \keys_variable_set:cnNN} -% \begin{macro}[int]{\keys_variable_set:NnN, \keys_variable_set:cnN} +% \begin{macro}[int]{\@@_variable_set:NnNN, \@@_variable_set:cnNN} +% \begin{macro}[int]{\@@_variable_set:NnN, \@@_variable_set:cnN} % Setting a variable takes the type and scope separately so that % it is easy to make a new variable if needed. The three-argument % version is set up so that the use of |{ }| as an \texttt{N}-type % variable is only done once! % \begin{macrocode} -\cs_new_protected:Npn \keys_variable_set:NnNN #1#2#3#4 +\cs_new_protected:Npn \@@_variable_set:NnNN #1#2#3#4 { \use:c { #2_if_exist:NF } #1 { \use:c { #2 _new:N } #1 } - \keys_cmd_set:nx { \l_keys_path_tl } + \@@_cmd_set:nx { \l_keys_path_tl } { \exp_not:c { #2 _ #3 set:N #4 } \exp_not:N #1 {##1} } } -\cs_new_protected:Npn \keys_variable_set:NnN #1#2#3 - { \keys_variable_set:NnNN #1 {#2} { } #3 } -\cs_generate_variant:Nn \keys_variable_set:NnNN { c } -\cs_generate_variant:Nn \keys_variable_set:NnN { c } +\cs_new_protected:Npn \@@_variable_set:NnN #1#2#3 + { \@@_variable_set:NnNN #1 {#2} { } #3 } +\cs_generate_variant:Nn \@@_variable_set:NnNN { c } +\cs_generate_variant:Nn \@@_variable_set:NnN { c } % \end{macrocode} % \end{macro} % \end{macro} @@ -1500,10 +1429,10 @@ % \begin{macro}{.bool_gset:N} % One function for this. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .bool_set:N } #1 - { \keys_bool_set:NN #1 { } } -\cs_new_protected:cpn { \c_keys_props_root_tl .bool_gset:N } #1 - { \keys_bool_set:NN #1 g } +\cs_new_protected:cpn { \c_@@_props_root_tl .bool_set:N } #1 + { \@@_bool_set:NN #1 { } } +\cs_new_protected:cpn { \c_@@_props_root_tl .bool_gset:N } #1 + { \@@_bool_set:NN #1 g } % \end{macrocode} % \end{macro} % \end{macro} @@ -1512,10 +1441,10 @@ % \begin{macro}{.bool_gset_inverse:N} % One function for this. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .bool_set_inverse:N } #1 - { \keys_bool_set_inverse:NN #1 { } } -\cs_new_protected:cpn { \c_keys_props_root_tl .bool_gset_inverse:N } #1 - { \keys_bool_set_inverse:NN #1 g } +\cs_new_protected:cpn { \c_@@_props_root_tl .bool_set_inverse:N } #1 + { \@@_bool_set_inverse:NN #1 { } } +\cs_new_protected:cpn { \c_@@_props_root_tl .bool_gset_inverse:N } #1 + { \@@_bool_set_inverse:NN #1 g } % \end{macrocode} % \end{macro} % \end{macro} @@ -1524,8 +1453,8 @@ % Making a choice is handled internally, as it is also needed by % \texttt{.generate_choices:n}. % \begin{macrocode} -\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .choice: } - { \keys_choice_make: } +\cs_new_protected_nopar:cpn { \c_@@_props_root_tl .choice: } + { \@@_choice_make: } % \end{macrocode} % \end{macro} % @@ -1534,8 +1463,8 @@ % Here, |#1| will consist of two separate % arguments, hence the slightly odd-looking implementation. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .choices:nn } #1 - { \keys_choices_make:nn #1 } +\cs_new_protected:cpn { \c_@@_props_root_tl .choices:nn } #1 + { \@@_choices_make:nn #1 } % \end{macrocode} % \end{macro} % @@ -1543,35 +1472,34 @@ % Creating code is simply a case of passing through to the underlying % \texttt{set} function. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .code:n } #1 - { \keys_cmd_set:nn { \l_keys_path_tl } {#1} } -\cs_new_protected:cpn { \c_keys_props_root_tl .code:x } #1 - { \keys_cmd_set:nx { \l_keys_path_tl } {#1} } +\cs_new_protected:cpn { \c_@@_props_root_tl .code:n } #1 + { \@@_cmd_set:nn { \l_keys_path_tl } {#1} } +\cs_new_protected:cpn { \c_@@_props_root_tl .code:x } #1 + { \@@_cmd_set:nx { \l_keys_path_tl } {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}{.choice_code:n, .choice_code:x} -% Storing the code for choices, using \cs{exp_not:n} to avoid needing -% two internal functions. +% Storing the code for choices % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .choice_code:n } #1 - { \keys_choice_code_store:x { \exp_not:n {#1} } } -\cs_new_protected:cpn { \c_keys_props_root_tl .choice_code:x } #1 - { \keys_choice_code_store:x {#1} } +\cs_new_protected:cpn { \c_@@_props_root_tl .choice_code:n } #1 + { \@@_choice_code_store:n {#1} } +\cs_new_protected:cpn { \c_@@_props_root_tl .choice_code:x } #1 + { \@@_choice_code_store:x {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}{.clist_set:N, .clist_set:c} % \begin{macro}{.clist_gset:N, .clist_gset:c} % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .clist_set:N } #1 - { \keys_variable_set:NnN #1 { clist } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .clist_set:c } #1 - { \keys_variable_set:cnN {#1} { clist } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .clist_gset:N } #1 - { \keys_variable_set:NnNN #1 { clist } g n } -\cs_new_protected:cpn { \c_keys_props_root_tl .clist_gset:c } #1 - { \keys_variable_set:cnNN {#1} { clist } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .clist_set:N } #1 + { \@@_variable_set:NnN #1 { clist } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .clist_set:c } #1 + { \@@_variable_set:cnN {#1} { clist } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .clist_gset:N } #1 + { \@@_variable_set:NnNN #1 { clist } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .clist_gset:c } #1 + { \@@_variable_set:cnNN {#1} { clist } g n } % \end{macrocode} % \end{macro} % \end{macro} @@ -1579,10 +1507,10 @@ % \begin{macro}{.default:n, .default:V} % Expansion is left to the internal functions. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .default:n } #1 - { \keys_default_set:n {#1} } -\cs_new_protected:cpn { \c_keys_props_root_tl .default:V } #1 - { \keys_default_set:V #1 } +\cs_new_protected:cpn { \c_@@_props_root_tl .default:n } #1 + { \@@_default_set:n {#1} } +\cs_new_protected:cpn { \c_@@_props_root_tl .default:V } #1 + { \@@_default_set:V #1 } % \end{macrocode} % \end{macro} % @@ -1590,14 +1518,14 @@ % \begin{macro}{.dim_gset:N, .dim_gset:c} % Setting a variable is very easy: just pass the data along. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .dim_set:N } #1 - { \keys_variable_set:NnN #1 { dim } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .dim_set:c } #1 - { \keys_variable_set:cnN {#1} { dim } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .dim_gset:N } #1 - { \keys_variable_set:NnNN #1 { dim } g n } -\cs_new_protected:cpn { \c_keys_props_root_tl .dim_gset:c } #1 - { \keys_variable_set:cnNN {#1} { dim } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .dim_set:N } #1 + { \@@_variable_set:NnN #1 { dim } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .dim_set:c } #1 + { \@@_variable_set:cnN {#1} { dim } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .dim_gset:N } #1 + { \@@_variable_set:NnNN #1 { dim } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .dim_gset:c } #1 + { \@@_variable_set:cnNN {#1} { dim } g n } % \end{macrocode} % \end{macro} % \end{macro} @@ -1606,14 +1534,14 @@ % \begin{macro}{.fp_gset:N, .fp_gset:c} % Setting a variable is very easy: just pass the data along. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .fp_set:N } #1 - { \keys_variable_set:NnN #1 { fp } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .fp_set:c } #1 - { \keys_variable_set:cnN {#1} { fp } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .fp_gset:N } #1 - { \keys_variable_set:NnNN #1 { fp } g n } -\cs_new_protected:cpn { \c_keys_props_root_tl .fp_gset:c } #1 - { \keys_variable_set:cnNN {#1} { fp } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .fp_set:N } #1 + { \@@_variable_set:NnN #1 { fp } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .fp_set:c } #1 + { \@@_variable_set:cnN {#1} { fp } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .fp_gset:N } #1 + { \@@_variable_set:NnNN #1 { fp } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .fp_gset:c } #1 + { \@@_variable_set:cnNN {#1} { fp } g n } % \end{macrocode} % \end{macro} % \end{macro} @@ -1621,8 +1549,18 @@ % \begin{macro}{.generate_choices:n} % Making choices is easy. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .generate_choices:n } #1 - { \keys_choices_generate:n {#1} } +\cs_new_protected:cpn { \c_@@_props_root_tl .generate_choices:n } #1 + { \@@_choices_generate:n {#1} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.initial:n, .initial:V} +% The standard hand-off approach. +% \begin{macrocode} +\cs_new_protected:cpn { \c_@@_props_root_tl .initial:n } #1 + { \@@_initialise:n {#1} } +\cs_new_protected:cpn { \c_@@_props_root_tl .initial:V } #1 + { \@@_initialise:V #1 } % \end{macrocode} % \end{macro} % @@ -1630,14 +1568,14 @@ % \begin{macro}{.int_gset:N, .int_gset:c} % Setting a variable is very easy: just pass the data along. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .int_set:N } #1 - { \keys_variable_set:NnN #1 { int } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .int_set:c } #1 - { \keys_variable_set:cnN {#1} { int } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .int_gset:N } #1 - { \keys_variable_set:NnNN #1 { int } g n } -\cs_new_protected:cpn { \c_keys_props_root_tl .int_gset:c } #1 - { \keys_variable_set:cnNN {#1} { int } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .int_set:N } #1 + { \@@_variable_set:NnN #1 { int } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .int_set:c } #1 + { \@@_variable_set:cnN {#1} { int } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .int_gset:N } #1 + { \@@_variable_set:NnNN #1 { int } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .int_gset:c } #1 + { \@@_variable_set:cnNN {#1} { int } g n } % \end{macrocode} % \end{macro} % \end{macro} @@ -1645,10 +1583,10 @@ %\begin{macro}{.meta:n, .meta:x} % Making a meta is handled internally. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .meta:n } #1 - { \keys_meta_make:n {#1} } -\cs_new_protected:cpn { \c_keys_props_root_tl .meta:x } #1 - { \keys_meta_make:x {#1} } +\cs_new_protected:cpn { \c_@@_props_root_tl .meta:n } #1 + { \@@_meta_make:n {#1} } +\cs_new_protected:cpn { \c_@@_props_root_tl .meta:x } #1 + { \@@_meta_make:x {#1} } % \end{macrocode} % \end{macro} % @@ -1657,10 +1595,10 @@ % The same idea as \texttt{.choice:} and \texttt{.choices:nn}, but % where more than one choice is allowed. % \begin{macrocode} -\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .multichoice: } - { \keys_multichoice_make: } -\cs_new_protected:cpn { \c_keys_props_root_tl .multichoices:nn } #1 - { \keys_multichoices_make:nn #1 } +\cs_new_protected_nopar:cpn { \c_@@_props_root_tl .multichoice: } + { \@@_multichoice_make: } +\cs_new_protected:cpn { \c_@@_props_root_tl .multichoices:nn } #1 + { \@@_multichoices_make:nn #1 } % \end{macrocode} % \end{macro} % \end{macro} @@ -1669,14 +1607,14 @@ % \begin{macro}{.skip_gset:N, .skip_gset:c} % Setting a variable is very easy: just pass the data along. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .skip_set:N } #1 - { \keys_variable_set:NnN #1 { skip } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .skip_set:c } #1 - { \keys_variable_set:cnN {#1} { skip } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .skip_gset:N } #1 - { \keys_variable_set:NnNN #1 { skip } g n } -\cs_new_protected:cpn { \c_keys_props_root_tl .skip_gset:c } #1 - { \keys_variable_set:cnNN {#1} { skip } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .skip_set:N } #1 + { \@@_variable_set:NnN #1 { skip } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .skip_set:c } #1 + { \@@_variable_set:cnN {#1} { skip } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .skip_gset:N } #1 + { \@@_variable_set:NnNN #1 { skip } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .skip_gset:c } #1 + { \@@_variable_set:cnNN {#1} { skip } g n } % \end{macrocode} % \end{macro} % \end{macro} @@ -1688,22 +1626,22 @@ % \begin{macro}{.tl_gset_x:N, .tl_gset_x:c} % Setting a variable is very easy: just pass the data along. % \begin{macrocode} -\cs_new_protected:cpn { \c_keys_props_root_tl .tl_set:N } #1 - { \keys_variable_set:NnN #1 { tl } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .tl_set:c } #1 - { \keys_variable_set:cnN {#1} { tl } n } -\cs_new_protected:cpn { \c_keys_props_root_tl .tl_set_x:N } #1 - { \keys_variable_set:NnN #1 { tl } x } -\cs_new_protected:cpn { \c_keys_props_root_tl .tl_set_x:c } #1 - { \keys_variable_set:cnN {#1} { tl } x } -\cs_new_protected:cpn { \c_keys_props_root_tl .tl_gset:N } #1 - { \keys_variable_set:NnNN #1 { tl } g n } -\cs_new_protected:cpn { \c_keys_props_root_tl .tl_gset:c } #1 - { \keys_variable_set:cnNN {#1} { tl } g n } -\cs_new_protected:cpn { \c_keys_props_root_tl .tl_gset_x:N } #1 - { \keys_variable_set:NnNN #1 { tl } g x } -\cs_new_protected:cpn { \c_keys_props_root_tl .tl_gset_x:c } #1 - { \keys_variable_set:cnNN {#1} { tl } g x } +\cs_new_protected:cpn { \c_@@_props_root_tl .tl_set:N } #1 + { \@@_variable_set:NnN #1 { tl } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .tl_set:c } #1 + { \@@_variable_set:cnN {#1} { tl } n } +\cs_new_protected:cpn { \c_@@_props_root_tl .tl_set_x:N } #1 + { \@@_variable_set:NnN #1 { tl } x } +\cs_new_protected:cpn { \c_@@_props_root_tl .tl_set_x:c } #1 + { \@@_variable_set:cnN {#1} { tl } x } +\cs_new_protected:cpn { \c_@@_props_root_tl .tl_gset:N } #1 + { \@@_variable_set:NnNN #1 { tl } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .tl_gset:c } #1 + { \@@_variable_set:cnNN {#1} { tl } g n } +\cs_new_protected:cpn { \c_@@_props_root_tl .tl_gset_x:N } #1 + { \@@_variable_set:NnNN #1 { tl } g x } +\cs_new_protected:cpn { \c_@@_props_root_tl .tl_gset_x:c } #1 + { \@@_variable_set:cnNN {#1} { tl } g x } % \end{macrocode} % \end{macro} % \end{macro} @@ -1714,10 +1652,10 @@ % \begin{macro}{.value_required:} % These are very similar, so both call the same function. % \begin{macrocode} -\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .value_forbidden: } - { \keys_value_requirement:n { forbidden } } -\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .value_required: } - { \keys_value_requirement:n { required } } +\cs_new_protected_nopar:cpn { \c_@@_props_root_tl .value_forbidden: } + { \@@_value_requirement:n { forbidden } } +\cs_new_protected_nopar:cpn { \c_@@_props_root_tl .value_required: } + { \@@_value_requirement:n { required } } % \end{macrocode} % \end{macro} % \end{macro} @@ -1725,19 +1663,19 @@ % \subsection{Setting keys} % % \begin{macro}{\keys_set:nn, \keys_set:nV, \keys_set:nv, \keys_set:no} -% \begin{macro}[aux]{\keys_set_aux:nnn, \keys_set_aux:onn} +% \begin{macro}[aux]{\@@_set:nnn, \@@_set:onn} % A simple wrapper again. % \begin{macrocode} \cs_new_protected:Npn \keys_set:nn - { \keys_set_aux:onn { \l_keys_module_tl } } -\cs_new_protected:Npn \keys_set_aux:nnn #1#2#3 + { \@@_set:onn { \l_@@_module_tl } } +\cs_new_protected:Npn \@@_set:nnn #1#2#3 { - \tl_set:Nx \l_keys_module_tl { \tl_to_str:n {#2} } - \keyval_parse:NNn \keys_set_elt:n \keys_set_elt:nn {#3} - \tl_set:Nn \l_keys_module_tl {#1} + \tl_set:Nx \l_@@_module_tl { \tl_to_str:n {#2} } + \keyval_parse:NNn \@@_set_elt:n \@@_set_elt:nn {#3} + \tl_set:Nn \l_@@_module_tl {#1} } \cs_generate_variant:Nn \keys_set:nn { nV , nv , no } -\cs_generate_variant:Nn \keys_set_aux:nnn { o } +\cs_generate_variant:Nn \@@_set:nnn { o } % \end{macrocode} % \end{macro} % \end{macro} @@ -1747,89 +1685,89 @@ % \keys_set_known:nnN, \keys_set_known:nVN, % \keys_set_known:nvN, \keys_set_known:noN % } -% \begin{macro}[aux]{\keys_set_known_aux:nnnN, \keys_set_known_aux:onnN} +% \begin{macro}[aux]{\@@_set_known:nnnN, \@@_set_known:onnN} % \begin{macrocode} \cs_new_protected:Npn \keys_set_known:nnN - { \keys_set_known_aux:onnN { \l_keys_module_tl } } -\cs_new_protected:Npn \keys_set_known_aux:nnnN #1#2#3#4 + { \@@_set_known:onnN { \l_@@_module_tl } } +\cs_new_protected:Npn \@@_set_known:nnnN #1#2#3#4 { - \tl_set:Nx \l_keys_module_tl { \tl_to_str:n {#2} } - \clist_clear:N \l_keys_unknown_clist - \cs_set_eq:NN \keys_execute_unknown: \keys_execute_unknown_alt: - \keyval_parse:NNn \keys_set_elt:n \keys_set_elt:nn {#3} - \cs_set_eq:NN \keys_execute_unknown: \keys_execute_unknown_std: - \tl_set:Nn \l_keys_module_tl {#1} - \clist_set_eq:NN #4 \l_keys_unknown_clist + \tl_set:Nx \l_@@_module_tl { \tl_to_str:n {#2} } + \clist_clear:N \l_@@_unknown_clist + \cs_set_eq:NN \@@_execute_unknown: \@@_execute_unknown_alt: + \keyval_parse:NNn \@@_set_elt:n \@@_set_elt:nn {#3} + \cs_set_eq:NN \@@_execute_unknown: \@@_execute_unknown_std: + \tl_set:Nn \l_@@_module_tl {#1} + \clist_set_eq:NN #4 \l_@@_unknown_clist } \cs_generate_variant:Nn \keys_set_known:nnN { nV , nv , no } -\cs_generate_variant:Nn \keys_set_known_aux:nnnN { o } +\cs_generate_variant:Nn \@@_set_known:nnnN { o } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[int]{\keys_set_elt:n, \keys_set_elt:nn} -% \begin{macro}[aux]{\keys_set_elt_aux:nn} +% \begin{macro}[int]{\@@_set_elt:n, \@@_set_elt:nn} +% \begin{macro}[aux]{\@@_set_elt_aux:nn} % A shared system once again. First, set the current path and add a % default if needed. There are then checks to see if the a value is % required or forbidden. If everything passes, move on to execute the % code. % \begin{macrocode} -\cs_new_protected:Npn \keys_set_elt:n #1 +\cs_new_protected:Npn \@@_set_elt:n #1 { - \bool_set_true:N \l_keys_no_value_bool - \keys_set_elt_aux:nn {#1} { } + \bool_set_true:N \l_@@_no_value_bool + \@@_set_elt_aux:nn {#1} { } } -\cs_new_protected:Npn \keys_set_elt:nn #1#2 +\cs_new_protected:Npn \@@_set_elt:nn #1#2 { - \bool_set_false:N \l_keys_no_value_bool - \keys_set_elt_aux:nn {#1} {#2} + \bool_set_false:N \l_@@_no_value_bool + \@@_set_elt_aux:nn {#1} {#2} } -\cs_new_protected:Npn \keys_set_elt_aux:nn #1#2 +\cs_new_protected:Npn \@@_set_elt_aux:nn #1#2 { \tl_set:Nx \l_keys_key_tl { \tl_to_str:n {#1} } - \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / \l_keys_key_tl } - \keys_value_or_default:n {#2} + \tl_set:Nx \l_keys_path_tl { \l_@@_module_tl / \l_keys_key_tl } + \@@_value_or_default:n {#2} \bool_if:nTF { - \keys_if_value_p:n { required } && - \l_keys_no_value_bool + \@@_if_value_p:n { required } && + \l_@@_no_value_bool } { - \msg_kernel_error:nnx { keys } { value-required } + \__msg_kernel_error:nnx { kernel } { value-required } { \l_keys_path_tl } } { \bool_if:nTF { - \keys_if_value_p:n { forbidden } && - ! \l_keys_no_value_bool + \@@_if_value_p:n { forbidden } && + ! \l_@@_no_value_bool } { - \msg_kernel_error:nnxx { keys } { value-forbidden } + \__msg_kernel_error:nnxx { kernel } { value-forbidden } { \l_keys_path_tl } { \l_keys_value_tl } } - { \keys_execute: } + { \@@_execute: } } } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[int]{\keys_value_or_default:n} +% \begin{macro}[int]{\@@_value_or_default:n} % If a value is given, return it as |#1|, otherwise send a default if % available. % \begin{macrocode} -\cs_new_protected:Npn \keys_value_or_default:n #1 +\cs_new_protected:Npn \@@_value_or_default:n #1 { \tl_set:Nn \l_keys_value_tl {#1} - \bool_if:NT \l_keys_no_value_bool + \bool_if:NT \l_@@_no_value_bool { - \quark_if_no_value:cF { \c_keys_vars_root_tl \l_keys_path_tl .default } + \quark_if_no_value:cF { \c_@@_vars_root_tl \l_keys_path_tl .default } { - \cs_if_exist:cT { \c_keys_vars_root_tl \l_keys_path_tl .default } + \cs_if_exist:cT { \c_@@_vars_root_tl \l_keys_path_tl .default } { \tl_set_eq:Nc \l_keys_value_tl - { \c_keys_vars_root_tl \l_keys_path_tl .default } + { \c_@@_vars_root_tl \l_keys_path_tl .default } } } } @@ -1837,57 +1775,57 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\keys_if_value_p:n} +% \begin{macro}[int]{\@@_if_value_p:n} % To test if a value is required or forbidden. A simple check for % the existence of the appropriate marker. % \begin{macrocode} -\prg_new_conditional:Npnn \keys_if_value:n #1 { p } +\prg_new_conditional:Npnn \@@_if_value:n #1 { p } { - \tl_if_eq:ccTF { c_keys_value_ #1 _tl } - { \c_keys_vars_root_tl \l_keys_path_tl .req } + \tl_if_eq:ccTF { c_@@_value_ #1 _tl } + { \c_@@_vars_root_tl \l_keys_path_tl .req } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\keys_execute:} +% \begin{macro}[int]{\@@_execute:} % \begin{macro}[aux] % { -% \keys_execute_unknown:, -% \keys_execute_unknown_std:, -% \keys_execute_unknown_alt: +% \@@_execute_unknown:, +% \@@_execute_unknown_std:, +% \@@_execute_unknown_alt: % } -% \begin{macro}[aux]{\keys_execute:nn} +% \begin{macro}[aux]{\@@_execute:nn} % Actually executing a key is done in two parts. First, look for the % key itself, then look for the \texttt{unknown} key with the same % path. If both of these fail, complain. % \begin{macrocode} -\cs_new_nopar:Npn \keys_execute: - { \keys_execute:nn { \l_keys_path_tl } { \keys_execute_unknown: } } -\cs_new_nopar:Npn \keys_execute_unknown: +\cs_new_nopar:Npn \@@_execute: + { \@@_execute:nn { \l_keys_path_tl } { \@@_execute_unknown: } } +\cs_new_nopar:Npn \@@_execute_unknown: { - \keys_execute:nn { \l_keys_module_tl / unknown } + \@@_execute:nn { \l_@@_module_tl / unknown } { - \msg_kernel_error:nnxx { keys } { key-unknown } - { \l_keys_path_tl } { \l_keys_module_tl } + \__msg_kernel_error:nnxx { kernel } { key-unknown } + { \l_keys_path_tl } { \l_@@_module_tl } } } -\cs_new_eq:NN \keys_execute_unknown_std: \keys_execute_unknown: -\cs_new_nopar:Npn \keys_execute_unknown_alt: +\cs_new_eq:NN \@@_execute_unknown_std: \@@_execute_unknown: +\cs_new_nopar:Npn \@@_execute_unknown_alt: { - \clist_put_right:Nx \l_keys_unknown_clist + \clist_put_right:Nx \l_@@_unknown_clist { \exp_not:o \l_keys_key_tl - \bool_if:NF \l_keys_no_value_bool + \bool_if:NF \l_@@_no_value_bool { = { \exp_not:o \l_keys_value_tl } } } } -\cs_new:Npn \keys_execute:nn #1#2 +\cs_new:Npn \@@_execute:nn #1#2 { - \cs_if_exist:cTF { \c_keys_code_root_tl #1 } + \cs_if_exist:cTF { \c_@@_code_root_tl #1 } { - \exp_args:Nc \exp_args:No { \c_keys_code_root_tl #1 } + \exp_args:Nc \exp_args:No { \c_@@_code_root_tl #1 } \l_keys_value_tl } {#2} @@ -1897,15 +1835,15 @@ % \end{macro} % \end{macro} % -% \begin{macro}[int]{\keys_choice_find:n} +% \begin{macro}[int]{\@@_choice_find:n} % Executing a choice has two parts. First, try the choice given, then % if that fails call the unknown key. That will exist, as it is created % when a choice is first made. So there is no need for any escape code. % \begin{macrocode} -\cs_new:Npn \keys_choice_find:n #1 +\cs_new:Npn \@@_choice_find:n #1 { - \keys_execute:nn { \l_keys_path_tl / \tl_to_str:n {#1} } - { \keys_execute:nn { \l_keys_path_tl / unknown } { } } + \@@_execute:nn { \l_keys_path_tl / \tl_to_str:n {#1} } + { \@@_execute:nn { \l_keys_path_tl / unknown } { } } } % \end{macrocode} % \end{macro} @@ -1917,7 +1855,7 @@ % \begin{macrocode} \prg_new_conditional:Npnn \keys_if_exist:nn #1#2 { p , T , F , TF } { - \cs_if_exist:cTF { \c_keys_code_root_tl #1 / #2 } + \cs_if_exist:cTF { \c_@@_code_root_tl #1 / #2 } { \prg_return_true: } { \prg_return_false: } } @@ -1929,7 +1867,7 @@ % \begin{macrocode} \prg_new_conditional:Npnn \keys_if_choice_exist:nnn #1#2#3 { p , T , F , TF } { - \cs_if_exist:cTF { \c_keys_code_root_tl #1 / #2 / #3 } + \cs_if_exist:cTF { \c_@@_code_root_tl #1 / #2 / #3 } { \prg_return_true: } { \prg_return_false: } } @@ -1940,7 +1878,7 @@ % Showing a key is just a question of using the correct name. % \begin{macrocode} \cs_new:Npn \keys_show:nn #1#2 - { \cs_show:c { \c_keys_code_root_tl #1 / \tl_to_str:n {#2} } } + { \cs_show:c { \c_@@_code_root_tl #1 / \tl_to_str:n {#2} } } % \end{macrocode} % \end{macro} % @@ -1948,23 +1886,23 @@ % % For when there is a need to complain. % \begin{macrocode} -\msg_kernel_new:nnnn { keys } { boolean-values-only } +\__msg_kernel_new:nnnn { kernel } { boolean-values-only } { Key~'#1'~accepts~boolean~values~only. } { The~key~'#1'~only~accepts~the~values~'true'~and~'false'. } -\msg_kernel_new:nnnn { keys } { choice-unknown } +\__msg_kernel_new:nnnn { kernel } { choice-unknown } { Choice~'#2'~unknown~for~key~'#1'. } { The~key~'#1'~takes~a~limited~number~of~values.\\ The~input~given,~'#2',~is~not~on~the~list~accepted. } -\msg_kernel_new:nnnn { keys } { generate-choices-before-code } +\__msg_kernel_new:nnnn { kernel } { generate-choices-before-code } { No~code~available~to~generate~choices~for~key~'#1'. } { \c_msg_coding_error_text_tl Before~using~.generate_choices:n~the~code~should~be~defined~ with~'.choice_code:n'~or~'.choice_code:x'. } -\msg_kernel_new:nnnn { keys } { key-no-property } +\__msg_kernel_new:nnnn { kernel } { key-no-property } { No~property~given~in~definition~of~key~'#1'. } { \c_msg_coding_error_text_tl @@ -1973,39 +1911,33 @@ ~ ~ #1 .<property> \\ LaTeX~did~not~find~a~'.'~to~indicate~the~start~of~a~property. } -\msg_kernel_new:nnnn { keys } { key-unknown } +\__msg_kernel_new:nnnn { kernel } { key-unknown } { The~key~'#1'~is~unknown~and~is~being~ignored. } { The~module~'#2'~does~not~have~a~key~called~#1'.\\ Check~that~you~have~spelled~the~key~name~correctly. } -\msg_kernel_new:nnnn { keys } { option-unknown } - { Unknown~option~'#1'~for~package~#2. } - { - LaTeX~has~been~asked~to~set~an~option~called~'#1'~ - but~the~#2~package~has~not~created~an~option~with~this~name. - } -\msg_kernel_new:nnnn { keys } { property-requires-value } +\__msg_kernel_new:nnnn { kernel } { property-requires-value } { The~property~'#1'~requires~a~value. } { \c_msg_coding_error_text_tl LaTeX~was~asked~to~set~property~'#2'~for~key~'#1'.\\ No~value~was~given~for~the~property,~and~one~is~required. } -\msg_kernel_new:nnnn { keys } { property-unknown } +\__msg_kernel_new:nnnn { kernel } { property-unknown } { The~key~property~'#1'~is~unknown. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~set~the~property~'#1'~for~key~'#2':~ this~property~is~not~defined. } -\msg_kernel_new:nnnn { keys } { value-forbidden } +\__msg_kernel_new:nnnn { kernel } { value-forbidden } { The~key~'#1'~does~not~taken~a~value. } { The~key~'#1'~should~be~given~without~a~value.\\ LaTeX~will~ignore~the~given~value~'#2'. } -\msg_kernel_new:nnnn { keys } { value-required } +\__msg_kernel_new:nnnn { kernel } { value-required } { The~key~'#1'~requires~a~value. } { The~key~'#1'~must~have~a~value.\\ @@ -2031,6 +1963,12 @@ % \end{macro} % \end{macro} % \end{macro} +% +% Internal material for removal by 2012-12-31. +% +% \begin{macrocode} +\cs_new_eq:NN \c_keys_code_root_tl \c__keys_code_root_tl +% \end{macrocode} % % \begin{macrocode} %</initex|package> diff --git a/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx b/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx index 212c953b2aa..5fbaea8cbd6 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx @@ -35,7 +35,7 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3luatex.dtx 3355 2012-02-09 07:18:22Z joseph $ +\GetIdInfo$Id: l3luatex.dtx 3986 2012-07-15 19:23:51Z joseph $ {L3 Experimental LuaTeX-specific functions} %</driver|package> %<*driver> @@ -158,7 +158,7 @@ % \cs{cctab_gset:Nn} \meta{category code table} \Arg{category code set up} % \end{syntax} % Sets the \meta{category code table} to apply the category codes -% which apply when the prevailing regime is modified by the +% which apply when the prevailing r{\'e}gime is modified by the % \meta{category code set up}. Thus within a standard code block % the starting point will be the code applied by \cs{c_code_cctab}. % The assignment of the table is global: the underlying primitive does @@ -226,27 +226,17 @@ %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % -% An error message. -% \begin{macrocode} -\msg_kernel_new:nnnn { luatex } { bad-engine } - { LuaTeX~engine~not~in~use!~Ignoring~#1. } - { - The~feature~you~are~using~is~only~available~ - with~the~LuaTeX~engine.~LaTeX3~ignored~`#1#2'. - } -% \end{macrocode} -% % \begin{macro}{\lua_now:n, \lua_now:x} % \begin{macro}{\lua_shipout_x:n, \lua_shipout_x:x} % \begin{macro}{\lua_shipout:n, \lua_shipout:x} % When \LuaTeX{} is in use, this is all a question of primitives with new % names. On the other hand, for \pdfTeX{} and \XeTeX{} the argument should % be removed from the input stream before issuing an error. This is -% expandable, using \cs{msg_expandable_kernel_error:nnn} +% expandable, using \cs{__msg_kernel_expandable_error:nnn} % as done for \texttt{V}-type expansion in \pkg{l3expan}. % \begin{macrocode} \luatex_if_engine:TF @@ -257,13 +247,13 @@ { \cs_new:Npn \lua_now:x #1 { - \msg_expandable_kernel_error:nnn - { luatex } { bad-engine } { \lua_now:x } + \__msg_kernel_expandable_error:nnn + { kernel } { bad-engine } { \lua_now:x } } \cs_new_protected:Npn \lua_shipout_x:n #1 { - \msg_expandable_kernel_error:nnn - { luatex } { bad-engine } { \lua_shipout_x:n } + \__msg_kernel_expandable_error:nnn + { kernel } { bad-engine } { \lua_shipout_x:n } } } \cs_new:Npn \lua_now:n #1 @@ -279,17 +269,21 @@ % % \subsection{Category code tables} % -% \begin{variable}{\g_cctab_allocate_int} -% \begin{variable}{\g_cctab_stack_int} -% \begin{variable}{\g_cctab_stack_seq} +% \begin{macrocode} +%<@@=cctab> +% \end{macrocode} +% +% \begin{variable}{\g_@@_allocate_int} +% \begin{variable}{\g_@@_stack_int} +% \begin{variable}{\g_@@_stack_seq} % To allocate category code tables, both the read-only and stack % tables need to be followed. There is also a sequence stack for the % dynamic tables themselves. % \begin{macrocode} -\int_new:N \g_cctab_allocate_int -\int_set:Nn \g_cctab_allocate_int { \c_minus_one } -\int_new:N \g_cctab_stack_int -\seq_new:N \g_cctab_stack_seq +\int_new:N \g_@@_allocate_int +\int_set:Nn \g_@@_allocate_int { \c_minus_one } +\int_new:N \g_@@_stack_int +\seq_new:N \g_@@_stack_seq % \end{macrocode} % \end{variable} % \end{variable} @@ -306,21 +300,21 @@ % \begin{macrocode} \cs_new_protected:Npn \cctab_new:N #1 { - \chk_if_free_cs:N #1 - \int_gadd:Nn \g_cctab_allocate_int { \c_two } + \__chk_if_free_cs:N #1 + \int_gadd:Nn \g_@@_allocate_int { \c_two } \int_compare:nNnTF - \g_cctab_allocate_int < { \c_max_register_int + \c_one } + \g_@@_allocate_int < { \c_max_register_int + \c_one } { - \tex_global:D \tex_chardef:D #1 \g_cctab_allocate_int + \tex_global:D \tex_chardef:D #1 \g_@@_allocate_int \luatex_initcatcodetable:D #1 } - { \msg_kernel_fatal:nnx { kernel } { out-of-registers } { cctab } } + { \__msg_kernel_fatal:nnx { kernel } { out-of-registers } { cctab } } } \luatex_if_engine:F { \cs_set_protected:Npn \cctab_new:N #1 { - \msg_kernel_error:nnx { luatex } { bad-engine } + \__msg_kernel_error:nnx { kernel } { bad-engine } { \exp_not:N \cctab_new:N } } } @@ -329,7 +323,7 @@ { \cs_set_protected:Npn \cctab_new:N #1 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \newcatcodetable #1 \luatex_initcatcodetable:D #1 } @@ -340,39 +334,39 @@ % % \begin{macro}{\cctab_begin:N} % \begin{macro}{\cctab_end:} -% \begin{variable}{\l_cctab_internal_tl} +% \begin{variable}{\l_@@_internal_tl} % The aim here is to ensure that the saved tables are read-only. This is % done by using a stack of tables which are not read only, and actually % having them as \enquote{in use} copies. % \begin{macrocode} \cs_new_protected:Npn \cctab_begin:N #1 { - \seq_gpush:Nx \g_cctab_stack_seq { \tex_the:D \luatex_catcodetable:D } + \seq_gpush:Nx \g_@@_stack_seq { \tex_the:D \luatex_catcodetable:D } \luatex_catcodetable:D #1 - \int_gadd:Nn \g_cctab_stack_int { \c_two } - \int_compare:nNnT \g_cctab_stack_int > \c_max_register_int - { \msg_kernel_fatal:nn { code } { cctab-stack-full } } - \luatex_savecatcodetable:D \g_cctab_stack_int - \luatex_catcodetable:D \g_cctab_stack_int + \int_gadd:Nn \g_@@_stack_int { \c_two } + \int_compare:nNnT \g_@@_stack_int > \c_max_register_int + { \__msg_kernel_fatal:nn { kernel } { cctab-stack-full } } + \luatex_savecatcodetable:D \g_@@_stack_int + \luatex_catcodetable:D \g_@@_stack_int } \cs_new_protected_nopar:Npn \cctab_end: { - \int_gsub:Nn \g_cctab_stack_int { \c_two } - \seq_if_empty:NTF \g_cctab_stack_seq - { \tl_set:Nn \l_cctab_internal_tl { 0 } } - { \seq_gpop:NN \g_cctab_stack_seq \l_cctab_internal_tl } - \luatex_catcodetable:D \l_cctab_internal_tl \scan_stop: + \int_gsub:Nn \g_@@_stack_int { \c_two } + \seq_if_empty:NTF \g_@@_stack_seq + { \tl_set:Nn \l_@@_internal_tl { 0 } } + { \seq_gpop:NN \g_@@_stack_seq \l_@@_internal_tl } + \luatex_catcodetable:D \l_@@_internal_tl \scan_stop: } \luatex_if_engine:F { \cs_set_protected:Npn \cctab_begin:N #1 { - \msg_kernel_error:nnxx { luatex } { bad-engine } + \__msg_kernel_error:nnxx { kernel } { bad-engine } { \exp_not:N \cctab_begin:N } {#1} } \cs_set_protected_nopar:Npn \cctab_end: { - \msg_kernel_error:nnx { luatex } { bad-engine } + \__msg_kernel_error:nnx { kernel } { bad-engine } { \exp_not:N \cctab_end: } } } @@ -383,7 +377,7 @@ \cs_set_protected_nopar:Npn \cctab_end: { \EndCatcodeRegime } } %</package> -\tl_new:N \l_cctab_internal_tl +\tl_new:N \l_@@_internal_tl % \end{macrocode} % \end{variable} % \end{macro} @@ -405,7 +399,7 @@ { \cs_set_protected:Npn \cctab_gset:Nn #1#2 { - \msg_kernel_error:nnxx { luatex } { bad-engine } + \__msg_kernel_error:nnxx { kernel } { bad-engine } { \exp_not:N \cctab_gset:Nn } { #1 {#2} } } } @@ -454,12 +448,12 @@ } \cctab_gset:Nn \c_other_cctab { - \prg_stepwise_inline:nnnn { 0 } { 1 } { 127 } + \int_step_inline:nnnn { 0 } { 1 } { 127 } { \char_set_catcode_other:n {#1} } } \cctab_gset:Nn \c_str_cctab { - \prg_stepwise_inline:nnnn { 0 } { 1 } { 127 } + \int_step_inline:nnnn { 0 } { 1 } { 127 } { \char_set_catcode_other:n {#1} } \char_set_catcode_space:n { 32 } } @@ -471,6 +465,23 @@ % \end{variable} % \end{variable} % \end{variable} +% +% \subsection{Messages} +% +% \begin{macrocode} +\__msg_kernel_new:nnnn { kernel } { bad-engine } + { LuaTeX~engine~not~in~use!~Ignoring~#1. } + { + The~feature~you~are~using~is~only~available~ + with~the~LuaTeX~engine.~LaTeX3~ignored~`#1#2'. + } +\__msg_kernel_new:nnnn { kernel } { cctab-stack-full } + { The~category~code~table~stack~is~exhausted. } + { + LaTeX~has~been~asked~to~switch~to~a~new~category~code~table,~ + but~there~is~no~more~space~to~do~this! + } +% \end{macrocode} % % \subsection{Deprecated functions} % @@ -478,7 +489,9 @@ % % \begin{variable}{\c_string_cctab} % \begin{macrocode} +%<*deprecated> \cs_new_eq:NN \c_string_cctab \c_str_cctab +%</deprecated> % \end{macrocode} % \end{variable} % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx index 89362b7e7d4..a545ab5e126 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3msg.dtx 3568 2012-04-23 13:23:58Z joseph $ - {L3 Experimental messages} +\GetIdInfo$Id: l3msg.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Messages} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -91,12 +91,7 @@ % % \section{Creating new messages} % -% ^^A Wrong: "\msg_new:nnnn" is (as it should) global. -% ^^A However, redirections are indeed local. -% All messages have to be created before they can be used. All message -% setting is local, with the general assumption that messages will -% be managed as part of module set up outside of any \TeX{} grouping. -% +% All messages have to be created before they can be used. % The text of messages will automatically by wrapped to the length % available in the console. As a result, formatting is only needed % where it will help to show meaning. In particular, |\\| may be @@ -124,9 +119,8 @@ % \meta{more text} if the user requests it. If no \meta{more text} is % available then a standard text is given instead. Within \meta{text} % and \meta{more text} four parameters (|#1| to |#4|) can be used: -% these will be supplied at the time the message is used. The -% parameters will be expanded when the message is used. An error will -% be raised if the \meta{message} already exists. +% these will be supplied at the time the message is +% used. An error will be raised if the \meta{message} already exists. % \end{function} % % \begin{function}{\msg_set:nnnn, \msg_set:nnn, \msg_gset:nnnn, \msg_gset:nnn} @@ -138,11 +132,10 @@ % \meta{more text} if the user requests it. If no \meta{more text} is % available then a standard text is given instead. Within \meta{text} % and \meta{more text} four parameters (|#1| to |#4|) can be used: -% these will be supplied at the time the message is used. The -% parameters will be expanded when the message is used. +% these will be supplied at the time the message is used. % \end{function} % -% \begin{function}[EXP,pTF, added=2012-03-03]{\msg_if_exist:nn} +% \begin{function}[EXP, pTF, added = 2012-03-03]{\msg_if_exist:nn} % \begin{syntax} % \cs{msg_if_exist_p:nn} \Arg{module} \Arg{message} % \cs{msg_if_exist:nnTF} \Arg{module} \Arg{message} \Arg{true code} \Arg{false code} @@ -169,33 +162,15 @@ % Prints the current line number when a message is given. % \end{function} % -% \begin{variable}{\c_msg_return_text_tl} -% Standard text to indicate that the user should try pressing -% \meta{return} to continue. The standard definition reads: -% \begin{verbatim} -% Try typing <return> to proceed. -% -% If that doesn't work, type X <return> to quit. -% \end{verbatim} -% \end{variable} -% -% \begin{variable}{\c_msg_trouble_text_tl} -% Standard text to indicate that the more errors are likely and -% that aborting the run is advised. The standard definition reads: -% \begin{verbatim} -% More errors will almost certainly follow: -% the LaTeX run should be aborted. -% \end{verbatim} -% \end{variable} -% % \begin{function}[EXP]{\msg_fatal_text:n} % \begin{syntax} % \cs{msg_fatal_text:n} \Arg{module} % \end{syntax} -% Produces the standard text: -% \begin{verbatim} -% Fatal <module> error -% \end{verbatim} +% Produces the standard text +% \begin{quote} +% \ttfamily +% Fatal \meta{module} error +% \end{quote} % This function can be redefined to alter the language in which the % message is given, using |#1| as the name of the \meta{module} to % be included. @@ -205,10 +180,11 @@ % \begin{syntax} % \cs{msg_critical_text:n} \Arg{module} % \end{syntax} -% Produces the standard text: -% \begin{verbatim} -% Critical <module> error -% \end{verbatim} +% Produces the standard text +% \begin{quote} +% \ttfamily +% Critical \meta{module} error +% \end{quote} % This function can be redefined to alter the language in which the % message is given, using |#1| as the name of the \meta{module} to % be included. @@ -218,10 +194,11 @@ % \begin{syntax} % \cs{msg_error_text:n} \Arg{module} % \end{syntax} -% Produces the standard text: -% \begin{verbatim} -% <module> error -% \end{verbatim} +% Produces the standard text +% \begin{quote} +% \ttfamily +% \meta{module} error +% \end{quote} % This function can be redefined to alter the language in which the % message is given, using |#1| as the name of the \meta{module} to % be included. @@ -231,10 +208,11 @@ % \begin{syntax} % \cs{msg_warning_text:n} \Arg{module} % \end{syntax} -% Produces the standard text: -% \begin{verbatim} -% <module> warning -% \end{verbatim} +% Produces the standard text +% \begin{quote} +% \ttfamily +% \meta{module} warning +% \end{quote} % This function can be redefined to alter the language in which the % message is given, using |#1| as the name of the \meta{module} to % be included. @@ -245,161 +223,184 @@ % \cs{msg_info_text:n} \Arg{module} % \end{syntax} % Produces the standard text: -% \begin{verbatim} -% <module> info -% \end{verbatim} +% \begin{quote} +% \ttfamily +% \meta{module} info +% \end{quote} % This function can be redefined to alter the language in which the % message is given, using |#1| as the name of the \meta{module} to % be included. % \end{function} -% -% \section{Issuing messages} -% -% Messages behave differently depending on the message class. A number -% of standard message classes are supplied, but more can be -% created. -% -% When issuing messages, any arguments passed should use -% \cs{tl_to_str:n} or \cs{token_to_str:N} to prevent unwanted expansion -% of the material. -% -% \begin{function}[updated = 2012-04-12]{\msg_class_set:nn} +% +% \begin{function}[EXP]{\msg_see_documentation_text:n} % \begin{syntax} -% \cs{msg_class_set:nn} \Arg{class} \Arg{code} +% \cs{msg_see_documentation_text:n} \Arg{module} % \end{syntax} -% Sets a \meta{class} to output a message, using \meta{code} -% to process the message text. The \meta{class} should be a text -% value, while the \meta{code} may be any arbitrary material. -% The \meta{code} will receive~$6$ arguments: the module -% name (|#1|), the message name (|#2|) and the four arguments -% taken by the message text (|#3| to |#6|). -% ^^A Add an example? An application could be that an IDE redirects -% ^^A classes from 'error' to 'IDEerror', 'warning' to 'IDEwarning', -% ^^A etc, and defines 'IDEerror' and 'IDEwarning' to produce messages -% ^^A which are simpler to parse. +% Produces the standard text +% \begin{quote} +% \ttfamily +% +% See the \meta{module} documentation for further information. +% \end{quote} +% This function can be redefined to alter the language in which the +% message is given, using |#1| as the name of the \meta{module} to +% be included. % \end{function} % -% The kernel defines several common message classes. The following -% describes the standard behaviour of each class if no redirection of -% the class or message is active. In all cases, the message may be -% issued supplying~$0$ to~$4$ arguments. The code will -% ensure that there an no errors if the number of arguments supplied -% here does not match the number in the definition of the message -% (although of course the sense of the message may be impaired). +% \section{Issuing messages} +% +% Messages behave differently depending on the message class. In all cases, +% the message may be issued supplying~$0$ to~$4$ arguments. If the number of +% arguments supplied here does not match the number in the definition of the +% message, extra arguments will be ignored, or empty arguments added (of +% course the sense of the message may be impaired). The four arguments will +% be converted to strings before being added to the message text: the +% \texttt{x}-type variants should be used to expand material. % -% \begin{function} +% \begin{function}[updated = 2012-06-29] % { +% \msg_fatal:nnnnnn , +% \msg_fatal:nnnnn , +% \msg_fatal:nnnn , +% \msg_fatal:nnn , +% \msg_fatal:nn , % \msg_fatal:nnxxxx , % \msg_fatal:nnxxx , % \msg_fatal:nnxx , -% \msg_fatal:nnx , -% \msg_fatal:nn +% \msg_fatal:nnx % } % \begin{syntax} -% \cs{msg_fatal:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{msg_fatal:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} % Issues \meta{module} error \meta{message}, passing \meta{arg one} to % \meta{arg four} to the text-creating functions. After issuing a % fatal error the \TeX{} run will halt. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-06-29] % { +% \msg_critical:nnnnnn , +% \msg_critical:nnnnn , +% \msg_critical:nnnn , +% \msg_critical:nnn , +% \msg_critical:nn , % \msg_critical:nnxxxx , % \msg_critical:nnxxx , % \msg_critical:nnxx , -% \msg_critical:nnx , -% \msg_critical:nn +% \msg_critical:nnx % } % \begin{syntax} -% \cs{msg_critical:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{msg_critical:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} % Issues \meta{module} error \meta{message}, passing \meta{arg one} to -% \meta{arg four} to the text-creating functions. After issuing the -% message reading the current input file will stop. This may halt -% the \TeX{} run (if the current file is the main file) or -% may abort reading a sub-file. +% \meta{arg four} to the text-creating functions. After issuing a +% critical error, \TeX{} will stop reading the current input file. +% This may halt the \TeX{} run (if the current file is the main file) +% or may abort reading a sub-file. +% \begin{texnote} +% The \TeX{} \tn{endinput} primitive is used to exit the file. In +% particular, the rest of the current line remains in the input +% stream. ^^A Can we fix that? +% \end{texnote} % \end{function} -% ^^A Perhaps add detection that we are in the main file to really do -% ^^A '\tex_end:D' in that case? % -% \begin{function} +% \begin{function}[updated = 2012-06-29] % { +% \msg_error:nnnnnn , +% \msg_error:nnnnn , +% \msg_error:nnnn , +% \msg_error:nnn , +% \msg_error:nn , % \msg_error:nnxxxx , % \msg_error:nnxxx , % \msg_error:nnxx , -% \msg_error:nnx , -% \msg_error:nn +% \msg_error:nnx % } % \begin{syntax} -% \cs{msg_error:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{msg_error:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} % Issues \meta{module} error \meta{message}, passing \meta{arg one} to -% \meta{arg four} to the text-creating functions. The error will -% stop processing and issue the text at the terminal. After user input, -% the run will continue. +% \meta{arg four} to the text-creating functions. The error will +% interrupt processing and issue the text at the terminal. After user +% input, the run will continue. % \end{function} % -% \begin{function} -% { -% \msg_warning:nnxxxx , -% \msg_warning:nnxxx , -% \msg_warning:nnxx , -% \msg_warning:nnx , -% \msg_warning:nn -% } -% \begin{syntax} -% \cs{msg_warning:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} -% \end{syntax} -% Issues \meta{module} warning \meta{message}, passing \meta{arg one} to -% \meta{arg four} to the text-creating functions. The warning text -% will be added to the log file, but the \TeX{} run will not be -% interrupted. -% \end{function} +% \begin{function}[updated = 2012-06-29] +% { +% \msg_warning:nnnnnn , +% \msg_warning:nnnnn , +% \msg_warning:nnnn , +% \msg_warning:nnn , +% \msg_warning:nn , +% \msg_warning:nnxxxx , +% \msg_warning:nnxxx , +% \msg_warning:nnxx , +% \msg_warning:nnx +% } +% \begin{syntax} +% \cs{msg_warning:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues \meta{module} warning \meta{message}, passing \meta{arg one} +% to \meta{arg four} to the text-creating functions. The warning text +% will be added to the log file and the terminal, but the \TeX{} run +% will not be interrupted. +% \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-06-29] % { +% \msg_info:nnnnnn , +% \msg_info:nnnnn , +% \msg_info:nnnn , +% \msg_info:nnn , +% \msg_info:nn , % \msg_info:nnxxxx , % \msg_info:nnxxx , % \msg_info:nnxx , -% \msg_info:nnx , -% \msg_info:nn +% \msg_info:nnx % } % \begin{syntax} -% \cs{msg_info:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{msg_info:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} % Issues \meta{module} information \meta{message}, passing % \meta{arg one} to \meta{arg four} to the text-creating functions. % The information text will be added to the log file. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-07-14] % { +% \msg_log:nnnnnn , +% \msg_log:nnnnn , +% \msg_log:nnnn , +% \msg_log:nnn , +% \msg_log:nn , % \msg_log:nnxxxx , % \msg_log:nnxxx , % \msg_log:nnxx , -% \msg_log:nnx , -% \msg_log:nn +% \msg_log:nnx % } % \begin{syntax} -% \cs{msg_log:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{msg_log:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} % Issues \meta{module} information \meta{message}, passing % \meta{arg one} to \meta{arg four} to the text-creating functions. % The information text will be added to the log file: the output -% is briefer than \cs{msg_info:nnxxxx}. +% is briefer than \cs{msg_info:nnnnnn}. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-06-29] % { +% \msg_none:nnnnnn , +% \msg_none:nnnnn , +% \msg_none:nnnn , +% \msg_none:nnn , +% \msg_none:nn , % \msg_none:nnxxxx , % \msg_none:nnxxx , % \msg_none:nnxx , -% \msg_none:nnx , -% \msg_none:nn +% \msg_none:nnx % } % \begin{syntax} -% \cs{msg_none:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{msg_none:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} % Does nothing: used as a message class to prevent any output at % all (see the discussion of message redirection). @@ -434,18 +435,23 @@ % it is possible to select out an individual message for special treatment % even if the entire class is already redirected. % -% \begin{function}[updated = 2012-04-12]{\msg_redirect_class:nn} +% Multiple redirections are possible. Redirections can be cancelled by +% providing an empty argument for the target class. Redirection to a +% missing class will raise errors immediately. Infinite loops are +% prevented by eliminating the redirection starting from the target of +% the redirection that caused the loop to appear. Namely, if +% redirections are requested as $A \to B$, $B \to C$ and $C \to A$ in +% this order, then the $A \to B$ redirection is cancelled. +% +% \begin{function}[updated = 2012-04-27]{\msg_redirect_class:nn} % \begin{syntax} % \cs{msg_redirect_class:nn} \Arg{class one} \Arg{class two} % \end{syntax} % Changes the behaviour of messages of \meta{class one} so that they -% are processed using the code for those of \meta{class two}. Multiple -% redirections are possible. Redirection to a missing class or -% infinite loops will raise errors when the messages are used, -% rather than at the point of redirection. +% are processed using the code for those of \meta{class two}. % \end{function} % -% \begin{function}[updated = 2012-04-12]{\msg_redirect_module:nnn} +% \begin{function}[updated = 2012-04-27]{\msg_redirect_module:nnn} % \begin{syntax} % \cs{msg_redirect_module:nnn} \Arg{module} \Arg{class one} \Arg{class two} % \end{syntax} @@ -460,14 +466,14 @@ % \end{verbatim} % \end{function} % -% \begin{function}[updated = 2012-04-12]{\msg_redirect_name:nnn} +% \begin{function}[updated = 2012-04-27]{\msg_redirect_name:nnn} % \begin{syntax} % \cs{msg_redirect_name:nnn} \Arg{module} \Arg{message} \Arg{class} % \end{syntax} -% Redirects a specific \meta{message} from a specific \meta{module} -% to act as a member of \meta{class} of messages. This function can -% be used to make a selected message \enquote{silent} without -% changing global parameters: +% Redirects a specific \meta{message} from a specific \meta{module} to +% act as a member of \meta{class} of messages. No further redirection +% is performed. This function can be used to make a selected message +% \enquote{silent} without changing global parameters: % \begin{verbatim} % \msg_redirect_name:nnn { module } { annoying-message } { none } % \end{verbatim} @@ -479,18 +485,9 @@ % higher-level system. However, there are occasions where direct % access to these functions is desirable. % -% \begin{function}[EXP]{\msg_newline:, \msg_two_newlines:} -% \begin{syntax} -% \cs{msg_newline:} -% \end{syntax} -% Forces a new line in a message. This is a low-level function, which -% will not include any additional printing information in the message: -% contrast with |\\| in messages. The |two| version adds two lines. -% \end{function} -% -% \begin{function}{\msg_interrupt:xxx} +% \begin{function}[added = 2012-06-28]{\msg_interrupt:nnn} % \begin{syntax} -% \cs{msg_interrupt:xxx} \Arg{first line} \Arg{text} \Arg{extra text} +% \cs{msg_interrupt:nnn} \Arg{first line} \Arg{text} \Arg{extra text} % \end{syntax} % Interrupts the \TeX{} run, issuing a formatted message comprising % \meta{first line} and \meta{text} laid out in the format @@ -511,13 +508,15 @@ % | <extra text> % |............................................... % \end{verbatim} -% where the \meta{extra text} will be wrapped to fit within the current -% line length. +% where the \meta{extra text} will be wrapped within the current +% line length. Wrapping of both \meta{text} and \meta{more text} takes place +% using \cs{iow_wrap:nnnN}; the documentation for the latter should be +% consulted for full details. % \end{function} % -% \begin{function}{\msg_log:x} +% \begin{function}[added = 2012-06-28]{\msg_log:n} % \begin{syntax} -% \cs{msg_log:x} \Arg{text} +% \cs{msg_log:n} \Arg{text} % \end{syntax} % Writes to the log file with the \meta{text} laid out in the format % \begin{verbatim} @@ -526,12 +525,13 @@ % ................................................. % \end{verbatim} % where the \meta{text} will be wrapped to fit within the current -% line length. +% line length. Wrapping takes place using \cs{iow_wrap:nnnN}; the +% documentation for the latter should be consulted for full details. % \end{function} % -% \begin{function}{\msg_term:x} +% \begin{function}[added = 2012-06-28]{\msg_term:n} % \begin{syntax} -% \cs{msg_term:x} \Arg{text} +% \cs{msg_term:n} \Arg{text} % \end{syntax} % Writes to the terminal and log file with the \meta{text} laid out in the % format @@ -541,7 +541,8 @@ % ************************************************* % \end{verbatim} % where the \meta{text} will be wrapped to fit within the current -% line length. +% line length. Wrapping takes place using \cs{iow_wrap:nnnN}; the +% documentation for the latter should be consulted for full details. % \end{function} % % \section{Kernel-specific functions} @@ -551,59 +552,65 @@ % and also ensures that serious errors can be handled properly. % % \begin{function}[updated = 2011-08-16] -% {\msg_kernel_new:nnnn, \msg_kernel_new:nnn} +% {\__msg_kernel_new:nnnn, \__msg_kernel_new:nnn} % \begin{syntax} -% \cs{msg_kernel_new:nnnn} \Arg{module} \Arg{message} \Arg{text} \Arg{more text} +% \cs{__msg_kernel_new:nnnn} \Arg{module} \Arg{message} \Arg{text} \Arg{more text} % \end{syntax} % Creates a kernel \meta{message} for a given \meta{module}. % The message will be defined to first give \meta{text} and then % \meta{more text} if the user requests it. If no \meta{more text} is % available then a standard text is given instead. Within \meta{text} % and \meta{more text} four parameters (|#1| to |#4|) can be used: -% these will be supplied at the time the message is used. The -% parameters will be expanded when the message is used. An error will -% be raised if the \meta{message} already exists. +% these will be supplied and expanded at the time the message is used. +% An error will be raised if the \meta{message} already exists. % \end{function} % -% \begin{function}{\msg_kernel_set:nnnn, \msg_kernel_set:nnn} +% \begin{function}{\__msg_kernel_set:nnnn, \__msg_kernel_set:nnn} % \begin{syntax} -% \cs{msg_kernel_set:nnnn} \Arg{module} \Arg{message} \Arg{text} \Arg{more text} +% \cs{__msg_kernel_set:nnnn} \Arg{module} \Arg{message} \Arg{text} \Arg{more text} % \end{syntax} % Sets up the text for a kernel \meta{message} for a given \meta{module}. % The message will be defined to first give \meta{text} and then % \meta{more text} if the user requests it. If no \meta{more text} is % available then a standard text is given instead. Within \meta{text} % and \meta{more text} four parameters (|#1| to |#4|) can be used: -% these will be supplied at the time the message is used. The -% parameters will be expanded when the message is used. +% these will be supplied and expanded at the time the message is used. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-06-29] % { -% \msg_kernel_fatal:nnxxxx , -% \msg_kernel_fatal:nnxxx , -% \msg_kernel_fatal:nnxx , -% \msg_kernel_fatal:nnx , -% \msg_kernel_fatal:nn +% \__msg_kernel_fatal:nnnnnn , +% \__msg_kernel_fatal:nnnnn , +% \__msg_kernel_fatal:nnnn , +% \__msg_kernel_fatal:nnn , +% \__msg_kernel_fatal:nn , +% \__msg_kernel_fatal:nnxxxx , +% \__msg_kernel_fatal:nnxxx , +% \__msg_kernel_fatal:nnxx , +% \__msg_kernel_fatal:nnx % } % \begin{syntax} -% \cs{msg_kernel_fatal:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{__msg_kernel_fatal:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} % Issues kernel \meta{module} error \meta{message}, passing \meta{arg one} % to \meta{arg four} to the text-creating functions. After issuing a % fatal error the \TeX{} run will halt. Cannot be redirected. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-06-29] % { -% \msg_kernel_error:nnxxxx , -% \msg_kernel_error:nnxxx , -% \msg_kernel_error:nnxx , -% \msg_kernel_error:nnx , -% \msg_kernel_error:nn +% \__msg_kernel_error:nnnnnn , +% \__msg_kernel_error:nnnnn , +% \__msg_kernel_error:nnnn , +% \__msg_kernel_error:nnn , +% \__msg_kernel_error:nn , +% \__msg_kernel_error:nnxxxx , +% \__msg_kernel_error:nnxxx , +% \__msg_kernel_error:nnxx , +% \__msg_kernel_error:nnx % } % \begin{syntax} -% \cs{msg_kernel_error:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{__msg_kernel_error:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} % Issues kernel \meta{module} error \meta{message}, passing \meta{arg one} % to @@ -612,34 +619,42 @@ % the run will continue. Cannot be redirected. % \end{function} % -% \begin{function} -% { -% \msg_kernel_warning:nnxxxx , -% \msg_kernel_warning:nnxxx , -% \msg_kernel_warning:nnxx , -% \msg_kernel_warning:nnx , -% \msg_kernel_warning:nn -% } -% \begin{syntax} -% \cs{msg_kernel_warning:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} -% \end{syntax} -% Issues kernel \meta{module} warning \meta{message}, passing -% \meta{arg one} to -% \meta{arg four} to the text-creating functions. The warning text -% will be added to the log file, but the \TeX{} run will not be -% interrupted. -% \end{function} +% \begin{function}[updated = 2012-06-29] +% { +% \__msg_kernel_warning:nnnnnn , +% \__msg_kernel_warning:nnnnn , +% \__msg_kernel_warning:nnnn , +% \__msg_kernel_warning:nnn , +% \__msg_kernel_warning:nn , +% \__msg_kernel_warning:nnxxxx , +% \__msg_kernel_warning:nnxxx , +% \__msg_kernel_warning:nnxx , +% \__msg_kernel_warning:nnx +% } +% \begin{syntax} +% \cs{__msg_kernel_warning:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues kernel \meta{module} warning \meta{message}, passing +% \meta{arg one} to +% \meta{arg four} to the text-creating functions. The warning text +% will be added to the log file, but the \TeX{} run will not be +% interrupted. +% \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-06-29] % { -% \msg_kernel_info:nnxxxx , -% \msg_kernel_info:nnxxx , -% \msg_kernel_info:nnxx , -% \msg_kernel_info:nnx , -% \msg_kernel_info:nn +% \__msg_kernel_info:nnnnnn , +% \__msg_kernel_info:nnnnn , +% \__msg_kernel_info:nnnn , +% \__msg_kernel_info:nnn , +% \__msg_kernel_info:nn , +% \__msg_kernel_info:nnxxxx , +% \__msg_kernel_info:nnxxx , +% \__msg_kernel_info:nnxx , +% \__msg_kernel_info:nnx % } % \begin{syntax} -% \cs{msg_kernel_info:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{__msg_kernel_info:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} % Issues kernel \meta{module} information \meta{message}, passing % \meta{arg one} to \meta{arg four} to the text-creating functions. @@ -658,14 +673,14 @@ % % \begin{function}[EXP, added = 2011-11-23] % { -% \msg_expandable_kernel_error:nnnnnn, -% \msg_expandable_kernel_error:nnnnn, -% \msg_expandable_kernel_error:nnnn, -% \msg_expandable_kernel_error:nnn, -% \msg_expandable_kernel_error:nn +% \__msg_kernel_expandable_error:nnnnnn, +% \__msg_kernel_expandable_error:nnnnn, +% \__msg_kernel_expandable_error:nnnn, +% \__msg_kernel_expandable_error:nnn, +% \__msg_kernel_expandable_error:nn % } % \begin{syntax} -% \cs{msg_expandable_kernel_error:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{__msg_kernel_expandable_error:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} % Issues an error, passing \meta{arg one} to \meta{arg four} % to the text-creating functions. The resulting string must @@ -673,9 +688,9 @@ % \end{function} % % \begin{function}[EXP, added = 2011-08-11, updated = 2011-08-13] -% {\msg_expandable_error:n} +% {\__msg_expandable_error:n} % \begin{syntax} -% \cs{msg_expandable_error:n} \Arg{error message} +% \cs{__msg_expandable_error:n} \Arg{error message} % \end{syntax} % Issues an \enquote{Undefined error} message from \TeX{} itself, % and prints the \meta{error message}. The \meta{error message} @@ -692,30 +707,53 @@ % % The following functions are used in several kernel modules. % -% \begin{function}{\msg_aux_use:nn, \msg_aux_use:nnxxxx} +% \begin{function} +% { +% \__msg_term:nnnnnn, +% \__msg_term:nnnnnV, +% \__msg_term:nnnnn, +% \__msg_term:nnn , +% \__msg_term:nn +% } % \begin{syntax} -% \cs{msg_aux_use:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} +% \cs{__msg_term:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four} % \end{syntax} -% Prints the \meta{message} from \meta{module} in the terminal, -% without formatting. +% Prints the \meta{message} from \meta{module} in the terminal without +% formatting. Used in messages which print complex variable contents +% completely. % \end{function} -% -% \begin{function}{\msg_aux_show:x} +% +% \begin{function}{\__msg_show_variable:Nnn, \__msg_show_variable:Nnx} % \begin{syntax} -% \cs{msg_aux_show:x} \Arg{formatted string} +% \cs{__msg_show_variable:Nnn} \meta{variable} \Arg{type} \Arg{formatted content} +% \end{syntax} +% Displays the \meta{formatted content} of the \meta{variable} of \meta{type} +% in the terminal. The \meta{formatted content} will typically be generated +% by \texttt{x}-type expansion using the \cs{__msg_show_variable:Nnx} variant: +% the nature of the formatting is dependent on the calling module. +% \end{function} +% +% \begin{function}{\__msg_show_variable:n, \__msg_show_variable:x} +% \begin{syntax} +% \cs{__msg_show_variable:n} \Arg{formatted string} % \end{syntax} % Shows the \meta{formatted string} on the terminal. After expansion, % unless it is empty, the \meta{formatted string} must contain |>|, % and the part of \meta{formatted string} before the first |>| is % removed. Failure to do so causes low-level \TeX{} errors. % \end{function} -% -% \begin{function}{\msg_aux_show:Nnx} +% +% \begin{function} +% {\__msg_show_item:n, \__msg_show_item:nn, \__msg_show_item_unbraced:nn} % \begin{syntax} -% \cs{msg_aux_show:Nnx} \meta{variable} \Arg{module} \Arg{token list} +% \cs{__msg_show_item:n} \meta{item} +% \cs{__msg_show_item:nn} \meta{item-key} \meta{item-value} % \end{syntax} -% Auxiliary common to \pkg{l3clist}, \pkg{l3prop} and \pkg{seq}, -% which displays an appropriate message and the contents of the variable. +% Auxiliary functions used within the argument of +% \cs{__msg_show_variable:Nnx} to format variable items correctly for +% display. The \cs{__msg_show_item:n} version is used for simple lists, +% the \cs{__msg_show_item:nn} and \cs{__msg_show_item_ubraced:nn} versions +% for key--value like data structures. % \end{function} % % \end{documentation} @@ -727,19 +765,23 @@ % \begin{macrocode} %<*initex|package> % \end{macrocode} +% +% \begin{macrocode} +%<@@=msg> +% \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % -% \begin{variable}{\l_msg_internal_tl} +% \begin{variable}{\l_@@_internal_tl} % A general scratch for the module. % \begin{macrocode} -\tl_new:N \l_msg_internal_tl +\tl_new:N \l_@@_internal_tl % \end{macrocode} % \end{variable} % @@ -749,11 +791,11 @@ % the code here. First, a mechanism for creating message text. % This is pretty simple, as there is not actually a lot to do. % -% \begin{variable}{\c_msg_text_prefix_tl, \c_msg_more_text_prefix_tl} +% \begin{variable}{\c_@@_text_prefix_tl, \c_@@_more_text_prefix_tl} % Locations for the text of messages. % \begin{macrocode} -\tl_const:Nn \c_msg_text_prefix_tl { msg~text~>~ } -\tl_const:Nn \c_msg_more_text_prefix_tl { msg~extra~text~>~ } +\tl_const:Nn \c_@@_text_prefix_tl { msg~text~>~ } +\tl_const:Nn \c_@@_more_text_prefix_tl { msg~extra~text~>~ } % \end{macrocode} % \end{variable} % @@ -763,37 +805,37 @@ % \begin{macrocode} \prg_new_conditional:Npnn \msg_if_exist:nn #1#2 { p , T , F , TF } { - \cs_if_exist:cTF { \c_msg_text_prefix_tl #1 / #2 } + \cs_if_exist:cTF { \c_@@_text_prefix_tl #1 / #2 } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\chk_if_free_msg:nn} -% This auxiliary is similar to \cs{chk_if_free_cs:N}, and is used when +% \begin{macro}[aux]{\__chk_if_free_msg:nn} +% This auxiliary is similar to \cs{__chk_if_free_cs:N}, and is used when % defining messages with \cs{msg_new:nnnn}. It could be inlined in % \cs{msg_new:nnnn}, but the experimental \pkg{l3trace} module needs % to disable this check when reloading a package with the extra % tracing information. % \begin{macrocode} -\cs_new_protected:Npn \chk_if_free_msg:nn #1#2 +\cs_new_protected:Npn \__chk_if_free_msg:nn #1#2 { \msg_if_exist:nnT {#1} {#2} { - \msg_kernel_error:nnxx { msg } { message-already-defined } + \@@_kernel_error:nnxx { kernel } { message-already-defined } {#1} {#2} } } %<*package> \tex_ifodd:D \l@expl@log@functions@bool - \cs_gset_protected:Npn \chk_if_free_msg:nn #1#2 + \cs_gset_protected:Npn \__chk_if_free_msg:nn #1#2 { \msg_if_exist:nnT {#1} {#2} { - \msg_kernel_error:nnxx { msg } { message-already-defined } + \@@_kernel_error:nnxx { kernel } { message-already-defined } {#1} {#2} } - \iow_log:x { Defining~message~#1/#2~ \msg_line_context: } + \iow_log:x { Defining~message~ #1 / #2 ~\msg_line_context: } } \fi: %</package> @@ -808,25 +850,25 @@ % \begin{macrocode} \cs_new_protected:Npn \msg_new:nnnn #1#2 { - \chk_if_free_msg:nn {#1} {#2} + \__chk_if_free_msg:nn {#1} {#2} \msg_gset:nnnn {#1} {#2} } \cs_new_protected:Npn \msg_new:nnn #1#2#3 { \msg_new:nnnn {#1} {#2} {#3} { } } \cs_new_protected:Npn \msg_set:nnnn #1#2#3#4 { - \cs_set:cpn { \c_msg_text_prefix_tl #1 / #2 } + \cs_set:cpn { \c_@@_text_prefix_tl #1 / #2 } ##1##2##3##4 {#3} - \cs_set:cpn { \c_msg_more_text_prefix_tl #1 / #2 } + \cs_set:cpn { \c_@@_more_text_prefix_tl #1 / #2 } ##1##2##3##4 {#4} } \cs_new_protected:Npn \msg_set:nnn #1#2#3 { \msg_set:nnnn {#1} {#2} {#3} { } } \cs_new_protected:Npn \msg_gset:nnnn #1#2#3#4 { - \cs_gset:cpn { \c_msg_text_prefix_tl #1 / #2 } + \cs_gset:cpn { \c_@@_text_prefix_tl #1 / #2 } ##1##2##3##4 {#3} - \cs_gset:cpn { \c_msg_more_text_prefix_tl #1 / #2 } + \cs_gset:cpn { \c_@@_more_text_prefix_tl #1 / #2 } ##1##2##3##4 {#4} } \cs_new_protected:Npn \msg_gset:nnn #1#2#3 @@ -887,15 +929,7 @@ % \end{macrocode} % \end{variable} % -% \begin{macro}{\msg_newline:, \msg_two_newlines:} -% New lines are printed in the same way as for low-level file writing. -% \begin{macrocode} -\cs_new_nopar:Npn \msg_newline: { ^^J } -\cs_new_nopar:Npn \msg_two_newlines: { ^^J ^^J } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\msg_line_number, \msg_line_context:} +% \begin{macro}{\msg_line_number:, \msg_line_context:} % For writing the line number nicely. \cs{msg_line_context:} was set up % earlier, so this is not \texttt{new}. % \begin{macrocode} @@ -911,7 +945,7 @@ % % \subsection{Showing messages: low level mechanism} % -% \begin{macro}{\msg_interrupt:xxx} +% \begin{macro}{\msg_interrupt:nnn} % The low-level interruption macro is rather opaque, unfortunately. % Depending on the availability of more information there is a choice % of how to set up the further help. We feed the extra help text and @@ -919,36 +953,36 @@ % must first setup \TeX{}'s \tn{errhelp} register before issuing an % \tn{errmessage}. % \begin{macrocode} -\cs_new_protected:Npn \msg_interrupt:xxx #1#2#3 +\cs_new_protected:Npn \msg_interrupt:nnn #1#2#3 { \tl_if_empty:nTF {#3} { - \msg_interrupt_wrap:xx { \\ \c_msg_no_info_text_tl } + \@@_interrupt_wrap:nn { \\ \c_msg_no_info_text_tl } {#1 \\\\ #2 \\\\ \c_msg_continue_text_tl } } { - \msg_interrupt_wrap:xx { \\ #3 } + \@@_interrupt_wrap:nn { \\ #3 } {#1 \\\\ #2 \\\\ \c_msg_help_text_tl } } } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\msg_interrupt_wrap:xx} -% \begin{macro}[aux]{\msg_interrupt_more_text:n} +% \begin{macro}[aux]{\@@_interrupt_wrap:nn} +% \begin{macro}[aux]{\@@_interrupt_more_text:n} % First setup \TeX{}'s \tn{errhelp} register with the extra help |#1|, % then build a nice-looking error message with |#2|. Everything is % done using \texttt{x}-type expansion as the new line markers are % different for the two type of text and need to be correctly set up. -% The auxiliary \cs{msg_interrupt_more_text:n} recieves its argument +% The auxiliary \cs{@@_interrupt_more_text:n} receives its argument % as a line-wrapped string, which is thus unaffected by expansion. % \begin{macrocode} -\cs_new_protected:Npn \msg_interrupt_wrap:xx #1#2 +\cs_new_protected:Npn \@@_interrupt_wrap:nn #1#2 { - \iow_wrap:xnnnN {#1} { | ~ } { 2 } { } \msg_interrupt_more_text:n - \iow_wrap:xnnnN {#2} { ! ~ } { 2 } { } \msg_interrupt_text:n + \iow_wrap:nnnN {#1} { | ~ } { } \@@_interrupt_more_text:n + \iow_wrap:nnnN {#2} { ! ~ } { } \@@_interrupt_text:n } -\cs_new_protected:Npn \msg_interrupt_more_text:n #1 +\cs_new_protected:Npn \@@_interrupt_more_text:n #1 { \exp_args:Nx \tex_errhelp:D { @@ -961,17 +995,16 @@ % \end{macro} % \end{macro} % -% \begin{macro}[aux]{\msg_interrupt_text:n} -% \begin{variable}{\c_msg_hide_tl<dots>} +% \begin{macro}[aux]{\@@_interrupt_text:n} % The business end of the process starts by producing some visual % separation of the message from the main part of the log. The error % message needs to be printed with everything made % \enquote{invisible}: \TeX{}'s own information involves the macro in % which \tn{errmessage} is called, and the end of the argument of the % \tn{errmessage}, including the closing brace. We use an active |!| -% to call the \tn{errmessage} primitive, and end its argument with an -% odd \cs{c_msg_hide_tl<dots>} which fills the output with dots. The -% trailing closing brace is turned into a space to hide it as well. +% to call the \tn{errmessage} primitive, and end its argument with +% \cs{use_none:n} \Arg{dots} which fills the output with dots. Two +% trailing closing braces are turned into spaces to hide them as well. % The group in which we alter the definition of the active |!| is % closed before producing the message: this ensures that tokens % inserted by typing |I| in the command-line will bee inserted after @@ -982,13 +1015,10 @@ \char_set_lccode:nn {`\}} {`\ } \char_set_lccode:nn {`\&} {`\!} \char_set_catcode_active:N \& - \char_set_catcode_letter:N \. - \tl_new:N - \c_msg_hide_tl............................................ \tl_to_lowercase:n { \group_end: - \cs_new_protected:Npn \msg_interrupt_text:n #1 + \cs_new_protected:Npn \@@_interrupt_text:n #1 { \iow_term:x { @@ -1003,7 +1033,8 @@ \tex_errmessage:D { #1 - \c_msg_hide_tl............................................ + \use_none:n + { ............................................ } } } \exp_after:wN @@ -1012,27 +1043,24 @@ } } % \end{macrocode} -% \end{variable} % \end{macro} % -% \begin{macro}{\msg_log:x} -% \begin{macro}{\msg_term:x} +% \begin{macro}{\msg_log:n} +% \begin{macro}{\msg_term:n} % Printing to the log or terminal without a stop is rather easier. % A bit of simple visual work sets things off nicely. % \begin{macrocode} -\cs_new_protected:Npn \msg_log:x #1 +\cs_new_protected:Npn \msg_log:n #1 { - \iow_log:x { ................................................. } - \iow_wrap:xnnnN { . ~ #1} { . ~ } { 2 } { } - \iow_log:x - \iow_log:x { ................................................. } + \iow_log:n { ................................................. } + \iow_wrap:nnnN { . ~ #1} { . ~ } { } \iow_log:n + \iow_log:n { ................................................. } } -\cs_new_protected:Npn \msg_term:x #1 +\cs_new_protected:Npn \msg_term:n #1 { - \iow_term:x { ************************************************* } - \iow_wrap:xnnnN { * ~ #1} { * ~ } { 2 } { } - \iow_term:x - \iow_term:x { ************************************************* } + \iow_term:n { ************************************************* } + \iow_wrap:nnnN { * ~ #1} { * ~ } { } \iow_term:n + \iow_term:n { ************************************************* } } % \end{macrocode} % \end{macro} @@ -1041,8 +1069,12 @@ % \subsection{Displaying messages} % % \LaTeX{} is handling error messages and so the \TeX{} ones are disabled. +% This is already done by the \LaTeXe{} kernel, so to avoid messing up any +% deliberate change by a user this is only set in format mode. % \begin{macrocode} -\int_gset:Nn \tex_errorcontextlines:D { -1 } +%<*initex> +\int_gset_eq:NN \tex_errorcontextlines:D \c_minus_one +%</initex> % \end{macrocode} % % \begin{macro} @@ -1054,7 +1086,7 @@ % \msg_info_text:n % } % A function for issuing messages: both the text and order could -% in principal vary. +% in principle vary. % \begin{macrocode} \cs_new:Npn \msg_fatal_text:n #1 { Fatal~#1~error } \cs_new:Npn \msg_critical_text:n #1 { Critical~#1~error } @@ -1065,591 +1097,637 @@ % \end{macro} % % \begin{macro}{\msg_see_documentation_text:n} -% Contextual footer information. +% Contextual footer information. The \LaTeX{} module only comprises +% \LaTeX3 code, so we refer to the \LaTeX3 documentation rather than +% simply \enquote{\LaTeX{}}. % \begin{macrocode} \cs_new:Npn \msg_see_documentation_text:n #1 - { \\ \\ See~the~#1~documentation~for~further~information. } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\msg_class_set:nn} -% Setting up a message class does two tasks. Any existing redirection -% is cleared, and the various message functions are created -% to simply use the code stored for the message. -% \begin{macrocode} -\cs_new_protected:Npn \msg_class_set:nn #1#2 { - \prop_clear_new:c { l_msg_redirect_ #1 _prop } - \cs_set_protected:cpn { msg_ #1 :nnxxxx } ##1##2##3##4##5##6 - { \msg_use:nnnnxxxx {#1} {#2} {##1} {##2} {##3} {##4} {##5} {##6} } - \cs_set_protected:cpx { msg_ #1 :nnxxx } ##1##2##3##4##5 - { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} { } } - \cs_set_protected:cpx { msg_ #1 :nnxx } ##1##2##3##4 - { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { } } - \cs_set_protected:cpx { msg_ #1 :nnx } ##1##2##3 - { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { } } - \cs_set_protected:cpx { msg_ #1 :nn } ##1##2 - { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} { } { } { } { } } + \\ \\ See~the~ + \str_if_eq:nnTF {#1} { LaTeX } { LaTeX3 } {#1} ~ + documentation~for~further~information. } % \end{macrocode} % \end{macro} -% -% \begin{macro}[pTF]{\msg_if_more_text:N, \msg_if_more_text:c} -% \begin{macro}[aux]{\msg_no_more_text:xxxx} -% A test to see if any more text is available, using a -% permanently-empty text function. -% ^^A It would be more efficient to not define the more-text when absent. +% +% \begin{macro}{\@@_class_new:nn} % \begin{macrocode} -\prg_new_conditional:Npnn \msg_if_more_text:N #1 { p , T , F , TF } - { - \cs_if_eq:NNTF #1 \msg_no_more_text:xxxx - { \prg_return_false: } - { \prg_return_true: } - } -\cs_new:Npn \msg_no_more_text:xxxx #1#2#3#4 { } -\cs_generate_variant:Nn \msg_if_more_text_p:N { c } -\cs_generate_variant:Nn \msg_if_more_text:NT { c } -\cs_generate_variant:Nn \msg_if_more_text:NF { c } -\cs_generate_variant:Nn \msg_if_more_text:NTF { c } +\group_begin: + \cs_set_protected:Npn \@@_class_new:nn #1#2 + { + \prop_new:c { l_@@_redirect_ #1 _prop } + \cs_new_protected:cpn { @@_ #1 _code:nnnnnn } ##1##2##3##4##5##6 {#2} + \cs_new_protected:cpn { msg_ #1 :nnnnnn } ##1##2##3##4##5##6 + { + \@@_use:nnnnnnn {#1} {##1} {##2} + { \tl_to_str:n {##3} } { \tl_to_str:n {##4} } + { \tl_to_str:n {##5} } { \tl_to_str:n {##6} } + } + \cs_new_protected:cpx { msg_ #1 :nnnnn } ##1##2##3##4##5 + { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} {##3} {##4} {##5} { } } + \cs_new_protected:cpx { msg_ #1 :nnnn } ##1##2##3##4 + { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} {##3} {##4} { } { } } + \cs_new_protected:cpx { msg_ #1 :nnn } ##1##2##3 + { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} {##3} { } { } { } } + \cs_new_protected:cpx { msg_ #1 :nn } ##1##2 + { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} { } { } { } { } } + \cs_new_protected:cpn { msg_ #1 :nnxxxx } ##1##2##3##4##5##6 + { + \use:x + { + \@@_use:nnnnnnn + { \exp_not:n {#1} } { \exp_not:n {##1} } { \exp_not:n {##2} } + {##3} {##4} {##5} {##6} + } + } + \cs_new_protected:cpx { msg_ #1 :nnxxx } ##1##2##3##4##5 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} { } } + \cs_new_protected:cpx { msg_ #1 :nnxx } ##1##2##3##4 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { } } + \cs_new_protected:cpx { msg_ #1 :nnx } ##1##2##3 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { } } + } % \end{macrocode} % \end{macro} -% \end{macro} % % \begin{macro} -% { -% \msg_fatal:nnxxxx , -% \msg_fatal:nnxxx , -% \msg_fatal:nnxx , -% \msg_fatal:nnx , -% \msg_fatal:nn -% } +% { +% \msg_fatal:nnnnnn , +% \msg_fatal:nnnnn , +% \msg_fatal:nnnn , +% \msg_fatal:nnn , +% \msg_fatal:nn , +% \msg_fatal:nnxxxx , +% \msg_fatal:nnxxx , +% \msg_fatal:nnxx , +% \msg_fatal:nnx +% } % For fatal errors, after the error message \TeX{} bails out. % \begin{macrocode} -\msg_class_set:nn { fatal } - { - \msg_interrupt:xxx - { \msg_fatal_text:n {#1} : ~ "#2" } - { - \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} - \msg_see_documentation_text:n {#1} - } - { \c_msg_fatal_text_tl } - \tex_end:D - } + \@@_class_new:nn { fatal } + { + \msg_interrupt:nnn + { \msg_fatal_text:n {#1} : ~ "#2" } + { + \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + { \c_msg_fatal_text_tl } + \tex_end:D + } % \end{macrocode} % \end{macro} % % \begin{macro} % { +% \msg_critical:nnnnnn , +% \msg_critical:nnnnn , +% \msg_critical:nnnn , +% \msg_critical:nnn , +% \msg_critical:nn , % \msg_critical:nnxxxx , % \msg_critical:nnxxx , % \msg_critical:nnxx , -% \msg_critical:nnx , -% \msg_critical:nn -% } +% \msg_critical:nnx +% } % Not quite so bad: just end the current file. % \begin{macrocode} -\msg_class_set:nn { critical } - { - \msg_interrupt:xxx - { \msg_critical_text:n {#1} : ~ "#2" } - { - \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} - \msg_see_documentation_text:n {#1} - } - { \c_msg_critical_text_tl } - \tex_endinput:D - } + \@@_class_new:nn { critical } + { + \msg_interrupt:nnn + { \msg_critical_text:n {#1} : ~ "#2" } + { + \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + { \c_msg_critical_text_tl } + \tex_endinput:D + } % \end{macrocode} % \end{macro} % % \begin{macro} % { +% \msg_error:nnnnnn , +% \msg_error:nnnnn , +% \msg_error:nnnn , +% \msg_error:nnn , +% \msg_error:nn , % \msg_error:nnxxxx , % \msg_error:nnxxx , % \msg_error:nnxx , -% \msg_error:nnx , -% \msg_error:nn +% \msg_error:nnx % } -% For an error, the interrupt routine is called, then any recovery code -% is tried. +% \begin{macro}[aux]{\@@_error:cnnnnn, \@@_no_more_text:nnnn} +% For an error, the interrupt routine is called. We check if there is +% a \enquote{more text} by comparing that control sequence with a +% permanently empty text. % \begin{macrocode} -\msg_class_set:nn { error } - { - \msg_if_more_text:cTF { \c_msg_more_text_prefix_tl #1 / #2 } - { - \msg_interrupt:xxx - { \msg_error_text:n {#1} : ~ "#2" } - { - \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} - \msg_see_documentation_text:n {#1} - } - { \use:c { \c_msg_more_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } - } - { - \msg_interrupt:xxx - { \msg_error_text:n {#1} : ~ "#2" } - { - \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} - \msg_see_documentation_text:n {#1} - } - { } - } - } + \@@_class_new:nn { error } + { + \@@_error:cnnnnn + { \c_@@_more_text_prefix_tl #1 / #2 } + {#3} {#4} {#5} {#6} + { + \msg_interrupt:nnn + { \msg_error_text:n {#1} : ~ "#2" } + { + \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + } + } + \cs_new_protected:Npn \@@_error:cnnnnn #1#2#3#4#5#6 + { + \cs_if_eq:cNTF {#1} \@@_no_more_text:nnnn + { #6 { } } + { #6 { \use:c {#1} {#2} {#3} {#4} {#5} } } + } + \cs_new:Npn \@@_no_more_text:nnnn #1#2#3#4 { } % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro} % { +% \msg_warning:nnnnnn , +% \msg_warning:nnnnn , +% \msg_warning:nnnn , +% \msg_warning:nnn , +% \msg_warning:nn , % \msg_warning:nnxxxx , % \msg_warning:nnxxx , % \msg_warning:nnxx , -% \msg_warning:nnx , -% \msg_warning:nn +% \msg_warning:nnx % } % Warnings are printed to the terminal. % \begin{macrocode} -\msg_class_set:nn { warning } - { - \msg_term:x - { - \msg_warning_text:n {#1} : ~ "#2" \\ \\ - \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} - } - } + \@@_class_new:nn { warning } + { + \msg_term:n + { + \msg_warning_text:n {#1} : ~ "#2" \\ \\ + \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + } + } % \end{macrocode} % \end{macro} % % \begin{macro} % { +% \msg_info:nnnnnn , +% \msg_info:nnnnn , +% \msg_info:nnnn , +% \msg_info:nnn , +% \msg_info:nn , % \msg_info:nnxxxx , % \msg_info:nnxxx , % \msg_info:nnxx , -% \msg_info:nnx , -% \msg_info:nn +% \msg_info:nnx % } % Information only goes into the log. % \begin{macrocode} -\msg_class_set:nn { info } - { - \msg_log:x - { - \msg_info_text:n {#1} : ~ "#2" \\ \\ - \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} - } - } + \@@_class_new:nn { info } + { + \msg_log:n + { + \msg_info_text:n {#1} : ~ "#2" \\ \\ + \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + } + } % \end{macrocode} % \end{macro} % % \begin{macro} % { +% \msg_log:nnnnnn , +% \msg_log:nnnnn , +% \msg_log:nnnn , +% \msg_log:nnn , +% \msg_log:nn , % \msg_log:nnxxxx , % \msg_log:nnxxx , % \msg_log:nnxx , -% \msg_log:nnx , -% \msg_log:nn +% \msg_log:nnx % } % \enquote{Log} data is very similar to information, but with no extras % added. % \begin{macrocode} -\msg_class_set:nn { log } - { - \msg_log:x - { \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } - } + \@@_class_new:nn { log } + { + \iow_wrap:nnnN + { \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } + { } { } \iow_log:n + } % \end{macrocode} % \end{macro} % % \begin{macro} % { +% \msg_none:nnnnnn , +% \msg_none:nnnnn , +% \msg_none:nnnn , +% \msg_none:nnn , +% \msg_none:nn , % \msg_none:nnxxxx , % \msg_none:nnxxx , % \msg_none:nnxx , -% \msg_none:nnx , -% \msg_none:nn +% \msg_none:nnx % } % The \texttt{none} message type is needed so that input can be gobbled. % \begin{macrocode} -\msg_class_set:nn { none } { } + \@@_class_new:nn { none } { } % \end{macrocode} % \end{macro} % -% \begin{variable}{\l_msg_class_tl, \l_msg_current_class_tl} +% End the group to eliminate \cs{@@_class_new:nn}. +% \begin{macrocode} +\group_end: +% \end{macrocode} +% +% \begin{macro}[aux]{\@@_class_chk_exist:nT} +% Checking that a message class exists. We build this from +% \cs{cs_if_free:cTF} rather than \cs{cs_if_exist:cTF} because that +% avoids reading the second argument earlier than necessary. +% \begin{macrocode} +\cs_new:Npn \@@_class_chk_exist:nT #1 + { + \cs_if_free:cTF { @@_ #1 _code:nnnnnn } + { \@@_kernel_error:nnx { kernel } { message-class-unknown } {#1} } + } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_@@_class_tl, \l_@@_current_class_tl} % Support variables needed for the redirection system. % \begin{macrocode} -\tl_new:N \l_msg_class_tl -\tl_new:N \l_msg_current_class_tl +\tl_new:N \l_@@_class_tl +\tl_new:N \l_@@_current_class_tl % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_msg_redirect_classes_prop, \l_msg_redirect_names_prop} -% For filtering messages, a list of all messages and of those which have -% to be modified is required. +% \begin{variable}{\l_@@_redirect_prop} +% For redirection of individually-named messages % \begin{macrocode} -\prop_new:N \l_msg_redirect_classes_prop -\prop_new:N \l_msg_redirect_names_prop +\prop_new:N \l_@@_redirect_prop % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_msg_redirect_prop} -% For redirection of individually-named messages +% \begin{variable}{\l_@@_hierarchy_seq} +% During redirection, split the message name into a sequence with +% items |{/module/submodule}|, |{/module}|, and |{}|. % \begin{macrocode} -\prop_new:N \l_msg_redirect_prop +\seq_new:N \l_@@_hierarchy_seq % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_msg_use_direct_bool} -% Used to force redirection when a name is given directly. +% \begin{variable}{\l_@@_class_loop_seq} +% Classes encountered when following redirections to check for loops. % \begin{macrocode} -\bool_new:N \l_msg_use_direct_bool +\seq_new:N \l_@@_class_loop_seq % \end{macrocode} % \end{variable} % -% \begin{macro}[int]{\msg_use:nnnnxxxx} -% \begin{macro}[aux]{\msg_use_code:, \msg_use_or_change_class:} -% \begin{macro}[aux]{\msg_use_aux_i:nn, \msg_use_aux_ii:nn} -% \begin{macro}[aux]{\msg_use_aux_iii:w} -% \begin{macro}[aux]{\msg_use_aux_iv:w} -% \begin{macro}[aux]{\msg_use_aux_v:} -% Actually using a message is a multi-step process. First, some safety -% checks on the message and class requested. The code and arguments are -% then stored to avoid passing them around. +% \begin{macro}[int]{\@@_use:nnnnnnn} +% \begin{macro}[aux] +% { +% \@@_use_redirect_name:n , \@@_use_hierarchy:nwwN , +% \@@_use_redirect_module:n, \@@_use_code: +% } +% Actually using a message is a multi-step process. First, some +% safety checks on the message and class requested. The code and +% arguments are then stored to avoid passing them around. The +% assignment to \cs{@@_use_code:} is similar to \cs{tl_set:Nn}. +% The message is eventually produced with whatever \cs{l_@@_class_tl} +% is when \cs{@@_use_code:} is called. % \begin{macrocode} -\cs_new_protected:Npn \msg_use:nnnnxxxx #1#2#3#4#5#6#7#8 +\cs_new_protected:Npn \@@_use:nnnnnnn #1#2#3#4#5#6#7 { - \msg_if_exist:nnTF {#3} {#4} + \msg_if_exist:nnTF {#2} {#3} { - \cs_if_exist:cTF { msg_ #1 :nnxxxx } + \@@_class_chk_exist:nT {#1} { - \tl_set:Nn \l_msg_current_class_tl {#1} - \cs_set_protected_nopar:Npx \msg_use_code: { \exp_not:n {#2} } - \cs_set_protected_nopar:Npn \msg_use_or_change_class: + \tl_set:Nn \l_@@_current_class_tl {#1} + \cs_set_protected_nopar:Npx \@@_use_code: { - \tl_if_eq:NNTF \l_msg_current_class_tl \l_msg_class_tl - { \msg_use_code: } + \exp_not:n { - \use:c { msg_ \l_msg_class_tl :nnxxxx } - {#3} {#4} {#5} {#6} {#7} {#8} + \use:c { @@_ \l_@@_class_tl _code:nnnnnn } + {#2} {#3} {#4} {#5} {#6} {#7} } } - \bool_if:NTF \l_msg_use_direct_bool - { - \bool_set_false:N \l_msg_use_direct_bool - \msg_use_code: - } - { \msg_use_aux_i:nn {#3} {#4} } + \@@_use_redirect_name:n { #2 / #3 } } - { \msg_kernel_error:nnx { msg } { message-class-unknown } {#1} } } - { \msg_kernel_error:nnxx { msg } { message-unknown } {#3} {#4} } + { \@@_kernel_error:nnxx { kernel } { message-unknown } {#2} {#3} } } -\cs_new_protected_nopar:Npn \msg_use_code: { } -\cs_new_protected_nopar:Npn \msg_use_or_change_class: { } +\cs_new_protected_nopar:Npn \@@_use_code: { } % \end{macrocode} -% The first check is for a individual message redirection. If this applies -% then no further redirection is attempted. +% The first check is for a individual message redirection. If this +% applies then no further redirection is attempted. Otherwise, split +% the message name into \texttt{module/submodule/message} (with an +% arbitrary number of slashes), and store |{/module/submodule}|, +% |{/module}| and |{}| into \cs{l_@@_hierarchy_seq}. We will then +% map through this sequence, applying the most specific redirection. % \begin{macrocode} -\cs_new_protected:Npn \msg_use_aux_i:nn #1#2 +\cs_new_protected:Npn \@@_use_redirect_name:n #1 { - \prop_get:NnNTF \l_msg_redirect_prop { #1 / #2 } \l_msg_class_tl + \prop_get:NnNTF \l_@@_redirect_prop { / #1 } \l_@@_class_tl + { \@@_use_code: } { - \bool_set_true:N \l_msg_use_direct_bool - \msg_use_or_change_class: + \seq_clear:N \l_@@_hierarchy_seq + \@@_use_hierarchy:nwwN { } + #1 \q_mark \@@_use_hierarchy:nwwN + / \q_mark \use_none_delimit_by_q_stop:w + \q_stop + \@@_use_redirect_module:n { } } - { \msg_use_aux_ii:nn {#1} {#2} } } -% \end{macrocode} -% Next check if there is a redirection by module or by submodule. -% \begin{macrocode} -\cs_new_protected:Npn \msg_use_aux_ii:nn #1#2 +\cs_new_protected:Npn \@@_use_hierarchy:nwwN #1#2 / #3 \q_mark #4 { - \prop_get:coNTF { l_msg_redirect_ \l_msg_current_class_tl _ prop } - { \msg_use_aux_iii:w #1 / #2 / \q_stop } \l_msg_class_tl - { \msg_use_or_change_class: } - { - \prop_get:coNTF { l_msg_redirect_ \l_msg_current_class_tl _ prop } - { \msg_use_aux_iv:w #1 / #2 \q_stop } \l_msg_class_tl - { \msg_use_or_change_class: } - { \msg_use_aux_v: } - } + \seq_put_left:Nn \l_@@_hierarchy_seq {#1} + #4 { #1 / #2 } #3 \q_mark #4 } -\cs_new:Npn \msg_use_aux_iii:w #1 / #2 / #3 \q_stop { #1 / #2 } -\cs_new:Npn \msg_use_aux_iv:w #1 / #2 \q_stop { #1 } % \end{macrocode} -% Finally test for redirection of an entire class. +% At this point, the items of \cs{l_@@_hierarchy_seq} are the +% various levels at which we should look for a redirection. +% Redirections which are less specific than the argument of +% \cs{@@_use_redirect_module:n} are not attempted. This argument is +% empty for a class redirection, \texttt{/module} for a module +% redirection, \emph{etc.} Loop through the sequence to find the most +% specific redirection, with module |##1|. The loop is interrupted +% after testing for a redirection for |##1| equal to the argument |#1| +% (least specific redirection allowed). When a redirection is found, +% break the mapping, then if the redirection targets the same class, +% output the code with that class, and otherwise set the target as the +% new current class, and search for further redirections. Those +% redirections should be at least as specific as |##1|. % \begin{macrocode} -\cs_new_protected:Npn \msg_use_aux_v: +\cs_new_protected:Npn \@@_use_redirect_module:n #1 { - \prop_get:cnNF { l_msg_redirect_ \l_msg_current_class_tl _ prop } - { * } \l_msg_class_tl - { \tl_set_eq:NN \l_msg_class_tl \l_msg_current_class_tl } - \msg_use_or_change_class: + \seq_map_inline:Nn \l_@@_hierarchy_seq + { + \prop_get:cnNTF { l_@@_redirect_ \l_@@_current_class_tl _prop } + {##1} \l_@@_class_tl + { + \seq_map_break:n + { + \tl_if_eq:NNTF \l_@@_current_class_tl \l_@@_class_tl + { \@@_use_code: } + { + \tl_set_eq:NN \l_@@_current_class_tl \l_@@_class_tl + \@@_use_redirect_module:n {##1} + } + } + } + { + \str_if_eq:nnT {##1} {#1} + { + \tl_set_eq:NN \l_@@_class_tl \l_@@_current_class_tl + \seq_map_break:n { \@@_use_code: } + } + } + } } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % -% \begin{macro}{\msg_redirect_class:nn} -% \begin{macro}[aux]{\msg_redirect_class_aux:nnn, \msg_redirect_class_aux:nVn} -% Converts class one into class two. +% \begin{macro}{\msg_redirect_name:nnn} +% Named message will always use the given class even if that class is +% redirected further. An empty target class cancels any existing +% redirection for that message. % \begin{macrocode} -\cs_new_protected:Npn \msg_redirect_class:nn #1#2 - { - \cs_if_exist:cTF { msg_ #1 :nnxxxx } - { - \cs_if_exist:cTF { msg_ #2 :nnxxxx } - { - \tl_set:Nn \l_msg_current_class_tl {#1} - \msg_redirect_class_aux:nnn {#1} {#2} {#2} - } - { \msg_kernel_error:nnx { msg } { message-class-unknown } {#2} } - } - { \msg_kernel_error:nnx { msg } { message-class-unknown } {#1} } - } -\cs_new_protected:Npn \msg_redirect_class_aux:nnn #1#2#3 +\cs_new_protected:Npn \msg_redirect_name:nnn #1#2#3 { - \prop_get:cnNTF { l_msg_redirect_ #2 _prop } { * } \l_msg_class_tl + \tl_if_empty:nTF {#3} + { \prop_remove:Nn \l_@@_redirect_prop { / #1 / #2 } } { - \tl_if_eq:NNTF \l_msg_class_tl \l_msg_current_class_tl - { \msg_kernel_error:nnxx { msg } { message-loop } {#1} {#3} } - { \msg_redirect_class_aux:nVn {#1} \l_msg_class_tl {#3} } + \@@_class_chk_exist:nT {#3} + { \prop_put:Nnn \l_@@_redirect_prop { / #1 / #2 } {#3} } } - { \prop_put:cnn { l_msg_redirect_ #1 _prop } { * } {#3} } } -\cs_generate_variant:Nn \msg_redirect_class_aux:nnn { nV } % \end{macrocode} % \end{macro} -% \end{macro} % -% \begin{macro}{\msg_redirect_module:nnn} -% \begin{macro}[aux] -% {\msg_redirect_module_aux:nnnn, \msg_redirect_module_aux:nnVn} -% For when all messages of a class should be altered for a given module. +% \begin{macro}{\msg_redirect_class:nn, \msg_redirect_module:nnn} +% \begin{macro}[aux]{\@@_redirect:nnn, \@@_redirect_loop_chk:nnn} +% \begin{macro}[aux]{\@@_redirect_loop_list:n} +% If the target class is empty, eliminate the corresponding +% redirection. Otherwise, add the redirection. We must then check +% for a loop: as an initialization, we start by storing the initial +% class in \cs{l_@@_current_class_tl}. % \begin{macrocode} -\cs_new_protected:Npn \msg_redirect_module:nnn #1#2#3 +\cs_new_protected_nopar:Npn \msg_redirect_class:nn + { \@@_redirect:nnn { } } +\cs_new_protected:Npn \msg_redirect_module:nnn #1 + { \@@_redirect:nnn { / #1 } } +\cs_new_protected:Npn \@@_redirect:nnn #1#2#3 { - \cs_if_exist:cTF { msg_ #2 :nnxxxx } + \@@_class_chk_exist:nT {#2} { - \cs_if_exist:cTF { msg_ #3 :nnxxxx } + \tl_if_empty:nTF {#3} + { \prop_remove:cn { l_@@_redirect_ #2 _prop } {#1} } { - \tl_set:Nn \l_msg_current_class_tl {#1} - \msg_redirect_module_aux:nnnn {#1} {#2} {#3} {#3} + \@@_class_chk_exist:nT {#3} + { + \prop_put:cnn { l_@@_redirect_ #2 _prop } {#1} {#3} + \tl_set:Nn \l_@@_current_class_tl {#2} + \seq_clear:N \l_@@_class_loop_seq + \@@_redirect_loop_chk:nnn {#2} {#3} {#1} + } } - { \msg_kernel_error:nnx { msg } { message-class-unknown } {#3} } } - { \msg_kernel_error:nnx { msg } { message-class-unknown } {#2} } } -\cs_new_protected:Npn \msg_redirect_module_aux:nnnn #1#2#3#4 +% \end{macrocode} +% Since multiple redirections can only happen with increasing +% specificity, a loop requires that all steps are of the same +% specificity. The new redirection can thus only create a loop with +% other redirections for the exact same module, |#1|, and not +% submodules. After some initialization above, follow redirections +% with \cs{l_@@_class_tl}, and keep track in +% \cs{l_@@_class_loop_seq} of the various classes encountered. A +% redirection from a class to itself, or the absence of redirection +% both mean that there is no loop. A redirection to the initial class +% marks a loop. To break it, we must decide which redirection to +% cancel. The user most likely wants the newly added redirection to +% hold with no further redirection. We thus remove the redirection +% starting from |#2|, target of the new redirection. Note that no +% message is emitted by any of the underlying functions: otherwise we +% may get an infinite loop because of a message from the message +% system itself. +% \begin{macrocode} +\cs_new_protected:Npn \@@_redirect_loop_chk:nnn #1#2#3 { - \prop_get:cnNTF { l_msg_redirect_ #3 _prop } {#1} \l_msg_class_tl + \seq_put_right:Nn \l_@@_class_loop_seq {#1} + \prop_get:cnNT { l_@@_redirect_ #1 _prop } {#3} \l_@@_class_tl { - \tl_if_eq:NNTF \l_msg_class_tl \l_msg_current_class_tl - { \msg_kernel_error:nnxx { msg } { message-loop } {#2} {#4} } - { \msg_redirect_moduel_aux:nVn {#1} {#2} \l_msg_class_tl {#4} } + \str_if_eq_x:nnF { \l_@@_class_tl } {#1} + { + \tl_if_eq:NNTF \l_@@_class_tl \l_@@_current_class_tl + { + \prop_put:cnn { l_@@_redirect_ #2 _prop } {#3} {#2} + \@@_kernel_warning:nnxxxx { kernel } { message-redirect-loop } + { \seq_item:Nn \l_@@_class_loop_seq { \c_one } } + { \seq_item:Nn \l_@@_class_loop_seq { \c_two } } + {#3} + { + \seq_map_function:NN \l_@@_class_loop_seq + \@@_redirect_loop_list:n + { \seq_item:Nn \l_@@_class_loop_seq { \c_one } } + } + } + { \@@_redirect_loop_chk:onn \l_@@_class_tl {#2} {#3} } + } } - { \prop_put:cnn { l_msg_redirect_ #2 _prop } {#1} {#4} } } -\cs_generate_variant:Nn \msg_redirect_module_aux:nnnn { nnV } +\cs_generate_variant:Nn \@@_redirect_loop_chk:nnn { o } +\cs_new:Npn \@@_redirect_loop_list:n #1 { {#1} ~ => ~ } % \end{macrocode} % \end{macro} % \end{macro} -% -% \begin{macro}{\msg_redirect_name:nnn} -% Named message will always use the given class even if that class is -% redirected further. -% \begin{macrocode} -\cs_new_protected:Npn \msg_redirect_name:nnn #1#2#3 - { - \cs_if_exist:cTF { msg_ #3 :nnxxxx } - { \prop_put:Nnn \l_msg_redirect_prop { #1 / #2 } {#3} } - { \msg_kernel_error:nnx { msg } { message-class-unknown } {#3} } - } -% \end{macrocode} % \end{macro} % % \subsection{Kernel-specific functions} % -% \begin{macro}{\msg_kernel_new:nnnn} -% \begin{macro}{\msg_kernel_new:nnn} -% \begin{macro}{\msg_kernel_set:nnnn} -% \begin{macro}{\msg_kernel_set:nnn} +% \begin{macro}{\@@_kernel_new:nnnn, \@@_kernel_new:nnn} +% \begin{macro}{\@@_kernel_set:nnnn, \@@_kernel_set:nnn} % The kernel needs some messages of its own. These are created using % pre-built functions. Two functions are provided: one more general % and one which only has the short text part. % \begin{macrocode} -\cs_new_protected:Npn \msg_kernel_new:nnnn #1#2 +\cs_new_protected:Npn \@@_kernel_new:nnnn #1#2 { \msg_new:nnnn { LaTeX } { #1 / #2 } } -\cs_new_protected:Npn \msg_kernel_new:nnn #1#2 +\cs_new_protected:Npn \@@_kernel_new:nnn #1#2 { \msg_new:nnn { LaTeX } { #1 / #2 } } -\cs_new_protected:Npn \msg_kernel_set:nnnn #1#2 +\cs_new_protected:Npn \@@_kernel_set:nnnn #1#2 { \msg_set:nnnn { LaTeX } { #1 / #2 } } -\cs_new_protected:Npn \msg_kernel_set:nnn #1#2 +\cs_new_protected:Npn \@@_kernel_set:nnn #1#2 { \msg_set:nnn { LaTeX } { #1 / #2 } } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} % -% \begin{macro}{\msg_kernel_fatal:nnxxxx} -% \begin{macro}{\msg_kernel_fatal:nnxxx} -% \begin{macro}{\msg_kernel_fatal:nnxx} -% \begin{macro}{\msg_kernel_fatal:nnx} -% \begin{macro}{\msg_kernel_fatal:nn} -% Fatal kernel errors cannot be re-defined. +% \begin{macro}[aux]{\@@_kernel_class_new:nn} +% \begin{macro}[aux]{\@@_kernel_class_new_aux:nn} +% All the functions for kernel messages come in variants ranging +% from~$0$ to~$4$ arguments. Those with less than~$4$ arguments are +% defined in terms of the $4$-argument variant, in a way very similar +% to \cs{msg_class_set:nn}. This auxiliary is destroyed at the end of +% the group. % \begin{macrocode} -\cs_new_protected:Npn \msg_kernel_fatal:nnxxxx #1#2#3#4#5#6 - { - \msg_interrupt:xxx - { \msg_fatal_text:n { LaTeX } : ~ "#1 / #2" } - { - \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } - {#3} {#4} {#5} {#6} - \msg_see_documentation_text:n { LaTeX3 } - } - { \c_msg_fatal_text_tl } - \tex_end:D - } -\cs_new_protected:Npn \msg_kernel_fatal:nnxxx #1#2#3#4#5 - {\msg_kernel_fatal:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } -\cs_new_protected:Npn \msg_kernel_fatal:nnxx #1#2#3#4 - { \msg_kernel_fatal:nnxxxx {#1} {#2} {#3} {#4} { } { } } -\cs_new_protected:Npn \msg_kernel_fatal:nnx #1#2#3 - { \msg_kernel_fatal:nnxxxx {#1} {#2} {#3} { } { } { } } -\cs_new_protected:Npn \msg_kernel_fatal:nn #1#2 - { \msg_kernel_fatal:nnxxxx {#1} {#2} { } { } { } { } } +\group_begin: + \cs_set_protected:Npn \@@_kernel_class_new:nn #1 + { \@@_kernel_class_new_aux:nn { kernel_ #1 } } + \cs_set_protected:Npn \@@_kernel_class_new_aux:nn #1#2 + { + \cs_new_protected:cpn { @@_ #1 :nnnnnn } ##1##2 {#2} + \cs_new_protected:cpx { @@_ #1 :nnnnn } ##1##2##3##4##5 + { \exp_not:c { @@_ #1 :nnnnnn } {##1} {##2} {##3} {##4} {##5} { } } + \cs_new_protected:cpx { @@_ #1 :nnnn } ##1##2##3##4 + { \exp_not:c { @@_ #1 :nnnnnn } {##1} {##2} {##3} {##4} { } { } } + \cs_new_protected:cpx { @@_ #1 :nnn } ##1##2##3 + { \exp_not:c { @@_ #1 :nnnnnn } {##1} {##2} {##3} { } { } { } } + \cs_new_protected:cpx { @@_ #1 :nn } ##1##2 + { \exp_not:c { @@_ #1 :nnnnnn } {##1} {##2} { } { } { } { } } + \cs_new_protected:cpx { @@_ #1 :nnxxxx } ##1##2##3##4##5##6 + { + \use:x + { + \exp_not:c { @@_ #1 :nnnnnn } + { \exp_not:N \exp_not:n {##1} } + { \exp_not:N \exp_not:n {##2} } + {##3} {##4} {##5} {##6} + } + } + \cs_new_protected:cpx { @@_ #1 :nnxxx } ##1##2##3##4##5 + { \exp_not:c { @@_ #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} { } } + \cs_new_protected:cpx { @@_ #1 :nnxx } ##1##2##3##4 + { \exp_not:c { @@_ #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { } } + \cs_new_protected:cpx { @@_ #1 :nnx } ##1##2##3 + { \exp_not:c { @@_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { } } + } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % -% \begin{macro}{\msg_kernel_error:nnxxxx} -% \begin{macro}{\msg_kernel_error:nnxxx} -% \begin{macro}{\msg_kernel_error:nnxx} -% \begin{macro}{\msg_kernel_error:nnx} -% \begin{macro}{\msg_kernel_error:nn} -% Neither can kernel errors. +% \begin{macro} +% { +% \@@_kernel_fatal:nnnnnn , +% \@@_kernel_fatal:nnnnn , +% \@@_kernel_fatal:nnnn , +% \@@_kernel_fatal:nnn , +% \@@_kernel_fatal:nn , +% \@@_kernel_fatal:nnxxxx , +% \@@_kernel_fatal:nnxxx , +% \@@_kernel_fatal:nnxx , +% \@@_kernel_fatal:nnx , +% \@@_kernel_error:nnnnnn , +% \@@_kernel_error:nnnnn , +% \@@_kernel_error:nnnn , +% \@@_kernel_error:nnn , +% \@@_kernel_error:nn , +% \@@_kernel_error:nnxxxx , +% \@@_kernel_error:nnxxx , +% \@@_kernel_error:nnxx , +% \@@_kernel_error:nnx +% } +% Neither fatal kernel errors nor kernel errors can be redirected. We +% directly use the code for (non-kernel) fatal errors and errors, +% adding the \enquote{\LaTeX{}} module name. Three functions are +% already defined by \pkg{l3basics}; we need to undefine them to avoid +% errors. % \begin{macrocode} -\cs_new_protected:Npn \msg_kernel_error:nnxxxx #1#2#3#4#5#6 - { - \msg_if_more_text:cTF { \c_msg_more_text_prefix_tl LaTeX / #1 / #2 } - { - \msg_interrupt:xxx - { \msg_error_text:n { LaTeX } : ~ " #1 / #2 " } - { - \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } - {#3} {#4} {#5} {#6} - \msg_see_documentation_text:n { LaTeX3 } - } - { - \use:c { \c_msg_more_text_prefix_tl LaTeX / #1 / #2 } - {#3} {#4} {#5} {#6} - } - } - { - \msg_interrupt:xxx - { \msg_error_text:n { LaTeX } : ~ " #1 / #2 " } - { - \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } - {#3} {#4} {#5} {#6} - \msg_see_documentation_text:n { LaTeX3 } - } - { } - } - } -\cs_new_protected:Npn \msg_kernel_error:nnxxx #1#2#3#4#5 - {\msg_kernel_error:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } -\cs_gset_protected:Npn \msg_kernel_error:nnxx #1#2#3#4 - { \msg_kernel_error:nnxxxx {#1} {#2} {#3} {#4} { } { } } -\cs_gset_protected:Npn \msg_kernel_error:nnx #1#2#3 - { \msg_kernel_error:nnxxxx {#1} {#2} {#3} { } { } { } } -\cs_gset_protected:Npn \msg_kernel_error:nn #1#2 - { \msg_kernel_error:nnxxxx {#1} {#2} { } { } { } { } } + \@@_kernel_class_new:nn { fatal } + { \@@_fatal_code:nnnnnn { LaTeX } { #1 / #2 } } + \cs_undefine:N \@@_kernel_error:nnxx + \cs_undefine:N \@@_kernel_error:nnx + \cs_undefine:N \@@_kernel_error:nn + \@@_kernel_class_new:nn { error } + { \@@_error_code:nnnnnn { LaTeX } { #1 / #2 } } % \end{macrocode} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % -% \begin{macro}{\msg_kernel_warning:nnxxxx} -% \begin{macro}{\msg_kernel_warning:nnxxx} -% \begin{macro}{\msg_kernel_warning:nnxx} -% \begin{macro}{\msg_kernel_warning:nnx} -% \begin{macro}{\msg_kernel_warning:nn} -% \begin{macro}{\msg_kernel_info:nnxxxx} -% \begin{macro}{\msg_kernel_info:nnxxx} -% \begin{macro}{\msg_kernel_info:nnxx} -% \begin{macro}{\msg_kernel_info:nnx} -% \begin{macro}{\msg_kernel_info:nn} -% Kernel messages which can be redirected. +% \begin{macro} +% { +% \@@_kernel_warning:nnnnnn , +% \@@_kernel_warning:nnnnn , +% \@@_kernel_warning:nnnn , +% \@@_kernel_warning:nnn , +% \@@_kernel_warning:nn , +% \@@_kernel_warning:nnxxxx , +% \@@_kernel_warning:nnxxx , +% \@@_kernel_warning:nnxx , +% \@@_kernel_warning:nnx , +% \@@_kernel_info:nnnnnn , +% \@@_kernel_info:nnnnn , +% \@@_kernel_info:nnnn , +% \@@_kernel_info:nnn , +% \@@_kernel_info:nn , +% \@@_kernel_info:nnxxxx , +% \@@_kernel_info:nnxxx , +% \@@_kernel_info:nnxx , +% \@@_kernel_info:nnx +% } +% Kernel messages which can be redirected simply use the machinery for +% normal messages, with the module name \enquote{\LaTeX{}}. % \begin{macrocode} -\prop_new:N \l_msg_redirect_kernel_warning_prop -\cs_new_protected:Npn \msg_kernel_warning:nnxxxx #1#2#3#4#5#6 - { - \msg_use:nnnnxxxx { warning } - { - \msg_term:x - { - \msg_warning_text:n { LaTeX } : ~ " #1 / #2 " \\ \\ - \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } - {#3} {#4} {#5} {#6} - } - } - { LaTeX } { #1 / #2 } {#3} {#4} {#5} {#6} - } -\cs_new_protected:Npn \msg_kernel_warning:nnxxx #1#2#3#4#5 - { \msg_kernel_warning:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } -\cs_new_protected:Npn \msg_kernel_warning:nnxx #1#2#3#4 - { \msg_kernel_warning:nnxxxx {#1} {#2} {#3} {#4} { } { } } -\cs_new_protected:Npn \msg_kernel_warning:nnx #1#2#3 - { \msg_kernel_warning:nnxxxx {#1} {#2} {#3} { } { } { } } -\cs_new_protected:Npn \msg_kernel_warning:nn #1#2 - { \msg_kernel_warning:nnxxxx {#1} {#2} { } { } { } { } } -\prop_new:N \l_msg_redirect_kernel_info_prop -\cs_new_protected:Npn \msg_kernel_info:nnxxxx #1#2#3#4#5#6 - { - \msg_use:nnnnxxxx { info } - { - \msg_log:x - { - \msg_info_text:n { LaTeX } : ~ " #1 / #2 " \\ \\ - \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } - {#3} {#4} {#5} {#6} - } - } - { LaTeX } { #1 / #2 } {#3} {#4} {#5} {#6} - } -\cs_new_protected:Npn \msg_kernel_info:nnxxx #1#2#3#4#5 - { \msg_kernel_info:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } -\cs_new_protected:Npn \msg_kernel_info:nnxx #1#2#3#4 - { \msg_kernel_info:nnxxxx {#1} {#2} {#3} {#4} { } { } } -\cs_new_protected:Npn \msg_kernel_info:nnx #1#2#3 - { \msg_kernel_info:nnxxxx {#1} {#2} {#3} { } { } { } } -\cs_new_protected:Npn \msg_kernel_info:nn #1#2 - { \msg_kernel_info:nnxxxx {#1} {#2} { } { } { } { } } + \@@_kernel_class_new:nn { warning } + { \msg_warning:nnxxxx { LaTeX } { #1 / #2 } } + \@@_kernel_class_new:nn { info } + { \msg_info:nnxxxx { LaTeX } { #1 / #2 } } % \end{macrocode} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} +% +% End the group to eliminate \cs{@@_kernel_class_new:nn}. +% \begin{macrocode} +\group_end: +% \end{macrocode} % % Error messages needed to actually implement the message system % itself. % \begin{macrocode} -\msg_kernel_new:nnnn { msg } { message-already-defined } +\@@_kernel_new:nnnn { kernel } { message-already-defined } { Message~'#2'~for~module~'#1'~already~defined. } { \c_msg_coding_error_text_tl @@ -1657,41 +1735,45 @@ by~the~module~'#1':~this~message~already~exists. \c_msg_return_text_tl } -\msg_kernel_new:nnnn { msg } { message-unknown } +\@@_kernel_new:nnnn { kernel } { message-unknown } { Unknown~message~'#2'~for~module~'#1'. } { \c_msg_coding_error_text_tl LaTeX~was~asked~to~display~a~message~called~'#2'\\ - by~the~module~'#1'~module:~this~message~does~not~exist. + by~the~module~'#1':~this~message~does~not~exist. \c_msg_return_text_tl } -\msg_kernel_new:nnnn { msg } { message-class-unknown } +\@@_kernel_new:nnnn { kernel } { message-class-unknown } { Unknown~message~class~'#1'. } { LaTeX~has~been~asked~to~redirect~messages~to~a~class~'#1':\\ this~was~never~defined. \c_msg_return_text_tl } -\msg_kernel_new:nnnn { msg } { redirect-loop } - { Message~redirection~loop~for~message~class~'#1'. } +\@@_kernel_new:nnnn { kernel } { message-redirect-loop } + { + Message~redirection~loop~caused~by~ {#1} ~=>~ {#2} + \tl_if_empty:nF {#3} { ~for~module~' \use_none:n #3 ' } . + } { - LaTeX~has~been~asked~to~redirect~messages~in~an~infinite~loop.\\ - The~original~message~here~has~been~lost. - \c_msg_return_text_tl + Adding~the~message~redirection~ {#1} ~=>~ {#2} + \tl_if_empty:nF {#3} { ~for~the~module~' \use_none:n #3 ' } ~ + created~an~infinite~loop\\\\ + \iow_indent:n { #4 \\\\ } } % \end{macrocode} % % Messages for earlier kernel modules. % \begin{macrocode} -\msg_kernel_new:nnnn { kernel } { bad-number-of-arguments } +\@@_kernel_new:nnnn { kernel } { bad-number-of-arguments } { Function~'#1'~cannot~be~defined~with~#2~arguments. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~define~a~function~'#1'~with~ - #2~arguments. \\ + #2~arguments.~ TeX~allows~between~0~and~9~arguments~for~a~single~function. } -\msg_kernel_new:nnnn { kernel } { command-already-defined } +\@@_kernel_new:nnnn { kernel } { command-already-defined } { Control~sequence~#1~already~defined. } { \c_msg_coding_error_text_tl @@ -1700,102 +1782,123 @@ The~current~meaning~is:\\ \ \ #2 } -\msg_kernel_new:nnnn { kernel } { command-not-defined } +\@@_kernel_new:nnnn { kernel } { command-not-defined } { Control~sequence~#1~undefined. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~use~a~command~#1,~but~this~has~not~ been~defined~yet. } -\msg_kernel_new:nnnn { kernel } { out-of-registers } +\@@_kernel_new:nnnn { kernel } { empty-search-pattern } + { Empty~search~pattern. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~replace~an~empty~pattern~by~'#1':~that~ + would~lead~to~an~infinite~loop! + } +\@@_kernel_new:nnnn { kernel } { out-of-registers } { No~room~for~a~new~#1. } { TeX~only~supports~\int_use:N \c_max_register_int \ of~each~type.~All~the~#1~registers~have~been~used.~ This~run~will~be~aborted~now. } -\msg_kernel_new:nnnn { kernel } { variable-not-defined } - { Variable~#1~undefined. } +\@@_kernel_new:nnnn { kernel } { missing-colon } + { Function~'#1'~contains~no~':'. } { \c_msg_coding_error_text_tl - LaTeX~has~been~asked~to~show~a~variable~#1,~but~this~has~not~ - been~defined~yet. + Code-level~functions~must~contain~':'~to~separate~the~ + argument~specification~from~the~function~name.~This~is~ + needed~when~defining~conditionals~or~when~building~a~ + parameter~text~from~the~number~of~arguments~of~the~function. } -\msg_kernel_new:nnnn { seq } { empty-sequence } - { Empty~sequence~#1. } +\@@_kernel_new:nnnn { kernel } { protected-predicate } + { Predicate~'#1'~must~be~expandable. } { \c_msg_coding_error_text_tl - LaTeX~has~been~asked~to~recover~an~entry~from~a~sequence~that~ - has~no~content:~that~cannot~happen! + LaTeX~has~been~asked~to~define~'#1'~as~a~protected~predicate.~ + Only~expandable~tests~can~have~a~predicate~version. } -\msg_kernel_new:nnnn { tl } { empty-search-pattern } - { Empty~search~pattern. } +\@@_kernel_new:nnnn { kernel } { conditional-form-unknown } + { Conditional~form~'#1'~for~function~'#2'~unknown. } { \c_msg_coding_error_text_tl - LaTeX~has~been~asked~to~replace~an~empty~pattern~by~'#1':~that~% - would~lead~to~an~infinite~loop! + LaTeX~has~been~asked~to~define~the~conditional~form~'#1'~of~ + the~function~'#2',~but~only~'TF',~'T',~'F',~and~'p'~forms~exist. } -\msg_kernel_new:nnnn { scan } { already-defined } +\@@_kernel_new:nnnn { kernel } { scanmark-already-defined } { Scan~mark~#1~already~defined. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~create~a~new~scan~mark~'#1'~ but~this~name~has~already~been~used~for~a~scan~mark. } +\@@_kernel_new:nnnn { kernel } { variable-not-defined } + { Variable~#1~undefined. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~show~a~variable~#1,~but~this~has~not~ + been~defined~yet. + } +\@@_kernel_new:nnnn { kernel } { variant-too-long } + { Variant~form~'#1'~longer~than~base~signature~of~'#2'. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~create~a~variant~of~the~function~'#2'~ + with~a~signature~starting~with~'#1',~but~that~is~longer~than~ + the~signature~(part~after~the~colon)~of~'#2'. + } % \end{macrocode} % % Some errors only appear in expandable settings, % hence don't need a \enquote{more-text} argument. % \begin{macrocode} -\msg_kernel_new:nnn { seq } { misused } - { A~sequence~was~misused. } -\msg_kernel_new:nnn { kernel } { bad-var } +\@@_kernel_new:nnn { kernel } { bad-variable } { Erroneous~variable~#1 used! } -\msg_kernel_new:nnn { prg } { zero-step } - { Zero~step~size~for~stepwise~function~#1. } -\msg_kernel_new:nnn { prg } { replicate-neg } +\@@_kernel_new:nnn { kernel } { misused-sequence } + { A~sequence~was~misused. } +\@@_kernel_new:nnn { kernel } { negative-replication } { Negative~argument~for~\prg_replicate:nn. } -\msg_kernel_new:nnn { kernel } { unknown-comparison } +\@@_kernel_new:nnn { kernel } { unknown-comparison } { Relation~symbol~'#1'~unknown:~use~=,~<,~>,~==,~!=,~<=,~>=. } +\@@_kernel_new:nnn { kernel } { zero-step } + { Zero~step~size~for~step~function~#1. } % \end{macrocode} % % Messages used by the \enquote{\texttt{show}} functions. % \begin{macrocode} -\msg_kernel_new:nnn { seq } { show } +\@@_kernel_new:nnn { kernel } { show-clist } { - The~sequence~\token_to_str:N #1~ - \seq_if_empty:NTF #1 + The~comma~list~ + \str_if_eq:nnF {#1} { \l__clist_internal_clist } { \token_to_str:N #1~} + \clist_if_empty:NTF #1 { is~empty } { contains~the~items~(without~outer~braces): } } -\msg_kernel_new:nnn { prop } { show } +\@@_kernel_new:nnn { kernel } { show-prop } { The~property~list~\token_to_str:N #1~ \prop_if_empty:NTF #1 { is~empty } { contains~the~pairs~(without~outer~braces): } } -\msg_kernel_new:nnn { clist } { show } +\@@_kernel_new:nnn { kernel } { show-seq } { - The~comma~list~ - \str_if_eq:nnF {#1} { \l_clist_internal_clist } { \token_to_str:N #1~} - \clist_if_empty:NTF #1 + The~sequence~\token_to_str:N #1~ + \seq_if_empty:NTF #1 { is~empty } { contains~the~items~(without~outer~braces): } } -\msg_kernel_new:nnn { ior } { show-no-stream } - { No~input~streams~are~open } -\msg_kernel_new:nnn { ior } { show-open-streams } - { The~following~input~streams~are~in~use: } -\msg_kernel_new:nnn { iow } { show-no-stream } - { No~output~streams~are~open } -\msg_kernel_new:nnn { iow } { show-open-streams } - { The~following~output~streams~are~in~use: } +\@@_kernel_new:nnn { kernel } { show-no-stream } + { No~ #1 ~streams~are~open } +\@@_kernel_new:nnn { kernel } { show-open-streams } + { The~following~ #1 ~streams~are~in~use: } % \end{macrocode} % % \subsection{Expandable errors} % -% \begin{macro}[int]{\msg_expandable_error:n} +% \begin{macro}[int]{\@@_expandable_error:n} +% \begin{macro}[aux]{\@@_expandable_error:w} % In expansion only context, we cannot use the normal means of % reporting errors. Instead, we feed \TeX{} an undefined control % sequence, \cs{LaTeX3 error:}. It is thus interrupted, and shows @@ -1806,7 +1909,7 @@ % \end{verbatim} % In other words, \TeX{} is processing the argument of \cs{use:n}, % which is \cs{LaTeX3 error:} \meta{error message}. -% Then \cs{msg_expandable_error_aux:w} cleans up. In fact, there +% Then \cs{@@_expandable_error:w} cleans up. In fact, there % is an extra subtlety: if the user inserts tokens for error recovery, % they should be kept. Thus we also use an odd space character % (with category code $7$) and keep tokens until that space character, @@ -1816,70 +1919,71 @@ % \begin{macrocode} \group_begin: \char_set_catcode_math_superscript:N \^ -\char_set_lccode:nn {`^} {`\ } -\char_set_lccode:nn {`L} {`L} -\char_set_lccode:nn {`T} {`T} -\char_set_lccode:nn {`X} {`X} +\char_set_lccode:nn { `^ } { `\ } +\char_set_lccode:nn { `L } { `L } +\char_set_lccode:nn { `T } { `T } +\char_set_lccode:nn { `X } { `X } \tl_to_lowercase:n { - \cs_new:Npx \msg_expandable_error:n #1 + \cs_new:Npx \@@_expandable_error:n #1 { \exp_not:n { \tex_romannumeral:D \exp_after:wN \exp_after:wN - \exp_after:wN \msg_expandable_error_aux:w + \exp_after:wN \@@_expandable_error:w \exp_after:wN \exp_after:wN \exp_after:wN \c_zero } \exp_not:N \use:n { \exp_not:c { LaTeX3~error: } ^ #1 } ^ } - \cs_new:Npn \msg_expandable_error_aux:w #1 ^ #2 ^ { #1 } + \cs_new:Npn \@@_expandable_error:w #1 ^ #2 ^ { #1 } } \group_end: % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro} % { -% \msg_expandable_kernel_error:nnnnnn, -% \msg_expandable_kernel_error:nnnnn, -% \msg_expandable_kernel_error:nnnn, -% \msg_expandable_kernel_error:nnn, -% \msg_expandable_kernel_error:nn +% \@@_kernel_expandable_error:nnnnnn, +% \@@_kernel_expandable_error:nnnnn, +% \@@_kernel_expandable_error:nnnn, +% \@@_kernel_expandable_error:nnn, +% \@@_kernel_expandable_error:nn % } % The command built from the csname -% |\c_msg_text_prefix_tl LaTeX / #1 / #2| +% |\c_@@_text_prefix_tl LaTeX / #1 / #2| % takes four arguments and builds the error text, which is fed to -% \cs{msg_expandable_error:n}. +% \cs{@@_expandable_error:n}. % \begin{macrocode} -\cs_new:Npn \msg_expandable_kernel_error:nnnnnn #1#2#3#4#5#6 +\cs_new:Npn \@@_kernel_expandable_error:nnnnnn #1#2#3#4#5#6 { - \exp_args:Nf \msg_expandable_error:n + \exp_args:Nf \@@_expandable_error:n { \exp_args:NNc \exp_after:wN \exp_stop_f: - { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + { \c_@@_text_prefix_tl LaTeX / #1 / #2 } {#3} {#4} {#5} {#6} } } -\cs_new:Npn \msg_expandable_kernel_error:nnnnn #1#2#3#4#5 +\cs_new:Npn \@@_kernel_expandable_error:nnnnn #1#2#3#4#5 { - \msg_expandable_kernel_error:nnnnnn + \@@_kernel_expandable_error:nnnnnn {#1} {#2} {#3} {#4} {#5} { } } -\cs_new:Npn \msg_expandable_kernel_error:nnnn #1#2#3#4 +\cs_new:Npn \@@_kernel_expandable_error:nnnn #1#2#3#4 { - \msg_expandable_kernel_error:nnnnnn + \@@_kernel_expandable_error:nnnnnn {#1} {#2} {#3} {#4} { } { } } -\cs_new:Npn \msg_expandable_kernel_error:nnn #1#2#3 +\cs_new:Npn \@@_kernel_expandable_error:nnn #1#2#3 { - \msg_expandable_kernel_error:nnnnnn + \@@_kernel_expandable_error:nnnnnn {#1} {#2} {#3} { } { } { } } -\cs_new:Npn \msg_expandable_kernel_error:nn #1#2 +\cs_new:Npn \@@_kernel_expandable_error:nn #1#2 { - \msg_expandable_kernel_error:nnnnnn + \@@_kernel_expandable_error:nnnnnn {#1} {#2} { } { } { } { } } % \end{macrocode} @@ -1888,93 +1992,103 @@ % \subsection{Showing variables} % % Functions defined in this section are used for diagnostic functions -% in \pkg{l3clist}, \pkg{l3io}, \pkg{l3prop}, \pkg{l3seq}, \pkg{xtemplate} -% -% \begin{macro}[aux]{\msg_aux_use:nn} -% \begin{macro}[aux]{\msg_aux_use:nnxxxx} -% Print the text of a message to the terminal, without formatting. +% in \pkg{l3clist}, \pkg{l3file}, \pkg{l3prop}, \pkg{l3seq}, \pkg{xtemplate} +% +% \begin{macro}[int] +% {\@@_term:nnnnnn, \@@_term:nnnnnV} +% \begin{macro}[int]{\@@_term:nnnnn} +% \begin{macro}[int]{\@@_term:nnn} +% \begin{macro}[int]{\@@_term:nn} +% Print the text of a message to the terminal without formatting: +% short cuts around \cs{iow_wrap:nnnN}. % \begin{macrocode} -\cs_new_protected:Npn \msg_aux_use:nn #1#2 - { \msg_aux_use:nnxxxx {#1} {#2} { } { } { } { } } -\cs_new_protected:Npn \msg_aux_use:nnxxxx #1#2#3#4#5#6 - { - \iow_wrap:xnnnN - { - \use:c { \c_msg_text_prefix_tl #1 / #2 } - {#3} {#4} {#5} {#6} - } - { } \c_zero { } \iow_term:x - } +\cs_new_protected:Npn \@@_term:nnnnnn #1#2#3#4#5#6 + { + \iow_wrap:nnnN + { \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } + { } { } \iow_term:n + } +\cs_generate_variant:Nn \@@_term:nnnnnn { nnnnnV } +\cs_new_protected:Npn \@@_term:nnnnn #1#2#3#4#5 + { \@@_term:nnnnnn {#1} {#2} {#3} {#4} {#5} { } } +\cs_new_protected:Npn \@@_term:nnn #1#2#3 + { \@@_term:nnnnnn {#1} {#2} {#3} { } { } { } } +\cs_new_protected:Npn \@@_term:nn #1#2 + { \@@_term:nnnnnn {#1} {#2} { } { } { } { } } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} % -% \begin{macro}[int]{\msg_aux_show:Nnx} -% \begin{macro}[aux]{\msg_aux_show:x} -% \begin{macro}[aux,EXP]{\msg_aux_show:w} -% The arguments of \cs{msg_aux_show:Nnx} are +% \begin{macro}[int]{\@@_show_variable:Nnn, \@@_show_variable:Nnn} +% \begin{macro}[int]{\@@_show_variable:n, \@@_show_variable:x} +% \begin{macro}[aux,EXP]{\@@_show_variable:w} +% The arguments of \cs{@@_show_variable:Nnn} are % \begin{itemize} -% \item The \meta{variable} to be shown. -% \item The \texttt{TF} emptyness conditional for that type of variables. -% \item The type of the variable. -% \item A mapping of the form \cs{seq_map_function:NN} \meta{variable} -% \cs{msg_aux_show:n}, which produces the formatted string. +% \item The \meta{variable} to be shown. +% \item The \texttt{TF} emptiness conditional for that type of variables. +% \item The type of the variable. +% \item A mapping of the form \cs{seq_map_function:NN} \meta{variable} +% \cs{@@_show_item:n}, which produces the formatted string. % \end{itemize} % We remove a new line and \verb*|> | from the first item using % a \texttt{w}-type auxiliary, and the fact that \texttt{f}-expansion % removes a space. To avoid a low-level \TeX{} error if there is % an empty argument, a simple test is used to keep the output -% \enquote{clean}. The odd \cs{exp_after:wN} and trailing -% \cs{prg_do_nothing:} improve the output slightly. +% \enquote{clean}. The odd \cs{exp_after:wN} which expands the closing +% brace improves the output slightly. % \begin{macrocode} -\cs_new_protected:Npn \msg_aux_show:Nnx #1#2#3 +\cs_new_protected:Npn \@@_show_variable:Nnn #1#2#3 { \cs_if_exist:NTF #1 { - \msg_aux_use:nnxxxx { LaTeX / #2 } { show } {#1} { } { } { } - \msg_aux_show:x {#3} + \@@_term:nnn { LaTeX / kernel } { show- #2 } {#1} + \@@_show_variable:x {#3} } { - \msg_kernel_error:nnx { kernel } { variable-not-defined } + \@@_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } -\cs_new_protected:Npn \msg_aux_show:x #1 +\cs_generate_variant:Nn \@@_show_variable:Nnn { Nnx } +\cs_new_protected:Npn \@@_show_variable:n #1 { - \tl_set:Nx \l_msg_internal_tl {#1} - \tl_if_empty:NT \l_msg_internal_tl - { \tl_set:Nx \l_msg_internal_tl { > } } - \exp_args:Nf \etex_showtokens:D + \tl_set:Nn \l_@@_internal_tl {#1} + \tl_if_empty:NTF \l_@@_internal_tl + { \etex_showtokens:D \exp_after:wN { } } { - \exp_after:wN \exp_after:wN - \exp_after:wN \msg_aux_show:w - \exp_after:wN \l_msg_internal_tl - \exp_after:wN + \exp_args:Nf \etex_showtokens:D + { + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_show_variable:w + \exp_after:wN \l_@@_internal_tl + } } - \prg_do_nothing: } -\cs_new:Npn \msg_aux_show:w #1 > { } +\cs_generate_variant:Nn \@@_show_variable:n { x } +\cs_new:Npn \@@_show_variable:w #1 > { } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % -% \begin{macro}[aux,EXP]{\msg_aux_show:n} -% \begin{macro}[aux,EXP]{\msg_aux_show:nn} -% \begin{macro}[aux,EXP]{\msg_aux_show_unbraced:nn} +% \begin{macro}[int,EXP]{\@@_show_item:n} +% \begin{macro}[int,EXP]{\@@_show_item:nn} +% \begin{macro}[int,EXP]{\@@_show_item_unbraced:nn} % Each item in the variable is formatted using one of % the following functions. % \begin{macrocode} -\cs_new:Npn \msg_aux_show:n #1 +\cs_new:Npn \@@_show_item:n #1 { \iow_newline: > \c_space_tl \c_space_tl { \exp_not:n {#1} } } -\cs_new:Npn \msg_aux_show:nn #1#2 +\cs_new:Npn \@@_show_item:nn #1#2 { \iow_newline: > \c_space_tl \c_space_tl { \exp_not:n {#1} } \c_space_tl \c_space_tl => \c_space_tl \c_space_tl { \exp_not:n {#2} } } -\cs_new:Npn \msg_aux_show_unbraced:nn #1#2 +\cs_new:Npn \@@_show_item_unbraced:nn #1#2 { \iow_newline: > \c_space_tl \c_space_tl \exp_not:n {#1} \c_space_tl \c_space_tl => \c_space_tl \c_space_tl \exp_not:n {#2} @@ -2042,22 +2156,22 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\msg_kernel_bug:x} -% \begin{variable}{\c_msg_kernel_bug_text_tl, \c_msg_kernel_bug_more_text_tl} +% \begin{macro}{\@@_kernel_bug:x} +% \begin{variable}{\c_@@_kernel_bug_text_tl, \c_@@_kernel_bug_more_text_tl} % \begin{macrocode} %<*deprecated> -\cs_set_protected:Npn \msg_kernel_bug:x #1 +\cs_set_protected:Npn \@@_kernel_bug:x #1 { - \msg_interrupt:xxx { \c_msg_kernel_bug_text_tl } + \msg_interrupt:nnn { \c_@@_kernel_bug_text_tl } { #1 \msg_see_documentation_text:n { LaTeX3 } } - { \c_msg_kernel_bug_more_text_tl } + { \c_@@_kernel_bug_more_text_tl } } -\tl_const:Nn \c_msg_kernel_bug_text_tl +\tl_const:Nn \c_@@_kernel_bug_text_tl { This~is~a~LaTeX~bug:~check~coding! } -\tl_const:Nn \c_msg_kernel_bug_more_text_tl +\tl_const:Nn \c_@@_kernel_bug_more_text_tl { There~is~a~coding~bug~somewhere~around~here. \\ This~probably~needs~examining~by~an~expert. @@ -2067,6 +2181,55 @@ % \end{macrocode} % \end{variable} % \end{macro} +% +% Deprecated on 2012-06-28, for removal by 2012-12-31. +% +% \begin{macro}{\msg_newline:, \msg_two_newlines:} +% New lines are printed in the same way as for low-level file writing. +% \begin{macrocode} +\cs_new_nopar:Npn \msg_newline: { ^^J } +\cs_new_nopar:Npn \msg_two_newlines: { ^^J ^^J } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\msg_log:x, \msg_term:x} +% \begin{macro}{\msg_interrupt:xxx} +% These were all misnamed. +% \begin{macrocode} +\cs_generate_variant:Nn \msg_log:n { x } +\cs_generate_variant:Nn \msg_term:n { x } +\cs_generate_variant:Nn \msg_interrupt:nnn { xxx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% Deprecated on 2012-06-29, for removal by 2012-12-31. +% +% \begin{macro}{\msg_class_set:nn} +% Setting up a message class does two tasks. Any existing redirection +% is cleared, and the various message functions are created +% to simply use the code stored for the message. +% \begin{macrocode} +\cs_new_protected:Npn \msg_class_set:nn #1#2 + { + \cs_if_exist:cTF { @@_ #1 _code:nnnnnn } + \cs_set_protected:cpn + \cs_new_protected:cpn + { @@_ #1 _code:nnnnnn } ##1##2##3##4##5##6 {#2} + \prop_clear_new:c { l_@@_redirect_ #1 _prop } + \cs_set_protected_nopar:cpn { msg_ #1 :nnxxxx } + { \@@_use:nnnnnnn {#1} } + \cs_set_protected:cpx { msg_ #1 :nnxxx } ##1##2##3##4##5 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} { } } + \cs_set_protected:cpx { msg_ #1 :nnxx } ##1##2##3##4 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { } } + \cs_set_protected:cpx { msg_ #1 :nnx } ##1##2##3 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { } } + \cs_set_protected:cpx { msg_ #1 :nn } ##1##2 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} { } { } { } { } } + } +% \end{macrocode} +% \end{macro} % % \begin{macrocode} %</initex|package> diff --git a/Master/texmf-dist/source/latex/l3kernel/l3names.dtx b/Master/texmf-dist/source/latex/l3kernel/l3names.dtx index 13d403f4633..a77f3103063 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3names.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3names.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3names.dtx Copyright (C) 1990-2011 The LaTeX3 project +%% File: l3names.dtx Copyright (C) 1990-2012 The LaTeX3 project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -34,9 +34,9 @@ %% ----------------------------------------------------------------------- % %<*package> -\RequirePackage{l3bootstrap}[2011-12-29] -\GetIdInfo$Id: l3names.dtx 3494 2012-03-04 09:58:29Z joseph $ - {L3 Experimental namespace for primitives} +\RequirePackage{l3bootstrap}[2012/07/15] +\GetIdInfo$Id: l3names.dtx 3990 2012-07-16 07:46:03Z joseph $ + {L3 Namespace for primitives} %</package> %<*driver> \documentclass[full]{l3doc} @@ -73,7 +73,7 @@ % performs the following tasks: % \begin{itemize} % \item defines new names for all \TeX{} primitives; -% \item switches to the category code regime for programming; +% \item switches to the category code r{\'e}gime for programming; % \item provides support settings for building the code as a \TeX{} format. % \end{itemize} % @@ -111,12 +111,12 @@ % % The code here simply renames all of the primitives to new, internal, % names. In format mode, it also deletes all of the existing names (although -% some od come back later). +% some do come back later). % % \begin{macro}{\tex_undefined:D} -% This function does not exist at all, but is the name used by the -% plain \TeX{} format for an undefined function. So it should -% be marked here as \enquote{taken}. +% This function does not exist at all, but is the name used by the +% plain \TeX{} format for an undefined function. So it should +% be marked here as \enquote{taken}. % \end{macro} % % The \tn{let} primitive is renamed by hand first as it is essential for @@ -127,17 +127,17 @@ \let \tex_let:D \let % \end{macrocode} % -% Everything is inside a (rather long) group, which kees \cs{name_primitve:NN} -% trapped. +% Everything is inside a (rather long) group, which keeps +% \cs{__expl_primitive:NN} trapped. % \begin{macrocode} \begingroup % \end{macrocode} % -% \begin{macro}[aux]{\name_primitive:NN} +% \begin{macro}[aux]{\__expl_primitive:NN} % A temporary function to actually do the renaming. This also allows the % original names to be removed in format mode. % \begin{macrocode} - \long \def \name_primitive:NN #1#2 + \long \def \__expl_primitive:NN #1#2 { \tex_global:D \tex_let:D #2 #1 %<*initex> @@ -153,406 +153,406 @@ % These are given modified new names, so that they may be entered % without catcode tricks. % \begin{macrocode} - \name_primitive:NN \ \tex_space:D - \name_primitive:NN \/ \tex_italiccor:D - \name_primitive:NN \- \tex_hyphen:D + \__expl_primitive:NN \ \tex_space:D + \__expl_primitive:NN \/ \tex_italiccorrection:D + \__expl_primitive:NN \- \tex_hyphen:D % \end{macrocode} % % Now all the other primitives. % \begin{macrocode} - \name_primitive:NN \let \tex_let:D - \name_primitive:NN \def \tex_def:D - \name_primitive:NN \edef \tex_edef:D - \name_primitive:NN \gdef \tex_gdef:D - \name_primitive:NN \xdef \tex_xdef:D - \name_primitive:NN \chardef \tex_chardef:D - \name_primitive:NN \countdef \tex_countdef:D - \name_primitive:NN \dimendef \tex_dimendef:D - \name_primitive:NN \skipdef \tex_skipdef:D - \name_primitive:NN \muskipdef \tex_muskipdef:D - \name_primitive:NN \mathchardef \tex_mathchardef:D - \name_primitive:NN \toksdef \tex_toksdef:D - \name_primitive:NN \futurelet \tex_futurelet:D - \name_primitive:NN \advance \tex_advance:D - \name_primitive:NN \divide \tex_divide:D - \name_primitive:NN \multiply \tex_multiply:D - \name_primitive:NN \font \tex_font:D - \name_primitive:NN \fam \tex_fam:D - \name_primitive:NN \global \tex_global:D - \name_primitive:NN \long \tex_long:D - \name_primitive:NN \outer \tex_outer:D - \name_primitive:NN \setlanguage \tex_setlanguage:D - \name_primitive:NN \globaldefs \tex_globaldefs:D - \name_primitive:NN \afterassignment \tex_afterassignment:D - \name_primitive:NN \aftergroup \tex_aftergroup:D - \name_primitive:NN \expandafter \tex_expandafter:D - \name_primitive:NN \noexpand \tex_noexpand:D - \name_primitive:NN \begingroup \tex_begingroup:D - \name_primitive:NN \endgroup \tex_endgroup:D - \name_primitive:NN \halign \tex_halign:D - \name_primitive:NN \valign \tex_valign:D - \name_primitive:NN \cr \tex_cr:D - \name_primitive:NN \crcr \tex_crcr:D - \name_primitive:NN \noalign \tex_noalign:D - \name_primitive:NN \omit \tex_omit:D - \name_primitive:NN \span \tex_span:D - \name_primitive:NN \tabskip \tex_tabskip:D - \name_primitive:NN \everycr \tex_everycr:D - \name_primitive:NN \if \tex_if:D - \name_primitive:NN \ifcase \tex_ifcase:D - \name_primitive:NN \ifcat \tex_ifcat:D - \name_primitive:NN \ifnum \tex_ifnum:D - \name_primitive:NN \ifodd \tex_ifodd:D - \name_primitive:NN \ifdim \tex_ifdim:D - \name_primitive:NN \ifeof \tex_ifeof:D - \name_primitive:NN \ifhbox \tex_ifhbox:D - \name_primitive:NN \ifvbox \tex_ifvbox:D - \name_primitive:NN \ifvoid \tex_ifvoid:D - \name_primitive:NN \ifx \tex_ifx:D - \name_primitive:NN \iffalse \tex_iffalse:D - \name_primitive:NN \iftrue \tex_iftrue:D - \name_primitive:NN \ifhmode \tex_ifhmode:D - \name_primitive:NN \ifmmode \tex_ifmmode:D - \name_primitive:NN \ifvmode \tex_ifvmode:D - \name_primitive:NN \ifinner \tex_ifinner:D - \name_primitive:NN \else \tex_else:D - \name_primitive:NN \fi \tex_fi:D - \name_primitive:NN \or \tex_or:D - \name_primitive:NN \immediate \tex_immediate:D - \name_primitive:NN \closeout \tex_closeout:D - \name_primitive:NN \openin \tex_openin:D - \name_primitive:NN \openout \tex_openout:D - \name_primitive:NN \read \tex_read:D - \name_primitive:NN \write \tex_write:D - \name_primitive:NN \closein \tex_closein:D - \name_primitive:NN \newlinechar \tex_newlinechar:D - \name_primitive:NN \input \tex_input:D - \name_primitive:NN \endinput \tex_endinput:D - \name_primitive:NN \inputlineno \tex_inputlineno:D - \name_primitive:NN \errmessage \tex_errmessage:D - \name_primitive:NN \message \tex_message:D - \name_primitive:NN \show \tex_show:D - \name_primitive:NN \showthe \tex_showthe:D - \name_primitive:NN \showbox \tex_showbox:D - \name_primitive:NN \showlists \tex_showlists:D - \name_primitive:NN \errhelp \tex_errhelp:D - \name_primitive:NN \errorcontextlines \tex_errorcontextlines:D - \name_primitive:NN \tracingcommands \tex_tracingcommands:D - \name_primitive:NN \tracinglostchars \tex_tracinglostchars:D - \name_primitive:NN \tracingmacros \tex_tracingmacros:D - \name_primitive:NN \tracingonline \tex_tracingonline:D - \name_primitive:NN \tracingoutput \tex_tracingoutput:D - \name_primitive:NN \tracingpages \tex_tracingpages:D - \name_primitive:NN \tracingparagraphs \tex_tracingparagraphs:D - \name_primitive:NN \tracingrestores \tex_tracingrestores:D - \name_primitive:NN \tracingstats \tex_tracingstats:D - \name_primitive:NN \pausing \tex_pausing:D - \name_primitive:NN \showboxbreadth \tex_showboxbreadth:D - \name_primitive:NN \showboxdepth \tex_showboxdepth:D - \name_primitive:NN \batchmode \tex_batchmode:D - \name_primitive:NN \errorstopmode \tex_errorstopmode:D - \name_primitive:NN \nonstopmode \tex_nonstopmode:D - \name_primitive:NN \scrollmode \tex_scrollmode:D - \name_primitive:NN \end \tex_end:D - \name_primitive:NN \csname \tex_csname:D - \name_primitive:NN \endcsname \tex_endcsname:D - \name_primitive:NN \ignorespaces \tex_ignorespaces:D - \name_primitive:NN \relax \tex_relax:D - \name_primitive:NN \the \tex_the:D - \name_primitive:NN \mag \tex_mag:D - \name_primitive:NN \language \tex_language:D - \name_primitive:NN \mark \tex_mark:D - \name_primitive:NN \topmark \tex_topmark:D - \name_primitive:NN \firstmark \tex_firstmark:D - \name_primitive:NN \botmark \tex_botmark:D - \name_primitive:NN \splitfirstmark \tex_splitfirstmark:D - \name_primitive:NN \splitbotmark \tex_splitbotmark:D - \name_primitive:NN \fontname \tex_fontname:D - \name_primitive:NN \escapechar \tex_escapechar:D - \name_primitive:NN \endlinechar \tex_endlinechar:D - \name_primitive:NN \mathchoice \tex_mathchoice:D - \name_primitive:NN \delimiter \tex_delimiter:D - \name_primitive:NN \mathaccent \tex_mathaccent:D - \name_primitive:NN \mathchar \tex_mathchar:D - \name_primitive:NN \mskip \tex_mskip:D - \name_primitive:NN \radical \tex_radical:D - \name_primitive:NN \vcenter \tex_vcenter:D - \name_primitive:NN \mkern \tex_mkern:D - \name_primitive:NN \above \tex_above:D - \name_primitive:NN \abovewithdelims \tex_abovewithdelims:D - \name_primitive:NN \atop \tex_atop:D - \name_primitive:NN \atopwithdelims \tex_atopwithdelims:D - \name_primitive:NN \over \tex_over:D - \name_primitive:NN \overwithdelims \tex_overwithdelims:D - \name_primitive:NN \displaystyle \tex_displaystyle:D - \name_primitive:NN \textstyle \tex_textstyle:D - \name_primitive:NN \scriptstyle \tex_scriptstyle:D - \name_primitive:NN \scriptscriptstyle \tex_scriptscriptstyle:D - \name_primitive:NN \nonscript \tex_nonscript:D - \name_primitive:NN \eqno \tex_eqno:D - \name_primitive:NN \leqno \tex_leqno:D - \name_primitive:NN \abovedisplayshortskip \tex_abovedisplayshortskip:D - \name_primitive:NN \abovedisplayskip \tex_abovedisplayskip:D - \name_primitive:NN \belowdisplayshortskip \tex_belowdisplayshortskip:D - \name_primitive:NN \belowdisplayskip \tex_belowdisplayskip:D - \name_primitive:NN \displaywidowpenalty \tex_displaywidowpenalty:D - \name_primitive:NN \displayindent \tex_displayindent:D - \name_primitive:NN \displaywidth \tex_displaywidth:D - \name_primitive:NN \everydisplay \tex_everydisplay:D - \name_primitive:NN \predisplaysize \tex_predisplaysize:D - \name_primitive:NN \predisplaypenalty \tex_predisplaypenalty:D - \name_primitive:NN \postdisplaypenalty \tex_postdisplaypenalty:D - \name_primitive:NN \mathbin \tex_mathbin:D - \name_primitive:NN \mathclose \tex_mathclose:D - \name_primitive:NN \mathinner \tex_mathinner:D - \name_primitive:NN \mathop \tex_mathop:D - \name_primitive:NN \displaylimits \tex_displaylimits:D - \name_primitive:NN \limits \tex_limits:D - \name_primitive:NN \nolimits \tex_nolimits:D - \name_primitive:NN \mathopen \tex_mathopen:D - \name_primitive:NN \mathord \tex_mathord:D - \name_primitive:NN \mathpunct \tex_mathpunct:D - \name_primitive:NN \mathrel \tex_mathrel:D - \name_primitive:NN \overline \tex_overline:D - \name_primitive:NN \underline \tex_underline:D - \name_primitive:NN \left \tex_left:D - \name_primitive:NN \right \tex_right:D - \name_primitive:NN \binoppenalty \tex_binoppenalty:D - \name_primitive:NN \relpenalty \tex_relpenalty:D - \name_primitive:NN \delimitershortfall \tex_delimitershortfall:D - \name_primitive:NN \delimiterfactor \tex_delimiterfactor:D - \name_primitive:NN \nulldelimiterspace \tex_nulldelimiterspace:D - \name_primitive:NN \everymath \tex_everymath:D - \name_primitive:NN \mathsurround \tex_mathsurround:D - \name_primitive:NN \medmuskip \tex_medmuskip:D - \name_primitive:NN \thinmuskip \tex_thinmuskip:D - \name_primitive:NN \thickmuskip \tex_thickmuskip:D - \name_primitive:NN \scriptspace \tex_scriptspace:D - \name_primitive:NN \noboundary \tex_noboundary:D - \name_primitive:NN \accent \tex_accent:D - \name_primitive:NN \char \tex_char:D - \name_primitive:NN \discretionary \tex_discretionary:D - \name_primitive:NN \hfil \tex_hfil:D - \name_primitive:NN \hfilneg \tex_hfilneg:D - \name_primitive:NN \hfill \tex_hfill:D - \name_primitive:NN \hskip \tex_hskip:D - \name_primitive:NN \hss \tex_hss:D - \name_primitive:NN \vfil \tex_vfil:D - \name_primitive:NN \vfilneg \tex_vfilneg:D - \name_primitive:NN \vfill \tex_vfill:D - \name_primitive:NN \vskip \tex_vskip:D - \name_primitive:NN \vss \tex_vss:D - \name_primitive:NN \unskip \tex_unskip:D - \name_primitive:NN \kern \tex_kern:D - \name_primitive:NN \unkern \tex_unkern:D - \name_primitive:NN \hrule \tex_hrule:D - \name_primitive:NN \vrule \tex_vrule:D - \name_primitive:NN \leaders \tex_leaders:D - \name_primitive:NN \cleaders \tex_cleaders:D - \name_primitive:NN \xleaders \tex_xleaders:D - \name_primitive:NN \lastkern \tex_lastkern:D - \name_primitive:NN \lastskip \tex_lastskip:D - \name_primitive:NN \indent \tex_indent:D - \name_primitive:NN \par \tex_par:D - \name_primitive:NN \noindent \tex_noindent:D - \name_primitive:NN \vadjust \tex_vadjust:D - \name_primitive:NN \baselineskip \tex_baselineskip:D - \name_primitive:NN \lineskip \tex_lineskip:D - \name_primitive:NN \lineskiplimit \tex_lineskiplimit:D - \name_primitive:NN \clubpenalty \tex_clubpenalty:D - \name_primitive:NN \widowpenalty \tex_widowpenalty:D - \name_primitive:NN \exhyphenpenalty \tex_exhyphenpenalty:D - \name_primitive:NN \hyphenpenalty \tex_hyphenpenalty:D - \name_primitive:NN \linepenalty \tex_linepenalty:D - \name_primitive:NN \doublehyphendemerits \tex_doublehyphendemerits:D - \name_primitive:NN \finalhyphendemerits \tex_finalhyphendemerits:D - \name_primitive:NN \adjdemerits \tex_adjdemerits:D - \name_primitive:NN \hangafter \tex_hangafter:D - \name_primitive:NN \hangindent \tex_hangindent:D - \name_primitive:NN \parshape \tex_parshape:D - \name_primitive:NN \hsize \tex_hsize:D - \name_primitive:NN \lefthyphenmin \tex_lefthyphenmin:D - \name_primitive:NN \righthyphenmin \tex_righthyphenmin:D - \name_primitive:NN \leftskip \tex_leftskip:D - \name_primitive:NN \rightskip \tex_rightskip:D - \name_primitive:NN \looseness \tex_looseness:D - \name_primitive:NN \parskip \tex_parskip:D - \name_primitive:NN \parindent \tex_parindent:D - \name_primitive:NN \uchyph \tex_uchyph:D - \name_primitive:NN \emergencystretch \tex_emergencystretch:D - \name_primitive:NN \pretolerance \tex_pretolerance:D - \name_primitive:NN \tolerance \tex_tolerance:D - \name_primitive:NN \spaceskip \tex_spaceskip:D - \name_primitive:NN \xspaceskip \tex_xspaceskip:D - \name_primitive:NN \parfillskip \tex_parfillskip:D - \name_primitive:NN \everypar \tex_everypar:D - \name_primitive:NN \prevgraf \tex_prevgraf:D - \name_primitive:NN \spacefactor \tex_spacefactor:D - \name_primitive:NN \shipout \tex_shipout:D - \name_primitive:NN \vsize \tex_vsize:D - \name_primitive:NN \interlinepenalty \tex_interlinepenalty:D - \name_primitive:NN \brokenpenalty \tex_brokenpenalty:D - \name_primitive:NN \topskip \tex_topskip:D - \name_primitive:NN \maxdeadcycles \tex_maxdeadcycles:D - \name_primitive:NN \maxdepth \tex_maxdepth:D - \name_primitive:NN \output \tex_output:D - \name_primitive:NN \deadcycles \tex_deadcycles:D - \name_primitive:NN \pagedepth \tex_pagedepth:D - \name_primitive:NN \pagestretch \tex_pagestretch:D - \name_primitive:NN \pagefilstretch \tex_pagefilstretch:D - \name_primitive:NN \pagefillstretch \tex_pagefillstretch:D - \name_primitive:NN \pagefilllstretch \tex_pagefilllstretch:D - \name_primitive:NN \pageshrink \tex_pageshrink:D - \name_primitive:NN \pagegoal \tex_pagegoal:D - \name_primitive:NN \pagetotal \tex_pagetotal:D - \name_primitive:NN \outputpenalty \tex_outputpenalty:D - \name_primitive:NN \hoffset \tex_hoffset:D - \name_primitive:NN \voffset \tex_voffset:D - \name_primitive:NN \insert \tex_insert:D - \name_primitive:NN \holdinginserts \tex_holdinginserts:D - \name_primitive:NN \floatingpenalty \tex_floatingpenalty:D - \name_primitive:NN \insertpenalties \tex_insertpenalties:D - \name_primitive:NN \lower \tex_lower:D - \name_primitive:NN \moveleft \tex_moveleft:D - \name_primitive:NN \moveright \tex_moveright:D - \name_primitive:NN \raise \tex_raise:D - \name_primitive:NN \copy \tex_copy:D - \name_primitive:NN \lastbox \tex_lastbox:D - \name_primitive:NN \vsplit \tex_vsplit:D - \name_primitive:NN \unhbox \tex_unhbox:D - \name_primitive:NN \unhcopy \tex_unhcopy:D - \name_primitive:NN \unvbox \tex_unvbox:D - \name_primitive:NN \unvcopy \tex_unvcopy:D - \name_primitive:NN \setbox \tex_setbox:D - \name_primitive:NN \hbox \tex_hbox:D - \name_primitive:NN \vbox \tex_vbox:D - \name_primitive:NN \vtop \tex_vtop:D - \name_primitive:NN \prevdepth \tex_prevdepth:D - \name_primitive:NN \badness \tex_badness:D - \name_primitive:NN \hbadness \tex_hbadness:D - \name_primitive:NN \vbadness \tex_vbadness:D - \name_primitive:NN \hfuzz \tex_hfuzz:D - \name_primitive:NN \vfuzz \tex_vfuzz:D - \name_primitive:NN \overfullrule \tex_overfullrule:D - \name_primitive:NN \boxmaxdepth \tex_boxmaxdepth:D - \name_primitive:NN \splitmaxdepth \tex_splitmaxdepth:D - \name_primitive:NN \splittopskip \tex_splittopskip:D - \name_primitive:NN \everyhbox \tex_everyhbox:D - \name_primitive:NN \everyvbox \tex_everyvbox:D - \name_primitive:NN \nullfont \tex_nullfont:D - \name_primitive:NN \textfont \tex_textfont:D - \name_primitive:NN \scriptfont \tex_scriptfont:D - \name_primitive:NN \scriptscriptfont \tex_scriptscriptfont:D - \name_primitive:NN \fontdimen \tex_fontdimen:D - \name_primitive:NN \hyphenchar \tex_hyphenchar:D - \name_primitive:NN \skewchar \tex_skewchar:D - \name_primitive:NN \defaulthyphenchar \tex_defaulthyphenchar:D - \name_primitive:NN \defaultskewchar \tex_defaultskewchar:D - \name_primitive:NN \number \tex_number:D - \name_primitive:NN \romannumeral \tex_romannumeral:D - \name_primitive:NN \string \tex_string:D - \name_primitive:NN \lowercase \tex_lowercase:D - \name_primitive:NN \uppercase \tex_uppercase:D - \name_primitive:NN \meaning \tex_meaning:D - \name_primitive:NN \penalty \tex_penalty:D - \name_primitive:NN \unpenalty \tex_unpenalty:D - \name_primitive:NN \lastpenalty \tex_lastpenalty:D - \name_primitive:NN \special \tex_special:D - \name_primitive:NN \dump \tex_dump:D - \name_primitive:NN \patterns \tex_patterns:D - \name_primitive:NN \hyphenation \tex_hyphenation:D - \name_primitive:NN \time \tex_time:D - \name_primitive:NN \day \tex_day:D - \name_primitive:NN \month \tex_month:D - \name_primitive:NN \year \tex_year:D - \name_primitive:NN \jobname \tex_jobname:D - \name_primitive:NN \everyjob \tex_everyjob:D - \name_primitive:NN \count \tex_count:D - \name_primitive:NN \dimen \tex_dimen:D - \name_primitive:NN \skip \tex_skip:D - \name_primitive:NN \toks \tex_toks:D - \name_primitive:NN \muskip \tex_muskip:D - \name_primitive:NN \box \tex_box:D - \name_primitive:NN \wd \tex_wd:D - \name_primitive:NN \ht \tex_ht:D - \name_primitive:NN \dp \tex_dp:D - \name_primitive:NN \catcode \tex_catcode:D - \name_primitive:NN \delcode \tex_delcode:D - \name_primitive:NN \sfcode \tex_sfcode:D - \name_primitive:NN \lccode \tex_lccode:D - \name_primitive:NN \uccode \tex_uccode:D - \name_primitive:NN \mathcode \tex_mathcode:D + \__expl_primitive:NN \let \tex_let:D + \__expl_primitive:NN \def \tex_def:D + \__expl_primitive:NN \edef \tex_edef:D + \__expl_primitive:NN \gdef \tex_gdef:D + \__expl_primitive:NN \xdef \tex_xdef:D + \__expl_primitive:NN \chardef \tex_chardef:D + \__expl_primitive:NN \countdef \tex_countdef:D + \__expl_primitive:NN \dimendef \tex_dimendef:D + \__expl_primitive:NN \skipdef \tex_skipdef:D + \__expl_primitive:NN \muskipdef \tex_muskipdef:D + \__expl_primitive:NN \mathchardef \tex_mathchardef:D + \__expl_primitive:NN \toksdef \tex_toksdef:D + \__expl_primitive:NN \futurelet \tex_futurelet:D + \__expl_primitive:NN \advance \tex_advance:D + \__expl_primitive:NN \divide \tex_divide:D + \__expl_primitive:NN \multiply \tex_multiply:D + \__expl_primitive:NN \font \tex_font:D + \__expl_primitive:NN \fam \tex_fam:D + \__expl_primitive:NN \global \tex_global:D + \__expl_primitive:NN \long \tex_long:D + \__expl_primitive:NN \outer \tex_outer:D + \__expl_primitive:NN \setlanguage \tex_setlanguage:D + \__expl_primitive:NN \globaldefs \tex_globaldefs:D + \__expl_primitive:NN \afterassignment \tex_afterassignment:D + \__expl_primitive:NN \aftergroup \tex_aftergroup:D + \__expl_primitive:NN \expandafter \tex_expandafter:D + \__expl_primitive:NN \noexpand \tex_noexpand:D + \__expl_primitive:NN \begingroup \tex_begingroup:D + \__expl_primitive:NN \endgroup \tex_endgroup:D + \__expl_primitive:NN \halign \tex_halign:D + \__expl_primitive:NN \valign \tex_valign:D + \__expl_primitive:NN \cr \tex_cr:D + \__expl_primitive:NN \crcr \tex_crcr:D + \__expl_primitive:NN \noalign \tex_noalign:D + \__expl_primitive:NN \omit \tex_omit:D + \__expl_primitive:NN \span \tex_span:D + \__expl_primitive:NN \tabskip \tex_tabskip:D + \__expl_primitive:NN \everycr \tex_everycr:D + \__expl_primitive:NN \if \tex_if:D + \__expl_primitive:NN \ifcase \tex_ifcase:D + \__expl_primitive:NN \ifcat \tex_ifcat:D + \__expl_primitive:NN \ifnum \tex_ifnum:D + \__expl_primitive:NN \ifodd \tex_ifodd:D + \__expl_primitive:NN \ifdim \tex_ifdim:D + \__expl_primitive:NN \ifeof \tex_ifeof:D + \__expl_primitive:NN \ifhbox \tex_ifhbox:D + \__expl_primitive:NN \ifvbox \tex_ifvbox:D + \__expl_primitive:NN \ifvoid \tex_ifvoid:D + \__expl_primitive:NN \ifx \tex_ifx:D + \__expl_primitive:NN \iffalse \tex_iffalse:D + \__expl_primitive:NN \iftrue \tex_iftrue:D + \__expl_primitive:NN \ifhmode \tex_ifhmode:D + \__expl_primitive:NN \ifmmode \tex_ifmmode:D + \__expl_primitive:NN \ifvmode \tex_ifvmode:D + \__expl_primitive:NN \ifinner \tex_ifinner:D + \__expl_primitive:NN \else \tex_else:D + \__expl_primitive:NN \fi \tex_fi:D + \__expl_primitive:NN \or \tex_or:D + \__expl_primitive:NN \immediate \tex_immediate:D + \__expl_primitive:NN \closeout \tex_closeout:D + \__expl_primitive:NN \openin \tex_openin:D + \__expl_primitive:NN \openout \tex_openout:D + \__expl_primitive:NN \read \tex_read:D + \__expl_primitive:NN \write \tex_write:D + \__expl_primitive:NN \closein \tex_closein:D + \__expl_primitive:NN \newlinechar \tex_newlinechar:D + \__expl_primitive:NN \input \tex_input:D + \__expl_primitive:NN \endinput \tex_endinput:D + \__expl_primitive:NN \inputlineno \tex_inputlineno:D + \__expl_primitive:NN \errmessage \tex_errmessage:D + \__expl_primitive:NN \message \tex_message:D + \__expl_primitive:NN \show \tex_show:D + \__expl_primitive:NN \showthe \tex_showthe:D + \__expl_primitive:NN \showbox \tex_showbox:D + \__expl_primitive:NN \showlists \tex_showlists:D + \__expl_primitive:NN \errhelp \tex_errhelp:D + \__expl_primitive:NN \errorcontextlines \tex_errorcontextlines:D + \__expl_primitive:NN \tracingcommands \tex_tracingcommands:D + \__expl_primitive:NN \tracinglostchars \tex_tracinglostchars:D + \__expl_primitive:NN \tracingmacros \tex_tracingmacros:D + \__expl_primitive:NN \tracingonline \tex_tracingonline:D + \__expl_primitive:NN \tracingoutput \tex_tracingoutput:D + \__expl_primitive:NN \tracingpages \tex_tracingpages:D + \__expl_primitive:NN \tracingparagraphs \tex_tracingparagraphs:D + \__expl_primitive:NN \tracingrestores \tex_tracingrestores:D + \__expl_primitive:NN \tracingstats \tex_tracingstats:D + \__expl_primitive:NN \pausing \tex_pausing:D + \__expl_primitive:NN \showboxbreadth \tex_showboxbreadth:D + \__expl_primitive:NN \showboxdepth \tex_showboxdepth:D + \__expl_primitive:NN \batchmode \tex_batchmode:D + \__expl_primitive:NN \errorstopmode \tex_errorstopmode:D + \__expl_primitive:NN \nonstopmode \tex_nonstopmode:D + \__expl_primitive:NN \scrollmode \tex_scrollmode:D + \__expl_primitive:NN \end \tex_end:D + \__expl_primitive:NN \csname \tex_csname:D + \__expl_primitive:NN \endcsname \tex_endcsname:D + \__expl_primitive:NN \ignorespaces \tex_ignorespaces:D + \__expl_primitive:NN \relax \tex_relax:D + \__expl_primitive:NN \the \tex_the:D + \__expl_primitive:NN \mag \tex_mag:D + \__expl_primitive:NN \language \tex_language:D + \__expl_primitive:NN \mark \tex_mark:D + \__expl_primitive:NN \topmark \tex_topmark:D + \__expl_primitive:NN \firstmark \tex_firstmark:D + \__expl_primitive:NN \botmark \tex_botmark:D + \__expl_primitive:NN \splitfirstmark \tex_splitfirstmark:D + \__expl_primitive:NN \splitbotmark \tex_splitbotmark:D + \__expl_primitive:NN \fontname \tex_fontname:D + \__expl_primitive:NN \escapechar \tex_escapechar:D + \__expl_primitive:NN \endlinechar \tex_endlinechar:D + \__expl_primitive:NN \mathchoice \tex_mathchoice:D + \__expl_primitive:NN \delimiter \tex_delimiter:D + \__expl_primitive:NN \mathaccent \tex_mathaccent:D + \__expl_primitive:NN \mathchar \tex_mathchar:D + \__expl_primitive:NN \mskip \tex_mskip:D + \__expl_primitive:NN \radical \tex_radical:D + \__expl_primitive:NN \vcenter \tex_vcenter:D + \__expl_primitive:NN \mkern \tex_mkern:D + \__expl_primitive:NN \above \tex_above:D + \__expl_primitive:NN \abovewithdelims \tex_abovewithdelims:D + \__expl_primitive:NN \atop \tex_atop:D + \__expl_primitive:NN \atopwithdelims \tex_atopwithdelims:D + \__expl_primitive:NN \over \tex_over:D + \__expl_primitive:NN \overwithdelims \tex_overwithdelims:D + \__expl_primitive:NN \displaystyle \tex_displaystyle:D + \__expl_primitive:NN \textstyle \tex_textstyle:D + \__expl_primitive:NN \scriptstyle \tex_scriptstyle:D + \__expl_primitive:NN \scriptscriptstyle \tex_scriptscriptstyle:D + \__expl_primitive:NN \nonscript \tex_nonscript:D + \__expl_primitive:NN \eqno \tex_eqno:D + \__expl_primitive:NN \leqno \tex_leqno:D + \__expl_primitive:NN \abovedisplayshortskip \tex_abovedisplayshortskip:D + \__expl_primitive:NN \abovedisplayskip \tex_abovedisplayskip:D + \__expl_primitive:NN \belowdisplayshortskip \tex_belowdisplayshortskip:D + \__expl_primitive:NN \belowdisplayskip \tex_belowdisplayskip:D + \__expl_primitive:NN \displaywidowpenalty \tex_displaywidowpenalty:D + \__expl_primitive:NN \displayindent \tex_displayindent:D + \__expl_primitive:NN \displaywidth \tex_displaywidth:D + \__expl_primitive:NN \everydisplay \tex_everydisplay:D + \__expl_primitive:NN \predisplaysize \tex_predisplaysize:D + \__expl_primitive:NN \predisplaypenalty \tex_predisplaypenalty:D + \__expl_primitive:NN \postdisplaypenalty \tex_postdisplaypenalty:D + \__expl_primitive:NN \mathbin \tex_mathbin:D + \__expl_primitive:NN \mathclose \tex_mathclose:D + \__expl_primitive:NN \mathinner \tex_mathinner:D + \__expl_primitive:NN \mathop \tex_mathop:D + \__expl_primitive:NN \displaylimits \tex_displaylimits:D + \__expl_primitive:NN \limits \tex_limits:D + \__expl_primitive:NN \nolimits \tex_nolimits:D + \__expl_primitive:NN \mathopen \tex_mathopen:D + \__expl_primitive:NN \mathord \tex_mathord:D + \__expl_primitive:NN \mathpunct \tex_mathpunct:D + \__expl_primitive:NN \mathrel \tex_mathrel:D + \__expl_primitive:NN \overline \tex_overline:D + \__expl_primitive:NN \underline \tex_underline:D + \__expl_primitive:NN \left \tex_left:D + \__expl_primitive:NN \right \tex_right:D + \__expl_primitive:NN \binoppenalty \tex_binoppenalty:D + \__expl_primitive:NN \relpenalty \tex_relpenalty:D + \__expl_primitive:NN \delimitershortfall \tex_delimitershortfall:D + \__expl_primitive:NN \delimiterfactor \tex_delimiterfactor:D + \__expl_primitive:NN \nulldelimiterspace \tex_nulldelimiterspace:D + \__expl_primitive:NN \everymath \tex_everymath:D + \__expl_primitive:NN \mathsurround \tex_mathsurround:D + \__expl_primitive:NN \medmuskip \tex_medmuskip:D + \__expl_primitive:NN \thinmuskip \tex_thinmuskip:D + \__expl_primitive:NN \thickmuskip \tex_thickmuskip:D + \__expl_primitive:NN \scriptspace \tex_scriptspace:D + \__expl_primitive:NN \noboundary \tex_noboundary:D + \__expl_primitive:NN \accent \tex_accent:D + \__expl_primitive:NN \char \tex_char:D + \__expl_primitive:NN \discretionary \tex_discretionary:D + \__expl_primitive:NN \hfil \tex_hfil:D + \__expl_primitive:NN \hfilneg \tex_hfilneg:D + \__expl_primitive:NN \hfill \tex_hfill:D + \__expl_primitive:NN \hskip \tex_hskip:D + \__expl_primitive:NN \hss \tex_hss:D + \__expl_primitive:NN \vfil \tex_vfil:D + \__expl_primitive:NN \vfilneg \tex_vfilneg:D + \__expl_primitive:NN \vfill \tex_vfill:D + \__expl_primitive:NN \vskip \tex_vskip:D + \__expl_primitive:NN \vss \tex_vss:D + \__expl_primitive:NN \unskip \tex_unskip:D + \__expl_primitive:NN \kern \tex_kern:D + \__expl_primitive:NN \unkern \tex_unkern:D + \__expl_primitive:NN \hrule \tex_hrule:D + \__expl_primitive:NN \vrule \tex_vrule:D + \__expl_primitive:NN \leaders \tex_leaders:D + \__expl_primitive:NN \cleaders \tex_cleaders:D + \__expl_primitive:NN \xleaders \tex_xleaders:D + \__expl_primitive:NN \lastkern \tex_lastkern:D + \__expl_primitive:NN \lastskip \tex_lastskip:D + \__expl_primitive:NN \indent \tex_indent:D + \__expl_primitive:NN \par \tex_par:D + \__expl_primitive:NN \noindent \tex_noindent:D + \__expl_primitive:NN \vadjust \tex_vadjust:D + \__expl_primitive:NN \baselineskip \tex_baselineskip:D + \__expl_primitive:NN \lineskip \tex_lineskip:D + \__expl_primitive:NN \lineskiplimit \tex_lineskiplimit:D + \__expl_primitive:NN \clubpenalty \tex_clubpenalty:D + \__expl_primitive:NN \widowpenalty \tex_widowpenalty:D + \__expl_primitive:NN \exhyphenpenalty \tex_exhyphenpenalty:D + \__expl_primitive:NN \hyphenpenalty \tex_hyphenpenalty:D + \__expl_primitive:NN \linepenalty \tex_linepenalty:D + \__expl_primitive:NN \doublehyphendemerits \tex_doublehyphendemerits:D + \__expl_primitive:NN \finalhyphendemerits \tex_finalhyphendemerits:D + \__expl_primitive:NN \adjdemerits \tex_adjdemerits:D + \__expl_primitive:NN \hangafter \tex_hangafter:D + \__expl_primitive:NN \hangindent \tex_hangindent:D + \__expl_primitive:NN \parshape \tex_parshape:D + \__expl_primitive:NN \hsize \tex_hsize:D + \__expl_primitive:NN \lefthyphenmin \tex_lefthyphenmin:D + \__expl_primitive:NN \righthyphenmin \tex_righthyphenmin:D + \__expl_primitive:NN \leftskip \tex_leftskip:D + \__expl_primitive:NN \rightskip \tex_rightskip:D + \__expl_primitive:NN \looseness \tex_looseness:D + \__expl_primitive:NN \parskip \tex_parskip:D + \__expl_primitive:NN \parindent \tex_parindent:D + \__expl_primitive:NN \uchyph \tex_uchyph:D + \__expl_primitive:NN \emergencystretch \tex_emergencystretch:D + \__expl_primitive:NN \pretolerance \tex_pretolerance:D + \__expl_primitive:NN \tolerance \tex_tolerance:D + \__expl_primitive:NN \spaceskip \tex_spaceskip:D + \__expl_primitive:NN \xspaceskip \tex_xspaceskip:D + \__expl_primitive:NN \parfillskip \tex_parfillskip:D + \__expl_primitive:NN \everypar \tex_everypar:D + \__expl_primitive:NN \prevgraf \tex_prevgraf:D + \__expl_primitive:NN \spacefactor \tex_spacefactor:D + \__expl_primitive:NN \shipout \tex_shipout:D + \__expl_primitive:NN \vsize \tex_vsize:D + \__expl_primitive:NN \interlinepenalty \tex_interlinepenalty:D + \__expl_primitive:NN \brokenpenalty \tex_brokenpenalty:D + \__expl_primitive:NN \topskip \tex_topskip:D + \__expl_primitive:NN \maxdeadcycles \tex_maxdeadcycles:D + \__expl_primitive:NN \maxdepth \tex_maxdepth:D + \__expl_primitive:NN \output \tex_output:D + \__expl_primitive:NN \deadcycles \tex_deadcycles:D + \__expl_primitive:NN \pagedepth \tex_pagedepth:D + \__expl_primitive:NN \pagestretch \tex_pagestretch:D + \__expl_primitive:NN \pagefilstretch \tex_pagefilstretch:D + \__expl_primitive:NN \pagefillstretch \tex_pagefillstretch:D + \__expl_primitive:NN \pagefilllstretch \tex_pagefilllstretch:D + \__expl_primitive:NN \pageshrink \tex_pageshrink:D + \__expl_primitive:NN \pagegoal \tex_pagegoal:D + \__expl_primitive:NN \pagetotal \tex_pagetotal:D + \__expl_primitive:NN \outputpenalty \tex_outputpenalty:D + \__expl_primitive:NN \hoffset \tex_hoffset:D + \__expl_primitive:NN \voffset \tex_voffset:D + \__expl_primitive:NN \insert \tex_insert:D + \__expl_primitive:NN \holdinginserts \tex_holdinginserts:D + \__expl_primitive:NN \floatingpenalty \tex_floatingpenalty:D + \__expl_primitive:NN \insertpenalties \tex_insertpenalties:D + \__expl_primitive:NN \lower \tex_lower:D + \__expl_primitive:NN \moveleft \tex_moveleft:D + \__expl_primitive:NN \moveright \tex_moveright:D + \__expl_primitive:NN \raise \tex_raise:D + \__expl_primitive:NN \copy \tex_copy:D + \__expl_primitive:NN \lastbox \tex_lastbox:D + \__expl_primitive:NN \vsplit \tex_vsplit:D + \__expl_primitive:NN \unhbox \tex_unhbox:D + \__expl_primitive:NN \unhcopy \tex_unhcopy:D + \__expl_primitive:NN \unvbox \tex_unvbox:D + \__expl_primitive:NN \unvcopy \tex_unvcopy:D + \__expl_primitive:NN \setbox \tex_setbox:D + \__expl_primitive:NN \hbox \tex_hbox:D + \__expl_primitive:NN \vbox \tex_vbox:D + \__expl_primitive:NN \vtop \tex_vtop:D + \__expl_primitive:NN \prevdepth \tex_prevdepth:D + \__expl_primitive:NN \badness \tex_badness:D + \__expl_primitive:NN \hbadness \tex_hbadness:D + \__expl_primitive:NN \vbadness \tex_vbadness:D + \__expl_primitive:NN \hfuzz \tex_hfuzz:D + \__expl_primitive:NN \vfuzz \tex_vfuzz:D + \__expl_primitive:NN \overfullrule \tex_overfullrule:D + \__expl_primitive:NN \boxmaxdepth \tex_boxmaxdepth:D + \__expl_primitive:NN \splitmaxdepth \tex_splitmaxdepth:D + \__expl_primitive:NN \splittopskip \tex_splittopskip:D + \__expl_primitive:NN \everyhbox \tex_everyhbox:D + \__expl_primitive:NN \everyvbox \tex_everyvbox:D + \__expl_primitive:NN \nullfont \tex_nullfont:D + \__expl_primitive:NN \textfont \tex_textfont:D + \__expl_primitive:NN \scriptfont \tex_scriptfont:D + \__expl_primitive:NN \scriptscriptfont \tex_scriptscriptfont:D + \__expl_primitive:NN \fontdimen \tex_fontdimen:D + \__expl_primitive:NN \hyphenchar \tex_hyphenchar:D + \__expl_primitive:NN \skewchar \tex_skewchar:D + \__expl_primitive:NN \defaulthyphenchar \tex_defaulthyphenchar:D + \__expl_primitive:NN \defaultskewchar \tex_defaultskewchar:D + \__expl_primitive:NN \number \tex_number:D + \__expl_primitive:NN \romannumeral \tex_romannumeral:D + \__expl_primitive:NN \string \tex_string:D + \__expl_primitive:NN \lowercase \tex_lowercase:D + \__expl_primitive:NN \uppercase \tex_uppercase:D + \__expl_primitive:NN \meaning \tex_meaning:D + \__expl_primitive:NN \penalty \tex_penalty:D + \__expl_primitive:NN \unpenalty \tex_unpenalty:D + \__expl_primitive:NN \lastpenalty \tex_lastpenalty:D + \__expl_primitive:NN \special \tex_special:D + \__expl_primitive:NN \dump \tex_dump:D + \__expl_primitive:NN \patterns \tex_patterns:D + \__expl_primitive:NN \hyphenation \tex_hyphenation:D + \__expl_primitive:NN \time \tex_time:D + \__expl_primitive:NN \day \tex_day:D + \__expl_primitive:NN \month \tex_month:D + \__expl_primitive:NN \year \tex_year:D + \__expl_primitive:NN \jobname \tex_jobname:D + \__expl_primitive:NN \everyjob \tex_everyjob:D + \__expl_primitive:NN \count \tex_count:D + \__expl_primitive:NN \dimen \tex_dimen:D + \__expl_primitive:NN \skip \tex_skip:D + \__expl_primitive:NN \toks \tex_toks:D + \__expl_primitive:NN \muskip \tex_muskip:D + \__expl_primitive:NN \box \tex_box:D + \__expl_primitive:NN \wd \tex_wd:D + \__expl_primitive:NN \ht \tex_ht:D + \__expl_primitive:NN \dp \tex_dp:D + \__expl_primitive:NN \catcode \tex_catcode:D + \__expl_primitive:NN \delcode \tex_delcode:D + \__expl_primitive:NN \sfcode \tex_sfcode:D + \__expl_primitive:NN \lccode \tex_lccode:D + \__expl_primitive:NN \uccode \tex_uccode:D + \__expl_primitive:NN \mathcode \tex_mathcode:D % \end{macrocode} % Since \LaTeX3 requires at least the \eTeX{} extensions, % we also rename the additional primitives. These are all % given the prefix |\etex_|. % \begin{macrocode} - \name_primitive:NN \ifdefined \etex_ifdefined:D - \name_primitive:NN \ifcsname \etex_ifcsname:D - \name_primitive:NN \unless \etex_unless:D - \name_primitive:NN \eTeXversion \etex_eTeXversion:D - \name_primitive:NN \eTeXrevision \etex_eTeXrevision:D - \name_primitive:NN \marks \etex_marks:D - \name_primitive:NN \topmarks \etex_topmarks:D - \name_primitive:NN \firstmarks \etex_firstmarks:D - \name_primitive:NN \botmarks \etex_botmarks:D - \name_primitive:NN \splitfirstmarks \etex_splitfirstmarks:D - \name_primitive:NN \splitbotmarks \etex_splitbotmarks:D - \name_primitive:NN \unexpanded \etex_unexpanded:D - \name_primitive:NN \detokenize \etex_detokenize:D - \name_primitive:NN \scantokens \etex_scantokens:D - \name_primitive:NN \showtokens \etex_showtokens:D - \name_primitive:NN \readline \etex_readline:D - \name_primitive:NN \tracingassigns \etex_tracingassigns:D - \name_primitive:NN \tracingscantokens \etex_tracingscantokens:D - \name_primitive:NN \tracingnesting \etex_tracingnesting:D - \name_primitive:NN \tracingifs \etex_tracingifs:D - \name_primitive:NN \currentiflevel \etex_currentiflevel:D - \name_primitive:NN \currentifbranch \etex_currentifbranch:D - \name_primitive:NN \currentiftype \etex_currentiftype:D - \name_primitive:NN \tracinggroups \etex_tracinggroups:D - \name_primitive:NN \currentgrouplevel \etex_currentgrouplevel:D - \name_primitive:NN \currentgrouptype \etex_currentgrouptype:D - \name_primitive:NN \showgroups \etex_showgroups:D - \name_primitive:NN \showifs \etex_showifs:D - \name_primitive:NN \interactionmode \etex_interactionmode:D - \name_primitive:NN \lastnodetype \etex_lastnodetype:D - \name_primitive:NN \iffontchar \etex_iffontchar:D - \name_primitive:NN \fontcharht \etex_fontcharht:D - \name_primitive:NN \fontchardp \etex_fontchardp:D - \name_primitive:NN \fontcharwd \etex_fontcharwd:D - \name_primitive:NN \fontcharic \etex_fontcharic:D - \name_primitive:NN \parshapeindent \etex_parshapeindent:D - \name_primitive:NN \parshapelength \etex_parshapelength:D - \name_primitive:NN \parshapedimen \etex_parshapedimen:D - \name_primitive:NN \numexpr \etex_numexpr:D - \name_primitive:NN \dimexpr \etex_dimexpr:D - \name_primitive:NN \glueexpr \etex_glueexpr:D - \name_primitive:NN \muexpr \etex_muexpr:D - \name_primitive:NN \gluestretch \etex_gluestretch:D - \name_primitive:NN \glueshrink \etex_glueshrink:D - \name_primitive:NN \gluestretchorder \etex_gluestretchorder:D - \name_primitive:NN \glueshrinkorder \etex_glueshrinkorder:D - \name_primitive:NN \gluetomu \etex_gluetomu:D - \name_primitive:NN \mutoglue \etex_mutoglue:D - \name_primitive:NN \lastlinefit \etex_lastlinefit:D - \name_primitive:NN \interlinepenalties \etex_interlinepenalties:D - \name_primitive:NN \clubpenalties \etex_clubpenalties:D - \name_primitive:NN \widowpenalties \etex_widowpenalties:D - \name_primitive:NN \displaywidowpenalties \etex_displaywidowpenalties:D - \name_primitive:NN \middle \etex_middle:D - \name_primitive:NN \savinghyphcodes \etex_savinghyphcodes:D - \name_primitive:NN \savingvdiscards \etex_savingvdiscards:D - \name_primitive:NN \pagediscards \etex_pagediscards:D - \name_primitive:NN \splitdiscards \etex_splitdiscards:D - \name_primitive:NN \TeXXeTstate \etex_TeXXeTstate:D - \name_primitive:NN \beginL \etex_beginL:D - \name_primitive:NN \endL \etex_endL:D - \name_primitive:NN \beginR \etex_beginR:D - \name_primitive:NN \endR \etex_endR:D - \name_primitive:NN \predisplaydirection \etex_predisplaydirection:D - \name_primitive:NN \everyeof \etex_everyeof:D - \name_primitive:NN \protected \etex_protected:D + \__expl_primitive:NN \ifdefined \etex_ifdefined:D + \__expl_primitive:NN \ifcsname \etex_ifcsname:D + \__expl_primitive:NN \unless \etex_unless:D + \__expl_primitive:NN \eTeXversion \etex_eTeXversion:D + \__expl_primitive:NN \eTeXrevision \etex_eTeXrevision:D + \__expl_primitive:NN \marks \etex_marks:D + \__expl_primitive:NN \topmarks \etex_topmarks:D + \__expl_primitive:NN \firstmarks \etex_firstmarks:D + \__expl_primitive:NN \botmarks \etex_botmarks:D + \__expl_primitive:NN \splitfirstmarks \etex_splitfirstmarks:D + \__expl_primitive:NN \splitbotmarks \etex_splitbotmarks:D + \__expl_primitive:NN \unexpanded \etex_unexpanded:D + \__expl_primitive:NN \detokenize \etex_detokenize:D + \__expl_primitive:NN \scantokens \etex_scantokens:D + \__expl_primitive:NN \showtokens \etex_showtokens:D + \__expl_primitive:NN \readline \etex_readline:D + \__expl_primitive:NN \tracingassigns \etex_tracingassigns:D + \__expl_primitive:NN \tracingscantokens \etex_tracingscantokens:D + \__expl_primitive:NN \tracingnesting \etex_tracingnesting:D + \__expl_primitive:NN \tracingifs \etex_tracingifs:D + \__expl_primitive:NN \currentiflevel \etex_currentiflevel:D + \__expl_primitive:NN \currentifbranch \etex_currentifbranch:D + \__expl_primitive:NN \currentiftype \etex_currentiftype:D + \__expl_primitive:NN \tracinggroups \etex_tracinggroups:D + \__expl_primitive:NN \currentgrouplevel \etex_currentgrouplevel:D + \__expl_primitive:NN \currentgrouptype \etex_currentgrouptype:D + \__expl_primitive:NN \showgroups \etex_showgroups:D + \__expl_primitive:NN \showifs \etex_showifs:D + \__expl_primitive:NN \interactionmode \etex_interactionmode:D + \__expl_primitive:NN \lastnodetype \etex_lastnodetype:D + \__expl_primitive:NN \iffontchar \etex_iffontchar:D + \__expl_primitive:NN \fontcharht \etex_fontcharht:D + \__expl_primitive:NN \fontchardp \etex_fontchardp:D + \__expl_primitive:NN \fontcharwd \etex_fontcharwd:D + \__expl_primitive:NN \fontcharic \etex_fontcharic:D + \__expl_primitive:NN \parshapeindent \etex_parshapeindent:D + \__expl_primitive:NN \parshapelength \etex_parshapelength:D + \__expl_primitive:NN \parshapedimen \etex_parshapedimen:D + \__expl_primitive:NN \numexpr \etex_numexpr:D + \__expl_primitive:NN \dimexpr \etex_dimexpr:D + \__expl_primitive:NN \glueexpr \etex_glueexpr:D + \__expl_primitive:NN \muexpr \etex_muexpr:D + \__expl_primitive:NN \gluestretch \etex_gluestretch:D + \__expl_primitive:NN \glueshrink \etex_glueshrink:D + \__expl_primitive:NN \gluestretchorder \etex_gluestretchorder:D + \__expl_primitive:NN \glueshrinkorder \etex_glueshrinkorder:D + \__expl_primitive:NN \gluetomu \etex_gluetomu:D + \__expl_primitive:NN \mutoglue \etex_mutoglue:D + \__expl_primitive:NN \lastlinefit \etex_lastlinefit:D + \__expl_primitive:NN \interlinepenalties \etex_interlinepenalties:D + \__expl_primitive:NN \clubpenalties \etex_clubpenalties:D + \__expl_primitive:NN \widowpenalties \etex_widowpenalties:D + \__expl_primitive:NN \displaywidowpenalties \etex_displaywidowpenalties:D + \__expl_primitive:NN \middle \etex_middle:D + \__expl_primitive:NN \savinghyphcodes \etex_savinghyphcodes:D + \__expl_primitive:NN \savingvdiscards \etex_savingvdiscards:D + \__expl_primitive:NN \pagediscards \etex_pagediscards:D + \__expl_primitive:NN \splitdiscards \etex_splitdiscards:D + \__expl_primitive:NN \TeXXeTstate \etex_TeXXeTstate:D + \__expl_primitive:NN \beginL \etex_beginL:D + \__expl_primitive:NN \endL \etex_endL:D + \__expl_primitive:NN \beginR \etex_beginR:D + \__expl_primitive:NN \endR \etex_endR:D + \__expl_primitive:NN \predisplaydirection \etex_predisplaydirection:D + \__expl_primitive:NN \everyeof \etex_everyeof:D + \__expl_primitive:NN \protected \etex_protected:D % \end{macrocode} % The newer primitives are more complex: there are an awful lot of them, % and we don't use them all at the moment. So the following is selective. @@ -561,43 +561,43 @@ % there are a lot of \pdfTeX{} primitives that start \cs{pdf\ldots} but % are not related to PDF output. These ones related to PDF output. % \begin{macrocode} - \name_primitive:NN \pdfcreationdate \pdftex_pdfcreationdate:D - \name_primitive:NN \pdfcolorstack \pdftex_pdfcolorstack:D - \name_primitive:NN \pdfcompresslevel \pdftex_pdfcompresslevel:D - \name_primitive:NN \pdfdecimaldigits \pdftex_pdfdecimaldigits:D - \name_primitive:NN \pdfhorigin \pdftex_pdfhorigin:D - \name_primitive:NN \pdfinfo \pdftex_pdfinfo:D - \name_primitive:NN \pdflastxform \pdftex_pdflastxform:D - \name_primitive:NN \pdfliteral \pdftex_pdfliteral:D - \name_primitive:NN \pdfminorversion \pdftex_pdfminorversion:D - \name_primitive:NN \pdfobjcompresslevel \pdftex_pdfobjcompresslevel:D - \name_primitive:NN \pdfoutput \pdftex_pdfoutput:D - \name_primitive:NN \pdfrefxform \pdftex_pdfrefxform:D - \name_primitive:NN \pdfrestore \pdftex_pdfrestore:D - \name_primitive:NN \pdfsave \pdftex_pdfsave:D - \name_primitive:NN \pdfsetmatrix \pdftex_pdfsetmatrix:D - \name_primitive:NN \pdfpkresolution \pdftex_pdfpkresolution:D - \name_primitive:NN \pdftexrevision \pdftex_pdftextrevision:D - \name_primitive:NN \pdfvorigin \pdftex_pdfvorigin:D - \name_primitive:NN \pdfxform \pdftex_pdfxform:D + \__expl_primitive:NN \pdfcreationdate \pdftex_pdfcreationdate:D + \__expl_primitive:NN \pdfcolorstack \pdftex_pdfcolorstack:D + \__expl_primitive:NN \pdfcompresslevel \pdftex_pdfcompresslevel:D + \__expl_primitive:NN \pdfdecimaldigits \pdftex_pdfdecimaldigits:D + \__expl_primitive:NN \pdfhorigin \pdftex_pdfhorigin:D + \__expl_primitive:NN \pdfinfo \pdftex_pdfinfo:D + \__expl_primitive:NN \pdflastxform \pdftex_pdflastxform:D + \__expl_primitive:NN \pdfliteral \pdftex_pdfliteral:D + \__expl_primitive:NN \pdfminorversion \pdftex_pdfminorversion:D + \__expl_primitive:NN \pdfobjcompresslevel \pdftex_pdfobjcompresslevel:D + \__expl_primitive:NN \pdfoutput \pdftex_pdfoutput:D + \__expl_primitive:NN \pdfrefxform \pdftex_pdfrefxform:D + \__expl_primitive:NN \pdfrestore \pdftex_pdfrestore:D + \__expl_primitive:NN \pdfsave \pdftex_pdfsave:D + \__expl_primitive:NN \pdfsetmatrix \pdftex_pdfsetmatrix:D + \__expl_primitive:NN \pdfpkresolution \pdftex_pdfpkresolution:D + \__expl_primitive:NN \pdftexrevision \pdftex_pdftextrevision:D + \__expl_primitive:NN \pdfvorigin \pdftex_pdfvorigin:D + \__expl_primitive:NN \pdfxform \pdftex_pdfxform:D % \end{macrocode} % While these are not. % \begin{macrocode} - \name_primitive:NN \pdfstrcmp \pdftex_strcmp:D + \__expl_primitive:NN \pdfstrcmp \pdftex_strcmp:D % \end{macrocode} % \XeTeX{}-specific primitives. Note that \XeTeX{}'s \tn{strcmp} is % handled earlier and is \enquote{rolled up} into \tn{pdfstrcmp}. % \begin{macrocode} - \name_primitive:NN \XeTeXversion \xetex_XeTeXversion:D + \__expl_primitive:NN \XeTeXversion \xetex_XeTeXversion:D % \end{macrocode} % Primitives from \LuaTeX{}. % \begin{macrocode} - \name_primitive:NN \catcodetable \luatex_catcodetable:D - \name_primitive:NN \directlua \luatex_directlua:D - \name_primitive:NN \initcatcodetable \luatex_initcatcodetable:D - \name_primitive:NN \latelua \luatex_latelua:D - \name_primitive:NN \luatexversion \luatex_luatexversion:D - \name_primitive:NN \savecatcodetable \luatex_savecatcodetable:D + \__expl_primitive:NN \catcodetable \luatex_catcodetable:D + \__expl_primitive:NN \directlua \luatex_directlua:D + \__expl_primitive:NN \initcatcodetable \luatex_initcatcodetable:D + \__expl_primitive:NN \latelua \luatex_latelua:D + \__expl_primitive:NN \luatexversion \luatex_luatexversion:D + \__expl_primitive:NN \savecatcodetable \luatex_savecatcodetable:D % \end{macrocode} % The job is done: close the group (using the primitive renamed!). % \begin{macrocode} @@ -612,7 +612,7 @@ \tex_let:D \tex_everymath:D \frozen@everymath \tex_let:D \tex_hyphen:D \@@hyph \tex_let:D \tex_input:D \@@input -\tex_let:D \tex_italic_correction:D \@@italiccorr +\tex_let:D \tex_italiccorrection:D \@@italiccorr \tex_let:D \tex_underline:D \@@underline % \end{macrocode} % That is also true for the \pkg{luatex} package for \LaTeXe{}. diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx index 88f53e59759..6d4fb15351d 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3prg.dtx Copyright (C) 2005-2011 The LaTeX3 Project +%% File: l3prg.dtx Copyright (C) 2005-2012 The LaTeX3 Project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3prg.dtx 3490 2012-03-04 01:00:53Z bruno $ - {L3 Experimental control structures} +\GetIdInfo$Id: l3prg.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Control structures} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -78,13 +78,13 @@ % \LaTeX3 has two forms of conditional flow processing based % on these states. The firs form is predicate functions that turn the % returned state into a boolean \meta{true} or \meta{false}. For -% example, the function |\cs_if_free_p:N| checks whether the control +% example, the function \cs{cs_if_free_p:N} checks whether the control % sequence given as its argument is free and then returns the boolean % \meta{true} or \meta{false} values to be used in testing with -% |\if_predicate:w| or in functions to be described below. The second form +% \cs{if_predicate:w} or in functions to be described below. The second form % is the kind of functions choosing a particular argument from the % input stream based on the result of the testing as in -% |\cs_if_free:NTF| which also takes one argument (the |N|) and then +% \cs{cs_if_free:NTF} which also takes one argument (the |N|) and then % executes either \texttt{true} or \texttt{false} depending on the % result. Important to note here is that the arguments are executed % after exiting the underlying |\if...\fi:| structure. @@ -182,13 +182,13 @@ % This defines the function |\foo_if_bar_p:NN|, |\foo_if_bar:NNTF| and % |\foo_if_bar:NNT| but not |\foo_if_bar:NNF| (because |F| is missing % from the \meta{conditions} list). The return statements take care of -% resolving the remaining |\else:| and |\fi:| before returning the +% resolving the remaining \cs{else:} and \cs{fi:} before returning the % state. There must be a return statement for each branch, failing to do % so will result in an error if that branch is executed. % % \begin{function}{\prg_new_eq_conditional:NNn, \prg_set_eq_conditional:NNn} % \begin{syntax} -% \cs{prg_new_eq_conditional:NNn} \cs{\meta{name1}:\meta{arg spec1}} \cs{\meta{name2}:\meta{arg spec2}} \Arg{conditions} +% \cs{prg_new_eq_conditional:NNn} \cs{\meta{name_1}:\meta{arg spec_1}} \cs{\meta{name_2}:\meta{arg spec_2}} \Arg{conditions} % \end{syntax} % These functions copies a family of conditionals. The \texttt{new} version % will check for existing definitions (\emph{cf.}~\cs{cs_new:Npn}) whereas @@ -214,12 +214,12 @@ % connected to conditional processing as sometimes you want to % execute some code depending on the value of a switch % (\emph{e.g.},~draft/final) and other times you perhaps want to use it as a -% predicate function in an |\if_predicate:w| test. The problem of the -% primitive |\if_false:| and |\if_true:| tokens is that it is not +% predicate function in an \cs{if_predicate:w} test. The problem of the +% primitive \cs{if_false:} and \cs{if_true:} tokens is that it is not % always safe to pass them around as they may interfere with scanning % for termination of primitive conditional processing. Therefore, we -% employ two canonical booleans: |\c_true_bool| or -% |\c_false_bool|. Besides preventing problems as described above, it +% employ two canonical booleans: \cs{c_true_bool} or +% \cs{c_false_bool}. Besides preventing problems as described above, it % also allows us to implement a simple boolean parser supporting the % logical operations And, Or, Not, \emph{etc.}\ which can then be used on % both the boolean type and predicate functions. @@ -265,12 +265,12 @@ % \bool_gset_eq:NN, \bool_gset_eq:cN, \bool_gset_eq:Nc, \bool_gset_eq:cc % } % \begin{syntax} -% \cs{bool_set_eq:NN} \meta{boolean1} \meta{boolean2} +% \cs{bool_set_eq:NN} \meta{boolean_1} \meta{boolean_2} % \end{syntax} -% Sets the content of \meta{boolean1} equal to that of \meta{boolean2}. +% Sets the content of \meta{boolean_1} equal to that of \meta{boolean_2}. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2012-07-08] % {\bool_set:Nn, \bool_set:cn, \bool_gset:Nn, \bool_gset:cn} % \begin{syntax} % \cs{bool_set:Nn} \meta{boolean} \Arg{boolexpr} @@ -296,7 +296,7 @@ % Displays the logical truth of the \meta{boolean} on the terminal. % \end{function} % -% \begin{function}[added = 2012-02-09]{\bool_show:n} +% \begin{function}[added = 2012-02-09, updated = 2012-07-08]{\bool_show:n} % \begin{syntax} % \cs{bool_show:n} \Arg{boolean expression} % \end{syntax} @@ -314,14 +314,14 @@ % check that the \meta{boolean} really is a boolean variable. % \end{function} % -% \begin{variable}{\l_tmpa_bool} +% \begin{variable}{\l_tmpa_bool, \l_tmpb_bool} % A scratch boolean for local assignment. It is never used by % the kernel code, and so is safe for use with any \LaTeX3-defined % function. However, it may be overwritten by other non-kernel % code and so should only be used for short-term storage. % \end{variable} % -% \begin{variable}{\g_tmpa_bool} +% \begin{variable}{\g_tmpa_bool, \g_tmpb_bool} % A scratch boolean for global assignment. It is never used by % the kernel code, and so is safe for use with any \LaTeX3-defined % function. However, it may be overwritten by other non-kernel @@ -337,7 +337,8 @@ % A boolean expression is an expression which given input in the form % of predicate functions and boolean variables, return boolean % \meta{true} or \meta{false}. It supports the logical operations And, -% Or and Not as the well-known infix operators |&&|, \verb"||" and |!|. In +% Or and Not as the well-known infix operators |&&|, \verb"||" and |!| +% with their usual precedences. In % addition to this, parentheses can be used to isolate % sub-expressions. For example, % \begin{verbatim} @@ -354,7 +355,7 @@ % be changed any more, the remaining tests within the current group % are skipped. % -% \begin{function}[EXP,pTF]{\bool_if:n} +% \begin{function}[EXP, pTF, updated = 2012-07-08]{\bool_if:n} % \begin{syntax} % \cs{bool_if_p:n} \Arg{boolean expression} % \cs{bool_if:nTF} \Arg{boolean expression} \Arg{true code} \Arg{false code} @@ -367,7 +368,7 @@ % |!| (\enquote{Not}) and parentheses. Minimal evaluation is used % in the processing, so that once a result is defined there is % not further expansion of the tests. For example -% \begin{verbatim} +% \begin{verbatim} % \bool_if_p:n % { % \int_compare_p:nNn { 1 } = { 1 } @@ -378,17 +379,15 @@ % \int_compare_p:nNn { 1 } = { \error } % is skipped % ) % && -% ! ( \int_compare_p:nNn { 2 } = { 4 } ) +% ! \int_compare_p:nNn { 2 } = { 4 } % } % \end{verbatim} % will be \texttt{true} and will not evaluate % |\int_compare_p:nNn { 1 } = { \error }|. The logical Not applies to -% the next single predicate or group. As shown above, this means that -% any predicates requiring an argument have to be given within -% parentheses. +% the next predicate or group. % \end{function} % -% \begin{function}[EXP]{\bool_not_p:n} +% \begin{function}[EXP, updated = 2012-07-08]{\bool_not_p:n} % \begin{syntax} % \cs{bool_not_p:n} \Arg{boolean expression} % \end{syntax} @@ -396,9 +395,9 @@ % expression. % \end{function} % -% \begin{function}[EXP]{\bool_xor_p:nn} +% \begin{function}[EXP, updated = 2012-07-08]{\bool_xor_p:nn} % \begin{syntax} -% \cs{bool_xor_p:nn} \Arg{boolexpr_1} \Arg{boolexpr_1} +% \cs{bool_xor_p:nn} \Arg{boolexpr_1} \Arg{boolexpr_2} % \end{syntax} % Implements an \enquote{exclusive or} operation between two boolean % expressions. There is no infix operation for this logical @@ -431,7 +430,7 @@ % until the \meta{boolean} is \texttt{false}. % \end{function} % -% \begin{function}[rEXP]{\bool_until_do:nn} +% \begin{function}[rEXP, updated = 2012-07-08]{\bool_until_do:nn} % \begin{syntax} % \cs{bool_until_do:nn} \Arg{boolean expression} \Arg{code} % \end{syntax} @@ -443,7 +442,7 @@ % then loop until the \meta{boolean expression} is \texttt{true}. % \end{function} % -% \begin{function}[rEXP]{\bool_while_do:nn} +% \begin{function}[rEXP, updated = 2012-07-08]{\bool_while_do:nn} % \begin{syntax} % \cs{bool_while_do:nn} \Arg{boolean expression} \Arg{code} % \end{syntax} @@ -455,109 +454,6 @@ % then loop until the \meta{boolean expression} is \texttt{false}. % \end{function} % -% \section{Switching by case} -% -% For cases where a number of cases need to be considered a family of -% case-selecting functions are available. -% -% \begin{function}[updated = 2011-09-17, EXP]{\prg_case_int:nnn} -% \begin{syntax} -% \cs{prg_case_int:nnn} \Arg{test integer expression} \\ -% ~~|{| \\ -% ~~~~\Arg{intexpr case1} \Arg{code case1} \\ -% ~~~~\Arg{intexpr case2} \Arg{code case2} \\ -% ~~~~\ldots \\ -% ~~~~\Arg{intexpr case$\sb{n}$} \Arg{code case$\sb{n}$} \\ -% ~~|}| \\ -% ~~\Arg{else case} -% \end{syntax} -% This function evaluates the \meta{test integer expression} and -% compares this in turn to each of the -% \meta{integer expression cases}. If the two are equal then the -% associated \meta{code} is left in the input stream. If none of -% the tests are \texttt{true} then the \texttt{else code} will be -% left in the input stream. -% \end{function} -% -% As an example of \cs{prg_case_int:nnn}: -% \begin{verbatim} -% \prg_case_int:nnn -% { 2 * 5 } -% { -% { 5 } { Small } -% { 4 + 6 } { Medium } -% { -2 * 10 } { Negative } -% } -% { No idea! } -% \end{verbatim} -% will leave \enquote{\texttt{Medium}} in the input stream. -% -% \begin{function}[updated = 2011-07-06, EXP]{\prg_case_dim:nnn} -% \begin{syntax} -% \cs{prg_case_dim:nnn} \Arg{test dimension expression} \\ -% ~~|{| \\ -% ~~~~\Arg{dimexpr case1} \Arg{code case1} \\ -% ~~~~\Arg{dimexpr case2} \Arg{code case2} \\ -% ~~~~\ldots \\ -% ~~~~\Arg{dimexpr case$\sb{n}$} \Arg{code case$\sb{n}$} \\ -% ~~|}| \\ -% ~~\Arg{else case} -% \end{syntax} -% This function evaluates the \meta{test dimension expression} and -% compares this in turn to each of the -% \meta{dimension expression cases}. If the two are equal then the -% associated \meta{code} is left in the input stream. If none of -% the tests are \texttt{true} then the \texttt{else code} will be -% left in the input stream. -% \end{function} -% -% \begin{function}[updated = 2011-09-17, EXP] -% {\prg_case_str:nnn, \prg_case_str:onn, \prg_case_str:xxn} -% \begin{syntax} -% \cs{prg_case_str:nnn} \Arg{test string} \\ -% ~~|{| \\ -% ~~~~\Arg{string case1} \Arg{code case1} \\ -% ~~~~\Arg{string case2} \Arg{code case2} \\ -% ~~~~\ldots \\ -% ~~~~\Arg{string case$\sb{n}$} \Arg{code case$\sb{n}$} \\ -% ~~|}| \\ -% ~~\Arg{else case} -% \end{syntax} -% This function compares the \meta{test string} in turn with each -% of the \meta{string cases}. If the two are equal (as described for -% \cs{str_if_eq:nnTF} then the -% associated \meta{code} is left in the input stream. If none of -% the tests are \texttt{true} then the \texttt{else code} will be -% left in the input stream. The |xx| variant fully expands -% \meta{strings} before comparing them, but does not expand the -% corresponding \meta{code}. It is fully expandable, in the same way -% as the underlying \cs{str_if_eq:xxTF} test. -%^^A The \meta{test string} is expanded in each comparison, and must -%^^A always yield the same result: in particular, random numbers should -%^^A not be used within this string. -% \end{function} -% -% \begin{function}[updated = 2011-09-17, EXP] -% {\prg_case_tl:Nnn, \prg_case_tl:cnn} -% \begin{syntax} -% \cs{prg_case_tl:Nnn} \meta{test token list variable} \\ -% ~~"{" \\ -% ~~~~\meta{token list variable case1} \Arg{code case1} \\ -% ~~~~\meta{token list variable case2} \Arg{code case2} \\ -% ~~~~\ldots \\ -% ~~~~\meta{token list variable case$\sb{n}$} \Arg{code case$\sb{n}$} \\ -% ~~"}" \\ -% ~~\Arg{else case} -% \end{syntax} -% This function compares the \meta{test token list variable} in turn -% with each of the \meta{token list variable cases}. If the two -% are equal (as described for -% \cs{tl_if_eq:nnTF} -% then the associated \meta{code} is left in the input -% stream. If none of the tests are \texttt{true} then the -% \texttt{else code} will be left in the input stream. -% \end{function} -% % \section{Producing $n$ copies} % % \begin{function}[updated = 2011-07-04, EXP]{\prg_replicate:nn} @@ -570,54 +466,6 @@ % nesting. It yields its result after two expansion steps. % \end{function} % -% \begin{function}[updated = 2011-09-06,rEXP]{\prg_stepwise_function:nnnN} -% \begin{syntax} -% \cs{prg_stepwise_function:nnnN} \Arg{initial value} \Arg{step} \Arg{final value} \meta{function} -% \end{syntax} -% This function first evaluates the \meta{initial value}, \meta{step} -% and \meta{final value}, all of which should be integer expressions. -% The \meta{function} is then placed in front of each \meta{value} -% from the \meta{initial value} to the \meta{final value} in turn -% (using \meta{step} between each \meta{value}). Thus \meta{function} -% should absorb one numerical argument. For example -% \begin{verbatim} -% \cs_set:Npn \my_func:n #1 { [I~saw~#1] \quad } -% \prg_stepwise_function:nnnN { 1 } { 1 } { 5 } \my_func:n -% \end{verbatim} -% would print -% \begin{quote} -% [I saw 1] \quad -% [I saw 2] \quad -% [I saw 3] \quad -% [I saw 4] \quad -% [I saw 5] \quad -% \end{quote} -% \end{function} -% -% \begin{function}[updated = 2011-09-06]{\prg_stepwise_inline:nnnn} -% \begin{syntax} -% \cs{prg_stepwise_inline:nnnn} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code} -% \end{syntax} -% This function first evaluates the \meta{initial value}, \meta{step} -% and \meta{final value}, all of which should be integer expressions. -% The \meta{code} is then placed in front of each \meta{value} -% from the \meta{initial value} to the \meta{final value} in turn -% (using \meta{step} between each \meta{value}). Thus the \meta{code} -% should define a function of one argument (|#1|). -% \end{function} -% -% \begin{function}[updated = 2011-09-06]{\prg_stepwise_variable:nnnNn} -% \begin{syntax} -% \cs{prg_stepwise_variable:nnnNn} \\ -% ~~\Arg{initial value} \Arg{step} \Arg{final value} \meta{tl~var} \Arg{code} -% \end{syntax} -% This function first evaluates the \meta{initial value}, \meta{step} -% and \meta{final value}, all of which should be integer expressions. -% The \meta{code} is inserted into the input stream, with the -% \meta{tl~var} defined as the current \meta{value}. Thus the -% \meta{code} should make use of the \meta{tl~var}. -% \end{function} -% % \section{Detecting \TeX{}'s mode} % % \begin{function}[EXP,pTF]{\mode_if_horizontal:} @@ -651,6 +499,26 @@ % Detects if \TeX{} is currently in vertical mode. % \end{function} % +% \section{Primitive conditionals} +% +% \begin{function}[EXP]{\if_predicate:w} +% \begin{syntax} +% "\if_predicate:w" <predicate> <true code> "\else:" <false code> "\fi:" +% \end{syntax} +% This function takes a predicate function and +% branches according to the result. (In practice this function would also +% accept a single boolean variable in place of the <predicate> but to make the +% coding clearer this should be done through "\if_bool:N".) +% \end{function} +% +% \begin{function}[EXP]{\if_bool:N} +% \begin{syntax} +% "\if_bool:N" <boolean> <true code> "\else:" <false code> "\fi:" +% \end{syntax} +% This function takes a boolean variable and +% branches according to the result. +% \end{function} +% % \section{Internal programming functions} % % \begin{function}[updated = 2011-08-11, EXP] @@ -692,61 +560,70 @@ % \end{texnote} % \end{function} % -% \begin{function}[EXP]{\prg_variable_get_scope:N} +% \begin{function}[EXP]{\__prg_variable_get_scope:N} % \begin{syntax} -% \cs{prg_variable_get_scope:N} \meta{variable} +% \cs{__prg_variable_get_scope:N} \meta{variable} % \end{syntax} % Returns the scope (\texttt{g} for global, blank otherwise) for the % \meta{variable}. % \end{function} % -% \begin{function}[EXP]{\prg_variable_get_type:N} +% \begin{function}[EXP]{\__prg_variable_get_type:N} % \begin{syntax} -% \cs{prg_variable_get_type:N} \meta{variable} +% \cs{__prg_variable_get_type:N} \meta{variable} % \end{syntax} % Returns the type of \meta{variable} (\texttt{tl}, \texttt{int}, % \emph{etc.}) % \end{function} % -% \begin{function}[EXP]{\if_predicate:w} +% \begin{function}[EXP]{\__prg_break_point:Nn} % \begin{syntax} -% "\if_predicate:w" <predicate> <true code> "\else:" <false code> "\fi:" +% \cs{__prg_break_point:Nn} \cs{\meta{type}_map_break:} \meta{tokens} % \end{syntax} -% This function takes a predicate function and -% branches according to the result. (In practice this function would also -% accept a single boolean variable in place of the <predicate> but to make the -% coding clearer this should be done through "\if_bool:N".) +% Used to mark the end of a recursion or mapping: the functions +% \cs{\meta{type}_map_break:} and \cs{\meta{type}_map_break:n} use +% this to break out of the loop. After the loop ends, the +% \meta{tokens} are inserted into the input stream. This occurs even +% if the the break functions are \emph{not} applied: +% \cs{__prg_break_point:Nn} is functionally-equivalent in these cases +% to \cs{use_ii:nn}. % \end{function} % -% \begin{function}[EXP]{\if_bool:N} +% \begin{function}[EXP]{\__prg_map_break:Nn} % \begin{syntax} -% "\if_bool:N" <boolean> <true code> "\else:" <false code> "\fi:" +% \cs{__prg_map_break:Nn} \cs{\meta{type}_map_break:} \Arg{user code} +% \ldots{} +% \cs{__prg_break_point:Nn} \cs{\meta{type}_map_break:} \Arg{ending code} % \end{syntax} -% This function takes a boolean variable and -% branches according to the result. +% Breaks a recursion in mapping contexts, inserting in the input +% stream the \meta{user code} after the \meta{ending code} for the +% loop. The function breaks loops, inserting their \meta{ending +% code}, until reaching a loop with the same \meta{type} as its +% first argument. This \cs{\meta{type}_map_break:} argument is simply +% used as a recognizable marker for the \meta{type}. % \end{function} % -% \begin{function}[EXP]{\prg_break_point:n} -% \begin{syntax} -% \cs{prg_break_point:n} \meta{tokens} -% \end{syntax} -% Used to mark the end of a recursion or mapping: the functions -% \cs{prg_map_break:} and \cs{prg_map_break:n} use this to break out -% of the loop. After the loop ends, the \meta{tokens} are inserted into -% the input stream. This occurs even if the the break functions are -% \emph{not} applied: \cs{prg_break_point:n} is functionally-equivalent -% in these cases to \cs{use:n}. +% \begin{variable}{\g__prg_map_int} +% This integer is used by non-expandable mapping functions to track +% the level of nesting in force. The functions \cs{__prg_map_1:w}, +% \cs{__prg_map_2:w}, \emph{etc.}, labelled by \cs{g__prg_map_int} +% hold functions to be mapped over various list datatypes in inline +% and variable mappings. +% \end{variable} +% +% \begin{function}[EXP]{\__prg_break_point:} +% This copy of \cs{prg_do_nothing:} is used to mark the end of a fast +% short-term recursions: the function \cs{__prg_break:n} uses this to +% break out of the loop. % \end{function} % -% \begin{function}[EXP]{\prg_map_break:, \prg_map_break:n} +% \begin{function}[EXP]{\__prg_break:, \__prg_break:n} % \begin{syntax} -% \cs{prg_map_break:n} \Arg{user code} -% \ldots{} -% \cs{prg_break_point:n} \Arg{ending code} +% \cs{__prg_break:n} \Arg{tokens} \ldots{} \cs{__prg_break_point:} % \end{syntax} -% Breaks a recursion in mapping contexts, inserting -% in the input stream the \meta{user code} after the -% \meta{ending code} for the loop. +% Breaks a recursion which has no \meta{ending code} and which is not +% a user-breakable mapping (see for instance \cs{prop_get:Nn}), and +% inserts \meta{tokens} in the input stream. % \end{function} % % \end{documentation} @@ -765,7 +642,7 @@ %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -815,6 +692,10 @@ % % \subsection{The boolean data type} % +% \begin{macrocode} +%<@@=bool> +% \end{macrocode} +% % \begin{macro}{\bool_new:N, \bool_new:c} % \UnitTested % Boolean variables have to be initiated when they are created. Other @@ -874,7 +755,7 @@ % \begin{macro}{\bool_set:Nn,\bool_set:cn} % \begin{macro}{\bool_gset:Nn,\bool_gset:cn} % This function evaluates a boolean expression and assigns the first -% argument the meaning |\c_true_bool| or |\c_false_bool|. +% argument the meaning \cs{c_true_bool} or \cs{c_false_bool}. % \begin{macrocode} \cs_new_protected:Npn \bool_set:Nn #1#2 { \tex_chardef:D #1 = \bool_if_p:n {#2} } @@ -884,6 +765,7 @@ \cs_generate_variant:Nn \bool_gset:Nn { c } % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro}[pTF]{\bool_if:N, \bool_if:c} % \UnitTested @@ -904,11 +786,10 @@ \cs_generate_variant:Nn \bool_if:NTF { c } % \end{macrocode} % \end{macro} -% \end{macro} % % \begin{macro}{\bool_show:N, \bool_show:c, \bool_show:n} % Show the truth value of the boolean, as \texttt{true} or -% \texttt{false}. We use \cs{msg_aux_show:x} to get a better output; +% \texttt{false}. We use \cs{__msg_show_variable:x} to get a better output; % this function requires its argument to start with |>|. % \begin{macrocode} \cs_new_protected:Npn \bool_show:N #1 @@ -916,25 +797,27 @@ \bool_if_exist:NTF #1 { \bool_show:n {#1} } { - \msg_kernel_error:nnx { kernel } { variable-not-defined } + \__msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } \cs_new_protected:Npn \bool_show:n #1 { \bool_if:nTF {#1} - { \msg_aux_show:x { > true } } - { \msg_aux_show:x { > false } } + { \__msg_show_variable:x { > true } } + { \__msg_show_variable:x { > false } } } \cs_generate_variant:Nn \bool_show:N { c } % \end{macrocode} % \end{macro} % -% \begin{variable}{\l_tmpa_bool, \g_tmpa_bool} +% \begin{variable}{\l_tmpa_bool, \l_tmpb_bool, \g_tmpa_bool, \g_tmpb_bool} % A few booleans just if you need them. % \begin{macrocode} \bool_new:N \l_tmpa_bool +\bool_new:N \l_tmpb_bool \bool_new:N \g_tmpa_bool +\bool_new:N \g_tmpb_bool % \end{macrocode} % \end{variable} % @@ -956,36 +839,12 @@ % % \begin{macro}[pTF]{\bool_if:n} % \UnitTested -% \begin{macro}[aux]{\bool_get_next:N} -% \begin{macro}[aux]{\bool_cleanup:N} -% \begin{macro}[aux]{\bool_choose:NN} -% \begin{macro}[aux] -% { -% bool_!:w, -% \bool_Not:w, -% \bool_Not:w, -% \bool_(:w, -% \bool_p:w, -% \bool_8_1:w, -% \bool_I_1:w, -% \bool_8_0:w, -% \bool_I_0:w, -% \bool_)_0:w, -% \bool_)_1:w, -% \bool_S_0:w, -% \bool_S_1:w -% } -% \begin{macro}[aux] -% { -% \bool_eval_skip_to_end:Nw, \bool_eval_skip_to_end_aux:Nw, -% \bool_eval_skip_to_end_aux_ii:Nw -% } -% Evaluating the truth value of a list of predicates is done using -% an input syntax somewhat similar to the one found in other -% programming languages with |(| and |)| for grouping, |!| for -% logical \enquote{Not}, |&&| for logical \enquote{And} and \verb"||" -% for logical \enquote{Or}. We shall use the terms Not, And, Or, Open and -% Close for these operations. +% Evaluating the truth value of a list of predicates is done using an +% input syntax somewhat similar to the one found in other programming +% languages with |(| and |)| for grouping, |!| for logical +% \enquote{Not}, |&&| for logical \enquote{And} and \verb"||" for +% logical \enquote{Or}. We shall use the terms Not, And, Or, Open and +% Close for these operations. % % Any expression is terminated by a Close operation. Evaluation % happens from left to right in the following manner using a GetNext @@ -993,16 +852,18 @@ % \begin{itemize} % \item If an Open is seen, start evaluating a new expression using % the Eval function and call GetNext again. -% \item If a Not is seen, insert a negating function (if-even in -% this case) and call GetNext. -% \item If none of the above, start evaluating a new expression by -% reinserting the token found (this is supposed to be a predicate -% function) in front of Eval. +% \item If a Not is seen, remove the |!| and call a GetNotNext +% function, which eventually reverses the logic compared to +% GetNext. +% \item If none of the above, reinsert the token found (this is +% supposed to be a predicate function) in front of an Eval +% function, which evaluates it to the boolean value \meta{true} or +% \meta{false}. % \end{itemize} % The Eval function then contains a post-processing operation which -% grabs the instruction following the predicate. This is either And, -% Or or Close. In each case the truth value is used to determine -% where to go next. The following situations can arise: +% grabs the instruction following the predicate. This is either And, +% Or or Close. In each case the truth value is used to determine +% where to go next. The following situations can arise: % \begin{description} % \item[\meta{true}And] Current truth value is true, logical And % seen, continue with GetNext to examine truth value of next @@ -1021,8 +882,8 @@ % \item[\meta{false}Close] Current truth value is false, Close % seen, return \meta{false}. % \end{description} -% We introduce an additional Stop operation with the following -% semantics: +% We introduce an additional Stop operation with the same +% semantics as the Close operation. % \begin{description} % \item[\meta{true}Stop] Current truth value is true, return % \meta{true}. @@ -1030,17 +891,6 @@ % \meta{false}. % \end{description} % The reasons for this follow below. -% -% Now for how these works in practice. The canonical true and false -% values have numerical values $1$ and $0$ respectively. We evaluate -% this using the primitive |\int_value:w:D| operation. First we -% issue a |\group_align_safe_begin:| as we are using |&&| as syntax -% shorthand for the And operation and we need to hide it for \TeX{}. -% We also need to finish this special group before finally -% returning a |\c_true_bool| or |\c_false_bool| as there might -% otherwise be something left in front in the input stream. For -% this we call the Stop operation, denoted simply by a |S| -% following the last Close operation. % \begin{macrocode} \prg_new_conditional:Npnn \bool_if:n #1 { T , F , TF } { @@ -1050,178 +900,195 @@ \prg_return_false: \fi: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\bool_if_p:n} +% \begin{macro}[EXP, aux] +% { +% \@@_if_left_parentheses:wwwn , +% \@@_if_right_parentheses:wwwn , +% \@@_if_or:wwwn +% } +% First issue a \cs{group_align_safe_begin:} as we are using |&&| +% as syntax shorthand for the And operation and we need to hide it for +% \TeX{}. This will be closed at the end of the expression parsing +% (see |S| below). +% +% Minimal (\enquote{short-circuit}) evaluation of boolean expressions +% requires skipping to the end of the current parenthesized group when +% \meta{true}\verb"||" is seen, but to the next \verb"||" or closing +% parenthesis when \meta{false}|&&| is seen. To avoid having separate +% functions for the two cases, we transform the boolean expression by +% doubling each parenthesis and adding parenthesis around each +% \verb"||". This ensures that |&&| will bind tighter than \verb"||". +% +% The replacement is done in three passes, for left and right +% parentheses and for \verb"||". At each pass, the part of the +% expression that has been transformed is stored before \cs{q_nil}, +% the rest lies until the first \cs{q_mark}, followed by an empty +% brace group. A trailing marker ensures that the auxiliaries' +% delimited arguments will not run-away. As long as the delimiter +% matches inside the expression, material is moved before \cs{q_nil} +% and we continue. Afterwards, the trailing marker is taken as a +% delimiter, |#4| is the next auxiliary, immediately followed by a new +% \cs{q_nil} delimiter, which indicates that nothing has been treated +% at this pass. The last step calls \cs{@@_if_parse:NNNww} which +% cleans up and triggers the evaluation of the expression itself. +% \begin{macrocode} \cs_new:Npn \bool_if_p:n #1 { \group_align_safe_begin: - \bool_get_next:N ( #1 ) S + \@@_if_left_parentheses:wwwn \q_nil + #1 \q_mark { } + ( \q_mark { \@@_if_right_parentheses:wwwn \q_nil } + ) \q_mark { \@@_if_or:wwwn \q_nil } + || \q_mark \@@_if_parse:NNNww + \q_stop } +\cs_new:Npn \@@_if_left_parentheses:wwwn #1 \q_nil #2 ( #3 \q_mark #4 + { #4 \@@_if_left_parentheses:wwwn #1 #2 (( \q_nil #3 \q_mark {#4} } +\cs_new:Npn \@@_if_right_parentheses:wwwn #1 \q_nil #2 ) #3 \q_mark #4 + { #4 \@@_if_right_parentheses:wwwn #1 #2 )) \q_nil #3 \q_mark {#4} } +\cs_new:Npn \@@_if_or:wwwn #1 \q_nil #2 || #3 \q_mark #4 + { #4 \@@_if_or:wwwn #1 #2 )||( \q_nil #3 \q_mark {#4} } % \end{macrocode} -% The GetNext operation. We make it a switch: If not a |!| or |(|, we -% assume it is a predicate. +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP, aux]{\@@_if_parse:NNNww} +% After removing extra tokens from the transformation phase, start +% evaluating. At the end, we will need to finish the special +% \texttt{align_safe} group before finally +% returning a \cs{c_true_bool} or \cs{c_false_bool} as there might +% otherwise be something left in front in the input stream. For this +% we call the Stop operation, denoted simply by a |S| following the +% last Close operation. % \begin{macrocode} -\cs_new:Npn \bool_get_next:N #1 +\cs_new:Npn \@@_if_parse:NNNww #1#2#3#4 \q_mark #5 \q_stop { - \use:c - { - bool_ - \if_meaning:w !#1 ! \else: \if_meaning:w (#1 ( \else: p \fi: \fi: - :w - } - #1 + \__bool_get_next:NN \use_i:nn (( #4 )) S } % \end{macrocode} -% This variant gets called when a Not has just been entered. -% It (eventually) results in a reversal of the logic of the directly -% following material. +% \end{macro} +% +% \begin{macro}[aux]{\@@_get_next:NN} +% The GetNext operation. This is a switch: if what follows is neither +% |!| nor |(|, we assume it is a predicate. The first argument is +% \cs{use_ii:nn} if the logic must eventually be reversed (after a +% |!|), otherwise it is \cs{use_i:nn}. This function eventually +% expand to the truth value \cs{c_true_bool} or \cs{c_false_bool} of +% the expression which follows until the next unmatched closing +% parenthesis. % \begin{macrocode} -\cs_new:Npn \bool_get_not_next:N #1 +\cs_new:Npn \@@_get_next:NN #1#2 { \use:c { - bool_not_ - \if_meaning:w !#1 ! \else: \if_meaning:w (#1 ( \else: p \fi: \fi: - :w + @@_ + \if_meaning:w !#2 ! \else: \if_meaning:w (#2 ( \else: p \fi: \fi: + :Nw } - #1 - } -% \end{macrocode} -% We need these later on to nullify the unity operation |!!|. -% \begin{macrocode} -\cs_new:Npn \bool_get_next:NN #1#2 { \bool_get_next:N #2 } -\cs_new:Npn \bool_get_not_next:NN #1#2 { \bool_get_not_next:N #2 } -% \end{macrocode} -% The Not operation. Discard the token read and reverse the truth -% value of the next expression if there -% are brackets; otherwise -% if we're coming up to a |!| then we don't need to reverse anything -% (but we then want to continue scanning ahead in case some fool has written -% |!!(...)|); -% otherwise we have a boolean that we can reverse here and now. -% \begin{macrocode} -\cs_new:cpn { bool_!:w } #1#2 - { - \if_meaning:w ( #2 - \exp_after:wN \bool_Not:w - \else: - \if_meaning:w ! #2 - \exp_after:wN \exp_after:wN \exp_after:wN \bool_get_next:NN - \else: - \exp_after:wN \exp_after:wN \exp_after:wN \bool_Not:N - \fi: - \fi: - #2 - } -% \end{macrocode} -% Variant called when already inside a Not. -% Essentially the opposite of the above. -% \begin{macrocode} -\cs_new:cpn { bool_not_!:w } #1#2 - { - \if_meaning:w ( #2 - \exp_after:wN \bool_not_Not:w - \else: - \if_meaning:w ! #2 - \exp_after:wN \exp_after:wN \exp_after:wN \bool_get_not_next:NN - \else: - \exp_after:wN \exp_after:wN \exp_after:wN \bool_not_Not:N - \fi: - \fi: - #2 + #1 #2 } % \end{macrocode} -% These occur when processing |!(...)|. The idea is to use a variant -% of |\bool_get_next:N| that finishes its parsing with a logic reversal. -% Of course, the double logic reversal gets us back to where we started. +% \end{macro} +% +% \begin{macro}[aux]{\@@_!:Nw} +% The Not operation reverses the logic: discard the |!| token and call +% the GetNext operation with its first argument reversed. % \begin{macrocode} -\cs_new:Npn \bool_Not:w { \exp_after:wN \int_value:w \bool_get_not_next:N } -\cs_new:Npn \bool_not_Not:w { \exp_after:wN \int_value:w \bool_get_next:N } +\cs_new:cpn { @@_!:Nw } #1#2 + { \exp_after:wN \@@_get_next:NN #1 \use_ii:nn \use_i:nn } % \end{macrocode} -% These occur when processing |!<bool>| and can be evaluated directly. +% \end{macro} +% +% \begin{macro}[aux]{\@@_(:Nw} +% The Open operation starts a sub-expression after discarding the +% token. This is done by calling GetNext, with a post-processing step +% which looks for And, Or or Close afterwards. % \begin{macrocode} -\cs_new:Npn \bool_Not:N #1 +\cs_new:cpn { @@_(:Nw } #1#2 { - \exp_after:wN \bool_p:w - \if_meaning:w #1 \c_true_bool - \c_false_bool - \else: - \c_true_bool - \fi: + \exp_after:wN \@@_choose:NNN \exp_after:wN #1 + \__int_value:w \@@_get_next:NN \use_i:nn } -\cs_new:Npn \bool_not_Not:N #1 - { - \exp_after:wN \bool_p:w - \if_meaning:w #1 \c_true_bool - \c_true_bool - \else: - \c_false_bool - \fi: - } -% \end{macrocode} -% The Open operation. Discard the token read and start a -% sub-expression. -% |\bool_get_next:N| continues building up the logical expressions as usual; -% |\bool_not_cleanup:N| is what reverses the logic if we're inside |!(...)|. -% \begin{macrocode} -\cs_new:cpn { bool_(:w } #1 - { \exp_after:wN \bool_cleanup:N \int_value:w \bool_get_next:N } -\cs_new:cpn { bool_not_(:w } #1 - { \exp_after:wN \bool_not_cleanup:N \int_value:w \bool_get_next:N } % \end{macrocode} -% Otherwise just evaluate the predicate and look for And, Or or Close -% afterwards. +% \end{macro} +% +% \begin{macro}[aux]{\@@_p:Nw} +% If what follows GetNext is neither |!| nor |(|, evaluate the +% predicate using the primitive \cs{__int_value:w}. The canonical +% true and false values have numerical values $1$ and $0$ +% respectively. Look for And, Or or Close afterwards. % \begin{macrocode} -\cs_new:cpn { bool_p:w } { \exp_after:wN \bool_cleanup:N \int_value:w } -\cs_new:cpn { bool_not_p:w } {\exp_after:wN \bool_not_cleanup:N \int_value:w } +\cs_new:cpn { @@_p:Nw } #1 + { \exp_after:wN \@@_choose:NNN \exp_after:wN #1 \__int_value:w } % \end{macrocode} -% This cleanup function can be omitted once predicates return their -% true/false booleans outside the conditionals. +% \end{macro} +% +% \begin{macro}[aux]{\@@_choose:NNN} +% Branching the eight-way switch. The arguments are 1: \cs{use_i:nn} +% or \cs{use_ii:nn}, 2: $0$ or $1$ encoding the current truth value, +% 3: the next operation, And, Or, Close or Stop. If |#1| is +% \cs{use_ii:nn}, the logic of |#2| must be reversed. % \begin{macrocode} -\cs_new:Npn \bool_cleanup:N #1 +\cs_new:Npn \@@_choose:NNN #1#2#3 { - \exp_after:wN \bool_choose:NN \exp_after:wN #1 - \int_to_roman:w - `\q - } -\cs_new:Npn \bool_not_cleanup:N #1 - { - \exp_after:wN \bool_not_choose:NN \exp_after:wN #1 - \int_to_roman:w - `\q + \use:c + { + @@_ #3 _ + #1 #2 { \if_meaning:w 0 #2 1 \else: 0 \fi: } + :w + } } % \end{macrocode} -% Branching the six way switch. -% Reversals should be reasonably straightforward. -% \begin{macrocode} -\cs_new:Npn \bool_choose:NN #1#2 { \use:c { bool_ #2 _ #1 :w } } -\cs_new:Npn \bool_not_choose:NN #1#2 { \use:c { bool_not_ #2 _ #1 :w } } -% \end{macrocode} -% Continues scanning. Must remove the second "&" or \verb"|". -% \begin{macrocode} -\cs_new_nopar:cpn { bool_&_1:w } & { \bool_get_next:N } -\cs_new_nopar:cpn { bool_|_0:w } | { \bool_get_next:N } -\cs_new_nopar:cpn { bool_not_&_0:w } & { \bool_get_next:N } -\cs_new_nopar:cpn { bool_not_|_1:w } | { \bool_get_next:N } -% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux] +% { +% \@@_)_0:w, +% \@@_)_1:w, +% \@@_S_0:w, +% \@@_S_1:w, +% } % Closing a group is just about returning the result. The Stop % operation is similar except it closes the special alignment group % before returning the boolean. % \begin{macrocode} -\cs_new_nopar:cpn { bool_)_0:w } { \c_false_bool } -\cs_new_nopar:cpn { bool_)_1:w } { \c_true_bool } -\cs_new_nopar:cpn { bool_not_)_0:w } { \c_true_bool } -\cs_new_nopar:cpn { bool_not_)_1:w } { \c_false_bool } -\cs_new_nopar:cpn { bool_S_0:w } { \group_align_safe_end: \c_false_bool } -\cs_new_nopar:cpn { bool_S_1:w } { \group_align_safe_end: \c_true_bool } +\cs_new_nopar:cpn { @@_)_0:w } { \c_false_bool } +\cs_new_nopar:cpn { @@_)_1:w } { \c_true_bool } +\cs_new_nopar:cpn { @@_S_0:w } { \group_align_safe_end: \c_false_bool } +\cs_new_nopar:cpn { @@_S_1:w } { \group_align_safe_end: \c_true_bool } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]+\@@_&_1:w+ +% \begin{macro}[aux]+\@@_|_0:w+ +% Two cases where we simply continue scanning. We must remove the +% second "&" or \verb"|". +% \begin{macrocode} +\cs_new_nopar:cpn { @@_&_1:w } & { \@@_get_next:NN \use_i:nn } +\cs_new_nopar:cpn { @@_|_0:w } | { \@@_get_next:NN \use_i:nn } % \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]+\@@_&_0:w+ +% \begin{macro}[aux]+\@@_|_1:w+ +% \begin{macro}[aux] +% { +% \@@_eval_skip_to_end:Nw, +% \@@_eval_skip_to_end_ii:Nw, +% \@@_eval_skip_to_end_iii:Nw +% } % When the truth value has already been decided, we have to throw away % the remainder of the current group as we are doing minimal % evaluation. This is slightly tricky as there are no braces so we % have to play match the |()| manually. % \begin{macrocode} -\cs_new_nopar:cpn { bool_&_0:w } & { \bool_eval_skip_to_end:Nw \c_false_bool } -\cs_new_nopar:cpn { bool_|_1:w } | { \bool_eval_skip_to_end:Nw \c_true_bool } -\cs_new_nopar:cpn { bool_not_&_1:w } & - { \bool_eval_skip_to_end:Nw \c_false_bool } -\cs_new_nopar:cpn { bool_not_|_0:w } | - { \bool_eval_skip_to_end:Nw \c_true_bool } +\cs_new_nopar:cpn { @@_&_0:w } & { \@@_eval_skip_to_end:Nw \c_false_bool } +\cs_new_nopar:cpn { @@_|_1:w } | { \@@_eval_skip_to_end:Nw \c_true_bool } % \end{macrocode} % There is always at least one |)| waiting, namely the outer % one. However, we are facing the problem that there may be more than @@ -1275,9 +1142,9 @@ % finally close the group nicely. % \begin{macrocode} %% ( -\cs_new:Npn \bool_eval_skip_to_end:Nw #1#2 ) +\cs_new:Npn \@@_eval_skip_to_end:Nw #1#2 ) { - \bool_eval_skip_to_end_aux:Nw #1#2 ( % ) + \@@_eval_skip_to_end_ii:Nw #1#2 ( % ) \q_no_value \q_stop {#2} } @@ -1286,31 +1153,29 @@ % the boolean |#1|. If there is, we need to grab a |()| pair and then % recurse % \begin{macrocode} -\cs_new:Npn \bool_eval_skip_to_end_aux:Nw #1#2 ( #3#4 \q_stop #5 % ) +\cs_new:Npn \@@_eval_skip_to_end_ii:Nw #1#2 ( #3#4 \q_stop #5 % ) { \quark_if_no_value:NTF #3 {#1} - { \bool_eval_skip_to_end_aux_ii:Nw #1 #5 } + { \@@_eval_skip_to_end_iii:Nw #1 #5 } } % \end{macrocode} % Keep the boolean, throw away anything up to the |(| as it is % irrelevant, remove a |()| pair but remember to reinsert |#3| as it may % contain |(| tokens! % \begin{macrocode} -\cs_new:Npn \bool_eval_skip_to_end_aux_ii:Nw #1#2 ( #3 ) +\cs_new:Npn \@@_eval_skip_to_end_iii:Nw #1#2 ( #3 ) { % ( - \bool_eval_skip_to_end:Nw #1#3 ) + \@@_eval_skip_to_end:Nw #1#3 ) } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} % % \begin{macro}{\bool_not_p:n} % \UnitTested -% The Not variant just reverses the outcome of |\bool_if_p:n|. Can +% The Not variant just reverses the outcome of \cs{bool_if_p:n}. Can % be optimized but this is nice and simple and according to the % implementation plan. Not even particularly useful to have it when % the infix notation is easier to use. @@ -1410,156 +1275,42 @@ % \end{macrocode} % \end{macro} % -% \subsection{Switching by case} -% -% A family of functions to select one case of a number: the same ideas -% are used for a number of different situations. -% -% \begin{macro}[aux]{\prg_case_end:nw} -% In all cases the end statement is the same. Here, |#1| will be the -% code needed, |#2| the other cases to throw away, including the -% \enquote{else} case. The \cs{c_zero} marker stops the expansion of -% \tn{romannumeral} which begins each \cs{prg_case_...} function. -% \begin{macrocode} -\cs_new:Npn \prg_case_end:nw #1 #2 \q_recursion_stop { \c_zero #1 } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\prg_case_int:nnn} -% \UnitTested -% \begin{macro}[aux]{\prg_case_int_aux:nnn,\prg_case_int_aux:nw} -% For integer cases, the first task to fully expand the check -% condition. After that, a loop is started to compare each possible -% value and stop if the test is true. The tested value is put at the -% end to ensure that there is necessarily a match, which will fire the -% \enquote{else} pathway. The leading \tn{romannumeral} triggers an -% expansion which is then stopped in \cs{prg_case_end:nw}. -% \begin{macrocode} -\cs_new:Npn \prg_case_int:nnn #1 - { - \tex_romannumeral:D - \exp_args:Nf \prg_case_int_aux:nnn { \int_eval:n {#1} } - } -\cs_new:Npn \prg_case_int_aux:nnn #1 #2 #3 - { \prg_case_int_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } -\cs_new:Npn \prg_case_int_aux:nw #1#2#3 - { - \int_compare:nNnTF {#1} = {#2} - { \prg_case_end:nw {#3} } - { \prg_case_int_aux:nw {#1} } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\prg_case_dim:nnn} -% \UnitTested -% \begin{macro}[aux]{\prg_case_dim_aux:nnn,\prg_case_dim_aux:nw} -% The dimension function is the same, just a change of calculation -% method. -% \begin{macrocode} -\cs_new:Npn \prg_case_dim:nnn #1 - { - \tex_romannumeral:D - \exp_args:Nf \prg_case_dim_aux:nnn { \dim_eval:n {#1} } - } -\cs_new:Npn \prg_case_dim_aux:nnn #1 #2 #3 - { \prg_case_dim_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } -\cs_new:Npn \prg_case_dim_aux:nw #1#2#3 - { - \dim_compare:nNnTF {#1} = {#2} - { \prg_case_end:nw {#3} } - { \prg_case_dim_aux:nw {#1} } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\prg_case_str:nnn, \prg_case_str:onn, \prg_case_str:xxn} -% \UnitTested -% \begin{macro}[aux]{\prg_case_str_aux:nw, \prg_case_str_x_aux:nw} -% No calculations for strings, otherwise no surprises. -% \begin{macrocode} -\cs_new:Npn \prg_case_str:nnn #1#2#3 - { - \tex_romannumeral:D - \prg_case_str_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop - } -\cs_new:Npn \prg_case_str_aux:nw #1#2#3 - { - \str_if_eq:nnTF {#1} {#2} - { \prg_case_end:nw {#3} } - { \prg_case_str_aux:nw {#1} } - } -\cs_generate_variant:Nn \prg_case_str:nnn { o } -\cs_new:Npn \prg_case_str:xxn #1#2#3 - { - \tex_romannumeral:D - \prg_case_str_x_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop - } -\cs_new:Npn \prg_case_str_x_aux:nw #1#2#3 - { - \str_if_eq:xxTF {#1} {#2} - { \prg_case_end:nw {#3} } - { \prg_case_str_x_aux:nw {#1} } - } -% \end{macrocode} -% \end{macro} -% \end{macro} +% \subsection{Producing $n$ copies} % -% \begin{macro}{\prg_case_tl:Nnn, \prg_case_tl:cnn} -% \UnitTested -% \begin{macro}[aux]{\prg_case_tl_aux:Nw} -% Similar again, but this time with some variants. % \begin{macrocode} -\cs_new:Npn \prg_case_tl:Nnn #1#2#3 - { - \tex_romannumeral:D - \prg_case_tl_aux:Nw #1 #2 #1 {#3} \q_recursion_stop - } -\cs_new:Npn \prg_case_tl_aux:Nw #1#2#3 - { - \tl_if_eq:NNTF #1 #2 - { \prg_case_end:nw {#3} } - { \prg_case_tl_aux:Nw #1 } - } -\cs_generate_variant:Nn \prg_case_tl:Nnn { c } +%<@@=prg> % \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsection{Producing $n$ copies} % % \begin{macro}{\prg_replicate:nn} % \UnitTested -% \begin{macro}[aux]{\prg_replicate_aux:N, \prg_replicate_first_aux:N} -% \begin{macro}[aux]{\prg_replicate_} +% \begin{macro}[aux]{\@@_replicate:N, \@@_replicate_first:N} +% \begin{macro}[aux]{\@@_replicate_} % \begin{macro}[aux] % { -% \prg_replicate_0:n, -% \prg_replicate_1:n, -% \prg_replicate_2:n, -% \prg_replicate_3:n, -% \prg_replicate_4:n, -% \prg_replicate_5:n, -% \prg_replicate_6:n, -% \prg_replicate_7:n, -% \prg_replicate_8:n, -% \prg_replicate_9:n +% \@@_replicate_0:n, +% \@@_replicate_1:n, +% \@@_replicate_2:n, +% \@@_replicate_3:n, +% \@@_replicate_4:n, +% \@@_replicate_5:n, +% \@@_replicate_6:n, +% \@@_replicate_7:n, +% \@@_replicate_8:n, +% \@@_replicate_9:n % } % \begin{macro}[aux] % { -% \prg_replicate_first_-:n, -% \prg_replicate_first_0:n, -% \prg_replicate_first_1:n, -% \prg_replicate_first_2:n, -% \prg_replicate_first_3:n, -% \prg_replicate_first_4:n, -% \prg_replicate_first_5:n, -% \prg_replicate_first_6:n, -% \prg_replicate_first_7:n, -% \prg_replicate_first_8:n, -% \prg_replicate_first_9:n +% \@@_replicate_first_-:n, +% \@@_replicate_first_0:n, +% \@@_replicate_first_1:n, +% \@@_replicate_first_2:n, +% \@@_replicate_first_3:n, +% \@@_replicate_first_4:n, +% \@@_replicate_first_5:n, +% \@@_replicate_first_6:n, +% \@@_replicate_first_7:n, +% \@@_replicate_first_8:n, +% \@@_replicate_first_9:n % } % This function uses a cascading csname technique by David Kastrup % (who else :-) @@ -1577,7 +1328,7 @@ % to avoid the last function to insert say, $100$ copies of the original % argument just to gobble them again we define separate functions to % be inserted first. These functions also close the expansion of -% \cs{int_to_roman:w}, which ensures that \cs{prg_replicate:nn} only +% \cs{__int_to_roman:w}, which ensures that \cs{prg_replicate:nn} only % requires two steps of expansion. % % This function has one flaw though: Since it constantly passes down @@ -1587,144 +1338,67 @@ % necessary, it is possible to write % |\prg_replicate:nn{1000}{\prg_replicate:nn{1000}{|\meta{code}|}}|. An % alternative approach is to create a string of |m|'s with -% \cs{int_to_roman:w} which can be done with just four macros but that +% \cs{__int_to_roman:w} which can be done with just four macros but that % method has its own problems since it can exhaust the string % pool. Also, it is considerably slower than what we use here so the % few extra csnames are well spent I would say. % \begin{macrocode} \cs_new:Npn \prg_replicate:nn #1 { - \int_to_roman:w - \exp_after:wN \prg_replicate_first_aux:N - \int_value:w \int_eval:w #1 \int_eval_end: + \__int_to_roman:w + \exp_after:wN \@@_replicate_first:N + \__int_value:w \__int_eval:w #1 \__int_eval_end: \cs_end: } -\cs_new:Npn \prg_replicate_aux:N #1 - { \cs:w prg_replicate_#1 :n \prg_replicate_aux:N } -\cs_new:Npn \prg_replicate_first_aux:N #1 - { \cs:w prg_replicate_first_ #1 :n \prg_replicate_aux:N } +\cs_new:Npn \@@_replicate:N #1 + { \cs:w @@_replicate_#1 :n \@@_replicate:N } +\cs_new:Npn \@@_replicate_first:N #1 + { \cs:w @@_replicate_first_ #1 :n \@@_replicate:N } % \end{macrocode} -% Then comes all the functions that do the hard work of inserting all -% the copies. +% Then comes all the functions that do the hard work of inserting all +% the copies. The first function takes |:n| as a parameter. % \begin{macrocode} -\cs_new:Npn \prg_replicate_ :n #1 { \cs_end: } -\cs_new:cpn { prg_replicate_0:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} } -\cs_new:cpn { prg_replicate_1:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1 } -\cs_new:cpn { prg_replicate_2:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1 } -\cs_new:cpn { prg_replicate_3:n } #1 +\cs_new:Npn \@@_replicate_ :n #1 { \cs_end: } +\cs_new:cpn { @@_replicate_0:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} } +\cs_new:cpn { @@_replicate_1:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1 } +\cs_new:cpn { @@_replicate_2:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1 } +\cs_new:cpn { @@_replicate_3:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1 } -\cs_new:cpn { prg_replicate_4:n } #1 +\cs_new:cpn { @@_replicate_4:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1 } -\cs_new:cpn { prg_replicate_5:n } #1 +\cs_new:cpn { @@_replicate_5:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1 } -\cs_new:cpn { prg_replicate_6:n } #1 +\cs_new:cpn { @@_replicate_6:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1#1 } -\cs_new:cpn { prg_replicate_7:n } #1 +\cs_new:cpn { @@_replicate_7:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1#1#1 } -\cs_new:cpn { prg_replicate_8:n } #1 +\cs_new:cpn { @@_replicate_8:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1#1#1#1 } -\cs_new:cpn { prg_replicate_9:n } #1 +\cs_new:cpn { @@_replicate_9:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1#1#1#1#1 } % \end{macrocode} % Users shouldn't ask for something to be replicated once or even % not at all but\dots % \begin{macrocode} -\cs_new:cpn { prg_replicate_first_-:n } #1 - { \c_zero \msg_expandable_kernel_error:nn { prg } { replicate-neg } } -\cs_new:cpn { prg_replicate_first_0:n } #1 { \c_zero } -\cs_new:cpn { prg_replicate_first_1:n } #1 { \c_zero #1 } -\cs_new:cpn { prg_replicate_first_2:n } #1 { \c_zero #1#1 } -\cs_new:cpn { prg_replicate_first_3:n } #1 { \c_zero #1#1#1 } -\cs_new:cpn { prg_replicate_first_4:n } #1 { \c_zero #1#1#1#1 } -\cs_new:cpn { prg_replicate_first_5:n } #1 { \c_zero #1#1#1#1#1 } -\cs_new:cpn { prg_replicate_first_6:n } #1 { \c_zero #1#1#1#1#1#1 } -\cs_new:cpn { prg_replicate_first_7:n } #1 { \c_zero #1#1#1#1#1#1#1 } -\cs_new:cpn { prg_replicate_first_8:n } #1 { \c_zero #1#1#1#1#1#1#1#1 } -\cs_new:cpn { prg_replicate_first_9:n } #1 { \c_zero #1#1#1#1#1#1#1#1#1 } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\prg_stepwise_function:nnnN} -% \begin{macro}[aux]{\prg_stepwise_aux:nnnN} -% \begin{macro}[aux]{\prg_stepwise_aux:NnnnN} -% Repeating a function by steps first needs a check on the direction -% of the steps. After that, do the function for the start value -% then step and loop around. It would be more symmetrical to test -% for a step size of zero before checking the sign, but we optimize -% for the most frequent case (positive step). -% \begin{macrocode} -\cs_new:Npn \prg_stepwise_function:nnnN #1#2#3#4 +\cs_new:cpn { @@_replicate_first_-:n } #1 { - \prg_stepwise_aux:nnnN {#1} {#2} {#3} #4 - \prg_break_point:n { } - } -\cs_new:Npn \prg_stepwise_aux:nnnN #1#2#3#4 - { - \int_compare:nNnTF {#2} > \c_zero - { \exp_args:NNf \prg_stepwise_aux:NnnnN > } - { - \int_compare:nNnTF {#2} = \c_zero - { - \msg_expandable_kernel_error:nnn { prg } { zero-step } {#4} - \prg_map_break: - } - { \exp_args:NNf \prg_stepwise_aux:NnnnN < } - } - { \int_eval:n {#1} } {#2} {#3} #4 - } -\cs_new:Npn \prg_stepwise_aux:NnnnN #1#2#3#4#5 - { - \int_compare:nNnF {#2} #1 {#4} - { - #5 {#2} - \exp_args:NNf \prg_stepwise_aux:NnnnN - #1 { \int_eval:n { #2 + #3 } } {#3} {#4} #5 - } + \c_zero + \__msg_kernel_expandable_error:nn { kernel } { negative-replication } } +\cs_new:cpn { @@_replicate_first_0:n } #1 { \c_zero } +\cs_new:cpn { @@_replicate_first_1:n } #1 { \c_zero #1 } +\cs_new:cpn { @@_replicate_first_2:n } #1 { \c_zero #1#1 } +\cs_new:cpn { @@_replicate_first_3:n } #1 { \c_zero #1#1#1 } +\cs_new:cpn { @@_replicate_first_4:n } #1 { \c_zero #1#1#1#1 } +\cs_new:cpn { @@_replicate_first_5:n } #1 { \c_zero #1#1#1#1#1 } +\cs_new:cpn { @@_replicate_first_6:n } #1 { \c_zero #1#1#1#1#1#1 } +\cs_new:cpn { @@_replicate_first_7:n } #1 { \c_zero #1#1#1#1#1#1#1 } +\cs_new:cpn { @@_replicate_first_8:n } #1 { \c_zero #1#1#1#1#1#1#1#1 } +\cs_new:cpn { @@_replicate_first_9:n } #1 { \c_zero #1#1#1#1#1#1#1#1#1 } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} -% -% \begin{macro}{\prg_stepwise_inline:nnnn} -% \begin{macro}{\prg_stepwise_variable:nnnNn} -% \UnitTested -% \begin{macro}[aux]{\prg_stepwise_aux:NNnnnn} -% The approach here is to build a function, with a global integer required -% to make the nesting safe (as seen in other in line functions), -% and map that function using \cs{prg_stepwise_function:nnnN}. -% \begin{macrocode} -\cs_new_protected:Npn \prg_stepwise_inline:nnnn - { - \exp_args:NNc \prg_stepwise_aux:NNnnnn - \cs_gset_nopar:Npn - { g_prg_stepwise_ \int_use:N \g_prg_map_int :n } - } -\cs_new_protected:Npn \prg_stepwise_variable:nnnNn #1#2#3#4#5 - { - \exp_args:NNc \prg_stepwise_aux:NNnnnn - \cs_gset_nopar:Npx - { g_prg_stepwise_ \int_use:N \g_prg_map_int :n } - {#1}{#2}{#3} - { - \tl_set:Nn \exp_not:N #4 {##1} - \exp_not:n {#5} - } - } -\cs_new_protected:Npn \prg_stepwise_aux:NNnnnn #1#2#3#4#5#6 - { - #1 #2 ##1 {#6} - \int_gincr:N \g_prg_map_int - \prg_stepwise_aux:nnnN {#3} {#4} {#5} #2 - \prg_break_point:n { \int_gdecr:N \g_prg_map_int } - } -% \end{macrocode} -% \end{macro} % \end{macro} % \end{macro} % @@ -1735,7 +1409,7 @@ % For testing vertical mode. Strikes me here on the bus with David, % that as long as we are just talking about returning true and % false states, we can just use the primitive conditionals for this -% and gobbling the |\c_zero| in the input stream. However this +% and gobbling the \cs{c_zero} in the input stream. However this % requires knowledge of the implementation so we keep things nice % and clean and use the return statements. % \begin{macrocode} @@ -1779,13 +1453,13 @@ % \TeX{}'s alignment structures present many problems. As Knuth says % himself in \emph{\TeX : The Program}: \enquote{It's sort of a miracle % whenever \tn{halign} or \tn{valign} work, [\ldots]} One problem relates -% to commands that internally issues a |\cr| but also peek ahead for +% to commands that internally issues a \tn{cr} but also peek ahead for % the next character for use in, say, an optional argument. If the % next token happens to be a |&| with category code~4 we will get some % sort of weird error message because the underlying % \tn{futurelet} will store the token at the end of the alignment % template. This could be a |&|$_4$ giving a message like -% |! Misplaced \cr.| or even worse: it could be the |\endtemplate| +% |! Misplaced \cr.| or even worse: it could be the \tn{endtemplate} % token causing even more trouble! To solve this we have to open a % special group so that \TeX{} still thinks it's on safe ground but at % the same time we don't want to introduce any brace group that may @@ -1805,11 +1479,11 @@ % % \begin{macro}[int]{\scan_align_safe_stop:} % When \TeX{} is in the beginning of an align cell (right after the -% |\cr|) it is in a somewhat strange mode as it is looking ahead to +% \tn{cr}) it is in a somewhat strange mode as it is looking ahead to % find an \tn{omit} or \tn{noalign} and hasn't looked at the % preamble yet. Thus an \tn{ifmmode} test will always fail unless -% we insert |\scan_stop:| to stop \TeX{}'s scanning ahead. On the other -% hand we don't want to insert a |\scan_stop:| every time as that will +% we insert \cs{scan_stop:} to stop \TeX{}'s scanning ahead. On the other +% hand we don't want to insert a \cs{scan_stop:} every time as that will % destroy kerning between letters\footnote{Unless we enforce an extra % pass with an appropriate value of \tn{pretolerance}.} % Unfortunately there is no way to detect if we're in the beginning of @@ -1817,7 +1491,7 @@ % on column number, \emph{etc.} However we \emph{can} detect if we're in an % alignment cell by checking the current group type and we can also % check if the previous node was a character or ligature. What is done -% here is that |\scan_stop:| is only inserted if an only +% here is that \cs{scan_stop:} is only inserted if an only % if a)~we're in the outer part of an alignment cell and b)~the last node % \emph{wasn't} a char node or a ligature node. Thus an older definition % here was @@ -1842,47 +1516,51 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\prg_variable_get_scope:N} -% \begin{macro}[aux]{\prg_variable_get_scope_aux:w} -% \begin{macro}[int]{\prg_variable_get_type:N} -% \begin{macro}[aux]{\prg_variable_get_type:w} +% \begin{macrocode} +%<@@=prg> +% \end{macrocode} +% +% \begin{macro}[int]{\@@_variable_get_scope:N} +% \begin{macro}[aux]{\@@_variable_get_scope:w} +% \begin{macro}[int]{\@@_variable_get_type:N} +% \begin{macro}[aux]{\@@_variable_get_type:w} % Expandable functions to find the type of a variable, and to % return \texttt{g} if the variable is global. The trick for -% \cs{prg_variable_get_scope:N} is the same as that in -% \cs{cs_split_function:NN}, but it can be simplified as the +% \cs{@@_variable_get_scope:N} is the same as that in +% \cs{__cs_split_function:NN}, but it can be simplified as the % requirements here are less complex. % \begin{macrocode} \group_begin: - \tex_lccode:D `\& = `\g \scan_stop: - \tex_catcode:D `\& = \c_twelve + \tex_lccode:D `* = `g \scan_stop: + \tex_catcode:D `* = \c_twelve \tl_to_lowercase:n { \group_end: - \cs_new:Npn \prg_variable_get_scope:N #1 + \cs_new:Npn \@@_variable_get_scope:N #1 { \exp_after:wN \exp_after:wN - \exp_after:wN \prg_variable_get_scope_aux:w + \exp_after:wN \@@_variable_get_scope:w \cs_to_str:N #1 \exp_stop_f: \q_stop } - \cs_new:Npn \prg_variable_get_scope_aux:w #1#2 \q_stop - { \token_if_eq_meaning:NNT & #1 { g } } + \cs_new:Npn \@@_variable_get_scope:w #1#2 \q_stop + { \token_if_eq_meaning:NNT * #1 { g } } } \group_begin: - \tex_lccode:D `\& = `\_ \scan_stop: - \tex_catcode:D `\& = \c_twelve + \tex_lccode:D `* = `_ \scan_stop: + \tex_catcode:D `* = \c_twelve \tl_to_lowercase:n { \group_end: - \cs_new:Npn \prg_variable_get_type:N #1 + \cs_new:Npn \@@_variable_get_type:N #1 { - \exp_after:wN \prg_variable_get_type_aux:w - \token_to_str:N #1 & a \q_stop + \exp_after:wN \@@_variable_get_type:w + \token_to_str:N #1 * a \q_stop } - \cs_new:Npn \prg_variable_get_type_aux:w #1 & #2#3 \q_stop + \cs_new:Npn \@@_variable_get_type:w #1 * #2#3 \q_stop { \token_if_eq_meaning:NNTF a #2 {#1} - { \prg_variable_get_type_aux:w #2#3 \q_stop } + { \@@_variable_get_type:w #2#3 \q_stop } } } % \end{macrocode} @@ -1891,20 +1569,32 @@ % \end{macro} % \end{macro} % -% \begin{variable}{\g_prg_map_int} +% \begin{variable}{\g_@@_map_int} % A nesting counter for mapping. % \begin{macrocode} -\int_new:N \g_prg_map_int +\int_new:N \g_@@_map_int % \end{macrocode} % \end{variable} % -% \begin{macro}{\prg_break_point:n} -% \begin{macro}{\prg_map_break:} -% \begin{macro}{\prg_map_break:n} -% These are all defined in \pkg{l3basics}, as they are needed +% \begin{macro}{\@@_break_point:Nn} +% \begin{macro}{\@@_map_break:Nn} +% These are defined in \pkg{l3basics}, as they are needed % \enquote{early}. This is just a reminder that that is the case! % \end{macro} % \end{macro} +% +% \begin{macro}{\@@_break_point:} +% \begin{macro}{\@@_break:, \@@_break:n} +% Very simple analogs of \cs{@@_break_point:Nn} and +% \cs{@@_map_break:Nn}, for use in fast short-term recursions which +% are not mappings, do not need to support nesting, and in which +% nothing has to be done at the end of the loop. +% \begin{macrocode} +\cs_new_eq:NN \@@_break_point: \prg_do_nothing: +\cs_new:Npn \@@_break: #1 \@@_break_point: { } +\cs_new:Npn \@@_break:n #1#2 \@@_break_point: {#1} +% \end{macrocode} +% \end{macro} % \end{macro} % % \subsection{Deprecated functions} @@ -1939,6 +1629,7 @@ % by Bernd Raichle. Firstly we define the function for parsing the % initial list and then the braced list afterwards. % \begin{macrocode} +%<*deprecated> \cs_new_protected:Npn \prg_define_quicksort:nnn #1#2#3 { \cs_set:cpx{#1_quicksort:n}##1{ \exp_not:c{#1_quicksort_start_partition:w} ##1 @@ -1956,9 +1647,11 @@ \exp_not:N \quark_if_nil:nT {##1}\exp_not:N \use_none_delimit_by_q_stop:w \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn} {##1}{}{} } +%</deprecated> % \end{macrocode} % Now for doing the partitions. % \begin{macrocode} +%<*deprecated> \cs_set:cpx {#1_quicksort_do_partition_i:nnnw} ##1##2##3 #2 ##4 #3 { \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw} { @@ -1995,10 +1688,12 @@ } {##1}{##2}{##3}{##4} } +%</deprecated> % \end{macrocode} % This part of the code handles the two branches in each % sorting. Again we will also have to do it braced. % \begin{macrocode} +%<*deprecated> \cs_set:cpx {#1_quicksort_partition_less_i:nnnn} ##1##2##3##4{ \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{##2}{{##4}##3}} \cs_set:cpx {#1_quicksort_partition_less_ii:nnnn} ##1##2##3##4{ @@ -2015,15 +1710,18 @@ \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{{##4}##2}{##3}} \cs_set:cpx {#1_quicksort_partition_greater_ii_braced:nnnn} ##1##2##3##4{ \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2{##4}}{##3}} +%</deprecated> % \end{macrocode} % Finally, the big kahuna! This is where the sub-lists are sorted. % \begin{macrocode} +%<*deprecated> \cs_set:cpx {#1_do_quicksort_braced:nnnnw} ##1##2##3##4\q_stop { \exp_not:c{#1_quicksort_braced:n}{##2} \exp_not:c{#1_quicksort_function:n}{##1} \exp_not:c{#1_quicksort_braced:n}{##3} } } +%</deprecated> % \end{macrocode} % \end{macro} % @@ -2032,15 +1730,19 @@ % |\prg_quicksort_compare:nnTF| to compare items, and places the % function |\prg_quicksort_function:n| in front of each of them. % \begin{macrocode} +%<*deprecated> \prg_define_quicksort:nnn {prg}{}{} +%</deprecated> % \end{macrocode} % \end{macro} % % \begin{macro}{\prg_quicksort_function:n} % \begin{macro}{\prg_quicksort_compare:nnTF} % \begin{macrocode} +%<*deprecated> \cs_set:Npn \prg_quicksort_function:n {\ERROR} \cs_set:Npn \prg_quicksort_compare:nnTF {\ERROR} +%</deprecated> % \end{macrocode} % \end{macro} % \end{macro} @@ -2061,6 +1763,38 @@ % \end{macro} % \end{macro} % +% Deprecated 2012-06-03 for removal after 2012-12-31. +% +% \begin{macro}[EXP] +% { +% \prg_case_int:nnn, \prg_case_str:nnn, \prg_case_str:onn, +% \prg_case_str:xxn, \prg_case_tl:Nnn, \prg_case_tl:cnn +% } +% Moved to more sensible modules. +% \begin{macrocode} +\cs_new_eq:NN \prg_case_int:nnn \int_case:nnn +\cs_new_eq:NN \prg_case_str:nnn \str_case:nnn +\cs_new_eq:NN \prg_case_str:onn \str_case:onn +\cs_new_eq:NN \prg_case_str:xxn \str_case_x:nnn +\cs_new_eq:NN \prg_case_tl:Nnn \tl_case:Nnn +\cs_new_eq:NN \prg_case_tl:cnn \tl_case:cnn +% \end{macrocode} +% \end{macro} +% +% Deprecated 2012-06-04 for removal after 2012-12-31. +% +% \begin{macro} +% { +% \prg_stepwise_function:nnnN, \prg_stepwise_inline:nnnn, +% \prg_stepwise_variable:nnnNn +% } +% \begin{macrocode} +\cs_new_eq:NN \prg_stepwise_function:nnnN \int_step_function:nnnN +\cs_new_eq:NN \prg_stepwise_inline:nnnn \int_step_inline:nnnn +\cs_new_eq:NN \prg_stepwise_variable:nnnNn \int_step_variable:nnnNn +% \end{macrocode} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx index b90ff41e63a..e20e2aa5d26 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3prop.dtx 3490 2012-03-04 01:00:53Z bruno $ - {L3 Experimental property lists} +\GetIdInfo$Id: l3prop.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Property lists} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -90,7 +90,7 @@ % \cs{prop_new:N} \meta{property list} % \end{syntax} % Creates a new \meta{property list} or raises an error if the name is -% already taken. The declaration is global. The \meta{property lists} will +% already taken. The declaration is global. The \meta{property list} will % initially contain no entries. % \end{function} % @@ -121,15 +121,15 @@ % \prop_gset_eq:NN, \prop_gset_eq:cN, \prop_gset_eq:Nc, \prop_gset_eq:cc % } % \begin{syntax} -% \cs{prop_set_eq:NN} \meta{property list1} \meta{property list2} +% \cs{prop_set_eq:NN} \meta{property list_1} \meta{property list_2} % \end{syntax} -% Sets the content of \meta{property list1} equal to that of -% \meta{property list2}. +% Sets the content of \meta{property list_1} equal to that of +% \meta{property list_2}. % \end{function} % % \section{Adding entries to property lists} % -% \begin{function} +% \begin{function}[updated = 2012-07-09] % { % \prop_put:Nnn, \prop_put:NnV, \prop_put:Nno, \prop_put:Nnx, % \prop_put:NVn, \prop_put:NVV, \prop_put:Non, \prop_put:Noo, @@ -198,7 +198,7 @@ % \meta{property list} then the \meta{token list variable} will % contain the special marker \cs{q_no_value}. The \meta{key} and % \meta{value} are then deleted from the property list. Both -% assignments are local. +% assignments are local. See also \cs{prop_pop:NnNTF}. % \end{function} % % \begin{function}[updated = 2011-08-18] @@ -213,29 +213,29 @@ % contain the special marker \cs{q_no_value}. The \meta{key} and % \meta{value} are then deleted from the property list. % The \meta{property list} is modified globally, while the assignment of -% the \meta{token list variable} is local. +% the \meta{token list variable} is local. See also \cs{prop_gpop:NnNTF}. % \end{function} -%% +% % \section{Modifying property lists} % -% \begin{function} +% \begin{function}[added = 2012-05-12] % { -% \prop_del:Nn, \prop_del:NV, \prop_del:cn, \prop_del:cV, -% \prop_gdel:Nn, \prop_gdel:NV, \prop_gdel:cn, \prop_gdel:cV +% \prop_remove:Nn, \prop_remove:NV, \prop_remove:cn, \prop_remove:cV, +% \prop_gremove:Nn, \prop_gremove:NV, \prop_gremove:cn, \prop_gremove:cV % } % \begin{syntax} -% \cs{prop_del:Nn} \meta{property list} \Arg{key} +% \cs{prop_remove:Nn} \meta{property list} \Arg{key} % \end{syntax} -% Deletes the entry listed under \meta{key} from the -% \meta{property list} which may be accessed. If the \meta{key} is +% Removes the entry listed under \meta{key} from the +% \meta{property list}. If the \meta{key} is % not found in the \meta{property list} no change occurs, % \emph{i.e}~there is no need to test for the existence of a key before -% deleting it. The deletion is restricted to the current \TeX{} group. +% deleting it. % \end{function} % % \section{Property list conditionals} % -% \begin{function}[EXP, pTF, added=2012-03-03] +% \begin{function}[EXP, pTF, added = 2012-03-03] % {\prop_if_exist:N, \prop_if_exist:c} % \begin{syntax} % \cs{prop_if_exist_p:N} \meta{property list} @@ -278,7 +278,7 @@ % or absence of a key in a property list. They offer increased readability % and performance over separate testing and recovery phases. % -% \begin{function}[updated = 2011-08-28, TF] +% \begin{function}[updated = 2012-05-19, TF] % { % \prop_get:NnN, \prop_get:NVN, \prop_get:NoN, % \prop_get:cnN, \prop_get:cVN, \prop_get:coN @@ -288,21 +288,24 @@ % ~~\Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{key} is not present in the \meta{property list}, leaves -% the \meta{false code} in the input stream and leaves the -% \meta{token list variable} unchanged. If the \meta{key} is present in -% the \meta{property list}, stores the corresponding \meta{value} -% in the \meta{token list variable} without removing it from the -% \meta{property list}. The \meta{token list variable} is assigned locally. +% the \meta{false code} in the input stream. The value of the +% \meta{token list variable} is not defined in this case and should +% not be relied upon. If the \meta{key} is present in the +% \meta{property list}, stores the corresponding \meta{value} in the +% \meta{token list variable} without removing it from the +% \meta{property list}, then leaves the \meta{true code} in the input +% stream. The \meta{token list variable} is assigned locally. % \end{function} % -% \begin{function}[added = 2011-08-18,TF]{\prop_pop:NnN, \prop_pop:cnN} +% \begin{function}[TF, added = 2011-08-18, updated = 2012-05-19] +% {\prop_pop:NnN, \prop_pop:cnN} % \begin{syntax} -% \cs{prop_pop:NnNTF} \meta{property list} \Arg{key} \meta{token list variable} \\ -% ~~\Arg{true code} \Arg{false code} +% \cs{prop_pop:NnNTF} \meta{property list} \Arg{key} \meta{token list variable} \Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{key} is not present in the \meta{property list}, leaves -% the \meta{false code} in the input stream and leaves the -% \meta{token list variable} unchanged. If the \meta{key} is present in +% the \meta{false code} in the input stream. The value of the +% \meta{token list variable} is not defined in this case and should +% not be relied upon. If the \meta{key} is present in % the \meta{property list}, pops the corresponding \meta{value} % in the \meta{token list variable}, \emph{i.e.}~removes the item from % the \meta{property list}. @@ -310,9 +313,26 @@ % are assigned locally. % \end{function} % +% \begin{function}[TF, added = 2011-08-18, updated = 2012-05-19] +% {\prop_gpop:NnN, \prop_gpop:cnN} +% \begin{syntax} +% \cs{prop_gpop:NnNTF} \meta{property list} \Arg{key} \meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{key} is not present in the \meta{property list}, leaves +% the \meta{false code} in the input stream. The value of the +% \meta{token list variable} is not defined in this case and should +% not be relied upon. If the \meta{key} is present in +% the \meta{property list}, pops the corresponding \meta{value} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from +% the \meta{property list}. +% The \meta{property list} is modified globally, while the +% \meta{token list variable} is assigned locally. +% \end{function} +% % \section{Mapping to property lists} % -% \begin{function}[rEXP]{\prop_map_function:NN, \prop_map_function:cN} +% \begin{function}[updated = 2012-06-29, rEXP] +% {\prop_map_function:NN, \prop_map_function:cN} % \begin{syntax} % \cs{prop_map_function:NN} \meta{property list} \meta{function} % \end{syntax} @@ -323,7 +343,8 @@ % should not be relied upon. % \end{function} % -% \begin{function}{\prop_map_inline:Nn, \prop_map_inline:cn} +% \begin{function}[updated = 2012-06-29] +% {\prop_map_inline:Nn, \prop_map_inline:cn} % \begin{syntax} % \cs{prop_map_inline:Nn} \meta{property list} \Arg{inline function} % \end{syntax} @@ -335,7 +356,7 @@ % should not be relied upon. % \end{function} % -% \begin{function}[rEXP]{\prop_map_break:} +% \begin{function}[updated = 2012-06-29, rEXP]{\prop_map_break:} % \begin{syntax} % \cs{prop_map_break:} % \end{syntax} @@ -356,7 +377,7 @@ % level \TeX{} errors. % \end{function} % -% \begin{function}[rEXP]{\prop_map_break:n} +% \begin{function}[updated = 2012-06-29, rEXP]{\prop_map_break:n} % \begin{syntax} % \cs{prop_map_break:n} \Arg{tokens} % \end{syntax} @@ -387,103 +408,45 @@ % Displays the entries in the \meta{property list} in the terminal. % \end{function} % -% \section{Experimental property list functions} +% \section{Scratch property lists} % -% This section contains functions which may or may not be retained, depending -% on how useful they are found to be. +% \begin{variable}[added = 2012-06-23]{\l_tmpa_prop, \l_tmpb_prop} +% Scratch property lists for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} % -% \begin{function}[added = 2011-08-18,TF]{\prop_gpop:NnN, \prop_gpop:cnN} -% \begin{syntax} -% \cs{prop_gpop:NnNTF} \meta{property list} \Arg{key} \meta{token list variable} \\ -% ~~\Arg{true code} \Arg{false code} -% \end{syntax} -% If the \meta{key} is not present in the \meta{property list}, leaves -% the \meta{false code} in the input stream and leaves the -% \meta{token list variable} unchanged. If the \meta{key} is present in -% the \meta{property list}, pops the corresponding \meta{value} -% in the \meta{token list variable}, \emph{i.e.}~removes the item from -% the \meta{property list}. -% The \meta{property list} is modified globally, while the -% \meta{token list variable} is assigned locally. -% \end{function} +% \begin{variable}[added = 2012-06-23]{\g_tmpa_prop, \g_tmpb_prop} +% Scratch property lists for global assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} % -% \begin{function}[added = 2011-08-18,rEXP] -% {\prop_map_tokens:Nn, \prop_map_tokens:cn} -% \begin{syntax} -% \cs{prop_map_tokens:Nn} \meta{property list} \Arg{code} -% \end{syntax} -% Analogue of \cs{prop_map_function:NN} which maps several tokens -% instead of a single function. The \meta{code} receives each -% key--value pair in the \meta{property list} as two trailing brace -% groups. For instance, -% \begin{verbatim} -% \prop_map_tokens:Nn \l_my_prop { \str_if_eq:nnT { mykey } } -% \end{verbatim} -% will expand to the value corresponding to \texttt{mykey}: for each -% pair in \cs{l_my_prop} the function \cs{str_if_eq:nnT} receives -% \texttt{mykey}, the \meta{key} and the \meta{value} as its three -% arguments. For that specific task, \cs{prop_get:Nn} is faster. -% \end{function} +% \section{Constants} % -% \begin{function}[updated = 2012-01-08,EXP]{\prop_get:Nn, \prop_get:cn} -% \begin{syntax} -% \cs{prop_get:Nn} \meta{property list} \Arg{key} -% \end{syntax} -% Expands to the \meta{value} corresponding to the \meta{key} in -% the \meta{property list}. If the \meta{key} is missing, this has -% an empty expansion. -% \begin{texnote} -% This function is slower than the non-expandable analogue -% \cs{prop_get:NnN}. -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the \meta{value} -% will not expand further when appearing in an x-type -% argument expansion. -% \end{texnote} -% \end{function} +% \begin{variable}{\c_empty_prop} +% A permanently-empty property list used for internal comparisons. +% \end{variable} % % \section{Internal property list functions} % -% \begin{function}{\q_prop} +% \begin{variable}{\q__prop} % The internal token used to separate out property list entries, separating % both the \meta{key} from the \meta{value} and also one entry from another. -% \end{function} -% -% \begin{function}{\c_empty_prop} -% A permanently-empty property list used for internal comparisons. -% \end{function} -% -% \begin{function}{\prop_split:Nnn} -% \begin{syntax} -% \cs{prop_split:Nnn} \meta{property list} \Arg{key} \Arg{code} -% \end{syntax} -% Splits the \meta{property list} at the \meta{key}, giving three -% groups: the \meta{extract} of \meta{property list} before the -% \meta{key}, the \meta{value} associated with the \meta{key} and the -% \meta{extract} of the \meta{property list} after the \meta{value}. -% The first \meta{extract} retains the internal structure of a property -% list. The second is only missing the leading separator \cs{q_prop}. -% This ensures that the concatenation of the two \meta{extracts} is a -% property list. -% If the \meta{key} is not present in the \meta{property list} then -% the second group will contain the marker \cs{q_no_value} and the third -% is empty. -% Once the split has occurred, the \meta{code} is inserted followed by the -% three groups: thus the \meta{code} should properly absorb three -% arguments. -% The \meta{key} comparison takes place as described for \cs{str_if_eq:nn}. -% \end{function} +% \end{variable} % -% \begin{function}{\prop_split:NnTF} +% \begin{function}{\__prop_split:NnTF} % \begin{syntax} -% \cs{prop_split:NnTF} \meta{property list} \Arg{key} \Arg{true code} \Arg{false code} +% \cs{__prop_split:NnTF} \meta{property list} \Arg{key} \Arg{true code} \Arg{false code} % \end{syntax} % Splits the \meta{property list} at the \meta{key}, giving three % groups: the \meta{extract} of \meta{property list} before the % \meta{key}, the \meta{value} associated with the \meta{key} and the % \meta{extract} of the \meta{property list} after the \meta{value}. % The first \meta{extract} retains the internal structure of a property -% list. The second is only missing the leading separator \cs{q_prop}. +% list. The second is only missing the leading separator \cs{q__prop}. % This ensures that the concatenation of the two \meta{extracts} is a % property list. % If the \meta{key} is present in the \meta{property list} then the @@ -501,44 +464,51 @@ % % \section{\pkg{l3prop} implementation} % -% \TestFiles{m3prop001} +% \TestFiles{m3prop001, m3prop002, m3prop003, m3prop004, m3show001} % % \begin{macrocode} %<*initex|package> % \end{macrocode} % % \begin{macrocode} +%<@@=prop> +% \end{macrocode} +% +% \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % % A property list is a macro whose top-level expansion is for the form -% \enquote{\cs{q_prop} \meta{key$_0$} \cs{q_prop} \Arg{value$_0$} \cs{q_prop} -% \ldots \cs{q_prop} \meta{key$_{n-1}$} \cs{q_prop} \Arg{value$_{n-1}$} -% \cs{q_prop}}. -% The trailing \cs{q_prop} is always present for performance reasons: this -% means that empty property lists are not actually empty. -% -% \begin{macro}[int]{\q_prop} +% \begin{quote} +% \cs{q_@@} \meta{key_1} \cs{q_@@} \Arg{value_1} \\ +% \ldots{} \\ +% \cs{q_@@} \meta{key_n} \cs{q_@@} \Arg{value_n} \\ +% \cs{q_@@} +% \end{quote} +% where the trailing \cs{q_@@} is always present for performance +% reasons: this means that empty property lists are not actually empty. +% +% \begin{macro}[int]{\q_@@} % A private quark is used as a marker between entries. % \begin{macrocode} -\quark_new:N \q_prop +\quark_new:N \q_@@ % \end{macrocode} % \end{macro} % -% \begin{variable}{\c_empty_prop} -% An empty prop contains exactly one \cs{q_prop}. +% \begin{variable}[tested = m3prop004]{\c_empty_prop} +% An empty prop contains exactly one \cs{q_@@}. % \begin{macrocode} -\tl_const:Nn \c_empty_prop { \q_prop } +\tl_const:Nn \c_empty_prop { \q_@@ } % \end{macrocode} % \end{variable} % % \subsection{Allocation and initialisation} % -% \begin{macro}{\prop_new:N,\prop_new:c} +% \begin{macro}[tested = m3prop001]{\prop_new:N,\prop_new:c} % Internally, property lists are token lists, but an empty prop % is not an empty tl, so we need to do things by hand. % \begin{macrocode} @@ -547,20 +517,20 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\prop_clear:N, \prop_clear:c} -% \begin{macro}{\prop_gclear:N, \prop_gclear:c} +% \begin{macro}[tested = m3prop001]{\prop_clear:N, \prop_clear:c} +% \begin{macro}[tested = m3prop001]{\prop_gclear:N, \prop_gclear:c} % The same idea for clearing % \begin{macrocode} \cs_new_protected:Npn \prop_clear:N #1 { \cs_set_eq:NN #1 \c_empty_prop } -\cs_new_protected:Npn \prop_clear:c #1 { \cs_set_eq:cN {#1} \c_empty_prop } +\cs_generate_variant:Nn \prop_clear:N { c } \cs_new_protected:Npn \prop_gclear:N #1 { \cs_gset_eq:NN #1 \c_empty_prop } -\cs_new_protected:Npn \prop_gclear:c #1 { \cs_gset_eq:cN {#1} \c_empty_prop } +\cs_generate_variant:Nn \prop_gclear:N { c } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}{\prop_clear_new:N, \prop_clear_new:c} -% \begin{macro}{\prop_gclear_new:N, \prop_gclear_new:c} +% \begin{macro}[tested = m3prop001]{\prop_clear_new:N, \prop_clear_new:c} +% \begin{macro}[tested = m3prop001]{\prop_gclear_new:N, \prop_gclear_new:c} % Once again a simple copy from the token list functions. % \begin{macrocode} \cs_new_protected:Npn \prop_clear_new:N #1 @@ -573,9 +543,9 @@ % \end{macro} % \end{macro} % -% \begin{macro} +% \begin{macro}[tested = m3prop001] % {\prop_set_eq:NN, \prop_set_eq:cN, \prop_set_eq:Nc, \prop_set_eq:cc} -% \begin{macro} +% \begin{macro}[tested = m3prop001] % {\prop_gset_eq:NN, \prop_gset_eq:cN, \prop_gset_eq:Nc, \prop_gset_eq:cc} % Once again, these are simply copies from the token list functions. % \begin{macrocode} @@ -591,116 +561,109 @@ % \end{macro} % \end{macro} % +% \begin{variable}[tested = m3prop004]{\l_tmpa_prop, \l_tmpb_prop} +% \begin{variable}[tested = m3prop004]{\g_tmpa_prop, \g_tmpb_prop} +% We can now initialize the scratch variables. +% \begin{macrocode} +\prop_new:N \l_tmpa_prop +\prop_new:N \l_tmpb_prop +\prop_new:N \g_tmpa_prop +\prop_new:N \g_tmpb_prop +% \end{macrocode} +% \end{variable} +% \end{variable} +% % \subsection{Accessing data in property lists} % -% \begin{macro}[int]{\prop_split:NnTF} -% \begin{macro}[aux]{\prop_split_aux:NnTF} -% \begin{macro}[aux]{\prop_split_aux:nnnn} -% \begin{macro}[aux]{\prop_split_aux:w} +% \begin{macro}[int]{\@@_split:NnTF} +% \begin{macro}[aux]{\@@_split_aux:NnTF} +% \begin{macro}[aux]{\@@_split_aux:nnnn} +% \begin{macro}[aux]{\@@_split_aux:w} % This function is used by most of the module, and hence must be fast. % The aim here is to split a property list at a given key into the part % before the key--value pair, the value associated with the key and the part % after the key--value pair. To do this, the key is first detokenized (to % avoid repeatedly doing this), then a delimited function is constructed to -% match the key. It will match \cs{q_prop} \meta{detokenized key} \cs{q_prop} -% \marg{value} \meta{extra argument}, effectively separating an -% \meta{extract1} before the key in the property list and an \meta{extract2} +% match the key. It will match \cs{q_@@} \meta{detokenized key} \cs{q_@@} +% \Arg{value} \meta{extra argument}, effectively separating an +% \meta{extract_1} before the key in the property list and an \meta{extract_2} % after the key. % % If the key is present in the property list, then \meta{extra argument} -% is simply \cs{q_prop}, and \cs{prop_split_aux:nnnn} will gobble this +% is simply \cs{q_@@}, and \cs{@@_split_aux:nnnn} will gobble this % and the false branch (|#4|), leaving the correct code on the input % stream. More precisely, it leaves the user code (true branch), followed % by three groups, \Arg{extract_1} \Arg{value} \Arg{extract_2}. -% In order for \meta{extract1}\meta{extract2} to be a well-formed -% property list, \meta{extract1} has a leading and trailing \cs{q_prop}, -% retaining exactly the structure of a property list, while \meta{extract2} -% omits the leading \cs{q_prop}. -% -% If the key is not there, then \meta{extra argument} is -% |? \use_ii:nn { }|, and |\prop_split_aux:nnnn ? \use_ii:nn { }| removes -% the three brace groups that just follow. Then \cs{use_ii:nn} removes -% the true branch, leaving the false branch, with no trailing material. +% In order for \meta{extract_1}\meta{extract_2} to be a well-formed +% property list, \meta{extract_1} has a leading and trailing \cs{q_@@}, +% retaining exactly the structure of a property list, while \meta{extract_2} +% omits the leading \cs{q_@@}. +% +% If the key is not there, then \meta{extra argument} is |?| +% \cs{use_ii:nn} |{ }|, and \cs{@@_split_aux:nnnn} |?| \cs{use_ii:nn} +% |{ }| removes the three brace groups that just follow. Then +% \cs{use_ii:nn} removes the true branch, leaving the false branch, +% with no trailing material. % \begin{macrocode} -\cs_new_protected:Npn \prop_split:NnTF #1#2 - { \exp_args:NNo \prop_split_aux:NnTF #1 { \tl_to_str:n {#2} } } -\cs_new_protected:Npn \prop_split_aux:NnTF #1#2 +\cs_new_protected:Npn \@@_split:NnTF #1#2 + { \exp_args:NNo \@@_split_aux:NnTF #1 { \tl_to_str:n {#2} } } +\cs_new_protected:Npn \@@_split_aux:NnTF #1#2 { - \cs_set_protected:Npn \prop_split_aux:w - ##1 \q_prop #2 \q_prop ##2 ##3 ##4 \q_mark ##5 \q_stop - { \prop_split_aux:nnnn ##3 { {##1 \q_prop } {##2} {##4} } } - \exp_after:wN \prop_split_aux:w #1 \q_mark - \q_prop #2 \q_prop { } { ? \use_ii:nn { } } \q_mark \q_stop + \cs_set_protected:Npn \@@_split_aux:w + ##1 \q_@@ #2 \q_@@ ##2 ##3 ##4 \q_mark ##5 \q_stop + { \@@_split_aux:nnnn ##3 { {##1 \q_@@ } {##2} {##4} } } + \exp_after:wN \@@_split_aux:w #1 \q_mark + \q_@@ #2 \q_@@ { } { ? \use_ii:nn { } } \q_mark \q_stop } -\cs_new:Npn \prop_split_aux:nnnn #1#2#3#4 { #3 #2 } -\cs_new_protected:Npn \prop_split_aux:w { } +\cs_new:Npn \@@_split_aux:nnnn #1#2#3#4 { #3 #2 } +\cs_new_protected:Npn \@@_split_aux:w { } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % -% \begin{macro}[int]{\prop_split:Nnn} -% The goal here is to provide a common interface for both true and false -% branches of \cs{prop_split:NnTF}. In both cases, the code given by the -% user will be placed in front of three brace groups, \Arg{extract_1} -% \Arg{value} \Arg{extract_2}. -% If the key was missing from the property list, then \meta{extract1} -% is the full property list, \meta{value} is \cs{q_no_value}, and -% \meta{extract2} is empty. -% Otherwise, \meta{extract1} is the part of the property list before the -% \meta{key}, and has the structure of a property list, \meta{value} is -% the value corresponding to the \meta{key}, and \meta{extract2} (the part -% after the \meta{key}) is missing the leading \cs{q_prop}. -% \begin{macrocode} -\cs_new_protected:Npn \prop_split:Nnn #1#2#3 - { - \prop_split:NnTF #1 {#2} - {#3} - { \exp_args:Nno \use:n {#3} {#1} { \q_no_value } { } } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\prop_del:Nn, \prop_del:NV, \prop_del:cn, \prop_del:cV} -% \begin{macro}{\prop_gdel:Nn, \prop_gdel:NV, \prop_gdel:cn, \prop_gdel:cV} -% \begin{macro}[aux]{\prop_del_aux:NNnnn} +% \begin{macro}[tested = m3prop002] +% {\prop_remove:Nn, \prop_remove:NV, \prop_remove:cn, \prop_remove:cV} +% \begin{macro}[tested = m3prop002] +% {\prop_gremove:Nn, \prop_gremove:NV, \prop_gremove:cn, \prop_gremove:cV} +% \begin{macro}[aux]{\@@_remove:NNnnn} % Deleting from a property starts by splitting the list. % If the key is present in the property list, the returned value is ignored. % If the key is missing, nothing happens. % \begin{macrocode} -\cs_new_protected:Npn \prop_del:Nn #1#2 - { \prop_split:NnTF #1 {#2} { \prop_del_aux:NNnnn \tl_set:Nn #1 } { } } -\cs_new_protected:Npn \prop_gdel:Nn #1#2 - { \prop_split:NnTF #1 {#2} { \prop_del_aux:NNnnn \tl_gset:Nn #1 } { } } -\cs_new_protected:Npn \prop_del_aux:NNnnn #1#2#3#4#5 +\cs_new_protected:Npn \prop_remove:Nn #1#2 + { \@@_split:NnTF #1 {#2} { \@@_remove:NNnnn \tl_set:Nn #1 } { } } +\cs_new_protected:Npn \prop_gremove:Nn #1#2 + { \@@_split:NnTF #1 {#2} { \@@_remove:NNnnn \tl_gset:Nn #1 } { } } +\cs_new_protected:Npn \@@_remove:NNnnn #1#2#3#4#5 { #1 #2 { #3 #5 } } -\cs_generate_variant:Nn \prop_del:Nn { NV } -\cs_generate_variant:Nn \prop_del:Nn { c , cV } -\cs_generate_variant:Nn \prop_gdel:Nn { NV } -\cs_generate_variant:Nn \prop_gdel:Nn { c , cV } +\cs_generate_variant:Nn \prop_remove:Nn { NV } +\cs_generate_variant:Nn \prop_remove:Nn { c , cV } +\cs_generate_variant:Nn \prop_gremove:Nn { NV } +\cs_generate_variant:Nn \prop_gremove:Nn { c , cV } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % -% \begin{macro} +% \begin{macro}[tested = m3prop002] % { % \prop_get:NnN, \prop_get:NVN, \prop_get:NoN, -% \prop_get:cnN, \prop_get:cVN, \prop_get:NoN +% \prop_get:cnN, \prop_get:cVN, \prop_get:coN % } -% \begin{macro}[aux]{\prop_get_aux:Nnnn} +% \begin{macro}[aux]{\@@_get:Nnnn} % Getting an item from a list is very easy: after splitting, % if the key is in the property list, just set the token list variable % to the return value, otherwise to \cs{q_no_value}. % \begin{macrocode} \cs_new_protected:Npn \prop_get:NnN #1#2#3 { - \prop_split:NnTF #1 {#2} - { \prop_get_aux:Nnnn #3 } + \@@_split:NnTF #1 {#2} + { \@@_get:Nnnn #3 } { \tl_set:Nn #3 { \q_no_value } } } -\cs_new_protected:Npn \prop_get_aux:Nnnn #1#2#3#4 +\cs_new_protected:Npn \@@_get:Nnnn #1#2#3#4 { \tl_set:Nn #1 {#3} } \cs_generate_variant:Nn \prop_get:NnN { NV , No } \cs_generate_variant:Nn \prop_get:NnN { c , cV , co } @@ -708,9 +671,11 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\prop_pop:NnN, \prop_pop:NoN, \prop_pop:cnN, \prop_pop:coN} -% \begin{macro}{\prop_gpop:NnN, \prop_gpop:NoN, \prop_gpop:cnN, \prop_gpop:coN} -% \begin{macro}[aux]{\prop_pop_aux:NNNnnn} +% \begin{macro}[tested = m3prop002] +% {\prop_pop:NnN, \prop_pop:NoN, \prop_pop:cnN, \prop_pop:coN} +% \begin{macro}[tested = m3prop002] +% {\prop_gpop:NnN, \prop_gpop:NoN, \prop_gpop:cnN, \prop_gpop:coN} +% \begin{macro}[aux]{\@@_pop:NNNnnn} % Popping a value also starts by doing the split. % If the key is present, save the value in the token list and update the % property list as when deleting. @@ -718,17 +683,17 @@ % \begin{macrocode} \cs_new_protected:Npn \prop_pop:NnN #1#2#3 { - \prop_split:NnTF #1 {#2} - { \prop_pop_aux:NNNnnn \tl_set:Nn #1 #3 } + \@@_split:NnTF #1 {#2} + { \@@_pop:NNNnnn \tl_set:Nn #1 #3 } { \tl_set:Nn #3 { \q_no_value } } } \cs_new_protected:Npn \prop_gpop:NnN #1#2#3 { - \prop_split:NnTF #1 {#2} - { \prop_pop_aux:NNNnnn \tl_gset:Nn #1 #3 } + \@@_split:NnTF #1 {#2} + { \@@_pop:NNNnnn \tl_gset:Nn #1 #3 } { \tl_set:Nn #3 { \q_no_value } } } -\cs_new_protected:Npn \prop_pop_aux:NNNnnn #1#2#3#4#5#6 +\cs_new_protected:Npn \@@_pop:NNNnnn #1#2#3#4#5#6 { \tl_set:Nn #3 {#5} #1 #2 { #4 #6 } @@ -742,38 +707,82 @@ % \end{macro} % \end{macro} % -% \begin{macro} +% \begin{macro}[TF, tested = m3prop004] +% {\prop_pop:NnN, \prop_pop:cnN, \prop_gpop:NnN, \prop_gpop:cnN} +% \begin{macro}[aux]{\@@_pop_true:NNNnnn} +% Popping an item from a property list, keeping track of whether +% the key was present or not, is implemented as a conditional. +% If the key was missing, neither the property list, nor the token +% list are altered. Otherwise, \cs{prg_return_true:} is used after +% the assignments. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \prop_pop:NnN #1#2#3 { T , F , TF } + { + \@@_split:NnTF #1 {#2} + { \@@_pop_true:NNNnnn \tl_set:Nn #1 #3 } + { \prg_return_false: } + } +\prg_new_protected_conditional:Npnn \prop_gpop:NnN #1#2#3 { T , F , TF } + { + \@@_split:NnTF #1 {#2} + { \@@_pop_true:NNNnnn \tl_gset:Nn #1 #3 } + { \prg_return_false: } + } +\cs_new_protected:Npn \@@_pop_true:NNNnnn #1#2#3#4#5#6 + { + \tl_set:Nn #3 {#5} + #1 #2 { #4 #6 } + \prg_return_true: + } +\cs_generate_variant:Nn \prop_pop:NnNT { c } +\cs_generate_variant:Nn \prop_pop:NnNF { c } +\cs_generate_variant:Nn \prop_pop:NnNTF { c } +\cs_generate_variant:Nn \prop_gpop:NnNT { c } +\cs_generate_variant:Nn \prop_gpop:NnNF { c } +\cs_generate_variant:Nn \prop_gpop:NnNTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[tested = m3prop002] % { % \prop_put:Nnn, \prop_put:NnV, \prop_put:Nno, \prop_put:Nnx, % \prop_put:NVn, \prop_put:NVV, \prop_put:Non, \prop_put:Noo, % \prop_put:cnn, \prop_put:cnV, \prop_put:cno, \prop_put:cnx, % \prop_put:cVn, \prop_put:cVV, \prop_put:con, \prop_put:coo % } -% \begin{macro} +% \begin{macro}[tested = m3prop002] % { % \prop_gput:Nnn, \prop_gput:NnV, \prop_gput:Nno, \prop_gput:Nnx, % \prop_gput:NVn, \prop_gput:NVV, \prop_gput:Non, \prop_gput:Noo, % \prop_gput:cnn, \prop_gput:cnV, \prop_gput:cno, \prop_gput:cnx, % \prop_gput:cVn, \prop_gput:cVV, \prop_gput:con, \prop_gput:coo % } -% \begin{macro}[aux]{\prop_put_aux:NNnnnnn} -% Putting a key--value pair in a property list starts by splitting -% to remove any existing value. The property list is then -% reconstructed with the two remaining parts |#5| and |#7| first, -% followed by the new or updated entry. +% \begin{macro}[aux]{\@@_put:NNNnn, \@@_put:NNnnnnn} +% Putting a key--value pair in a property list starts by splitting to +% remove any existing value. If the \meta{key} was absent, append the +% new key--value pair. Otherwise, the property list is reconstructed +% from the two remaining parts |#5| and |#7|, and the updated entry. +% The updated entry is placed at the same spot as the original +% \meta{key} in the property list, preserving the order of entries. % \begin{macrocode} -\cs_new_protected:Npn \prop_put:Nnn { \prop_put_aux:NNnn \tl_set:Nx } -\cs_new_protected:Npn \prop_gput:Nnn { \prop_put_aux:NNnn \tl_gset:Nx } -\cs_new_protected:Npn \prop_put_aux:NNnn #1#2#3#4 +\cs_new_protected:Npn \prop_put:Nnn + { \@@_put:NNNnn \tl_set:Nx \tl_put_right:Nx } +\cs_new_protected:Npn \prop_gput:Nnn + { \@@_put:NNNnn \tl_gset:Nx \tl_gput_right:Nx } +\cs_new_protected:Npn \@@_put:NNNnn #1#2#3#4#5 { - \prop_split:Nnn #2 {#3} { \prop_put_aux:NNnnnnn #1 #2 {#3} {#4} } + \@@_split:NnTF #3 {#4} + { \@@_put:NNnnnnn #1 #3 {#4} {#5} } + { #2 #3 { \tl_to_str:n {#4} \exp_not:n { \q_@@ {#5} \q_@@ } } } } -\cs_new_protected:Npn \prop_put_aux:NNnnnnn #1#2#3#4#5#6#7 +\cs_new_protected:Npn \@@_put:NNnnnnn #1#2#3#4#5#6#7 { #1 #2 { - \exp_not:n { #5 #7 } - \tl_to_str:n {#3} \exp_not:n { \q_prop {#4} \q_prop } + \exp_not:n {#5} + \tl_to_str:n {#3} \exp_not:n { \q_@@ {#4} \q_@@ } + \exp_not:n {#7} } } \cs_generate_variant:Nn \prop_put:Nnn @@ -789,24 +798,27 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\prop_put_if_new:Nnn, \prop_put_if_new:cnn} -% \begin{macro}{\prop_gput_if_new:Nnn, \prop_gput_if_new:cnn} +% \begin{macro}[tested = m3prop002] +% {\prop_put_if_new:Nnn, \prop_put_if_new:cnn} +% \begin{macro}[tested = m3prop002] +% {\prop_gput_if_new:Nnn, \prop_gput_if_new:cnn} +% \begin{macro}[aux]{\@@_put_if_new:NNnn} % Adding conditionally also splits. If the key is already present, -% the three brace groups given by \cs{prop_split:NnTF} are removed. +% the three brace groups given by \cs{@@_split:NnTF} are removed. % If the key is new, then the value is added, being careful to % convert the key to a string using \cs{tl_to_str:n}. % \begin{macrocode} \cs_new_protected_nopar:Npn \prop_put_if_new:Nnn - { \prop_put_if_new_aux:NNnn \tl_put_right:Nx } + { \@@_put_if_new:NNnn \tl_put_right:Nx } \cs_new_protected_nopar:Npn \prop_gput_if_new:Nnn - { \prop_put_if_new_aux:NNnn \tl_gput_right:Nx } -\cs_new_protected:Npn \prop_put_if_new_aux:NNnn #1#2#3#4 + { \@@_put_if_new:NNnn \tl_gput_right:Nx } +\cs_new_protected:Npn \@@_put_if_new:NNnn #1#2#3#4 { - \prop_split:NnTF #2 {#3} + \@@_split:NnTF #2 {#3} { \use_none:nnn } { #1 #2 - { \tl_to_str:n {#3} \exp_not:n { \q_prop {#4} \q_prop } } + { \tl_to_str:n {#3} \exp_not:n { \q_@@ {#4} \q_@@ } } } } \cs_generate_variant:Nn \prop_put_if_new:Nnn { c } @@ -814,10 +826,11 @@ % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \subsection{Property list conditionals} % -% \begin{macro}[pTF]{\prop_if_exist:N, \prop_if_exist:c} +% \begin{macro}[pTF, tested = m3prop004]{\prop_if_exist:N, \prop_if_exist:c} % Copies of the \texttt{cs} functions defined in \pkg{l3basics}. % \begin{macrocode} \cs_new_eq:NN \prop_if_exist:NTF \cs_if_exist:NTF @@ -831,7 +844,7 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[pTF]{\prop_if_empty:N, \prop_if_empty:c} +% \begin{macro}[pTF, tested = m3prop003]{\prop_if_empty:N, \prop_if_empty:c} % The test here uses \cs{c_empty_prop} as it is not really empty! % \begin{macrocode} \prg_new_conditional:Npnn \prop_if_empty:N #1 { p, T , F , TF } @@ -849,19 +862,19 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[pTF] +% \begin{macro}[pTF, tested = m3prop003] % { % \prop_if_in:Nn, \prop_if_in:NV, \prop_if_in:No, % \prop_if_in:cn, \prop_if_in:cV, \prop_if_in:co % } -% \begin{macro}[aux]{\prop_if_in_aux:nwn,\prop_if_in_aux:N} +% \begin{macro}[aux]{\@@_if_in:nwn,\@@_if_in:N} % Testing expandably if a key is in a property list % requires to go through the key--value pairs one by one. % This is rather slow, and a faster test would be % \begin{verbatim} % \prg_new_protected_conditional:Npnn \prop_if_in:Nn #1 #2 % { -% \prop_split:NnTF #1 {#2} +% \@@_split:NnTF #1 {#2} % { % \prg_return_true: % \use_none:nnn @@ -869,15 +882,15 @@ % { \prg_return_false: } % } % \end{verbatim} -% but \cs{prop_split:NnTF} is non-expandable. +% but \cs{@@_split:NnTF} is non-expandable. % -% Instead, the key is compared to each key in turn using \cs{str_if_eq:xx}, +% Instead, the key is compared to each key in turn using \cs{str_if_eq_x:nn}, % which is expandable. To terminate the mapping, we add the key that % is search for at the end of the property list. This second % \cs{tl_to_str:n} is not expanded at the start, but only when included -% in the \cs{str_if_eq:xx}. It cannot make the breaking mechanism choke, +% in the \cs{str_if_eq_x:nn}. It cannot make the breaking mechanism choke, % because the arbitrary token list material is enclosed in braces. -% When ending, we test the next token: it is either \cs{q_prop} +% When ending, we test the next token: it is either \cs{q_@@} % or \cs{q_recursion_tail} in the case of a missing key. % Here, \cs{prop_map_function:NN} is not sufficient for the mapping, % since it can only map a single token, and cannot carry the key that @@ -885,26 +898,26 @@ % \begin{macrocode} \prg_new_conditional:Npnn \prop_if_in:Nn #1#2 { p , T , F , TF } { - \exp_last_unbraced:Noo \prop_if_in_aux:nwn + \exp_last_unbraced:Noo \@@_if_in:nwn { \tl_to_str:n {#2} } #1 - \tl_to_str:n {#2} \q_prop { } - \q_recursion_tail - \prg_break_point:n { } + \tl_to_str:n {#2} \q_@@ { } + \q_recursion_tail % could be any cs != \q_@@ + \__prg_break_point: } -\cs_new:Npn \prop_if_in_aux:nwn #1 \q_prop #2 \q_prop #3 +\cs_new:Npn \@@_if_in:nwn #1 \q_@@ #2 \q_@@ #3 { - \str_if_eq:xxTF {#1} {#2} - { \prop_if_in_aux:N } - { \prop_if_in_aux:nwn {#1} } + \str_if_eq_x:nnTF {#1} {#2} + { \@@_if_in:N } + { \@@_if_in:nwn {#1} } } -\cs_new:Npn \prop_if_in_aux:N #1 +\cs_new:Npn \@@_if_in:N #1 { - \if_meaning:w \q_prop #1 + \if_meaning:w \q_@@ #1 \prg_return_true: \else: \prg_return_false: \fi: - \prop_map_break: + \__prg_break: } \cs_generate_variant:Nn \prop_if_in_p:Nn { NV , No } \cs_generate_variant:Nn \prop_if_in_p:Nn { c , cV , co } @@ -920,23 +933,23 @@ % % \subsection{Recovering values from property lists with branching} % -% \begin{macro}[TF] +% \begin{macro}[TF, tested = m3prop004] % { % \prop_get:NnN, \prop_get:NVN, \prop_get:NoN, % \prop_get:cnN, \prop_get:cVN, \prop_get:coN % } -% \begin{macro}[aux]{\prop_get_aux_true:Nnnn} +% \begin{macro}[aux]{\@@_get_true:Nnnn} % Getting the value corresponding to a key, keeping track of whether % the key was present or not, is implemented as a conditional (with % side effects). If the key was absent, the token list is not altered. % \begin{macrocode} \prg_new_protected_conditional:Npnn \prop_get:NnN #1#2#3 { T , F , TF } { - \prop_split:NnTF #1 {#2} - { \prop_get_aux_true:Nnnn #3 } + \@@_split:NnTF #1 {#2} + { \@@_get_true:Nnnn #3 } { \prg_return_false: } } -\cs_new_protected:Npn \prop_get_aux_true:Nnnn #1#2#3#4 +\cs_new_protected:Npn \@@_get_true:Nnnn #1#2#3#4 { \tl_set:Nn #1 {#3} \prg_return_true: @@ -953,29 +966,27 @@ % % \subsection{Mapping to property lists} % -% \begin{macro} +% \begin{macro}[tested = m3prop003] % { % \prop_map_function:NN, \prop_map_function:Nc, % \prop_map_function:cN, \prop_map_function:cc % } -% \begin{macro}[aux]{\prop_map_function_aux:Nwn} -% The fastest way to do a recursion here is to use an +% \begin{macro}[aux]{\@@_map_function:Nwn} +% The fastest way to do a recursion here would be to use an % \cs{if_meaning:w} test: the keys are strings, and thus % cannot match the marker \cs{q_recursion_tail}. % \begin{macrocode} \cs_new:Npn \prop_map_function:NN #1#2 { - \exp_last_unbraced:NNo \prop_map_function_aux:Nwn #2 - #1 \q_recursion_tail \q_prop { } - \prg_break_point:n { } + \exp_last_unbraced:NNo \@@_map_function:Nwn #2 + #1 \q_recursion_tail \q_@@ { } + \__prg_break_point:Nn \prop_map_break: { } } -\cs_new:Npn \prop_map_function_aux:Nwn #1 \q_prop #2 \q_prop #3 +\cs_new:Npn \@@_map_function:Nwn #1 \q_@@ #2 \q_@@ #3 { - \if_meaning:w \q_recursion_tail #2 - \exp_after:wN \prop_map_break: - \fi: + \__quark_if_recursion_tail_break:nN {#2} \prop_map_break: #1 {#2} {#3} - \prop_map_function_aux:Nwn #1 + \@@_map_function:Nwn #1 } \cs_generate_variant:Nn \prop_map_function:NN { Nc } \cs_generate_variant:Nn \prop_map_function:NN { c , cc } @@ -983,145 +994,53 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\prop_map_inline:Nn, \prop_map_inline:cn} +% \begin{macro}[tested = m3prop003]{\prop_map_inline:Nn, \prop_map_inline:cn} % Mapping in line requires a nesting level counter. % \begin{macrocode} \cs_new_protected:Npn \prop_map_inline:Nn #1#2 { - \int_gincr:N \g_prg_map_int - \cs_gset:cpn { prop_map_inline_ \int_use:N \g_prg_map_int :nn } - ##1##2 {#2} - \exp_last_unbraced:Nco \prop_map_function_aux:Nwn - { prop_map_inline_ \int_use:N \g_prg_map_int :nn } + \int_gincr:N \g__prg_map_int + \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1##2 {#2} + \exp_last_unbraced:Nco \@@_map_function:Nwn + { __prg_map_ \int_use:N \g__prg_map_int :w } #1 - \q_recursion_tail \q_prop { } - \prg_break_point:n { \int_gdecr:N \g_prg_map_int } + \q_recursion_tail \q_@@ { } + \__prg_break_point:Nn \prop_map_break: { \int_gdecr:N \g__prg_map_int } } \cs_generate_variant:Nn \prop_map_inline:Nn { c } % \end{macrocode} % \end{macro} % -% \begin{macro}{\prop_map_break:} -% \begin{macro}{\prop_map_break:n} -% The break statements are simply copies. +% \begin{macro}[tested = m3prop003]{\prop_map_break:} +% \begin{macro}[tested = m3prop003]{\prop_map_break:n} +% The break statements are based on the general \cs{__prg_map_break:Nn}. % \begin{macrocode} -\cs_new_eq:NN \prop_map_break: \prg_map_break: -\cs_new_eq:NN \prop_map_break:n \prg_map_break:n +\cs_new_nopar:Npn \prop_map_break: + { \__prg_map_break:Nn \prop_map_break: { } } +\cs_new_nopar:Npn \prop_map_break:n + { \__prg_map_break:Nn \prop_map_break: } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Viewing property lists} % -% \begin{macro}{\prop_show:N, \prop_show:c} -% Apply the general \cs{msg_aux_show:Nnx}. Contrarily -% to sequences and comma lists, we use \cs{msg_aux_show:nn} +% \begin{macro}[tested = m3show001]{\prop_show:N, \prop_show:c} +% Apply the general \cs{__msg_show_variable:Nnn}. Contrarily +% to sequences and comma lists, we use \cs{__msg_show_item:nn} % to format both the key and the value for each pair. % \begin{macrocode} \cs_new_protected:Npn \prop_show:N #1 { - \msg_aux_show:Nnx + \__msg_show_variable:Nnn #1 { prop } - { \prop_map_function:NN #1 \msg_aux_show:nn } + { \prop_map_function:NN #1 \__msg_show_item:nn } } \cs_generate_variant:Nn \prop_show:N { c } % \end{macrocode} % \end{macro} % -% \subsection{Experimental functions} -% -% \begin{macro}[TF] -% {\prop_pop:NnN, \prop_pop:cnN, \prop_gpop:cnN, \prop_gpop:cnN} -% \begin{macro}[aux]{\prop_pop_aux_true:NNNnnn} -% Popping an item from a property list, keeping track of whether -% the key was present or not, is implemented as a conditional. -% If the key was missing, neither the property list, nor the token -% list are altered. Otherwise, \cs{prg_return_true:} is used after -% the assignments. -% \begin{macrocode} -\prg_new_protected_conditional:Npnn \prop_pop:NnN #1#2#3 { T , F , TF } - { - \prop_split:NnTF #1 {#2} - { \prop_pop_aux_true:NNNnnn \tl_set:Nn #1 #3 } - { \prg_return_false: } - } -\prg_new_protected_conditional:Npnn \prop_gpop:NnN #1#2#3 { T , F , TF } - { - \prop_split:NnTF #1 {#2} - { \prop_pop_aux_true:NNNnnn \tl_gset:Nn #1 #3 } - { \prg_return_false: } - } -\cs_new_protected:Npn \prop_pop_aux_true:NNNnnn #1#2#3#4#5#6 - { - \tl_set:Nn #3 {#5} - #1 #2 { #4 #6 } - \prg_return_true: - } -\cs_generate_variant:Nn \prop_pop:NnNT { c } -\cs_generate_variant:Nn \prop_pop:NnNF { c } -\cs_generate_variant:Nn \prop_pop:NnNTF { c } -\cs_generate_variant:Nn \prop_gpop:NnNT { c } -\cs_generate_variant:Nn \prop_gpop:NnNF { c } -\cs_generate_variant:Nn \prop_gpop:NnNTF { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[rEXP]{\prop_map_tokens:Nn, \prop_map_tokens:cn} -% \begin{macro}[aux]{\prop_map_tokens_aux:nwn} -% The mapping grabs one key--value pair at a time, and stops when -% reaching the marker key \cs{q_recursion_tail}, which -% cannot appear in normal keys since those are strings. The odd -% construction |\use:n {#1}| allows |#1| to contain any token. -% \begin{macrocode} -\cs_new:Npn \prop_map_tokens:Nn #1#2 - { - \exp_last_unbraced:Nno \prop_map_tokens_aux:nwn {#2} #1 - \q_recursion_tail \q_prop { } - \prg_break_point:n { } - } -\cs_new:Npn \prop_map_tokens_aux:nwn #1 \q_prop #2 \q_prop #3 - { - \if_meaning:w \q_recursion_tail #2 - \exp_after:wN \prop_map_break: - \fi: - \use:n {#1} {#2} {#3} - \prop_map_tokens_aux:nwn {#1} - } -\cs_generate_variant:Nn \prop_map_tokens:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP]{\prop_get:Nn, \prop_get:cn} -% \begin{macro}[aux]{\prop_get_Nn_aux:nwn} -% Getting the value corresponding to a key in a property list in an -% expandable fashion is a simple instance of mapping some tokens. -% Map the function \cs{prop_get_aux:nnn} which takes as its three -% arguments the \meta{key} that we are looking for, the current -% \meta{key} and the current \meta{value}. If the \meta{keys} match, -% the \meta{value} is returned. If none of the keys match, this expands -% to nothing. -% \begin{macrocode} -\cs_new:Npn \prop_get:Nn #1#2 - { - \exp_last_unbraced:Noo \prop_get_Nn_aux:nwn - { \tl_to_str:n {#2} } #1 - \tl_to_str:n {#2} \q_prop { } - \prg_break_point:n { } - } -\cs_new:Npn \prop_get_Nn_aux:nwn #1 \q_prop #2 \q_prop #3 - { - \str_if_eq:xxTF {#1} {#2} - { \prg_map_break:n { \exp_not:n {#3} } } - { \prop_get_Nn_aux:nwn {#1} } - } -\cs_generate_variant:Nn \prop_get:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% % \subsection{Deprecated interfaces} % % Deprecated on 2011-05-27, for removal by 2011-08-31. @@ -1142,10 +1061,12 @@ % the necessary code for the transition is provided directly. % \begin{macrocode} %<*deprecated> +\tl_new:N \l_@@_internal_tl \cs_new_protected:Npn \prop_gget:NnN #1#2#3 - { \prop_split:Nnn #1 {#2} { \prop_gget_aux:Nnnn #3 } } -\cs_new_protected:Npn \prop_gget_aux:Nnnn #1#2#3#4 - { \tl_gset:Nn #1 {#3} } + { + \prop_get:NnN #1 {#2} \l_@@_internal_tl + \tl_gset_eq:NN #3 \l_@@_internal_tl + } \cs_generate_variant:Nn \prop_gget:NnN { NV } \cs_generate_variant:Nn \prop_gget:NnN { c , cV } %</deprecated> @@ -1195,6 +1116,23 @@ % \end{macrocode} % \end{macro} % +% Deprecated on 2012-05-12, for removal by 2012-11-30. +% +% \begin{macro}{\prop_del:Nn, \prop_del:NV, \prop_del:cn, \prop_del:cV} +% \begin{macro}{\prop_gdel:Nn, \prop_gdel:NV, \prop_gdel:cn, \prop_gdel:cV} +% \begin{macrocode} +\cs_new_eq:NN \prop_del:Nn \prop_remove:Nn +\cs_new_eq:NN \prop_del:NV \prop_remove:NV +\cs_new_eq:NN \prop_del:cn \prop_remove:cn +\cs_new_eq:NN \prop_del:cV \prop_remove:cV +\cs_new_eq:NN \prop_gdel:Nn \prop_gremove:Nn +\cs_new_eq:NN \prop_gdel:NV \prop_gremove:NV +\cs_new_eq:NN \prop_gdel:cn \prop_gremove:cn +\cs_new_eq:NN \prop_gdel:cV \prop_gremove:cV +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx index 3cb65a59b33..b85b03440df 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3quark.dtx 3384 2012-02-12 13:13:11Z will $ - {L3 Experimental quarks} +\GetIdInfo$Id: l3quark.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Quarks} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -71,8 +71,9 @@ % % Two special types of constants in \LaTeX3 are \enquote{quarks} and % \enquote{scan marks}. By convention all constants of type quark -% start out with |\q_|, and scan marks start with |\s_|. -% \emph{Scan marks are an experimental feature.} +% start out with |\q_|, and scan marks start with |\s_|. Scan marks are +% for internal use by the kernel: they are not intended for more general +% use. % % \subsection{Quarks} % @@ -114,22 +115,6 @@ % An example of the quark testing functions and their use in recursion % can be seen in the implementation of \cs{clist_map_function:NN}. % -% -% \subsection{Scan marks} -% -% Scan marks are control sequences set equal to \cs{scan_stop:}, -% hence will never expand in an expansion context and will be (largely) -% invisible if they are encountered in a typesetting context. -% -% Like quarks, they can be used as delimiters in weird functions -% and are often safer to use for this purpose. -% Since they are harmless when executed by \TeX{} in non-expandable -% contexts, they can be used to mark the end of a set of instructions. -% This allows to skip to that point if the end of the instructions -% should not be performed (see \pkg{l3regex}). -% -%^^A todo: talk about the use of scan marks in galley and fp. -% % \section{Defining quarks} % % \begin{function}{\quark_new:N} @@ -279,63 +264,81 @@ % ended. % \end{function} % +% \section{Clearing quarks away} +% +% \begin{function}{\use_none_delimit_by_q_recursion_stop:w} +% \begin{syntax} +% \cs{use_none_delimit_by_q_recursion_stop:w} \meta{tokens} \cs{q_recursion_stop} +% \end{syntax} +% Used to prematurely terminate a recursion using \cs{q_recursion_stop} +% as the end marker, removing any remaining \meta{tokens} from the +% input stream. +% \end{function} +% +% \begin{function}{\use_i_delimit_by_q_recursion_stop:nw} +% \begin{syntax} +% \cs{use_i_delimit_by_q_recursion_stop:nw} \Arg{insertion} +% ~~\meta{tokens} \cs{q_recursion_stop} +% \end{syntax} +% Used to prematurely terminate a recursion using \cs{q_recursion_stop} +% as the end marker, removing any remaining \meta{tokens} from the +% input stream. The \meta{insertion} is then made into the input +% stream after the end of the recursion. +% \end{function} +% +% \section{Internal quark functions} +% % \begin{function} % { -% \quark_if_recursion_tail_break:N, -% \quark_if_recursion_tail_break:n +% \__quark_if_recursion_tail_break:NN, +% \__quark_if_recursion_tail_break:nN % } % \begin{syntax} -% \cs{quark_if_recursion_tail_break:n} \Arg{token list} +% \cs{__quark_if_recursion_tail_break:nN} \Arg{token list} \cs{\meta{type}_map_break:} % \end{syntax} -% Tests if \meta{token list} contains only \cs{q_recursion_tail}, -% and if so terminates the recursion using \cs{prg_map_break:}. -% The recursion end should be marked by \cs{prg_break_point:n}. +% Tests if \meta{token list} contains only \cs{q_recursion_tail}, and +% if so terminates the recursion using \cs{\meta{type}_map_break:}. +% The recursion end should be marked by \cs{prg_break_point:Nn} +% \cs{\meta{type}_map_break:}. % \end{function} % % \section{Scan marks} % -% \begin{function}{\scan_new:N} +% Scan marks are control sequences set equal to \cs{scan_stop:}, +% hence will never expand in an expansion context and will be (largely) +% invisible if they are encountered in a typesetting context. +% +% Like quarks, they can be used as delimiters in weird functions +% and are often safer to use for this purpose. +% Since they are harmless when executed by \TeX{} in non-expandable +% contexts, they can be used to mark the end of a set of instructions. +% This allows to skip to that point if the end of the instructions +% should not be performed (see \pkg{l3regex}). +% +% The scan marks system is only for internal use by the kernel team in +% a small number of very specific places. These functions should not be +% used more generally. +% +% \begin{function}{\__scan_new:N} % \begin{syntax} -% \cs{scan_new:N} \meta{scan mark} +% \cs{__scan_new:N} \meta{scan mark} % \end{syntax} % Creates a new \meta{scan mark} which is set equal to \cs{scan_stop:}. % The \meta{scan mark} will be defined globally, and an error message % will be raised if the name was already taken by another scan mark. % \end{function} % -% \begin{variable}{\s_stop} +% \begin{variable}{\s__stop} % Used at the end of a set of instructions, as a marker -% that can be jumped to using \cs{use_none_delimit_by_s_stop:w}. +% that can be jumped to using \cs{__use_none_delimit_by_s__stop:w}. % \end{variable} % -% \begin{function}{\use_none_delimit_by_s_stop:w} +% \begin{function}{\__use_none_delimit_by_s__stop:w} % \begin{syntax} -% \cs{use_none_delimit_by_s_stop:w} \meta{tokens} \cs{s_stop} +% \cs{__use_none_delimit_by_s__stop:w} \meta{tokens} \cs{s__stop} % \end{syntax} -% Removes the \meta{tokens} and \cs{s_stop} from the input stream. -% This leads to a low-level \TeX{} error if \cs{s_stop} is absent. -% \end{function} -% -% \section{Internal quark functions} -% -% \begin{function}{\use_none_delimit_by_q_recursion_stop:w} -% \begin{syntax} -% \cs{use_none_delimit_by_q_recursion_stop:w} \meta{tokens} \cs{q_recursion_stop} -% \end{syntax} -% Used to prematurely terminate a recursion using \cs{q_recursion_stop} -% as the end marker, removing any remaining \meta{tokens} from the -% input stream. -% \end{function} -% -% \begin{function}{\use_i_delimit_by_q_recursion_stop:nw} -% \begin{syntax} -% \cs{use_i_delimit_by_q_recursion_stop:nw} \Arg{insertion} -% ~~\meta{tokens} \cs{q_recursion_stop} -% \end{syntax} -% Used to prematurely terminate a recursion using \cs{q_recursion_stop} -% as the end marker, removing any remaining \meta{tokens} from the -% input stream. The \meta{insertion} is then made into the input -% stream after the end of the recursion. +% Removes the \meta{tokens} and \cs{s__stop} from the input stream. +% This leads to a low-level \TeX{} error if \cs{s__stop} is absent. % \end{function} % % \end{documentation} @@ -354,7 +357,7 @@ %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -453,22 +456,22 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\quark_if_recursion_tail_break:N} -% \begin{macro}{\quark_if_recursion_tail_break:n} +% \begin{macro}{\__quark_if_recursion_tail_break:NN} +% \begin{macro}{\__quark_if_recursion_tail_break:nN} % Analogs of the \cs{quark_if_recursion_tail_stop\ldots{}} functions. -% Break the mapping using \cs{prg_map_break:}. +% Break the mapping using |#2|. % \begin{macrocode} -\cs_new:Npn \quark_if_recursion_tail_break:N #1 +\cs_new:Npn \__quark_if_recursion_tail_break:NN #1#2 { \if_meaning:w \q_recursion_tail #1 - \exp_after:wN \prg_map_break: + \exp_after:wN #2 \fi: } -\cs_new:Npn \quark_if_recursion_tail_break:n #1 +\cs_new:Npn \__quark_if_recursion_tail_break:nN #1#2 { \if_int_compare:w \pdftex_strcmp:D { \exp_not:N \q_recursion_tail } { \exp_not:n {#1} } = \c_zero - \exp_after:wN \prg_map_break: + \exp_after:wN #2 \fi: } % \end{macrocode} @@ -477,7 +480,7 @@ % % \begin{macro}[pTF]{\quark_if_nil:N} % \UnitTested -% \begin{macro}[pTF]{\quark_if_no_value:N., \quark_if_no_value:c} +% \begin{macro}[pTF]{\quark_if_no_value:N, \quark_if_no_value:c} % \UnitTested % Here we test if we found a special quark as the first argument. % We better start with \cs{q_no_value} as the first argument since @@ -541,59 +544,77 @@ % \end{macro} % \end{macro} % -% \begin{variable}{\q_tl_act_mark,\q_tl_act_stop} +% \begin{variable}{\q__tl_act_mark, \q__tl_act_stop} % These private quarks are needed by \pkg{l3tl}, but that is loaded % before the quark module, hence their definition is deferred. % \begin{macrocode} -\quark_new:N \q_tl_act_mark -\quark_new:N \q_tl_act_stop +\quark_new:N \q__tl_act_mark +\quark_new:N \q__tl_act_stop % \end{macrocode} % \end{variable} % % \subsection{Scan marks} +% +% \begin{macrocode} +%<@@=scan> +% \end{macrocode} % -% \begin{variable}{\g_scan_marks_tl} +% \begin{variable}{\g_@@_marks_tl} % \UnitTested % The list of all scan marks currently declared. % \begin{macrocode} -\tl_new:N \g_scan_marks_tl +\tl_new:N \g_@@_marks_tl % \end{macrocode} % \end{variable} % -% \begin{macro}{\scan_new:N} +% \begin{macro}[int]{\@@_new:N} % \UnitTested % Check whether the variable is already a scan mark, % then declare it to be equal to \cs{scan_stop:} globally. % \begin{macrocode} -\cs_new_protected:Npn \scan_new:N #1 +\cs_new_protected:Npn \@@_new:N #1 { - \tl_if_in:NnTF \g_scan_marks_tl { #1 } + \tl_if_in:NnTF \g_@@_marks_tl { #1 } { - \msg_kernel_error:nnx { scan } { already-defined } + \__msg_kernel_error:nnx { kernel } { scanmark-already-defined } { \token_to_str:N #1 } } { - \tl_gput_right:Nn \g_scan_marks_tl {#1} + \tl_gput_right:Nn \g_@@_marks_tl {#1} \cs_new_eq:NN #1 \scan_stop: } } % \end{macrocode} % \end{macro} % -% \begin{variable}{\s_stop} +% \begin{variable}{\s__stop} % \UnitTested % We only declare one scan mark here, more can be defined % by specific modules. % \begin{macrocode} -\scan_new:N \s_stop +\@@_new:N \s__stop % \end{macrocode} % \end{variable} % -% \begin{macro}{\use_none_delimit_by_s_stop:w} +% \begin{macro}[int]{\__use_none_delimit_by_s__stop:w} % \UnitTested % Similar to \cs{use_none_delimit_by_q_stop:w}. % \begin{macrocode} -\cs_new:Npn \use_none_delimit_by_s_stop:w #1 \s_stop { } +\cs_new:Npn \__use_none_delimit_by_s__stop:w #1 \s__stop { } +% \end{macrocode} +% \end{macro} +% +% \subsection{Deprecated quark functions} +% +% \begin{macro} +% {\quark_if_recursion_tail_break:N, \quark_if_recursion_tail_break:n} +% It's not clear what breaking function we should be using here, so +% I'm picking one somewhat arbitrarily. +% \begin{macrocode} +\cs_new:Npn \quark_if_recursion_tail_break:N #1 + { \__quark_if_recursion_tail_break:NN #1 \prg_break: } +\cs_new:Npn \quark_if_recursion_tail_break:n #1 + { \__quark_if_recursion_tail_break:nN {#1} \prg_break: } % \end{macrocode} % \end{macro} % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx index d8dd80c75ed..d4a3688a068 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3seq.dtx 3490 2012-03-04 01:00:53Z bruno $ - {L3 Experimental sequences and stacks} +\GetIdInfo$Id: l3seq.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Sequences and stacks} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -109,14 +109,17 @@ % \seq_gset_eq:NN, \seq_gset_eq:cN, \seq_gset_eq:Nc, \seq_gset_eq:cc % } % \begin{syntax} -% \cs{seq_set_eq:NN} \meta{sequence1} \meta{sequence2} +% \cs{seq_set_eq:NN} \meta{sequence_1} \meta{sequence_2} % \end{syntax} -% Sets the content of \meta{sequence1} equal to that of -% \meta{sequence2}. +% Sets the content of \meta{sequence_1} equal to that of +% \meta{sequence_2}. % \end{function} % -% \begin{function}[added = 2011-08-15, updated = 2011-12-07] -% {\seq_set_split:Nnn, \seq_gset_split:Nnn} +% \begin{function}[added = 2011-08-15, updated = 2012-07-02] +% { +% \seq_set_split:Nnn , \seq_set_split:NnV , +% \seq_gset_split:Nnn, \seq_gset_split:NnV +% } % \begin{syntax} % \cs{seq_set_split:Nnn} \meta{sequence} \Arg{delimiter} \Arg{token list} % \end{syntax} @@ -137,11 +140,11 @@ % \begin{function} % {\seq_concat:NNN, \seq_concat:ccc, \seq_gconcat:NNN, \seq_gconcat:ccc} % \begin{syntax} -% \cs{seq_concat:NNN} \meta{sequence1} \meta{sequence2} \meta{sequence3} +% \cs{seq_concat:NNN} \meta{sequence_1} \meta{sequence_2} \meta{sequence_3} % \end{syntax} -% Concatenates the content of \meta{sequence2} and \meta{sequence3} -% together and saves the result in \meta{sequence1}. The items in -% \meta{sequence2} will be placed at the left side of the new sequence. +% Concatenates the content of \meta{sequence_2} and \meta{sequence_3} +% together and saves the result in \meta{sequence_1}. The items in +% \meta{sequence_2} will be placed at the left side of the new sequence. % \end{function} % % \begin{function}[EXP, pTF, added=2012-03-03] @@ -197,27 +200,29 @@ % \meta{token list variable} used with \cs{tl_set:Nn} and \emph{never} % \cs{tl_gset:Nn}. % -% \begin{function}{\seq_get_left:NN, \seq_get_left:cN} +% \begin{function}[updated = 2012-05-14]{\seq_get_left:NN, \seq_get_left:cN} % \begin{syntax} % \cs{seq_get_left:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Stores the left-most item from a \meta{sequence} in the % \meta{token list variable} without removing it from the % \meta{sequence}. The \meta{token list variable} is assigned locally. -% If \meta{sequence} is empty an error will be raised. +% If \meta{sequence} is empty the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. % \end{function} % -% \begin{function}{\seq_get_right:NN, \seq_get_right:cN} +% \begin{function}[updated = 2012-05-19]{\seq_get_right:NN, \seq_get_right:cN} % \begin{syntax} % \cs{seq_get_right:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Stores the right-most item from a \meta{sequence} in the % \meta{token list variable} without removing it from the % \meta{sequence}. The \meta{token list variable} is assigned locally. -% If \meta{sequence} is empty an error will be raised. +% If \meta{sequence} is empty the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. % \end{function} % -% \begin{function}{\seq_pop_left:NN, \seq_pop_left:cN} +% \begin{function}[updated = 2012-05-14]{\seq_pop_left:NN, \seq_pop_left:cN} % \begin{syntax} % \cs{seq_pop_left:NN} \meta{sequence} \meta{token list variable} % \end{syntax} @@ -225,10 +230,11 @@ % \meta{token list variable}, \emph{i.e.}~removes the item from the % sequence and stores it in the \meta{token list variable}. % Both of the variables are assigned locally. If \meta{sequence} is -% empty an error will be raised. +% empty the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. % \end{function} % -% \begin{function}{\seq_gpop_left:NN, \seq_gpop_left:cN} +% \begin{function}[updated = 2012-05-14]{\seq_gpop_left:NN, \seq_gpop_left:cN} % \begin{syntax} % \cs{seq_gpop_left:NN} \meta{sequence} \meta{token list variable} % \end{syntax} @@ -237,10 +243,11 @@ % sequence and stores it in the \meta{token list variable}. % The \meta{sequence} is modified globally, while the assignment of % the \meta{token list variable} is local. -% If \meta{sequence} is empty an error will be raised. +% If \meta{sequence} is empty the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. % \end{function} % -% \begin{function}{\seq_pop_right:NN, \seq_pop_right:cN} +% \begin{function}[updated = 2012-05-19]{\seq_pop_right:NN, \seq_pop_right:cN} % \begin{syntax} % \cs{seq_pop_right:NN} \meta{sequence} \meta{token list variable} % \end{syntax} @@ -248,10 +255,11 @@ % \meta{token list variable}, \emph{i.e.}~removes the item from the % sequence and stores it in in the \meta{token list variable}. % Both of the variables are assigned locally. If \meta{sequence} is -% empty an error will be raised. +% empty the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. % \end{function} % -% \begin{function}{\seq_gpop_right:NN, \seq_gpop_right:cN} +% \begin{function}[updated = 2012-05-19]{\seq_gpop_right:NN, \seq_gpop_right:cN} % \begin{syntax} % \cs{seq_gpop_right:NN} \meta{sequence} \meta{token list variable} % \end{syntax} @@ -260,7 +268,104 @@ % sequence and stores it in the \meta{token list variable}. % The \meta{sequence} is modified globally, while the assignment of % the \meta{token list variable} is local. -% If \meta{sequence} is empty an error will be raised. +% If \meta{sequence} is empty the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. +% \end{function} +% +% \section{Recovering values from sequences with branching} +% +% The functions in this section combine tests for non-empty sequences +% with recovery of an item from the sequence. They offer increased readability +% and performance over separate testing and recovery phases. +% +% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19] +% {\seq_get_left:NN, \seq_get_left:cN} +% \begin{syntax} +% \cs{seq_get_left:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{sequence} is non-empty, stores the left-most item from a +% \meta{sequence} +% in the \meta{token list variable} without removing it from a +% \meta{sequence}. +% The \meta{token list variable} is assigned locally. +% \end{function} +% +% \begin{function}[TF, added = 2012-05-19] +% {\seq_get_right:NN, \seq_get_right:cN} +% \begin{syntax} +% \cs{seq_get_right:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{sequence} is non-empty, stores the right-most item from a +% \meta{sequence} +% in the \meta{token list variable} without removing it from a +% \meta{sequence}. +% The \meta{token list variable} is assigned locally. +% \end{function} +% +% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19] +% {\seq_pop_left:NN, \seq_pop_left:cN} +% \begin{syntax} +% \cs{seq_pop_left:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{sequence} is non-empty, pops the left-most item from a +% \meta{sequence} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from a +% \meta{sequence}. +% Both the \meta{sequence} and the \meta{token list variable} are assigned +% locally. +% \end{function} +% +% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19] +% {\seq_gpop_left:NN, \seq_gpop_left:cN} +% \begin{syntax} +% \cs{seq_gpop_left:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{sequence} is non-empty, pops the left-most item from a \meta{sequence} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from a +% \meta{sequence}. +% The \meta{sequence} is modified globally, while the \meta{token list variable} +% is assigned locally. +% \end{function} +% +% \begin{function}[TF, added = 2012-05-19] +% {\seq_pop_right:NN, \seq_pop_right:cN} +% \begin{syntax} +% \cs{seq_pop_right:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{sequence} is non-empty, pops the right-most item from a \meta{sequence} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from a +% \meta{sequence}. +% Both the \meta{sequence} and the \meta{token list variable} are assigned +% locally. +% \end{function} +% +% \begin{function}[TF, added = 2012-05-19] +% {\seq_gpop_right:NN, \seq_gpop_right:cN} +% \begin{syntax} +% \cs{seq_gpop_right:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{sequence} is non-empty, pops the right-most item from a \meta{sequence} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from a +% \meta{sequence}. The \meta{sequence} is modified globally, while the +% \meta{token list variable} is assigned locally. % \end{function} % % \section{Modifying sequences} @@ -324,7 +429,8 @@ % % \section{Mapping to sequences} % -% \begin{function}[rEXP]{\seq_map_function:NN, \seq_map_function:cN} +% \begin{function}[rEXP, updated = 2012-06-29] +% {\seq_map_function:NN, \seq_map_function:cN} % \begin{syntax} % \cs{seq_map_function:NN} \meta{sequence} \meta{function} % \end{syntax} @@ -336,7 +442,8 @@ % One mapping may be nested inside another. % \end{function} % -% \begin{function}{\seq_map_inline:Nn, \seq_map_inline:cn} +% \begin{function}[updated = 2012-06-29] +% {\seq_map_inline:Nn, \seq_map_inline:cn} % \begin{syntax} % \cs{seq_map_inline:Nn} \meta{sequence} \Arg{inline function} % \end{syntax} @@ -347,10 +454,11 @@ % are returned from left to right. % \end{function} % -% \begin{function}{ -% \seq_map_variable:NNn, \seq_map_variable:Ncn, -% \seq_map_variable:cNn, \seq_map_variable:ccn -% } +% \begin{function}[updated = 2012-06-29] +% { +% \seq_map_variable:NNn, \seq_map_variable:Ncn, +% \seq_map_variable:cNn, \seq_map_variable:ccn +% } % \begin{syntax} % \cs{seq_map_variable:NNn} \meta{sequence} \meta{tl~var.} \Arg{function using tl~var.} % \end{syntax} @@ -362,7 +470,7 @@ % are returned from left to right. % \end{function} % -% \begin{function}[rEXP]{\seq_map_break:} +% \begin{function}[rEXP, updated = 2012-06-29]{\seq_map_break:} % \begin{syntax} % \cs{seq_map_break:} % \end{syntax} @@ -383,13 +491,13 @@ % level \TeX{} errors. % \begin{texnote} % When the mapping is broken, additional tokens may be inserted by the -% internal macro \cs{prg_break_point:n} before further items are taken +% internal macro \cs{__prg_break_point:Nn} before further items are taken % from the input stream. This will depend on the design of the mapping % function. % \end{texnote} % \end{function} % -% \begin{function}[rEXP]{\seq_map_break:n} +% \begin{function}[rEXP, updated = 2012-06-29]{\seq_map_break:n} % \begin{syntax} % \cs{seq_map_break:n} \Arg{tokens} % \end{syntax} @@ -411,12 +519,22 @@ % level \TeX{} errors. % \begin{texnote} % When the mapping is broken, additional tokens may be inserted by the -% internal macro \cs{prg_break_point:n} before the \meta{tokens} are +% internal macro \cs{__prg_break_point:Nn} before the \meta{tokens} are % inserted into the input stream. % This will depend on the design of the mapping function. % \end{texnote} % \end{function} % +% \begin{function}[EXP, added = 2012-07-13]{\seq_count:N, \seq_count:c} +% \begin{syntax} +% \cs{seq_count:N} \meta{sequence} +% \end{syntax} +% Leaves the number of items in the \meta{sequence} in the input +% stream as an \meta{integer denotation}. The total number of items +% in a \meta{sequence} will include those which are empty and duplicates, +% \emph{i.e.}~every item in a \meta{sequence} is unique. +% \end{function} +% % \section{Sequences as stacks} % % Sequences can be used as stacks, where data is pushed to and popped @@ -426,322 +544,147 @@ % in the previous section: a sequence should either be used as an % ordered data type or as a stack, but not in both ways. % -% \begin{function}{\seq_get:NN, \seq_get:cN} +% \begin{function}[updated = 2012-05-14]{\seq_get:NN, \seq_get:cN} % \begin{syntax} % \cs{seq_get:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Reads the top item from a \meta{sequence} into the % \meta{token list variable} without removing it from the % \meta{sequence}. The \meta{token list variable} is assigned locally. -% If \meta{sequence} is empty an error will be raised. +% If \meta{sequence} is empty the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. % \end{function} % -% \begin{function}{\seq_pop:NN, \seq_pop:cN} +% \begin{function}[updated = 2012-05-14]{\seq_pop:NN, \seq_pop:cN} % \begin{syntax} % \cs{seq_pop:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Pops the top item from a \meta{sequence} into the % \meta{token list variable}. Both of the variables are assigned -% locally. If \meta{sequence} is empty an error will be raised. +% locally. If \meta{sequence} is empty the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. % \end{function} % -% \begin{function}{\seq_gpop:NN, \seq_gpop:cN} +% \begin{function}[updated = 2012-05-14]{\seq_gpop:NN, \seq_gpop:cN} % \begin{syntax} % \cs{seq_gpop:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Pops the top item from a \meta{sequence} into the % \meta{token list variable}. The \meta{sequence} is modified globally, % while the \meta{token list variable} is assigned locally. If -% \meta{sequence} is empty an error will be raised. -% \end{function} -% -% \begin{function} -% { -% \seq_push:Nn, \seq_push:NV, \seq_push:Nv, \seq_push:No, \seq_push:Nx, -% \seq_push:cn, \seq_push:cV, \seq_push:cv, \seq_push:co, \seq_push:cx, -% \seq_gpush:Nn, \seq_gpush:NV, \seq_gpush:Nv, -% \seq_gpush:No, \seq_gpush:Nx, -% \seq_gpush:cn, \seq_gpush:cV, \seq_gpush:cv, -% \seq_gpush:co, \seq_gpush:cx -% } -% \begin{syntax} -% \cs{seq_push:Nn} \meta{sequence} \Arg{item} -% \end{syntax} -% Adds the \Arg{item} to the top of the \meta{sequence}. -% \end{function} -% -% \section{Viewing sequences} -% -% \begin{function}{\seq_show:N, \seq_show:c} -% \begin{syntax} -% \cs{seq_show:N} \meta{sequence} -% \end{syntax} -% Displays the entries in the \meta{sequence} in the terminal. -% \end{function} -% -% \section{Experimental sequence functions} -% -% This section contains functions which may or may not be retained, depending -% on how useful they are found to be. -% -% \begin{function}[TF]{\seq_get_left:NN, \seq_get_left:cN} -% \begin{syntax} -% \cs{seq_get_left:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} -% \end{syntax} -% If the \meta{sequence} is empty, leaves the \meta{false code} in the -% input stream and leaves the \meta{token list variable} unchanged. If the -% \meta{sequence} is non-empty, stores the left-most item from a -% \meta{sequence} -% in the \meta{token list variable} without removing it from a -% \meta{sequence}. -% The \meta{token list variable} is assigned locally. -% \end{function} -% -% \begin{function}[TF]{\seq_get_right:NN, \seq_get_right:cN} -% \begin{syntax} -% \cs{seq_get_right:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} -% \end{syntax} -% If the \meta{sequence} is empty, leaves the \meta{false code} in the -% input stream and leaves the \meta{token list variable} unchanged. If the -% \meta{sequence} is non-empty, stores the right-most item from a -% \meta{sequence} -% in the \meta{token list variable} without removing it from a -% \meta{sequence}. -% The \meta{token list variable} is assigned locally. -% \end{function} -% -% \begin{function}[TF]{\seq_pop_left:NN, \seq_pop_left:cN} -% \begin{syntax} -% \cs{seq_pop_left:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} -% \end{syntax} -% If the \meta{sequence} is empty, leaves the \meta{false code} in the -% input stream and leaves the \meta{token list variable} unchanged. If the -% \meta{sequence} is non-empty, pops the left-most item from a -% \meta{sequence} -% in the \meta{token list variable}, \emph{i.e.}~removes the item from a -% \meta{sequence}. -% Both the \meta{sequence} and the \meta{token list variable} are assigned -% locally. +% \meta{sequence} is empty the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. % \end{function} % -% \begin{function}[TF]{\seq_gpop_left:NN, \seq_gpop_left:cN} +% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19]{\seq_get:NN, \seq_get:cN} % \begin{syntax} -% \cs{seq_gpop_left:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} +% \cs{seq_get:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{sequence} is empty, leaves the \meta{false code} in the -% input stream and leaves the \meta{token list variable} unchanged. If the -% \meta{sequence} is non-empty, pops the left-most item from a \meta{sequence} -% in the \meta{token list variable}, \emph{i.e.}~removes the item from a -% \meta{sequence}. -% The \meta{sequence} is modified globally, while the \meta{token list variable} -% is assigned locally. +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{sequence} is non-empty, stores the top item from a +% \meta{sequence} in the \meta{token list variable} without removing it from +% the \meta{sequence}. The \meta{token list variable} is assigned locally. % \end{function} % -% \begin{function}[TF]{\seq_pop_right:NN, \seq_pop_right:cN} +% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19]{\seq_pop:NN, \seq_pop:cN} % \begin{syntax} -% \cs{seq_pop_right:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} +% \cs{seq_pop:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{sequence} is empty, leaves the \meta{false code} in the -% input stream and leaves the \meta{token list variable} unchanged. If the -% \meta{sequence} is non-empty, pops the right-most item from a \meta{sequence} -% in the \meta{token list variable}, \emph{i.e.}~removes the item from a -% \meta{sequence}. -% Both the \meta{sequence} and the \meta{token list variable} are assigned -% locally. +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{sequence} is non-empty, pops the top item from the +% \meta{sequence} in the \meta{token list variable}, \emph{i.e.}~removes the +% item from the \meta{sequence}. Both the \meta{sequence} and the +% \meta{token list variable} are assigned locally. % \end{function} % -% \begin{function}[TF]{\seq_gpop_right:NN, \seq_gpop_right:cN} +% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19]{\seq_gpop:NN, \seq_gpop:cN} % \begin{syntax} -% \cs{seq_gpop_right:NNTF} \meta{sequence} \meta{token list variable} -% ~~\Arg{true code} \Arg{false code} +% \cs{seq_gpop:NNTF} \meta{sequence} \meta{token list variable} \Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{sequence} is empty, leaves the \meta{false code} in the -% input stream and leaves the \meta{token list variable} unchanged. If the -% \meta{sequence} is non-empty, pops the right-most item from a \meta{sequence} -% in the \meta{token list variable}, \emph{i.e.}~removes the item from a -% \meta{sequence}. -% The \meta{sequence} is modified globally, while the \meta{token list variable} -% is assigned locally. -% \end{function} -% -% \begin{function}[EXP]{\seq_length:N, \seq_length:c} -% \begin{syntax} -% \cs{seq_length:N} \meta{sequence} -% \end{syntax} -% Leaves the number of items in the \meta{sequence} in the input -% stream as an \meta{integer denotation}. The total number of items -% in a \meta{sequence} will include those which are empty and duplicates, -% \emph{i.e.}~every item in a \meta{sequence} is unique. -% \end{function} -% -% \begin{function}[EXP, updated = 2012-01-08]{\seq_item:Nn, \seq_item:cn} -% \begin{syntax} -% \cs{seq_item:Nn} \meta{sequence} \Arg{integer expression} -% \end{syntax} -% Indexing items in the \meta{sequence} from $0$ at the top (left), this -% function will evaluate the \meta{integer expression} and leave the -% appropriate item from the sequence in the input stream. If the -% \meta{integer expression} is negative, indexing occurs from the -% bottom (right) of the sequence. When the \meta{integer expression} -% is larger than the number of items in the \meta{sequence} (as -% calculated by \cs{seq_length:N}) then the function will expand to -% nothing. -% \begin{texnote} -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the \meta{item} -% will not expand further when appearing in an x-type -% argument expansion. -% \end{texnote} -% \end{function} -% -% \begin{function}[rEXP]{\seq_use:N, \seq_use:c} -% \begin{syntax} -% \cs{seq_use:N} \meta{sequence} -% \end{syntax} -% Places each \meta{item} in the \meta{sequence} in turn in the input stream. -% This occurs in an expandable fashion, and is implemented as a mapping. -% This means that the process may be prematurely terminated using -% \cs{seq_map_break:} or \cs{seq_map_break:n}. The \meta{items} in the -% \meta{sequence} will be used from left (top) to right (bottom). -% \end{function} -% -% \begin{function}[rEXP] -% { -% \seq_mapthread_function:NNN, \seq_mapthread_function:NcN, -% \seq_mapthread_function:cNN, \seq_mapthread_function:ccN -% } -% \begin{syntax} -% \cs{seq_mapthread_function:NNN} \meta{seq1} \meta{seq2} \meta{function} -% \end{syntax} -% Applies \meta{function} to every pair of items -% \meta{seq1-item}--\meta{seq2-item} from the two sequences, returning -% items from both sequences from left to right. The \meta{function} will -% receive two \texttt{n}-type arguments for each iteration. The mapping -% will terminate when -% the end of either sequence is reached (\emph{i.e.}~whichever sequence has -% fewer items determines how many iterations -% occur). +% input stream. The value of the \meta{token list variable} is +% not defined in this case and should not be relied upon. If the +% \meta{sequence} is non-empty, pops the top item from the \meta{sequence} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from the +% \meta{sequence}. The \meta{sequence} is modified globally, while the +% \meta{token list variable} is assigned locally. % \end{function} % % \begin{function} % { -% \seq_set_from_clist:NN, \seq_set_from_clist:cN, -% \seq_set_from_clist:Nc, \seq_set_from_clist:cc, -% \seq_set_from_clist:Nn, \seq_set_from_clist:cn, -% \seq_gset_from_clist:NN, \seq_gset_from_clist:cN, -% \seq_gset_from_clist:Nc, \seq_gset_from_clist:cc, -% \seq_gset_from_clist:Nn, \seq_gset_from_clist:cn +% \seq_push:Nn, \seq_push:NV, \seq_push:Nv, \seq_push:No, \seq_push:Nx, +% \seq_push:cn, \seq_push:cV, \seq_push:cv, \seq_push:co, \seq_push:cx, +% \seq_gpush:Nn, \seq_gpush:NV, \seq_gpush:Nv, +% \seq_gpush:No, \seq_gpush:Nx, +% \seq_gpush:cn, \seq_gpush:cV, \seq_gpush:cv, +% \seq_gpush:co, \seq_gpush:cx % } % \begin{syntax} -% \cs{seq_set_from_clist:NN} \meta{sequence} \meta{comma-list} +% \cs{seq_push:Nn} \meta{sequence} \Arg{item} % \end{syntax} -% Sets the \meta{sequence} within the current \TeX{} group to be equal -% to the content of the \meta{comma-list}. +% Adds the \Arg{item} to the top of the \meta{sequence}. % \end{function} % -% \begin{function}[added = 2011-11-22, updated = 2011-11-24] -% {\seq_reverse:N, \seq_greverse:N} -% \begin{syntax} -% \cs{seq_reverse:N} \meta{sequence} -% \end{syntax} -% Reverses the order of items in the \meta{sequence}, and -% assigns the result to \meta{sequence}, locally or globally -% according to the variant chosen. -% \end{function} +% \section{Constant and scratch sequences} % -% \begin{function}[added = 2011-12-22] -% {\seq_set_filter:NNn, \seq_gset_filter:NNn} -% \begin{syntax} -% \cs{seq_set_filter:NNn} \meta{sequence1} \meta{sequence2} \Arg{inline boolexpr} -% \end{syntax} -% Evaluates the \meta{inline boolexpr} for every \meta{item} stored -% within the \meta{sequence2}. The \meta{inline boolexpr} will -% receive the \meta{item} as |#1|. The sequence of all \meta{items} -% for which the \meta{inline boolexpr} evaluated to \texttt{true} -% is assigned to \meta{sequence1}. -% \begin{texnote} -% Contrarily to other mapping functions, \cs{seq_map_break:} cannot -% be used in this function, and will lead to low-level \TeX{} errors. -% \end{texnote} -% \end{function} +% \begin{variable}[added = 2012-07-02]{\c_empty_seq} +% Constant that is always empty. +% \end{variable} % -% \begin{function}[added = 2011-12-22] -% {\seq_set_map:NNn, \seq_gset_map:NNn} -% \begin{syntax} -% \cs{seq_set_map:NNn} \meta{sequence1} \meta{sequence2} \Arg{inline function} -% \end{syntax} -% Applies \meta{inline function} to every \meta{item} stored -% within the \meta{sequence2}. The \meta{inline function} should -% consist of code which will receive the \meta{item} as |#1|. -% The sequence resulting from \texttt{x}-expanding -% \meta{inline function} applied to each \meta{item} -% is assigned to \meta{sequence1}. As such, the code -% in \meta{inline function} should be expandable. -% \begin{texnote} -% Contrarily to other mapping functions, \cs{seq_map_break:} cannot -% be used in this function, and will lead to low-level \TeX{} errors. -% \end{texnote} -% \end{function} +% \begin{variable}[added = 2012-04-26]{\l_tmpa_seq, \l_tmpb_seq} +% Scratch sequences for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} % -% \section{Internal sequence functions} +% \begin{variable}[added = 2012-04-26]{\g_tmpa_seq, \g_tmpb_seq} +% Scratch sequences for global assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \section{Viewing sequences} % -% \begin{function}{\seq_if_empty_err_break:N} +% \begin{function}{\seq_show:N, \seq_show:c} % \begin{syntax} -% \cs{seq_if_empty_err_break:N} \meta{sequence} +% \cs{seq_show:N} \meta{sequence} % \end{syntax} -% Tests if the \meta{sequence} is empty, and if so issues an error -% message before skipping over any tokens up to \cs{prg_break_point:n}. -% This function is used to avoid more serious errors which would -% otherwise occur if some internal functions were applied to an -% empty \meta{sequence}. +% Displays the entries in the \meta{sequence} in the terminal. % \end{function} % -% \begin{function}[EXP]{\seq_item:n} +% \section{Internal sequence functions} +% +% \begin{function}[EXP]{\__seq_item:n} % \begin{syntax} -% \cs{seq_item:n} \meta{item} +% \cs{__seq_item:n} \meta{item} % \end{syntax} % The internal token used to begin each sequence entry. If expanded % outside of a mapping or manipulation function, an error will be % raised. The definition should always be set globally. % \end{function} % -% \begin{function}{\seq_push_item_def:n, \seq_push_item_def:x} +% \begin{function}{\__seq_push_item_def:n, \__seq_push_item_def:x} % \begin{syntax} -% \cs{seq_push_item_def:n} \Arg{code} +% \cs{__seq_push_item_def:n} \Arg{code} % \end{syntax} -% Saves the definition of \cs{seq_item:n} and redefines it to +% Saves the definition of \cs{__seq_item:n} and redefines it to % accept one parameter and expand to \meta{code}. This function -% should always be balanced by use of \cs{seq_pop_item_def:}. -% \end{function} -% -% \begin{function}{\seq_pop_item_def:} -% \begin{syntax} -% \cs{seq_pop_item_def:} -% \end{syntax} -% Restores the definition of \cs{seq_item:n} most recently saved by -% \cs{seq_push_item_def:n}. This function should always be used in -% a balanced pair with \cs{seq_push_item_def:n}. +% should always be balanced by use of \cs{__seq_pop_item_def:}. % \end{function} % -% \begin{function}[EXP]{\seq_break:} +% \begin{function}{\__seq_pop_item_def:} % \begin{syntax} -% \cs{seq_break:} +% \cs{__seq_pop_item_def:} % \end{syntax} -% Used to terminate sequence functions by gobbling all tokens -% up to \cs{prg_break_point:n}. This function is a copy of -% \cs{seq_map_break:}, but is used in situations which are -% not mappings. -% \end{function} -% -% \begin{function}[EXP]{\seq_break:n} -% \begin{syntax} -% \cs{seq_break:n} \Arg{tokens} -% \end{syntax} -% Used to terminate sequence functions by gobbling all tokens -% up to \cs{prg_break_point:n}, then inserting the \meta{tokens} -% before continuing reading the input stream. This function is a copy -% of \cs{seq_map_break:n}, but is used in situations which are -% not mappings. +% Restores the definition of \cs{__seq_item:n} most recently saved by +% \cs{__seq_push_item_def:n}. This function should always be used in +% a balanced pair with \cs{__seq_push_item_def:n}. % \end{function} % % \end{documentation} @@ -757,41 +700,52 @@ % \end{macrocode} % % \begin{macrocode} +%<@@=seq> +% \end{macrocode} +% +% \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % % A sequence is a control sequence whose top-level expansion is of -% the form \enquote{\cs{seq_item:n} \marg{item$_0$} -% \ldots \cs{seq_item:n} \marg{item$_{n-1}$}}. An earlier implementation -% used the structure \enquote{\cs{seq_elt:w} \meta{item$_1$} -% \cs{seq_elt_end:} \ldots \cs{seq_elt:w} \meta{item$_n$} +% the form \enquote{\cs{@@_item:n} \marg{item_1} +% \ldots \cs{@@_item:n} \marg{item_n}}. An earlier implementation +% used the structure \enquote{\cs{seq_elt:w} \meta{item_1} +% \cs{seq_elt_end:} \ldots \cs{seq_elt:w} \meta{item_n} % \cs{seq_elt_end:}}. This allows rapid searching using a delimited % function, but is not suitable for items containing |{|, |}| and |#| % tokens, and also leads to the loss of surrounding braces % around items. % -% \begin{macro}[int]{\seq_item:n} +% \begin{macro}[int]{\@@_item:n} % The delimiter is always defined, but when used incorrectly simply % removes its argument and hits an undefined control sequence to % raise an error. % \begin{macrocode} -\cs_new:Npn \seq_item:n +\cs_new:Npn \@@_item:n { - \msg_expandable_kernel_error:nn { seq } { misused } + \__msg_kernel_expandable_error:nn { kernel } { misused-sequence } \use_none:n } % \end{macrocode} % \end{macro} % -% \begin{variable}{\l_seq_internal_a_tl, \l_seq_internal_b_tl} +% \begin{variable}{\l_@@_internal_a_tl, \l_@@_internal_b_tl} % Scratch space for various internal uses. % \begin{macrocode} -\tl_new:N \l_seq_internal_a_tl -\tl_new:N \l_seq_internal_b_tl +\tl_new:N \l_@@_internal_a_tl +\tl_new:N \l_@@_internal_b_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_empty_seq} +% Simply copy the empty token list. +% \begin{macrocode} +\cs_new_eq:NN \c_empty_seq \c_empty_tl % \end{macrocode} % \end{variable} % @@ -853,25 +807,29 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\seq_set_split:Nnn,\seq_gset_split:Nnn} -% \begin{macro}[aux]{\seq_set_split_aux:NNnn} +% \begin{macro} +% { +% \seq_set_split:Nnn , \seq_set_split:NnV , +% \seq_gset_split:Nnn, \seq_gset_split:NnV +% } +% \begin{macro}[aux]{\@@_set_split:NNnn} % \begin{macro}[aux] % { -% \seq_set_split_aux_i:w, \seq_set_split_aux_ii:w, -% \seq_set_split_aux_end: +% \@@_set_split_i:w, \@@_set_split_ii:w, +% \@@_set_split_end: % } % The goal is to split a given token list at a marker, % strip spaces from each item, and remove one set of % outer braces if after removing leading and trailing % spaces the item is enclosed within braces. After -% \cs{tl_replace_all:Nnn}, the token list \cs{l_seq_internal_a_tl} +% \cs{tl_replace_all:Nnn}, the token list \cs{l_@@_internal_a_tl} % is a repetition of the pattern -% \cs{seq_set_split_aux_i:w} \cs{prg_do_nothing:} -% \meta{item with spaces} \cs{seq_set_split_aux_end:}. -% Then, \texttt{x}-expansion causes \cs{seq_set_split_aux_i:w} +% \cs{@@_set_split_i:w} \cs{prg_do_nothing:} +% \meta{item with spaces} \cs{@@_set_split_end:}. +% Then, \texttt{x}-expansion causes \cs{@@_set_split_i:w} % to trim spaces, and leaves its result as -% \cs{seq_set_split_aux_ii:w} \meta{trimmed item} -% \cs{seq_set_split_aux_end:}. This is then converted +% \cs{@@_set_split_ii:w} \meta{trimmed item} +% \cs{@@_set_split_end:}. This is then converted % to the \pkg{l3seq} internal structure by another % \texttt{x}-expansion. In the first step, we insert % \cs{prg_do_nothing:} to avoid losing braces too early: @@ -880,37 +838,39 @@ % braces which are outermost after space trimming. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_set_split:Nnn - { \seq_set_split_aux:NNnn \tl_set:Nx } + { \@@_set_split:NNnn \tl_set:Nx } \cs_new_protected_nopar:Npn \seq_gset_split:Nnn - { \seq_set_split_aux:NNnn \tl_gset:Nx } -\cs_new_protected:Npn \seq_set_split_aux:NNnn #1 #2 #3 #4 + { \@@_set_split:NNnn \tl_gset:Nx } +\cs_new_protected:Npn \@@_set_split:NNnn #1 #2 #3 #4 { \tl_if_empty:nTF {#3} - { #1 #2 { \tl_map_function:nN {#4} \seq_wrap_item:n } } + { #1 #2 { \tl_map_function:nN {#4} \@@_wrap_item:n } } { - \tl_set:Nn \l_seq_internal_a_tl + \tl_set:Nn \l_@@_internal_a_tl { - \seq_set_split_aux_i:w \prg_do_nothing: + \@@_set_split_i:w \prg_do_nothing: #4 - \seq_set_split_aux_end: + \@@_set_split_end: } - \tl_replace_all:Nnn \l_seq_internal_a_tl { #3 } + \tl_replace_all:Nnn \l_@@_internal_a_tl { #3 } { - \seq_set_split_aux_end: - \seq_set_split_aux_i:w \prg_do_nothing: + \@@_set_split_end: + \@@_set_split_i:w \prg_do_nothing: } - \tl_set:Nx \l_seq_internal_a_tl { \l_seq_internal_a_tl } - #1 #2 { \l_seq_internal_a_tl } + \tl_set:Nx \l_@@_internal_a_tl { \l_@@_internal_a_tl } + #1 #2 { \l_@@_internal_a_tl } } } -\cs_new:Npn \seq_set_split_aux_i:w #1 \seq_set_split_aux_end: +\cs_new:Npn \@@_set_split_i:w #1 \@@_set_split_end: { - \exp_not:N \seq_set_split_aux_ii:w + \exp_not:N \@@_set_split_ii:w \exp_args:No \tl_trim_spaces:n {#1} - \exp_not:N \seq_set_split_aux_end: + \exp_not:N \@@_set_split_end: } -\cs_new:Npn \seq_set_split_aux_ii:w #1 \seq_set_split_aux_end: - { \seq_wrap_item:n {#1} } +\cs_new:Npn \@@_set_split_ii:w #1 \@@_set_split_end: + { \@@_wrap_item:n {#1} } +\cs_generate_variant:Nn \seq_set_split:Nnn { NnV } +\cs_generate_variant:Nn \seq_gset_split:Nnn { NnV } % \end{macrocode} % \end{macro} % \end{macro} @@ -965,9 +925,9 @@ % The code here is just a wrapper for adding to token lists. % \begin{macrocode} \cs_new_protected:Npn \seq_put_left:Nn #1#2 - { \tl_put_left:Nn #1 { \seq_item:n {#2} } } + { \tl_put_left:Nn #1 { \@@_item:n {#2} } } \cs_new_protected:Npn \seq_put_right:Nn #1#2 - { \tl_put_right:Nn #1 { \seq_item:n {#2} } } + { \tl_put_right:Nn #1 { \@@_item:n {#2} } } \cs_generate_variant:Nn \seq_put_left:Nn { NV , Nv , No , Nx } \cs_generate_variant:Nn \seq_put_left:Nn { c , cV , cv , co , cx } \cs_generate_variant:Nn \seq_put_right:Nn { NV , Nv , No , Nx } @@ -991,9 +951,9 @@ % The same for global addition. % \begin{macrocode} \cs_new_protected:Npn \seq_gput_left:Nn #1#2 - { \tl_gput_left:Nn #1 { \seq_item:n {#2} } } + { \tl_gput_left:Nn #1 { \@@_item:n {#2} } } \cs_new_protected:Npn \seq_gput_right:Nn #1#2 - { \tl_gput_right:Nn #1 { \seq_item:n {#2} } } + { \tl_gput_right:Nn #1 { \@@_item:n {#2} } } \cs_generate_variant:Nn \seq_gput_left:Nn { NV , Nv , No , Nx } \cs_generate_variant:Nn \seq_gput_left:Nn { c , cV , cv , co , cx } \cs_generate_variant:Nn \seq_gput_right:Nn { NV , Nv , No , Nx } @@ -1004,18 +964,18 @@ % % \subsection{Modifying sequences} % -% \begin{macro}[aux]{\seq_wrap_item:n} +% \begin{macro}[aux]{\@@_wrap_item:n} % This function converts its argument to a proper sequence item % in an \texttt{x}-expansion context. % \begin{macrocode} -\cs_new:Npn \seq_wrap_item:n #1 { \exp_not:n { \seq_item:n {#1} } } +\cs_new:Npn \@@_wrap_item:n #1 { \exp_not:n { \@@_item:n {#1} } } % \end{macrocode} % \end{macro} % -% \begin{variable}{\l_seq_internal_remove_seq} +% \begin{variable}{\l_@@_remove_seq} % An internal sequence for the removal routines. % \begin{macrocode} -\seq_new:N \l_seq_internal_remove_seq +\seq_new:N \l_@@_remove_seq % \end{macrocode} % \end{variable} % @@ -1023,22 +983,22 @@ % \UnitTested % \begin{macro}{\seq_gremove_duplicates:N, \seq_gremove_duplicates:c} % \UnitTested -% \begin{macro}[aux]{\seq_remove_duplicates_aux:NN} +% \begin{macro}[aux]{\@@_remove_duplicates:NN} % Removing duplicates means making a new list then copying it. % \begin{macrocode} \cs_new_protected:Npn \seq_remove_duplicates:N - { \seq_remove_duplicates_aux:NN \seq_set_eq:NN } + { \@@_remove_duplicates:NN \seq_set_eq:NN } \cs_new_protected:Npn \seq_gremove_duplicates:N - { \seq_remove_duplicates_aux:NN \seq_gset_eq:NN } -\cs_new_protected:Npn \seq_remove_duplicates_aux:NN #1#2 + { \@@_remove_duplicates:NN \seq_gset_eq:NN } +\cs_new_protected:Npn \@@_remove_duplicates:NN #1#2 { - \seq_clear:N \l_seq_internal_remove_seq + \seq_clear:N \l_@@_remove_seq \seq_map_inline:Nn #2 { - \seq_if_in:NnF \l_seq_internal_remove_seq {##1} - { \seq_put_right:Nn \l_seq_internal_remove_seq {##1} } + \seq_if_in:NnF \l_@@_remove_seq {##1} + { \seq_put_right:Nn \l_@@_remove_seq {##1} } } - #1 #2 \l_seq_internal_remove_seq + #1 #2 \l_@@_remove_seq } \cs_generate_variant:Nn \seq_remove_duplicates:N { c } \cs_generate_variant:Nn \seq_gremove_duplicates:N { c } @@ -1051,11 +1011,11 @@ % \UnitTested % \begin{macro}{\seq_gremove_all:Nn, \seq_gremove_all:cn} % \UnitTested -% \begin{macro}[aux]{\seq_remove_all_aux:NNn} +% \begin{macro}[aux]{\@@_remove_all_aux:NNn} % The idea of the code here is to avoid a relatively expensive addition of % items one at a time to an intermediate sequence. % The approach taken is therefore similar to -% that in \cs{seq_pop_right_aux_ii:NNN}, using a \enquote{flexible} +% that in \cs{@@_pop_right_aux_ii:NNN}, using a \enquote{flexible} % \texttt{x}-type expansion to do most of the work. As \cs{tl_if_eq:nnT} % is not expandable, a two-part strategy is needed. First, the % \texttt{x}-type expansion uses \cs{str_if_eq:nnT} to find potential @@ -1068,28 +1028,28 @@ % lost. % \begin{macrocode} \cs_new_protected:Npn \seq_remove_all:Nn - { \seq_remove_all_aux:NNn \tl_set:Nx } + { \@@_remove_all_aux:NNn \tl_set:Nx } \cs_new_protected:Npn \seq_gremove_all:Nn - { \seq_remove_all_aux:NNn \tl_gset:Nx } -\cs_new_protected:Npn \seq_remove_all_aux:NNn #1#2#3 + { \@@_remove_all_aux:NNn \tl_gset:Nx } +\cs_new_protected:Npn \@@_remove_all_aux:NNn #1#2#3 { - \seq_push_item_def:n + \@@_push_item_def:n { \str_if_eq:nnT {##1} {#3} { \if_false: { \fi: } - \tl_set:Nn \l_seq_internal_b_tl {##1} + \tl_set:Nn \l_@@_internal_b_tl {##1} #1 #2 { \if_false: } \fi: \exp_not:o {#2} - \tl_if_eq:NNT \l_seq_internal_a_tl \l_seq_internal_b_tl + \tl_if_eq:NNT \l_@@_internal_a_tl \l_@@_internal_b_tl { \use_none:nn } } - \seq_wrap_item:n {##1} + \@@_wrap_item:n {##1} } - \tl_set:Nn \l_seq_internal_a_tl {#3} + \tl_set:Nn \l_@@_internal_a_tl {#3} #1 #2 {#2} - \seq_pop_item_def: + \@@_pop_item_def: } \cs_generate_variant:Nn \seq_remove_all:Nn { c } \cs_generate_variant:Nn \seq_gremove_all:Nn { c } @@ -1117,33 +1077,35 @@ % \seq_if_in:cn, \seq_if_in:cV, \seq_if_in:cv, \seq_if_in:co, \seq_if_in:cx % } % \UnitTested -% \begin{macro}[aux]{\seq_if_in_aux:} -% The approach here is to define \cs{seq_item:n} to compare its +% \begin{macro}[aux]{\@@_if_in:} +% The approach here is to define \cs{@@_item:n} to compare its % argument with the test sequence. If the two items are equal, the -% mapping is terminated and \cs{prg_return_true:} is inserted. On the +% mapping is terminated and \cs{group_end:} \cs{prg_return_true:} +% is inserted after skipping over the rest of the recursion. On the % other hand, if there is no match then the loop will break returning -% \cs{prg_return_false:}. In either case, \cs{prg_break_point:n} -% ensures that the group ends before the logical value is returned. -% Everything is inside a group so that \cs{seq_item:n} is preserved +% \cs{prg_return_false:}. +% Everything is inside a group so that \cs{@@_item:n} is preserved % in nested situations. % \begin{macrocode} \prg_new_protected_conditional:Npnn \seq_if_in:Nn #1#2 { T , F , TF } { \group_begin: - \tl_set:Nn \l_seq_internal_a_tl {#2} - \cs_set_protected:Npn \seq_item:n ##1 + \tl_set:Nn \l_@@_internal_a_tl {#2} + \cs_set_protected:Npn \@@_item:n ##1 { - \tl_set:Nn \l_seq_internal_b_tl {##1} - \if_meaning:w \l_seq_internal_a_tl \l_seq_internal_b_tl - \exp_after:wN \seq_if_in_aux: + \tl_set:Nn \l_@@_internal_b_tl {##1} + \if_meaning:w \l_@@_internal_a_tl \l_@@_internal_b_tl + \exp_after:wN \@@_if_in: \fi: } #1 - \seq_break:n { \prg_return_false: } - \prg_break_point:n { \group_end: } + \group_end: + \prg_return_false: + \__prg_break_point: } -\cs_new_nopar:Npn \seq_if_in_aux: { \seq_break:n { \prg_return_true: } } +\cs_new_nopar:Npn \@@_if_in: + { \__prg_break:n { \group_end: \prg_return_true: } } \cs_generate_variant:Nn \seq_if_in:NnT { NV , Nv , No , Nx } \cs_generate_variant:Nn \seq_if_in:NnT { c , cV , cv , co , cx } \cs_generate_variant:Nn \seq_if_in:NnF { NV , Nv , No , Nx } @@ -1156,21 +1118,50 @@ % % \subsection{Recovering data from sequences} % +% \begin{macro}[int]{\@@_pop:NNNN, \@@_pop_TF:NNNN} +% The two \texttt{pop} functions share their emptiness tests. We also +% use a common emptiness test for all branching \texttt{get} and +% \texttt{pop} functions. +% \begin{macrocode} +\cs_new_protected:Npn \@@_pop:NNNN #1#2#3#4 + { + \if_meaning:w #3 \c_empty_seq + \tl_set:Nn #4 { \q_no_value } + \else: + #1#2#3#4 + \fi: + } +\cs_new_protected:Npn \@@_pop_TF:NNNN #1#2#3#4 + { + \if_meaning:w #3 \c_empty_seq + % \tl_set:Nn #4 { \q_no_value } + \prg_return_false: + \else: + #1#2#3#4 + \prg_return_true: + \fi: + } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\seq_get_left:NN, \seq_get_left:cN} % \UnitTested -% \begin{macro}[aux]{\seq_get_left_aux:NnwN} +% \begin{macro}[aux]{\@@_get_left:NnwN} % Getting an item from the left of a sequence is pretty easy: just -% trim off the first item after removing the \cs{seq_item:n} at -% the start. +% trim off the first item after removing the \cs{@@_item:n} at +% the start. We first append a \cs{q_no_value} item to cover the case +% of an empty sequence % \begin{macrocode} \cs_new_protected:Npn \seq_get_left:NN #1#2 { - \seq_if_empty_err_break:N #1 - \exp_after:wN \seq_get_left_aux:NnwN #1 \q_stop #2 - \prg_break_point:n { } + \tl_set:Nx #2 + { + \exp_after:wN \@@_get_left:Nnw + #1 \@@_item:n { \q_no_value } \q_stop + } } -\cs_new_protected:Npn \seq_get_left_aux:NnwN \seq_item:n #1#2 \q_stop #3 - { \tl_set:Nn #3 {#1} } +\cs_new:Npn \@@_get_left:Nnw \@@_item:n #1#2 \q_stop + { \exp_not:n {#1} } \cs_generate_variant:Nn \seq_get_left:NN { c } % \end{macrocode} % \end{macro} @@ -1180,24 +1171,19 @@ % \UnitTested % \begin{macro}{\seq_gpop_left:NN, \seq_gpop_left:cN} % \UnitTested -% \begin{macro}[aux]{\seq_pop_left_aux:NNN} -% \begin{macro}[aux]{\seq_pop_left_aux:NnwNNN} +% \begin{macro}[aux]{\@@_pop_left:NNN, \@@_pop_left:NnwNNN} % The approach to popping an item is pretty similar to that to get % an item, with the only difference being that the sequence itself has % to be redefined. This makes it more sensible to use an auxiliary % function for the local and global cases. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_pop_left:NN - { \seq_pop_left_aux:NNN \tl_set:Nn } + { \@@_pop:NNNN \@@_pop_left:NNN \tl_set:Nn } \cs_new_protected_nopar:Npn \seq_gpop_left:NN - { \seq_pop_left_aux:NNN \tl_gset:Nn } -\cs_new_protected:Npn \seq_pop_left_aux:NNN #1#2#3 - { - \seq_if_empty_err_break:N #2 - \exp_after:wN \seq_pop_left_aux:NnwNNN #2 \q_stop #1#2#3 - \prg_break_point:n { } - } -\cs_new_protected:Npn \seq_pop_left_aux:NnwNNN \seq_item:n #1#2 \q_stop #3#4#5 + { \@@_pop:NNNN \@@_pop_left:NNN \tl_gset:Nn } +\cs_new_protected:Npn \@@_pop_left:NNN #1#2#3 + { \exp_after:wN \@@_pop_left:NnwNNN #2 \q_stop #1#2#3 } +\cs_new_protected:Npn \@@_pop_left:NnwNNN \@@_item:n #1#2 \q_stop #3#4#5 { #3 #4 {#2} \tl_set:Nn #5 {#1} @@ -1208,94 +1194,84 @@ % \end{macro} % \end{macro} % \end{macro} -% \end{macro} % % \begin{macro}{\seq_get_right:NN, \seq_get_right:cN} % \UnitTested -% \begin{macro}[aux]{\seq_get_right_aux:NN} -% \begin{macro}[aux]{\seq_get_right_loop:nn} -% The idea here is to remove the very first \cs{seq_item:n} from the -% sequence, leaving a token list starting with the first braced entry. -% Two arguments at a time are then grabbed: apart from the right-hand end of -% the sequence, this will be a brace group followed by \cs{seq_item:n}. The -% set up code means that these all disappear. At the end of the sequence, -% the assignment is placed in front of the very last entry in the sequence, -% before a tidying-up step takes place to remove the loop and reset the -% meaning of \cs{seq_item:n}. +% \begin{macro}[aux]{\@@_get_right_loop:nn} +% First prepend \cs{q_no_value}, then take two arguments at a time. +% Apart from the right-hand end of the sequence, this be a brace group +% followed by \cs{@@_item:n}. The \cs{use_none:nn} removes both of +% those. At the end of the sequence, the two question marks are taken +% by \cs{use_none:nn}, and the assignment is placed before the +% right-most item. The \tn{afterassignment} primitive places +% \cs{use_none:n} to get rid of a trailing \cs{@@_get_right_loop:nn}. % \begin{macrocode} \cs_new_protected:Npn \seq_get_right:NN #1#2 { - \seq_if_empty_err_break:N #1 - \seq_get_right_aux:NN #1#2 - \prg_break_point:n { } + \exp_after:wN \@@_get_right_loop:nn + \exp_after:wN \q_no_value + #1 + { + ?? + \tex_afterassignment:D \use_none:n + \tl_set:Nn #2 + } } -\cs_new_protected:Npn \seq_get_right_aux:NN #1#2 - { - \seq_push_item_def:n { } - \exp_after:wN \exp_after:wN \exp_after:wN \seq_get_right_loop:nn - \exp_after:wN \use_none:n #1 - { \tl_set:Nn #2 } - { } - { - \seq_pop_item_def: - \seq_break: - } -} -\cs_new:Npn \seq_get_right_loop:nn #1#2 +\cs_new_protected:Npn \@@_get_right_loop:nn #1#2 { - #2 {#1} - \seq_get_right_loop:nn + \use_none:nn #2 {#1} + \@@_get_right_loop:nn } \cs_generate_variant:Nn \seq_get_right:NN { c } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} % % \begin{macro}{\seq_pop_right:NN, \seq_pop_right:cN} % \UnitTested % \begin{macro}{\seq_gpop_right:NN, \seq_gpop_right:cN} % \UnitTested -% \begin{macro}[aux]{\seq_pop_right_aux:NNN, \seq_pop_right_aux_ii:NNN} +% \begin{macro}[aux]{\@@_pop_right_aux:NNN, \@@_pop_right_loop:nn} % The approach to popping from the right is a bit more involved, but does % use some of the same ideas as getting from the right. What is needed is a % \enquote{flexible length} way to set a token list variable. This is -% supplied by the |{ \if_false:} \fi:| \ldots +% supplied by the |{ \if_false: } \fi:| \ldots % |\if_false: { \fi: }| construct. Using an \texttt{x}-type -% expansion and a \enquote{non-expanding} definition for \cs{seq_item:n}, +% expansion and a \enquote{non-expanding} definition for \cs{@@_item:n}, % the left-most $n - 1$ entries in a sequence of $n$ items will be stored % back in the sequence. That needs a loop of unknown length, hence using the % strange \cs{if_false:} way of including brackets. When the last item % of the sequence is reached, the closing bracket for the assignment is -% inserted, and |\tl_set:Nn #3| is inserted in front of the final entry. -% This therefore does the pop assignment, then a final loop clears up the -% code. +% inserted, and |\tl_set:Nn #3| is inserted in front of the final +% entry. This therefore does the pop assignment. The trailing +% looping macro is removed by placing a \cs{use_none:n} using the +% \tn{afterassignment} primitive. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_pop_right:NN - { \seq_pop_right_aux:NNN \tl_set:Nx } + { \@@_pop:NNNN \@@_pop_right_aux:NNN \tl_set:Nx } \cs_new_protected_nopar:Npn \seq_gpop_right:NN - { \seq_pop_right_aux:NNN \tl_gset:Nx } -\cs_new_protected:Npn \seq_pop_right_aux:NNN #1#2#3 - { - \seq_if_empty_err_break:N #2 - \seq_pop_right_aux_ii:NNN #1 #2 #3 - \prg_break_point:n { } - } -\cs_new_protected:Npn \seq_pop_right_aux_ii:NNN #1#2#3 + { \@@_pop:NNNN \@@_pop_right_aux:NNN \tl_gset:Nx } +\cs_new_protected:Npn \@@_pop_right_aux:NNN #1#2#3 { - \seq_push_item_def:n { \seq_wrap_item:n {##1} } - #1 #2 { \if_false: } \fi: - \exp_after:wN \exp_after:wN \exp_after:wN \seq_get_right_loop:nn - \exp_after:wN \use_none:n #2 + \cs_set_eq:NN \seq_tmp:w \@@_item:n + \cs_set_eq:NN \@@_item:n \scan_stop: + #1 #2 + { \if_false: } \fi: + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_pop_right_loop:nn + \exp_after:wN \use_none:n + #2 { \if_false: { \fi: } - \tl_set:Nn #3 - } - { } - { - \seq_pop_item_def: - \seq_break: + \tex_afterassignment:D \use_none:n + \tl_set:Nx #3 } + \cs_set_eq:NN \@@_item:n \seq_tmp:w + } +\cs_new:Npn \@@_pop_right_loop:nn #1#2 + { + #2 { \exp_not:n {#1} } + \@@_pop_right_loop:nn } \cs_generate_variant:Nn \seq_pop_right:NN { c } \cs_generate_variant:Nn \seq_gpop_right:NN { c } @@ -1304,99 +1280,130 @@ % \end{macro} % \end{macro} % +% \begin{macro}[TF]{\seq_get_left:NN, \seq_get_left:cN} +% \begin{macro}[TF]{\seq_get_right:NN, \seq_get_right:cN} +% Getting from the left or right with a check on the results. The +% first argument to \cs{@@_pop_TF:NNNN} is left unused. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \seq_get_left:NN #1#2 { T , F , TF } + { \@@_pop_TF:NNNN \prg_do_nothing: \seq_get_left:NN #1#2 } +\prg_new_protected_conditional:Npnn \seq_get_right:NN #1#2 { T , F , TF } + { \@@_pop_TF:NNNN \prg_do_nothing: \seq_get_right:NN #1#2 } +\cs_generate_variant:Nn \seq_get_left:NNT { c } +\cs_generate_variant:Nn \seq_get_left:NNF { c } +\cs_generate_variant:Nn \seq_get_left:NNTF { c } +\cs_generate_variant:Nn \seq_get_right:NNT { c } +\cs_generate_variant:Nn \seq_get_right:NNF { c } +\cs_generate_variant:Nn \seq_get_right:NNTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[TF]{\seq_pop_left:NN, \seq_pop_left:cN} +% \begin{macro}[TF]{\seq_gpop_left:NN, \seq_gpop_left:cN} +% \begin{macro}[TF]{\seq_pop_right:NN, \seq_pop_right:cN} +% \begin{macro}[TF]{\seq_gpop_right:NN, \seq_gpop_right:cN} +% More or less the same for popping. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \seq_pop_left:NN #1#2 { T , F , TF } + { \@@_pop_TF:NNNN \@@_pop_left:NNN \tl_set:Nn #1 #2 } +\prg_new_protected_conditional:Npnn \seq_gpop_left:NN #1#2 { T , F , TF } + { \@@_pop_TF:NNNN \@@_pop_left:NNN \tl_gset:Nn #1 #2 } +\prg_new_protected_conditional:Npnn \seq_pop_right:NN #1#2 { T , F , TF } + { \@@_pop_TF:NNNN \@@_pop_right_aux:NNN \tl_set:Nx #1 #2 } +\prg_new_protected_conditional:Npnn \seq_gpop_right:NN #1#2 { T , F , TF } + { \@@_pop_TF:NNNN \@@_pop_right_aux:NNN \tl_gset:Nx #1 #2 } +\cs_generate_variant:Nn \seq_pop_left:NNT { c } +\cs_generate_variant:Nn \seq_pop_left:NNF { c } +\cs_generate_variant:Nn \seq_pop_left:NNTF { c } +\cs_generate_variant:Nn \seq_gpop_left:NNT { c } +\cs_generate_variant:Nn \seq_gpop_left:NNF { c } +\cs_generate_variant:Nn \seq_gpop_left:NNTF { c } +\cs_generate_variant:Nn \seq_pop_right:NNT { c } +\cs_generate_variant:Nn \seq_pop_right:NNF { c } +\cs_generate_variant:Nn \seq_pop_right:NNTF { c } +\cs_generate_variant:Nn \seq_gpop_right:NNT { c } +\cs_generate_variant:Nn \seq_gpop_right:NNF { c } +\cs_generate_variant:Nn \seq_gpop_right:NNTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % \subsection{Mapping to sequences} % % \begin{macro}{\seq_map_break:} % \UnitTested % \begin{macro}{\seq_map_break:n} % \UnitTested -% \begin{macro}[int]{\seq_break:} -% \begin{macro}[int]{\seq_break:n} -% To break a function, the special token \cs{prg_break_point:n} is +% To break a function, the special token \cs{__prg_break_point:Nn} is % used to find the end of the code. Any ending code is then inserted % before the return value of \cs{seq_map_break:n} is inserted. -% Semantically-logical copies of the break functions for use inside -% mappings. % \begin{macrocode} -\cs_new_eq:NN \seq_break: \prg_map_break: -\cs_new_eq:NN \seq_break:n \prg_map_break:n -\cs_new_eq:NN \seq_map_break: \prg_map_break: -\cs_new_eq:NN \seq_map_break:n \prg_map_break:n +\cs_new_nopar:Npn \seq_map_break: + { \__prg_map_break:Nn \seq_map_break: { } } +\cs_new_nopar:Npn \seq_map_break:n + { \__prg_map_break:Nn \seq_map_break: } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}[int]{\seq_if_empty_err_break:N} -% A function to check that sequences really have some content. This -% is optimised for speed, hence the direct primitive use. -% \begin{macrocode} -\cs_new_protected:Npn \seq_if_empty_err_break:N #1 - { - \if_meaning:w #1 \c_empty_tl - \msg_kernel_error:nnx { seq } { empty-sequence } { \token_to_str:N #1 } - \exp_after:wN \seq_break: - \fi: - } -% \end{macrocode} -% \end{macro} % % \begin{macro}{\seq_map_function:NN, \seq_map_function:cN} % \UnitTested -% \begin{macro}[aux]{\seq_map_function_aux:NNn} +% \begin{macro}[aux]{\@@_map_function:NNn} % The idea here is to apply the code of |#2| to each item in the -% sequence without altering the definition of \cs{seq_item:n}. This +% sequence without altering the definition of \cs{@@_item:n}. This % is done as by noting that every odd token in the sequence must be -% \cs{seq_item:n}, which can be gobbled by \cs{use_none:n}. At the end of +% \cs{@@_item:n}, which can be gobbled by \cs{use_none:n}. At the end of % the loop, |#2| is instead |? \seq_map_break:|, which therefore breaks the % loop without needing to do a (relatively-expensive) quark test. % \begin{macrocode} \cs_new:Npn \seq_map_function:NN #1#2 { - \exp_after:wN \seq_map_function_aux:NNn \exp_after:wN #2 #1 + \exp_after:wN \@@_map_function:NNn \exp_after:wN #2 #1 { ? \seq_map_break: } { } - \prg_break_point:n { } + \__prg_break_point:Nn \seq_map_break: { } } -\cs_new:Npn \seq_map_function_aux:NNn #1#2#3 +\cs_new:Npn \@@_map_function:NNn #1#2#3 { \use_none:n #2 #1 {#3} - \seq_map_function_aux:NNn #1 + \@@_map_function:NNn #1 } \cs_generate_variant:Nn \seq_map_function:NN { c } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[int]{\seq_push_item_def:n, \seq_push_item_def:x} -% \begin{macro}[aux]{\seq_push_item_def_aux:} -% \begin{macro}[int]{\seq_pop_item_def:} -% The definition of \cs{seq_item:n} needs to be saved and restored at +% \begin{macro}[int]{\@@_push_item_def:n, \@@_push_item_def:x} +% \begin{macro}[aux]{\@@_push_item_def:} +% \begin{macro}[int]{\@@_pop_item_def:} +% The definition of \cs{@@_item:n} needs to be saved and restored at % various points within the mapping and manipulation code. That is handled % here: as always, this approach uses global assignments. % \begin{macrocode} -\cs_new_protected:Npn \seq_push_item_def:n +\cs_new_protected:Npn \@@_push_item_def:n { - \seq_push_item_def_aux: - \cs_gset:Npn \seq_item:n ##1 + \@@_push_item_def: + \cs_gset:Npn \@@_item:n ##1 } -\cs_new_protected:Npn \seq_push_item_def:x +\cs_new_protected:Npn \@@_push_item_def:x { - \seq_push_item_def_aux: - \cs_gset:Npx \seq_item:n ##1 + \@@_push_item_def: + \cs_gset:Npx \@@_item:n ##1 } -\cs_new_protected:Npn \seq_push_item_def_aux: +\cs_new_protected:Npn \@@_push_item_def: { - \cs_gset_eq:cN { seq_item_ \int_use:N \g_prg_map_int :n } - \seq_item:n - \int_gincr:N \g_prg_map_int + \int_gincr:N \g__prg_map_int + \cs_gset_eq:cN { __prg_map_ \int_use:N \g__prg_map_int :w } + \@@_item:n } -\cs_new_protected_nopar:Npn \seq_pop_item_def: +\cs_new_protected_nopar:Npn \@@_pop_item_def: { - \int_gdecr:N \g_prg_map_int - \cs_gset_eq:Nc \seq_item:n - { seq_item_ \int_use:N \g_prg_map_int :n } + \cs_gset_eq:Nc \@@_item:n + { __prg_map_ \int_use:N \g__prg_map_int :w } + \int_gdecr:N \g__prg_map_int } % \end{macrocode} % \end{macro} @@ -1405,15 +1412,15 @@ % % \begin{macro}{\seq_map_inline:Nn, \seq_map_inline:cn} % \UnitTested -% The idea here is that \cs{seq_item:n} is already \enquote{applied} to +% The idea here is that \cs{@@_item:n} is already \enquote{applied} to % each item in a sequence, and so an in-line mapping is just a case of -% redefining \cs{seq_item:n}. +% redefining \cs{@@_item:n}. % \begin{macrocode} \cs_new_protected:Npn \seq_map_inline:Nn #1#2 { - \seq_push_item_def:n {#2} + \@@_push_item_def:n {#2} #1 - \prg_break_point:n { \seq_pop_item_def: } + \__prg_break_point:Nn \seq_map_break: { \@@_pop_item_def: } } \cs_generate_variant:Nn \seq_map_inline:Nn { c } % \end{macrocode} @@ -1431,18 +1438,38 @@ % \begin{macrocode} \cs_new_protected:Npn \seq_map_variable:NNn #1#2#3 { - \seq_push_item_def:x + \@@_push_item_def:x { \tl_set:Nn \exp_not:N #2 {##1} \exp_not:n {#3} } #1 - \prg_break_point:n { \seq_pop_item_def: } + \__prg_break_point:Nn \seq_map_break: { \@@_pop_item_def: } } \cs_generate_variant:Nn \seq_map_variable:NNn { Nc } \cs_generate_variant:Nn \seq_map_variable:NNn { c , cc } % \end{macrocode} % \end{macro} +% +% \begin{macro}{\seq_count:N, \seq_count:c} +% \begin{macro}[aux]{\@@_count:n} +% Counting the items in a sequence is done using the same approach as for +% other count functions: turn each entry into a \texttt{+1} then use +% integer evaluation to actually do the mathematics. +% \begin{macrocode} +\cs_new:Npn \seq_count:N #1 + { + \int_eval:n + { + 0 + \seq_map_function:NN #1 \@@_count:n + } + } +\cs_new:Npn \@@_count:n #1 { + \c_one } +\cs_generate_variant:Nn \seq_count:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} % % \subsection{Sequence stacks} % @@ -1504,379 +1531,50 @@ % \end{macro} % \end{macro} % +% \begin{macro}[TF]{\seq_get:NN, \seq_get:cN} +% \begin{macro}[TF]{\seq_pop:NN, \seq_pop:cN} +% \begin{macro}[TF]{\seq_gpop:NN, \seq_gpop:cN} +% More copies. +% \begin{macrocode} +\prg_new_eq_conditional:NNn \seq_get:NN \seq_get_left:NN { T , F , TF } +\prg_new_eq_conditional:NNn \seq_get:cN \seq_get_left:cN { T , F , TF } +\prg_new_eq_conditional:NNn \seq_pop:NN \seq_pop_left:NN { T , F , TF } +\prg_new_eq_conditional:NNn \seq_pop:cN \seq_pop_left:cN { T , F , TF } +\prg_new_eq_conditional:NNn \seq_gpop:NN \seq_gpop_left:NN { T , F , TF } +\prg_new_eq_conditional:NNn \seq_gpop:cN \seq_gpop_left:cN { T , F , TF } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% % \subsection{Viewing sequences} % % \begin{macro}{\seq_show:N, \seq_show:c} % \UnitTested -% Apply the general \cs{msg_aux_show:Nnx}. +% Apply the general \cs{__msg_show_variable:Nnn}. % \begin{macrocode} \cs_new_protected:Npn \seq_show:N #1 { - \msg_aux_show:Nnx + \__msg_show_variable:Nnn #1 { seq } - { \seq_map_function:NN #1 \msg_aux_show:n } + { \seq_map_function:NN #1 \__msg_show_item:n } } \cs_generate_variant:Nn \seq_show:N { c } % \end{macrocode} % \end{macro} % -% \subsection{Experimental functions} +% \subsection{Scratch sequences} % -% \begin{macro}[aux]{\seq_if_empty_break_return_false:N} -% The name says it all: of the sequence is empty, returns logical -% \texttt{false}. +% \begin{variable}{\l_tmpa_seq, \l_tmpb_seq, \g_tmpa_seq, \g_tmpb_seq} +% Temporary comma list variables. % \begin{macrocode} -\cs_new:Npn \seq_if_empty_break_return_false:N #1 - { - \if_meaning:w #1 \c_empty_tl - \prg_return_false: - \exp_after:wN \seq_break: - \fi: - } +\seq_new:N \l_tmpa_seq +\seq_new:N \l_tmpb_seq +\seq_new:N \g_tmpa_seq +\seq_new:N \g_tmpb_seq % \end{macrocode} -% \end{macro} -% -% \begin{macro}[TF]{\seq_get_left:NN, \seq_get_left:cN} -% \begin{macro}[TF]{\seq_get_right:NN, \seq_get_right:cN} -% Getting from the left or right with a check on the results. -% \begin{macrocode} -\prg_new_protected_conditional:Npnn \seq_get_left:NN #1 #2 { T , F , TF } - { - \seq_if_empty_break_return_false:N #1 - \exp_after:wN \seq_get_left_aux:Nw #1 \q_stop #2 - \prg_return_true: - \seq_break: - \prg_break_point:n { } - } -\prg_new_protected_conditional:Npnn \seq_get_right:NN #1#2 { T , F , TF } - { - \seq_if_empty_break_return_false:N #1 - \seq_get_right_aux:NN #1#2 - \prg_return_true: \seq_break: - \prg_break_point:n { } - } -\cs_generate_variant:Nn \seq_get_left:NNT { c } -\cs_generate_variant:Nn \seq_get_left:NNF { c } -\cs_generate_variant:Nn \seq_get_left:NNTF { c } -\cs_generate_variant:Nn \seq_get_right:NNT { c } -\cs_generate_variant:Nn \seq_get_right:NNF { c } -\cs_generate_variant:Nn \seq_get_right:NNTF { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[TF]{\seq_pop_left:NN, \seq_pop_left:cN} -% \begin{macro}[TF]{\seq_gpop_left:NN, \seq_gpop_left:cN} -% \begin{macro}[TF]{\seq_pop_right:NN, \seq_pop_right:cN} -% \begin{macro}[TF]{\seq_gpop_right:NN, \seq_gpop_right:cN} -% More or less the same for popping. -% \begin{macrocode} -\prg_new_protected_conditional:Npnn \seq_pop_left:NN #1#2 { T , F , TF } - { - \seq_if_empty_break_return_false:N #1 - \exp_after:wN \seq_pop_left_aux:NnwNNN #1 \q_stop \tl_set:Nn #1#2 - \prg_return_true: \seq_break: - \prg_break_point:n { } - } -\prg_new_protected_conditional:Npnn \seq_gpop_left:NN #1#2 { T , F , TF } - { - \seq_if_empty_break_return_false:N #1 - \exp_after:wN \seq_pop_left_aux:NnwNNN #1 \q_stop \tl_gset:Nn #1#2 - \prg_return_true: \seq_break: - \prg_break_point:n { } - } -\prg_new_protected_conditional:Npnn \seq_pop_right:NN #1#2 { T , F , TF } - { - \seq_if_empty_break_return_false:N #1 - \seq_pop_right_aux_ii:NNN \tl_set:Nx #1 #2 - \prg_return_true: \seq_break: - \prg_break_point:n { } - } -\prg_new_protected_conditional:Npnn \seq_gpop_right:NN #1#2 { T , F , TF } - { - \seq_if_empty_break_return_false:N #1 - \seq_pop_right_aux_ii:NNN \tl_gset:Nx #1 #2 - \prg_return_true: \seq_break: - \prg_break_point:n { } - } -\cs_generate_variant:Nn \seq_pop_left:NNT { c } -\cs_generate_variant:Nn \seq_pop_left:NNF { c } -\cs_generate_variant:Nn \seq_pop_left:NNTF { c } -\cs_generate_variant:Nn \seq_gpop_left:NNT { c } -\cs_generate_variant:Nn \seq_gpop_left:NNF { c } -\cs_generate_variant:Nn \seq_gpop_left:NNTF { c } -\cs_generate_variant:Nn \seq_pop_right:NNT { c } -\cs_generate_variant:Nn \seq_pop_right:NNF { c } -\cs_generate_variant:Nn \seq_pop_right:NNTF { c } -\cs_generate_variant:Nn \seq_gpop_right:NNT { c } -\cs_generate_variant:Nn \seq_gpop_right:NNF { c } -\cs_generate_variant:Nn \seq_gpop_right:NNTF { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\seq_length:N, \seq_length:c} -% \begin{macro}[aux]{\seq_length_aux:n} -% Counting the items in a sequence is done using the same approach as for -% other length functions: turn each entry into a \texttt{+1} then use -% integer evaluation to actually do the mathematics. -% \begin{macrocode} -\cs_new:Npn \seq_length:N #1 - { - \int_eval:n - { - 0 - \seq_map_function:NN #1 \seq_length_aux:n - } - } -\cs_new:Npn \seq_length_aux:n #1 { +1 } -\cs_generate_variant:Nn \seq_length:N { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\seq_item:Nn, \seq_item:cn} -% \begin{macro}[aux]{\seq_item_aux:nnn} -% The idea here is to find the offset of the item from the left, then use -% a loop to grab the correct item. If the resulting offset is too large, -% then the stop code |{ ? \seq_break: } { }| will be used by the auxiliary, -% terminating the loop and returning nothing at all. -% \begin{macrocode} -\cs_new:Npn \seq_item:Nn #1#2 - { - \exp_last_unbraced:Nfo \seq_item_aux:nnn - { - \int_eval:n - { - \int_compare:nNnT {#2} < \c_zero - { \seq_length:N #1 + } - #2 - } - } - #1 - { ? \seq_break: } - { } - \prg_break_point:n { } - } -\cs_new:Npn \seq_item_aux:nnn #1#2#3 - { - \use_none:n #2 - \int_compare:nNnTF {#1} = \c_zero - { \seq_break:n { \exp_not:n {#3} } } - { \exp_args:Nf \seq_item_aux:nnn { \int_eval:n { #1 - 1 } } } - } -\cs_generate_variant:Nn \seq_item:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\seq_use:N, \seq_use:c} -% A simple short cut for a mapping. -% \begin{macrocode} -\cs_new:Npn \seq_use:N #1 { \seq_map_function:NN #1 \use:n } -\cs_generate_variant:Nn \seq_use:N { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro} -% { -% \seq_mapthread_function:NNN, \seq_mapthread_function:NcN, -% \seq_mapthread_function:cNN, \seq_mapthread_function:ccN -% } -% \begin{macro}[aux]{\seq_mapthread_function_aux:NN} -% \begin{macro}[aux]{\seq_mapthread_function_aux:Nnnwnn} -% The idea here is to first expand both of the sequences, adding the usual -% |{ ? \seq_break: } { }| to the end of each on. This is most conveniently -% done in two steps using an auxiliary function. The mapping then throws -% away the first token of |#2| and |#5|, which for items in the sequences -% will both be \cs{seq_item:n}. The function to be mapped will then be -% applied to the two entries. When the code hits the end of one of the -% sequences, the break material will stop the entire loop and tidy up. This -% avoids needing to find the length of the two sequences, or worrying about -% which is longer. -% \begin{macrocode} -\cs_new:Npn \seq_mapthread_function:NNN #1#2#3 - { - \exp_after:wN \seq_mapthread_function_aux:NN - \exp_after:wN #3 - \exp_after:wN #1 - #2 - { ? \seq_break: } { } - \prg_break_point:n { } - } -\cs_new:Npn \seq_mapthread_function_aux:NN #1#2 - { - \exp_after:wN \seq_mapthread_function_aux:Nnnwnn - \exp_after:wN #1 - #2 - { ? \seq_break: } { } - \q_stop - } -\cs_new:Npn \seq_mapthread_function_aux:Nnnwnn #1#2#3#4 \q_stop #5#6 - { - \use_none:n #2 - \use_none:n #5 - #1 {#3} {#6} - \seq_mapthread_function_aux:Nnnwnn #1 #4 \q_stop - } -\cs_generate_variant:Nn \seq_mapthread_function:NNN { Nc } -\cs_generate_variant:Nn \seq_mapthread_function:NNN { c , cc } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% { -% \seq_set_from_clist:NN, \seq_set_from_clist:cN, -% \seq_set_from_clist:Nc, \seq_set_from_clist:cc, -% \seq_set_from_clist:Nn, \seq_set_from_clist:cn -% } -% \begin{macro} -% { -% \seq_gset_from_clist:NN, \seq_gset_from_clist:cN, -% \seq_gset_from_clist:Nc, \seq_gset_from_clist:cc, -% \seq_gset_from_clist:Nn, \seq_gset_from_clist:cn -% } -% Setting a sequence from a comma-separated list is done using a simple -% mapping. -% \begin{macrocode} -\cs_new_protected:Npn \seq_set_from_clist:NN #1#2 - { - \tl_set:Nx #1 - { \clist_map_function:NN #2 \seq_wrap_item:n } - } -\cs_new_protected:Npn \seq_set_from_clist:Nn #1#2 - { - \tl_set:Nx #1 - { \clist_map_function:nN {#2} \seq_wrap_item:n } - } -\cs_new_protected:Npn \seq_gset_from_clist:NN #1#2 - { - \tl_gset:Nx #1 - { \clist_map_function:NN #2 \seq_wrap_item:n } - } -\cs_new_protected:Npn \seq_gset_from_clist:Nn #1#2 - { - \tl_gset:Nx #1 - { \clist_map_function:nN {#2} \seq_wrap_item:n } - } -\cs_generate_variant:Nn \seq_set_from_clist:NN { Nc } -\cs_generate_variant:Nn \seq_set_from_clist:NN { c , cc } -\cs_generate_variant:Nn \seq_set_from_clist:Nn { c } -\cs_generate_variant:Nn \seq_gset_from_clist:NN { Nc } -\cs_generate_variant:Nn \seq_gset_from_clist:NN { c , cc } -\cs_generate_variant:Nn \seq_gset_from_clist:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% {\seq_reverse:N, \seq_reverse:c, \seq_greverse:N, \seq_greverse:c} -% \begin{macro}[aux]{\seq_reverse_aux:NN} -% \begin{macro}[aux]{\seq_reverse_aux_item:nwn} -% Previously, \cs{seq_reverse:N} was coded by collecting the items -% in reverse order after an \cs{exp_stop_f:} marker. -% \begin{verbatim} -% \cs_new_protected:Npn \seq_reverse:N #1 -% { -% \cs_set_eq:NN \seq_item:n \seq_reverse_aux_item:nw -% \tl_set:Nf #2 { #2 \exp_stop_f: } -% } -% \cs_new:Npn \seq_reverse_aux_item:nw #1 #2 \exp_stop_f: -% { -% #2 \exp_stop_f: -% \seq_item:n {#1} -% } -% \end{verbatim} -% At first, this seems optimal, since we can forget about each item -% as soon as it is placed after \cs{exp_stop_f:}. Unfortunately, -% \TeX{}'s usual tail recursion does not take place in this case: -% since the following \cs{seq_reverse_aux_item:nw} only reads -% tokens until \cs{exp_stop_f:}, and never reads the -% |\seq_item:n {#1}| left by the previous call, \TeX{} cannot -% remove that previous call from the stack, and in particular -% must retain the various macro paramters in memory, until the -% end of the replacement text is reached. The stack is thus -% only flushed after all the \cs{seq_reverse_aux_item:nw} are -% expanded. Keeping track of the arguments of all those calls -% uses up a memory quadratic in the length of the sequence. -% \TeX{} can then not cope with more than a few thousand items. -% -% Instead, we collect the items in the argument -% of \cs{exp_not:n}. The previous calls are cleanly removed -% from the stack, and the memory consumption becomes linear. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \seq_tmp:w { } -\cs_new_protected_nopar:Npn \seq_reverse:N - { \seq_reverse_aux:NN \tl_set:Nx } -\cs_new_protected_nopar:Npn \seq_greverse:N - { \seq_reverse_aux:NN \tl_gset:Nx } -\cs_new_protected:Npn \seq_reverse_aux:NN #1 #2 - { - \cs_set_eq:NN \seq_tmp:w \seq_item:n - \cs_set_eq:NN \seq_item:n \seq_reverse_aux_item:nwn - #1 #2 { #2 \exp_not:n { } } - \cs_set_eq:NN \seq_item:n \seq_tmp:w - } -\cs_new:Npn \seq_reverse_aux_item:nwn #1 #2 \exp_not:n #3 - { - #2 - \exp_not:n { \seq_item:n {#1} #3 } - } -\cs_generate_variant:Nn \seq_reverse:N { c } -\cs_generate_variant:Nn \seq_greverse:N { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\seq_set_filter:NNn, \seq_gset_filter:NNn} -% \begin{macro}[aux]{\seq_set_filter_aux:NNNn} -% Similar to \cs{seq_map_inline:Nn}, without a -% \cs{prg_break_point:n} because the user's code -% is performed within the evaluation of a boolean expression, -% and skipping out of that would break horribly. -% The \cs{seq_wrap_item:n} function inserts the relevant -% \cs{seq_item:n} without expansion in the input stream, -% hence in the \texttt{x}-expanding assignment. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \seq_set_filter:NNn - { \seq_set_filter_aux:NNNn \tl_set:Nx } -\cs_new_protected_nopar:Npn \seq_gset_filter:NNn - { \seq_set_filter_aux:NNNn \tl_gset:Nx } -\cs_new_protected:Npn \seq_set_filter_aux:NNNn #1#2#3#4 - { - \seq_push_item_def:n { \bool_if:nT {#4} { \seq_wrap_item:n {##1} } } - #1 #2 { #3 \prg_break_point:n { } } - \seq_pop_item_def: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\seq_set_map:NNn,\seq_gset_map:NNn} -% \begin{macro}[aux]{\seq_set_map_aux:NNNn} -% Very similar to \cs{seq_set_filter:NNn}. We could actually -% merge the two within a single function, but it would have weird -% semantics. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \seq_set_map:NNn - { \seq_set_map_aux:NNNn \tl_set:Nx } -\cs_new_protected_nopar:Npn \seq_gset_map:NNn - { \seq_set_map_aux:NNNn \tl_gset:Nx } -\cs_new_protected:Npn \seq_set_map_aux:NNNn #1#2#3#4 - { - \seq_push_item_def:n { \exp_not:N \seq_item:n {#4} } - #1 #2 { #3 } - \seq_pop_item_def: - } -% \end{macrocode} -% \end{macro} -% \end{macro} +% \end{variable} % % \subsection{Deprecated interfaces} % @@ -1904,6 +1602,25 @@ % \end{macrocode} % \end{macro} % +% Deprecated 2012-05-13 for removal by 2012-11-30. +% +% \begin{macro}{\seq_length:N, \seq_length:c} +% \begin{macrocode} +\cs_new_eq:NN \seq_length:N \seq_count:N +\cs_new_eq:NN \seq_length:c \seq_count:c +% \end{macrocode} +% \end{macro} +% +% Deprecated 2012-05-23 for removal by 2012-08-30. +% +% \begin{macro}{\seq_use:N, \seq_use:c} +% A simple short cut for a mapping. +% \begin{macrocode} +\cs_new:Npn \seq_use:N #1 { \seq_map_function:NN #1 \use:n } +\cs_generate_variant:Nn \seq_use:N { c } +% \end{macrocode} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx index 9bb1fa1eadc..b83319e74b3 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx @@ -36,8 +36,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3skip.dtx 3499 2012-03-05 16:08:55Z bruno $ - {L3 Experimental dimensions and skips} +\GetIdInfo$Id: l3skip.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Dimensions and skips} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -150,10 +150,10 @@ % \dim_gset_eq:NN, \dim_gset_eq:cN, \dim_gset_eq:Nc, \dim_gset_eq:cc % } % \begin{syntax} -% \cs{dim_set_eq:NN} \meta{dimension1} \meta{dimension2} +% \cs{dim_set_eq:NN} \meta{dimension_1} \meta{dimension_2} % \end{syntax} -% Sets the content of \meta{dimension1} equal to that of -% \meta{dimension2}. +% Sets the content of \meta{dimension_1} equal to that of +% \meta{dimension_2}. % \end{function} % % \begin{function}[updated = 2012-02-06] @@ -220,7 +220,7 @@ % % \begin{function}[EXP,pTF]{\dim_compare:nNn} % \begin{syntax} -% \cs{dim_compare_p:nNn} \Arg{dimexpr_1} \meta{relation} \Arg{dimexpr_2} \\ +% \cs{@@_compare_p:nNn} \Arg{dimexpr_1} \meta{relation} \Arg{dimexpr_2} \\ % \cs{dim_compare:nNnTF} % ~~\Arg{dimexpr_1} \meta{relation} \Arg{dimexpr_2} % ~~\Arg{true code} \Arg{false code} @@ -239,9 +239,9 @@ % % \begin{function}[EXP,pTF]{\dim_compare:n} % \begin{syntax} -% \cs{dim_compare_p:n} \{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} \\ +% \cs{@@_compare_p:n} \{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} \\ % \cs{dim_compare:nTF} -% ~~\{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} +% ~~\{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % This function first evaluates each of the \meta{dimension expressions} @@ -259,6 +259,37 @@ % \end{center} % \end{function} % +% \begin{function}[added = 2012-06-03, EXP]{\dim_case:nnn} +% \begin{syntax} +% \cs{dim_case:nnn} \Arg{test dimension expression} \\ +% ~~|{| \\ +% ~~~~\Arg{dimexpr case_1} \Arg{code case_1} \\ +% ~~~~\Arg{dimexpr case_2} \Arg{code case_2} \\ +% ~~~~\ldots \\ +% ~~~~\Arg{dimexpr case_n} \Arg{code case_n} \\ +% ~~|}| \\ +% ~~\Arg{else code} +% \end{syntax} +% This function evaluates the \meta{test dimension expression} and +% compares this in turn to each of the +% \meta{dimension expression cases}. If the two are equal then the +% associated \meta{code} is left in the input stream. If none of +% the tests are \texttt{true} then the \texttt{else code} will be +% left in the input stream. For example +% \begin{verbatim} +% \dim_set:Nn \l_tmpa_dim { 5 pt } +% \dim_case:nnn +% { 2 \l_tmpa_dim } +% { +% { 5 pt } { Small } +% { 4 pt + 6 pt } { Medium } +% { - 10 pt } { Negative } +% } +% { No idea! } +% \end{verbatim} +% will leave \enquote{\texttt{Medium}} in the input stream. +% \end{function} +% % \section{Dimension expression loops} % % \begin{function}[rEXP]{\dim_do_while:nNnn} @@ -311,7 +342,7 @@ % % \begin{function}[rEXP]{\dim_do_while:nn} % \begin{syntax} -% \cs{dim_do_while:nn} \{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} \Arg{code} +% \cs{dim_do_while:nn} \{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} \Arg{code} % \end{syntax} % Evaluates the relationship between the two \meta{dimension expressions} % as described for \cs{dim_compare:nTF}, and then places the @@ -323,7 +354,7 @@ % % \begin{function}[rEXP]{\dim_do_until:nn} % \begin{syntax} -% \cs{dim_do_until:nn} \{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} \Arg{code} +% \cs{dim_do_until:nn} \{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} \Arg{code} % \end{syntax} % Evaluates the relationship between the two \meta{dimension expressions} % as described for \cs{dim_compare:nTF}, and then places the @@ -335,7 +366,7 @@ % % \begin{function}[rEXP]{\dim_until_do:nn} % \begin{syntax} -% \cs{dim_until_do:nn} \{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} \Arg{code} +% \cs{dim_until_do:nn} \{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} \Arg{code} % \end{syntax} % Places the \meta{code} in the input stream for \TeX{} to process, and % then evaluates the relationship between the two @@ -347,7 +378,7 @@ % % \begin{function}[rEXP]{\dim_while_do:nn} % \begin{syntax} -% \cs{dim_while_do:nn} \{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} \Arg{code} +% \cs{dim_while_do:nn} \{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} \Arg{code} % \end{syntax} % Places the \meta{code} in the input stream for \TeX{} to process, and % then evaluates the relationship between the two @@ -398,7 +429,7 @@ % Displays the value of the \meta{dimension} on the terminal. % \end{function} % -% \begin{function}[added = 2011-11-22]{\dim_show:n} +% \begin{function}[added = 2011-11-22, updated = 2012-05-27]{\dim_show:n} % \begin{syntax} % \cs{dim_show:n} \meta{dimension expression} % \end{syntax} @@ -419,7 +450,7 @@ % % \section{Scratch dimensions} % -% \begin{variable}{\l_tmpa_dim, \l_tmpb_dim, \l_tmpc_dim} +% \begin{variable}{\l_tmpa_dim, \l_tmpb_dim} % Scratch dimension for local assignment. These are never used by % the kernel code, and so are safe for use with any \LaTeX3-defined % function. However, they may be overwritten by other non-kernel @@ -507,9 +538,9 @@ % \skip_gset_eq:NN, \skip_gset_eq:cN, \skip_gset_eq:Nc, \skip_gset_eq:cc % } % \begin{syntax} -% \cs{skip_set_eq:NN} \meta{skip1} \meta{skip2} +% \cs{skip_set_eq:NN} \meta{skip_1} \meta{skip_2} % \end{syntax} -% Sets the content of \meta{skip1} equal to that of \meta{skip2}. +% Sets the content of \meta{skip_1} equal to that of \meta{skip_2}. % \end{function} % % \begin{function}[updated = 2011-10-22] @@ -527,7 +558,7 @@ % \begin{syntax} % \cs{skip_if_eq_p:nn} \Arg{skipexpr_1} \Arg{skipexpr_2} % \cs{dim_compare:nTF} -% ~~\Arg{skip expr1} \Arg{skip expr2} +% ~~\Arg{skipexpr_1} \Arg{skipexpr_2} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % This function first evaluates each of the @@ -537,16 +568,6 @@ % for the test to be true. % \end{function} % -% \begin{function}[EXP, pTF, updated = 2012-03-05]{\skip_if_infinite_glue:n} -% \begin{syntax} -% \cs{skip_if_infinite_glue_p:n} \Arg{skipexpr} -% \cs{skip_if_infinite_glue:nTF} \Arg{skipexpr} \Arg{true code} \Arg{false code} -% \end{syntax} -% Evaluates the \meta{skip expression} as described for \cs{skip_eval:n}, -% and then tests if this contains an infinite stretch or shrink -% component (or both). -% \end{function} -% % \begin{function}[EXP, pTF, added = 2012-03-05]{\skip_if_finite:n} % \begin{syntax} % \cs{skip_if_finite_p:n} \Arg{skipexpr} @@ -596,7 +617,7 @@ % Displays the value of the \meta{skip} on the terminal. % \end{function} % -% \begin{function}[added = 2011-11-22]{\skip_show:n} +% \begin{function}[added = 2011-11-22, updated = 2012-05-27]{\skip_show:n} % \begin{syntax} % \cs{skip_show:n} \meta{skip expression} % \end{syntax} @@ -617,7 +638,7 @@ % % \section{Scratch skips} % -% \begin{variable}{\l_tmpa_skip, \l_tmpb_skip, \l_tmpc_skip} +% \begin{variable}{\l_tmpa_skip, \l_tmpb_skip} % Scratch skip for local assignment. These are never used by % the kernel code, and so are safe for use with any \LaTeX3-defined % function. However, they may be overwritten by other non-kernel @@ -631,6 +652,32 @@ % code and so should only be used for short-term storage. % \end{variable} % +% \section{Inserting skips into the output} +% +% \begin{function}[updated = 2011-10-22] +% {\skip_horizontal:N, \skip_horizontal:c, \skip_horizontal:n} +% \begin{syntax} +% \cs{skip_horizontal:N} \meta{skip} +% \cs{skip_horizontal:n} \Arg{skipexpr} +% \end{syntax} +% Inserts a horizontal \meta{skip} into the current list. +% \begin{texnote} +% \cs{skip_horizontal:N} is the \TeX{} primitive \tn{hskip} renamed. +% \end{texnote} +% \end{function} +% +% \begin{function}[updated = 2011-10-22] +% {\skip_vertical:N, \skip_vertical:c, \skip_vertical:n} +% \begin{syntax} +% \cs{skip_vertical:N} \meta{skip} +% \cs{skip_vertical:n} \Arg{skipexpr} +% \end{syntax} +% Inserts a vertical \meta{skip} into the current list. +% \begin{texnote} +% \cs{skip_vertical:N} is the \TeX{} primitive \tn{vskip} renamed. +% \end{texnote} +% \end{function} +% % \section{Creating and initialising \texttt{muskip} variables} % % \begin{function}{\muskip_new:N, \muskip_new:c} @@ -711,10 +758,10 @@ % \muskip_gset_eq:Nc, \muskip_gset_eq:cc % } % \begin{syntax} -% \cs{muskip_set_eq:NN} \meta{muskip1} \meta{muskip2} +% \cs{muskip_set_eq:NN} \meta{muskip_1} \meta{muskip_2} % \end{syntax} -% Sets the content of \meta{muskip1} equal to that of -% \meta{muskip2}. +% Sets the content of \meta{muskip_1} equal to that of +% \meta{muskip_2}. % \end{function} % % \begin{function}[updated = 2011-10-22] @@ -757,32 +804,6 @@ % \end{texnote} % \end{function} % -% \section{Inserting skips into the output} -% -% \begin{function}[updated = 2011-10-22] -% {\skip_horizontal:N, \skip_horizontal:c, \skip_horizontal:n} -% \begin{syntax} -% \cs{skip_horizontal:N} \meta{skip} -% \cs{skip_horizontal:n} \Arg{skipexpr} -% \end{syntax} -% Inserts a horizontal \meta{skip} into the current list. -% \begin{texnote} -% \cs{skip_horizontal:N} is the \TeX{} primitive \tn{hskip} renamed. -% \end{texnote} -% \end{function} -% -% \begin{function}[updated = 2011-10-22] -% {\skip_vertical:N, \skip_vertical:c, \skip_vertical:n} -% \begin{syntax} -% \cs{skip_vertical:N} \meta{skip} -% \cs{skip_vertical:n} \Arg{skipexpr} -% \end{syntax} -% Inserts a vertical \meta{skip} into the current list. -% \begin{texnote} -% \cs{skip_vertical:N} is the \TeX{} primitive \tn{vskip} renamed. -% \end{texnote} -% \end{function} -% % \section{Viewing \texttt{muskip} variables} % % \begin{function}{\muskip_show:N, \muskip_show:c} @@ -792,7 +813,7 @@ % Displays the value of the \meta{muskip} on the terminal. % \end{function} % -% \begin{function}[added = 2011-11-22]{\muskip_show:n} +% \begin{function}[added = 2011-11-22, updated = 2012-05-27]{\muskip_show:n} % \begin{syntax} % \cs{muskip_show:n} \meta{muskip expression} % \end{syntax} @@ -800,11 +821,37 @@ % on the terminal. % \end{function} % -% \section{Internal functions} +% \section{Constant muskips} +% +% \begin{variable}{\c_max_muskip} +% The maximum value that can be stored as a muskip. +% \end{variable} +% +% \begin{variable}{\c_zero_muskip} +% A zero length as a muskip. +% \end{variable} +% +% \section{Scratch muskips} +% +% \begin{variable}{\l_tmpa_muskip, \l_tmpb_muskip} +% Scratch muskip for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \begin{variable}{\g_tmpa_muskip, \g_tmpb_muskip} +% Scratch muskip for global assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \section{Primitive conditional} % % \begin{function}{\if_dim:w} % \begin{syntax} -% \cs{if_dim:w} \meta{dimen1} \meta{relation} \meta{dimen1} +% \cs{if_dim:w} \meta{dimen_1} \meta{relation} \meta{dimen_2} % ~~\meta{true code} % \cs{else:} % ~~\meta{false} @@ -817,44 +864,28 @@ % \end{texnote} % \end{function} % -% \begin{function}[EXP]{\dim_eval:w, \dim_eval_end:} +% \section{Internal functions} +% +% \begin{function}[EXP]{\__dim_eval:w, \__dim_eval_end:} % \begin{syntax} -% \cs{dim_eval:w} \meta{dimexpr} \cs{dim_eval_end:} +% \cs{__dim_eval:w} \meta{dimexpr} \cs{__dim_eval_end:} % \end{syntax} % Evaluates \meta{dimension expression} as described for \cs{dim_eval:n}. % The evaluation stops when an unexpandable token which is not a valid -% part of a dimension is read or when \cs{dim_eval_end:} is +% part of a dimension is read or when \cs{__dim_eval_end:} is % reached. The latter is gobbled by the scanner mechanism: -% \cs{dim_eval_end:} itself is unexpandable but used correctly +% \cs{__dim_eval_end:} itself is unexpandable but used correctly % the entire construct is expandable. % \begin{texnote} % This is the \eTeX{} primitive \tn{dimexpr}. % \end{texnote} % \end{function} % -% \section{Experimental skip functions} -% -% \begin{function}[updated = 2011-10-22]{\skip_split_finite_else_action:nnNN} -% \begin{syntax} -% \cs{skip_split_finite_else_action:nnNN} \Arg{skipexpr} \Arg{action} -% ~~\meta{dimen1} \meta{dimen2} -% \end{syntax} -% Checks if the \meta{skipexpr} contains finite glue. If it does then it -% assigns -% \meta{dimen1} the stretch component and \meta{dimen2} the shrink -% component. If -% it contains infinite glue set \meta{dimen1} and \meta{dimen2} to $0$\,pt -% and place |#2| into the input stream: this is usually an error or -% warning message of some sort. -% \end{function} -% -% \section{Internal functions} -% % \begin{function}[added = 2011-11-11, EXP] -% {\dim_strip_bp:n, \dim_strip_pt:n} +% {\__dim_strip_bp:n, \__dim_strip_pt:n} % \begin{syntax} -% \cs{dim_strip_bp:n} \Arg{dimension expression} -% \cs{dim_strip_pt:n} \Arg{dimension expression} +% \cs{__dim_strip_bp:n} \Arg{dimension expression} +% \cs{__dim_strip_pt:n} \Arg{dimension expression} % \end{syntax} % Evaluates the \meta{dimension expression}, expanding any % dimensions and token list variables within the \meta{expression} @@ -867,7 +898,7 @@ % If the \Arg{dimension expression} contains additional units, these will % be ignored, so for example % \begin{verbatim} -% \dim_strip_pt:n { 1 bp pt } +% \__dim_strip_pt:n { 1 bp pt } % \end{verbatim} % will leave |1.00374| in the input stream (\emph{i.e.}~the magnitude of % one \enquote{big point} when converted to points). @@ -884,23 +915,27 @@ % \end{macrocode} % % \begin{macrocode} +%<@@=dim> +% \end{macrocode} +% +% \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % % \subsection{Length primitives renamed} % % \begin{macro}{\if_dim:w} -% \begin{macro}{\dim_eval:w} -% \begin{macro}{\dim_eval_end:} +% \begin{macro}{\@@_eval:w} +% \begin{macro}{\@@_eval_end:} % Primitives renamed. % \begin{macrocode} \cs_new_eq:NN \if_dim:w \tex_ifdim:D -\cs_new_eq:NN \dim_eval:w \etex_dimexpr:D -\cs_new_eq:NN \dim_eval_end: \tex_relax:D +\cs_new_eq:NN \@@_eval:w \etex_dimexpr:D +\cs_new_eq:NN \@@_eval_end: \tex_relax:D % \end{macrocode} % \end{macro} % \end{macro} @@ -914,7 +949,7 @@ %<*package> \cs_new_protected:Npn \dim_new:N #1 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \newdimen #1 } %</package> @@ -981,7 +1016,7 @@ % Setting dimensions is easy enough. % \begin{macrocode} \cs_new_protected:Npn \dim_set:Nn #1#2 - { #1 ~ \dim_eval:w #2 \dim_eval_end: } + { #1 ~ \@@_eval:w #2 \@@_eval_end: } \cs_new_protected:Npn \dim_gset:Nn { \tex_global:D \dim_set:Nn } \cs_generate_variant:Nn \dim_set:Nn { c } \cs_generate_variant:Nn \dim_gset:Nn { c } @@ -1008,19 +1043,19 @@ % \begin{macro}{\dim_set_min:Nn, \dim_set_min:cn} % \begin{macro}{\dim_gset_max:Nn, \dim_gset_max:cn} % \begin{macro}{\dim_gset_min:Nn, \dim_gset_min:cn} -% \begin{macro}[aux]{\dim_set_max_aux:NNNn} +% \begin{macro}[aux]{\@@_set_max:NNNn} % Setting maximum and minimum values is simply a case of so build-in % comparison. This only applies to dimensions as skips are not ordered. % \begin{macrocode} \cs_new_protected_nopar:Npn \dim_set_max:Nn - { \dim_set_max_aux:NNNn < \dim_set:Nn } + { \@@_set_max:NNNn < \dim_set:Nn } \cs_new_protected_nopar:Npn \dim_gset_max:Nn - { \dim_set_max_aux:NNNn < \dim_gset:Nn } + { \@@_set_max:NNNn < \dim_gset:Nn } \cs_new_protected_nopar:Npn \dim_set_min:Nn - { \dim_set_max_aux:NNNn > \dim_set:Nn } + { \@@_set_max:NNNn > \dim_set:Nn } \cs_new_protected_nopar:Npn \dim_gset_min:Nn - { \dim_set_max_aux:NNNn > \dim_gset:Nn } -\cs_new_protected:Npn \dim_set_max_aux:NNNn #1#2#3#4 + { \@@_set_max:NNNn > \dim_gset:Nn } +\cs_new_protected:Npn \@@_set_max:NNNn #1#2#3#4 { \dim_compare:nNnT {#3} #1 {#4} { #2 #3 {#4} } } \cs_generate_variant:Nn \dim_set_max:Nn { c } \cs_generate_variant:Nn \dim_gset_max:Nn { c } @@ -1040,12 +1075,12 @@ % Using |by| here deals with the (incorrect) case |\dimen123|. % \begin{macrocode} \cs_new_protected:Npn \dim_add:Nn #1#2 - { \tex_advance:D #1 by \dim_eval:w #2 \dim_eval_end: } + { \tex_advance:D #1 by \@@_eval:w #2 \@@_eval_end: } \cs_new_protected:Npn \dim_gadd:Nn { \tex_global:D \dim_add:Nn } \cs_generate_variant:Nn \dim_add:Nn { c } \cs_generate_variant:Nn \dim_gadd:Nn { c } \cs_new_protected:Npn \dim_sub:Nn #1#2 - { \tex_advance:D #1 by - \dim_eval:w #2 \dim_eval_end: } + { \tex_advance:D #1 by - \@@_eval:w #2 \@@_eval_end: } \cs_new_protected:Npn \dim_gsub:Nn { \tex_global:D \dim_sub:Nn } \cs_generate_variant:Nn \dim_sub:Nn { c } \cs_generate_variant:Nn \dim_gsub:Nn { c } @@ -1065,57 +1100,55 @@ \cs_new:Npn \dim_abs:n #1 { \dim_use:N - \dim_eval:w - \if_dim:w \dim_eval:w #1 < \c_zero_dim + \@@_eval:w + \if_dim:w \@@_eval:w #1 < \c_zero_dim - \fi: - \dim_eval:w #1 \dim_eval_end: - \dim_eval_end: + \@@_eval:w #1 \@@_eval_end: + \@@_eval_end: } % \end{macrocode} % \end{macro} % % \begin{macro}{\dim_ratio:nn} -% \begin{macro}[aux]{\dim_ratio_aux:n} +% \begin{macro}[aux]{\@@_ratio:n} % With dimension expressions, something like |10 pt * ( 5 pt / 10 pt )| will % not work. Instead, the ratio part needs to be converted to an integer -% expression. Using \cs{int_value:w} forces everything into |sp|, avoiding +% expression. Using \cs{__int_value:w} forces everything into |sp|, avoiding % any decimal parts. % \begin{macrocode} \cs_new:Npn \dim_ratio:nn #1#2 - { \dim_ratio_aux:n {#1} / \dim_ratio_aux:n {#2} } -\cs_new:Npn \dim_ratio_aux:n #1 - { \int_value:w \dim_eval:w #1 \dim_eval_end: } + { \@@_ratio:n {#1} / \@@_ratio:n {#2} } +\cs_new:Npn \@@_ratio:n #1 + { \__int_value:w \@@_eval:w #1 \@@_eval_end: } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Dimension expression conditionals} % -% \begin{macro}{\dim_compare_p:nNn} -% \begin{macro}[TF]{\dim_compare:nNn} +% \begin{macro}[pTF, EXP]{\dim_compare:nNn} % Simple comparison. % \begin{macrocode} \prg_new_conditional:Npnn \dim_compare:nNn #1#2#3 { p , T , F , TF } { - \if_dim:w \dim_eval:w #1 #2 \dim_eval:w #3 \dim_eval_end: + \if_dim:w \@@_eval:w #1 #2 \@@_eval:w #3 \@@_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} -% \end{macro} % % \begin{macro}[pTF, EXP]{\dim_compare:n} -% \begin{macro}[aux, EXP]{\dim_compare_aux:w, \dim_compare_aux:NNw} +% \begin{macro}[aux, EXP]{\@@_compare_aux:w, \@@_compare_aux:NNw} % \begin{macro}[aux, EXP] % { -% \dim_compare_=:NNw, -% \dim_compare_<:NNw, -% \dim_compare_>:NNw, -% \dim_compare_==:NNw, -% \dim_compare_!=:NNw, -% \dim_compare_<=:NNw, -% \dim_compare_>=:NNw +% \@@_compare_=:NNw, +% \@@_compare_<:NNw, +% \@@_compare_>:NNw, +% \@@_compare_==:NNw, +% \@@_compare_!=:NNw, +% \@@_compare_<=:NNw, +% \@@_compare_>=:NNw % } % This code is adapted from the \cs{int_compare:nTF} function. First % evaluate the left-hand side. Then access the relation symbol by @@ -1124,40 +1157,65 @@ % \begin{macrocode} \prg_new_conditional:Npnn \dim_compare:n #1 { p , T , F , TF } { - \exp_after:wN \dim_compare_aux:w \dim_use:N \dim_eval:w #1 - \kernel_compare_error: \dim_eval_end: + \exp_after:wN \@@_compare_aux:w \dim_use:N \@@_eval:w #1 + \__prg_compare_error: \@@_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } \exp_args:Nno \use:nn - { \cs_new:Npn \dim_compare_aux:w #1 } + { \cs_new:Npn \@@_compare_aux:w #1 } { \tl_to_str:n { pt } } - #2 \kernel_compare_error: + #2 \__prg_compare_error: { - \exp_after:wN \dim_compare_aux:NNw #2 ?? \q_mark + \exp_after:wN \@@_compare_aux:NNw #2 ?? \q_mark #1 pt #2 } -\cs_new:Npn \dim_compare_aux:NNw #1#2#3 \q_mark +\cs_new:Npn \@@_compare_aux:NNw #1#2#3 \q_mark { - \use:c { dim_compare_ #1 \if_meaning:w = #2 = \fi: :NNw } - \kernel_compare_error:Nw #1 + \use:c { @@_compare_ #1 \if_meaning:w = #2 = \fi: :NNw } + \__prg_compare_error:Nw #1 } -\cs_new:cpn { dim_compare_=:NNw } #1#2#3 = - { \if_dim:w #3 = \dim_eval:w } -\cs_new:cpn { dim_compare_<:NNw } #1#2#3 < - { \if_dim:w #3 < \dim_eval:w } -\cs_new:cpn { dim_compare_>:NNw } #1#2#3 > - { \if_dim:w #3 > \dim_eval:w } -\cs_new:cpn { dim_compare_==:NNw } #1#2#3 == - { \if_dim:w #3 = \dim_eval:w } -\cs_new:cpn { dim_compare_!=:NNw } #1#2#3 != - { \reverse_if:N \if_dim:w #3 = \dim_eval:w } -\cs_new:cpn { dim_compare_<=:NNw } #1#2#3 <= - { \reverse_if:N \if_dim:w #3 > \dim_eval:w } -\cs_new:cpn { dim_compare_>=:NNw } #1#2#3 >= - { \reverse_if:N \if_dim:w #3 < \dim_eval:w } +\cs_new:cpn { @@_compare_=:NNw } #1#2#3 = + { \if_dim:w #3 = \@@_eval:w } +\cs_new:cpn { @@_compare_<:NNw } #1#2#3 < + { \if_dim:w #3 < \@@_eval:w } +\cs_new:cpn { @@_compare_>:NNw } #1#2#3 > + { \if_dim:w #3 > \@@_eval:w } +\cs_new:cpn { @@_compare_==:NNw } #1#2#3 == + { \if_dim:w #3 = \@@_eval:w } +\cs_new:cpn { @@_compare_!=:NNw } #1#2#3 != + { \reverse_if:N \if_dim:w #3 = \@@_eval:w } +\cs_new:cpn { @@_compare_<=:NNw } #1#2#3 <= + { \reverse_if:N \if_dim:w #3 > \@@_eval:w } +\cs_new:cpn { @@_compare_>=:NNw } #1#2#3 >= + { \reverse_if:N \if_dim:w #3 < \@@_eval:w } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\dim_case:nnn} +% \begin{macro}[aux, EXP]{\@@_case_aux:nnn} +% \begin{macro}[aux, EXP]{\@@_case_aux:nw,\@@_case_end:nw} +% The dimension function is the same as the \texttt{int} version, so there +% is not much to say here. +% \begin{macrocode} +\cs_new:Npn \dim_case:nnn #1 + { + \tex_romannumeral:D + \exp_args:Nf \@@_case_aux:nnn { \dim_eval:n {#1} } + } +\cs_new:Npn \@@_case_aux:nnn #1#2#3 + { \@@_case_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } +\cs_new:Npn \@@_case_aux:nw #1#2#3 + { + \dim_compare:nNnTF {#1} = {#2} + { \@@_case_end:nw {#3} } + { \@@_case_aux:nw {#1} } + } +\cs_new_eq:NN \@@_case_end:nw \__prg_case_end:nw % \end{macrocode} % \end{macro} % \end{macro} @@ -1253,33 +1311,33 @@ % Evaluating a dimension expression expandably. % \begin{macrocode} \cs_new:Npn \dim_eval:n #1 - { \dim_use:N \dim_eval:w #1 \dim_eval_end: } + { \dim_use:N \@@_eval:w #1 \@@_eval_end: } % \end{macrocode} % \end{macro} % -% \begin{macro}[EXP]{\dim_strip_bp:n} +% \begin{macro}[EXP, int]{\@@_strip_bp:n} % \begin{macrocode} -\cs_new:Npn \dim_strip_bp:n #1 - { \dim_strip_pt:n { 0.996 26 \dim_eval:w #1 \dim_eval_end: } } +\cs_new:Npn \@@_strip_bp:n #1 + { \@@_strip_pt:n { 0.996 26 \@@_eval:w #1 \@@_eval_end: } } % \end{macrocode} % \end{macro} % -% \begin{macro}[EXP]{\dim_strip_pt:n} -% \begin{macro}[EXP, aux]{\dim_strip_pt:w} +% \begin{macro}[EXP]{\@@_strip_pt:n} +% \begin{macro}[EXP, aux]{\@@_strip_pt:w} % A function which comes up often enough to deserve a place in the kernel. % The idea here is that the input is assumed to be in \texttt{pt}, but can % be given in other units, while the output is the value of the dimension % in \texttt{pt} but with no units given. This is used a lot by low-level % manipulations. % \begin{macrocode} -\cs_new:Npn \dim_strip_pt:n #1 +\cs_new:Npn \@@_strip_pt:n #1 { \exp_after:wN - \dim_strip_pt:w \dim_use:N \dim_eval:w #1 \dim_eval_end: \q_stop + \@@_strip_pt:w \dim_use:N \@@_eval:w #1 \@@_eval_end: \q_stop } \use:x { - \cs_new:Npn \exp_not:N \dim_strip_pt:w + \cs_new:Npn \exp_not:N \@@_strip_pt:w ##1 . ##2 \tl_to_str:n { pt } ##3 \exp_not:N \q_stop { ##1 @@ -1304,16 +1362,18 @@ % \begin{macro}{\dim_show:N, \dim_show:c} % Diagnostics. % \begin{macrocode} -\cs_new_eq:NN \dim_show:N \kernel_register_show:N +\cs_new_eq:NN \dim_show:N \__kernel_register_show:N \cs_generate_variant:Nn \dim_show:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\dim_show:n} -% Diagnostics. +% Diagnostics. We don't use the \TeX{} primitive \tn{showthe} to show +% dimension expressions: this gives a more unified output, since the +% closing brace is read by the dimension expression in all cases. % \begin{macrocode} \cs_new_protected:Npn \dim_show:n #1 - { \tex_showthe:D \dim_eval:w #1 \dim_eval_end: } + { \etex_showtokens:D \exp_after:wN { \dim_use:N \@@_eval:w #1 } } % \end{macrocode} % \end{macro} % @@ -1338,14 +1398,13 @@ % % \subsection{Scratch dimensions} % -% \begin{variable}{\l_tmpa_dim, \l_tmpb_dim, \l_tmpc_dim} +% \begin{variable}{\l_tmpa_dim, \l_tmpb_dim} % \begin{variable}{\g_tmpa_dim, \g_tmpb_dim} -% We provide three local and two global scratch registers, maybe we +% We provide two local and two global scratch registers, maybe we % need more or less. % \begin{macrocode} \dim_new:N \l_tmpa_dim \dim_new:N \l_tmpb_dim -\dim_new:N \l_tmpc_dim \dim_new:N \g_tmpa_dim \dim_new:N \g_tmpb_dim % \end{macrocode} @@ -1360,7 +1419,7 @@ %<*package> \cs_new_protected:Npn \skip_new:N #1 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \newskip #1 } %</package> @@ -1493,7 +1552,7 @@ % \end{macro} % % \begin{macro}[EXP,pTF]{\skip_if_finite:n} -% \begin{macro}[EXP,aux]{\skip_if_finite_aux:wwNw} +% \begin{macro}[EXP,aux]{\__skip_if_finite:wwNw} % With \eTeX{}, we have an easy access to the order of infinities of % the stretch and shrink components of a skip. However, to access % both, we either need to evaluate the expression twice, or evaluate @@ -1502,29 +1561,21 @@ % it is quicker to make it search for the string \texttt{fil} which % characterizes infinite glue. % \begin{macrocode} -\cs_set_protected:Npn \cs_tmp:w #1 +\cs_set_protected:Npn \__cs_tmp:w #1 { \prg_new_conditional:Npnn \skip_if_finite:n ##1 { p , T , F , TF } { - \exp_after:wN \skip_if_finite_aux:wwNw + \exp_after:wN \__skip_if_finite:wwNw \skip_use:N \etex_glueexpr:D ##1 ; \prg_return_false: #1 ; \prg_return_true: \q_stop } - \cs_new:Npn \skip_if_finite_aux:wwNw ##1 #1 ##2 ; ##3 ##4 \q_stop {##3} + \cs_new:Npn \__skip_if_finite:wwNw ##1 #1 ##2 ; ##3 ##4 \q_stop {##3} } -\exp_args:No \cs_tmp:w { \tl_to_str:n { fil } } +\exp_args:No \__cs_tmp:w { \tl_to_str:n { fil } } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[EXP, pTF]{\skip_if_infinite_glue:n} -% Reverse of \cs{skip_if_finite:nTF}. -% \begin{macrocode} -\prg_new_conditional:Npnn \skip_if_infinite_glue:n #1 { p , T , F , TF } - { \skip_if_finite:nTF {#1} \prg_return_false: \prg_return_true: } -% \end{macrocode} -% \end{macro} -% % \subsection{Using \texttt{skip} expressions and variables} % % \begin{macro}{\skip_eval:n} @@ -1566,16 +1617,18 @@ % \begin{macro}{\skip_show:N, \skip_show:c} % Diagnostics. % \begin{macrocode} -\cs_new_eq:NN \skip_show:N \kernel_register_show:N +\cs_new_eq:NN \skip_show:N \__kernel_register_show:N \cs_generate_variant:Nn \skip_show:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\skip_show:n} -% Diagnostics. +% Diagnostics. We don't use the \TeX{} primitive \tn{showthe} to show +% skip expressions: this gives a more unified output, since the +% closing brace is read by the skip expression in all cases. % \begin{macrocode} \cs_new_protected:Npn \skip_show:n #1 - { \tex_showthe:D \etex_glueexpr:D #1 \scan_stop: } + { \etex_showtokens:D \exp_after:wN { \tex_the:D \etex_glueexpr:D #1 } } % \end{macrocode} % \end{macro} % @@ -1593,14 +1646,13 @@ % % \subsection{Scratch skips} % -% \begin{variable}{\l_tmpa_skip, \l_tmpb_skip, \l_tmpc_skip} +% \begin{variable}{\l_tmpa_skip, \l_tmpb_skip} % \begin{variable}{\g_tmpa_skip, \g_tmpb_skip} -% We provide three local and two global scratch registers, maybe we +% We provide two local and two global scratch registers, maybe we % need more or less. % \begin{macrocode} \skip_new:N \l_tmpa_skip \skip_new:N \l_tmpb_skip -\skip_new:N \l_tmpc_skip \skip_new:N \g_tmpa_skip \skip_new:N \g_tmpb_skip % \end{macrocode} @@ -1615,7 +1667,7 @@ %<*package> \cs_new_protected:Npn \muskip_new:N #1 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \newmuskip #1 } %</package> @@ -1761,44 +1813,76 @@ % \begin{macro}{\muskip_show:N, \muskip_show:c} % Diagnostics. % \begin{macrocode} -\cs_new_eq:NN \muskip_show:N \kernel_register_show:N +\cs_new_eq:NN \muskip_show:N \__kernel_register_show:N \cs_generate_variant:Nn \muskip_show:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\muskip_show:n} -% Diagnostics. +% Diagnostics. We don't use the \TeX{} primitive \tn{showthe} to show +% muskip expressions: this gives a more unified output, since the +% closing brace is read by the muskip expression in all cases. % \begin{macrocode} \cs_new_protected:Npn \muskip_show:n #1 - { \tex_showthe:D \etex_muexpr:D #1 \scan_stop: } + { \etex_showtokens:D \exp_after:wN { \tex_the:D \etex_muexpr:D #1 } } % \end{macrocode} % \end{macro} % -% \subsection{Experimental skip functions} +% \subsection{Constant muskips} % -% \begin{macro}{\skip_split_finite_else_action:nnNN} -% This macro is useful when performing error checking in certain -% circumstances. If the \meta{skip} register holds finite glue it sets -% |#3| and |#4| to the stretch and shrink component, resp. If it holds -% infinite glue set |#3| and |#4| to zero and issue the special action -% |#2| which is probably an error message. -% Assignments are local. +% \begin{macro}{\c_zero_muskip} +% \begin{macro}{\c_max_muskip} +% Constant muskips given by their value. % \begin{macrocode} -\cs_new:Npn \skip_split_finite_else_action:nnNN #1#2#3#4 - { - \skip_if_finite:nTF {#1} - { - #3 = \etex_gluestretch:D #1 \scan_stop: - #4 = \etex_glueshrink:D #1 \scan_stop: - } - { - #3 = \c_zero_skip - #4 = \c_zero_skip - #2 - } - } +\muskip_const:Nn \c_zero_muskip { 0 mu } +\muskip_const:Nn \c_max_muskip { 16383.99999 mu } % \end{macrocode} -% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Scratch muskips} +% +% \begin{variable}{\l_tmpa_muskip, \l_tmpb_muskip} +% \begin{variable}{\g_tmpa_muskip, \g_tmpb_muskip} +% We provide two local and two global scratch registers, maybe we +% need more or less. +% \begin{macrocode} +\muskip_new:N \l_tmpa_muskip +\muskip_new:N \l_tmpb_muskip +\muskip_new:N \g_tmpa_muskip +\muskip_new:N \g_tmpb_muskip +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \subsection{Deprecated functions} +% +% Deprecated on 2012-05-10, for removal by 2012-08-31. +% +% \begin{macro}[EXP, pTF]{\skip_if_infinite_glue:n} +% Reverse of \cs{skip_if_finite:nTF}. +% \begin{macrocode} +\prg_new_conditional:Npnn \skip_if_infinite_glue:n #1 { p , T , F , TF } + { \skip_if_finite:nTF {#1} \prg_return_false: \prg_return_true: } +% \end{macrocode} +% \end{macro} +% +% Deprecated 2012-06-03 for removal after 2012-12-31. +% +% \begin{macro}[EXP]{\prg_case_dim:nnn} +% Moved here, was in \pkg{l3prg} but load order means we define it here +% now. +% \begin{macrocode} +\cs_new_eq:NN \prg_case_dim:nnn \dim_case:nnn +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dim_eval:w, \dim_eval_end:} +% \begin{macrocode} +\cs_new_eq:NN \dim_eval:w \__dim_eval:w +\cs_new_eq:NN \dim_eval_end: \__dim_eval_end: +% \end{macrocode} +% \end{macro} % % \begin{macrocode} %</initex|package> diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx index 51fcddc242e..08d2630523d 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3tl.dtx 3490 2012-03-04 01:00:53Z bruno $ - {L3 Experimental token lists} +\GetIdInfo$Id: l3tl.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Token lists} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -148,10 +148,23 @@ % \tl_gset_eq:NN, \tl_gset_eq:cN, \tl_gset_eq:Nc, \tl_gset_eq:cc % } % \begin{syntax} -% \cs{tl_set_eq:NN} \meta{tl~var1} \meta{tl~var2} +% \cs{tl_set_eq:NN} \meta{tl~var_1} \meta{tl~var_2} % \end{syntax} -% Sets the content of \meta{tl~var1} equal to that of -% \meta{tl~var2}. +% Sets the content of \meta{tl~var_1} equal to that of +% \meta{tl~var_2}. +% \end{function} +% +% \begin{function}[added = 2012-05-18] +% { +% \tl_concat:NNN, \tl_concat:ccc, +% \tl_gconcat:NNN, \tl_gconcat:ccc +% } +% \begin{syntax} +% \cs{tl_concat:NNN} \meta{tl~var_1} \meta{tl~var_2} \meta{tl~var_3} +% \end{syntax} +% Concatenates the content of \meta{tl~var_2} and \meta{tl~var_3} +% together and saves the result in \meta{tl~var_1}. The \meta{tl~var_2} +% will be placed at the left side of the new token list. % \end{function} % % \begin{function}[EXP, pTF, added=2012-03-03]{\tl_if_exist:N, \tl_if_exist:c} @@ -363,23 +376,21 @@ % (\emph{i.e.}~contains no tokens at all). % \end{function} % -% \begin{function}[EXP,pTF] -% {\tl_if_empty:n, \tl_if_empty:V, \tl_if_empty:o, \tl_if_empty:x} +% \begin{function}[added = 2012-05-24, updated = 2012-06-05, EXP,pTF] +% {\tl_if_empty:n, \tl_if_empty:V, \tl_if_empty:o} % \begin{syntax} % \cs{tl_if_empty_p:n} \Arg{token list} % \cs{tl_if_empty:nTF} \Arg{token list} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the \meta{token list} is entirely empty % (\emph{i.e.}~contains no tokens at all). -% All versions of these functions are fully expandable -% (including those involving an \texttt{x}-type expansion). % \end{function} % % \begin{function}[EXP,pTF] % {\tl_if_eq:NN, \tl_if_eq:Nc, \tl_if_eq:cN, \tl_if_eq:cc} % \begin{syntax} -% \cs{tl_if_eq_p:NN} \Arg{tl var1} \Arg{tl var2} -% \cs{tl_if_eq:NNTF} \Arg{tl var1} \Arg{tl var2} \Arg{true code} \Arg{false code} +% \cs{tl_if_eq_p:NN} \Arg{tl var_1} \Arg{tl var_2} +% \cs{tl_if_eq:NNTF} \Arg{tl var_1} \Arg{tl var_2} \Arg{true code} \Arg{false code} % \end{syntax} % Compares the content of two \meta{token list variables} and % is logically \texttt{true} if the two contain the same list of @@ -395,9 +406,9 @@ % % \begin{function}[TF]{\tl_if_eq:nn} % \begin{syntax} -% \cs{tl_if_eq:nnTF} \meta{token list1} \Arg{token list2} \Arg{true code} \Arg{false code} +% \cs{tl_if_eq:nnTF} \meta{token list_1} \Arg{token list_2} \Arg{true code} \Arg{false code} % \end{syntax} -% Tests if \meta{token list1} and \meta{token list2} are equal, both in +% Tests if \meta{token list_1} and \meta{token list_2} are equal, both in % respect of character codes and category codes. % \end{function} % @@ -414,9 +425,9 @@ % \begin{function}[TF] % {\tl_if_in:nn, \tl_if_in:Vn, \tl_if_in:on, \tl_if_in:no} % \begin{syntax} -% \cs{tl_if_in:nnTF} \Arg{token list1} \Arg{token list2} \Arg{true code} \Arg{false code} +% \cs{tl_if_in:nnTF} \Arg{token list_1} \Arg{token list_2} \Arg{true code} \Arg{false code} % \end{syntax} -% Tests if <token list2> is found inside <token list1>. +% Tests if <token list_2> is found inside <token list_1>. % The \meta{token list} cannot contain the tokens |{|, |}| or |#| % (assuming the usual \TeX{} category codes apply). % \end{function} @@ -430,8 +441,8 @@ % Tests if the content of the \meta{tl~var} consists of a single item, % \emph{i.e.}~is either a single normal token (excluding spaces, % and brace tokens) or a single brace group, surrounded by optional -% spaces on both sides. In other words, such a token list has length -% $1$ according to \cs{tl_length:N}. +% spaces on both sides. In other words, such a token list has token count +% $1$ according to \cs{tl_count:N}. % \end{function} % % \begin{function}[updated = 2011-08-13, EXP,pTF]{\tl_if_single:n} @@ -442,22 +453,33 @@ % Tests if the token list has exactly one item, \emph{i.e.}~is either % a single normal token or a single brace group, surrounded by % optional spaces on both sides. In other words, such a token list -% has length $1$ according to \cs{tl_length:n}. +% has token count $1$ according to \cs{tl_count:n}. % \end{function} % -% \begin{function}[added = 2011-08-11,EXP,pTF]{\tl_if_single_token:n} +% \begin{function}[added = 2012-06-03, EXP]{\tl_case:Nnn, \tl_case:cnn} % \begin{syntax} -% \cs{tl_if_single_token_p:n} \Arg{token list} -% \cs{tl_if_single_token:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \cs{tl_case:Nnn} \meta{test token list variable} \\ +% ~~"{" \\ +% ~~~~\meta{token list variable case_1} \Arg{code case_1} \\ +% ~~~~\meta{token list variable case_2} \Arg{code case_2} \\ +% ~~~~\ldots \\ +% ~~~~\meta{token list variable case_n} \Arg{code case_n} \\ +% ~~"}" \\ +% ~~\Arg{else code} % \end{syntax} -% Tests if the token list consists of exactly one token, \emph{i.e.}~is -% either a single space character or a single \enquote{normal} token. -% Token groups (|{|\ldots|}|) are not single tokens. +% This function compares the \meta{test token list variable} in turn +% with each of the \meta{token list variable cases}. If the two +% are equal (as described for +% \cs{tl_if_eq:nnTF} +% then the associated \meta{code} is left in the input +% stream. If none of the tests are \texttt{true} then the +% \texttt{else code} will be left in the input stream. % \end{function} % % \section{Mapping to token lists} % -% \begin{function}[rEXP]{\tl_map_function:NN, \tl_map_function:cN} +% \begin{function}[updated = 2012-06-29, rEXP] +% {\tl_map_function:NN, \tl_map_function:cN} % \begin{syntax} % \cs{tl_map_function:NN} \meta{tl~var} \meta{function} % \end{syntax} @@ -468,7 +490,7 @@ % \texttt{n}-type arguments. See also \cs{tl_map_function:nN}. % \end{function} % -% \begin{function}[rEXP]{\tl_map_function:nN} +% \begin{function}[updated = 2012-06-29, rEXP]{\tl_map_function:nN} % \begin{syntax} % \cs{tl_map_function:nN} \meta{token list} \meta{function} % \end{syntax} @@ -479,7 +501,8 @@ % \texttt{n}-type arguments. See also \cs{tl_map_function:NN}. % \end{function} % -% \begin{function}{\tl_map_inline:Nn, \tl_map_inline:cn} +% \begin{function}[updated = 2012-06-29] +% {\tl_map_inline:Nn, \tl_map_inline:cn} % \begin{syntax} % \cs{tl_map_inline:Nn} \meta{tl~var} \Arg{inline function} % \end{syntax} @@ -489,7 +512,7 @@ % inside another. See also \cs{tl_map_function:Nn}. % \end{function} % -% \begin{function}{\tl_map_inline:nn} +% \begin{function}[updated = 2012-06-29]{\tl_map_inline:nn} % \begin{syntax} % \cs{tl_map_inline:nn} \meta{token list} \Arg{inline function} % \end{syntax} @@ -499,7 +522,8 @@ % inside another. See also \cs{tl_map_function:nn}. % \end{function} % -% \begin{function}{\tl_map_variable:NNn, \tl_map_variable:cNn} +% \begin{function}[updated = 2012-06-29] +% {\tl_map_variable:NNn, \tl_map_variable:cNn} % \begin{syntax} % \cs{tl_map_variable:NNn} \meta{tl~var} \meta{variable} \Arg{function} % \end{syntax} @@ -510,7 +534,7 @@ % \cs{tl_map_inline:Nn}. % \end{function} % -% \begin{function}{\tl_map_variable:nNn} +% \begin{function}[updated = 2012-06-29]{\tl_map_variable:nNn} % \begin{syntax} % \cs{tl_map_variable:nNn} \meta{token list} \meta{variable} \Arg{function} % \end{syntax} @@ -521,7 +545,7 @@ % \cs{tl_map_inline:nn}. % \end{function} % -% \begin{function}[rEXP]{\tl_map_break:} +% \begin{function}[updated = 2012-06-29, rEXP]{\tl_map_break:} % \begin{syntax} % \cs{tl_map_break:} % \end{syntax} @@ -540,6 +564,40 @@ % \end{verbatim} % Use outside of a \cs{tl_map_\ldots} scenario will lead low % level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{__prg_break_point:Nn} before the \meta{tokens} are +% inserted into the input stream. +% This will depend on the design of the mapping function. +% \end{texnote} +% \end{function} +% +% \begin{function}[updated = 2012-06-29, rEXP]{\tl_map_break:n} +% \begin{syntax} +% \cs{tl_map_break:n} \Arg{tokens} +% \end{syntax} +% Used to terminate a \cs{tl_map_\ldots} function before all +% entries in the \meta{token list variable} have been processed, inserting +% the \meta{tokens} after the mapping has ended. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \tl_map_inline:Nn \l_my_tl +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \tl_map_break:n { <tokens> } } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{tl_map_\ldots} scenario will lead to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{__prg_break_point:Nn} before the \meta{tokens} are +% inserted into the input stream. +% This will depend on the design of the mapping function. +% \end{texnote} % \end{function} % % \section{Using token lists} @@ -564,7 +622,8 @@ % in the input stream. Note that this function requires only a single % expansion. % \begin{texnote} -% This is the \eTeX{} primitive \tn{detokenize}. +% This is the \eTeX{} primitive \tn{detokenize}. Hence its argument +% \emph{must} be given within braces. % \end{texnote} % \end{function} % @@ -580,28 +639,28 @@ % % \section{Working with the content of token lists} % -% \begin{function}[updated = 2011-08-13, EXP] -% {\tl_length:n, \tl_length:V, \tl_length:o} +% \begin{function}[added = 2012-05-13, EXP] +% {\tl_count:n, \tl_count:V, \tl_count:o} % \begin{syntax} -% \cs{tl_length:n} \Arg{tokens} +% \cs{tl_count:n} \Arg{tokens} % \end{syntax} % Counts the number of \meta{items} in \meta{tokens} and leaves this % information in the input stream. Unbraced tokens count as one % element as do each token group (|{|\ldots|}|). This process will % ignore any unprotected spaces within \meta{tokens}. See also -% \cs{tl_length:N}. This function requires three expansions, +% \cs{tl_count:N}. This function requires three expansions, % giving an \meta{integer denotation}. % \end{function} % -% \begin{function}[updated = 2011-08-13, EXP]{\tl_length:N, \tl_length:c} +% \begin{function}[added = 2012-05-13, EXP]{\tl_count:N, \tl_count:c} % \begin{syntax} -% \cs{tl_length:N} \Arg{tl~var} +% \cs{tl_count:N} \Arg{tl~var} % \end{syntax} % Counts the number of token groups in the \meta{tl~var} % and leaves this information in the input stream. Unbraced tokens % count as one element as do each token group (|{|\ldots|}|). This % process will ignore any unprotected spaces within \meta{tokens}. -% See also \cs{tl_length:n}. This function requires three expansions, +% See also \cs{tl_count:n}. This function requires three expansions, % giving an \meta{integer denotation}. % \end{function} % @@ -611,8 +670,8 @@ % \cs{tl_reverse:n} \Arg{token list} % \end{syntax} % Reverses the order of the \meta{items} in the \meta{token list}, -% so that \meta{item1}\meta{item2}\meta{item3} \ldots \meta{item$_n$} -% becomes \meta{item$_n$}\ldots \meta{item3}\meta{item2}\meta{item1}. +% so that \meta{item_1}\meta{item_2}\meta{item_3} \ldots \meta{item_n} +% becomes \meta{item_n}\ldots \meta{item_3}\meta{item_2}\meta{item_1}. % This process will preserve unprotected space within the % \meta{token list}. Tokens are not reversed within braced token % groups, which keep their outer set of braces. @@ -633,8 +692,8 @@ % \cs{tl_reverse:N} \Arg{tl~var} % \end{syntax} % Reverses the order of the \meta{items} stored in \meta{tl~var}, so -% that \meta{item1}\meta{item2}\meta{item3} \ldots \meta{item$_n$} -% becomes \meta{item$_n$}\ldots \meta{item3}\meta{item2}\meta{item1}. +% that \meta{item_1}\meta{item_2}\meta{item_3} \ldots \meta{item_n} +% becomes \meta{item_n}\ldots \meta{item_3}\meta{item_2}\meta{item_1}. % This process will preserve unprotected spaces within the % \meta{token list variable}. Braced token groups are copied without % reversing the order of tokens, but keep the outer set of braces. @@ -646,8 +705,8 @@ % \cs{tl_reverse_items:n} \Arg{token list} % \end{syntax} % Reverses the order of the \meta{items} stored in \meta{tl~var}, -% so that \Arg{item_1}\Arg{item_2}\Arg{item_3} \ldots \Arg{item$_n$} -% becomes \Arg{item$_n$} \ldots{} \Arg{item_3}\Arg{item_2}\Arg{item_1}. +% so that \Arg{item_1}\Arg{item_2}\Arg{item_3} \ldots \Arg{item_n} +% becomes \Arg{item_n} \ldots{} \Arg{item_3}\Arg{item_2}\Arg{item_1}. % This process will remove any unprotected space within the % \meta{token list}. Braced token groups are copied without % reversing the order of tokens, and keep the outer set of braces. @@ -662,14 +721,14 @@ % \end{texnote} % \end{function} % -% \begin{function}[added = 2011-07-09, updated = 2011-08-13, EXP] +% \begin{function}[added = 2011-07-09, updated = 2012-06-25, EXP] % {\tl_trim_spaces:n} % \begin{syntax} % \cs{tl_trim_spaces:n} \meta{token list} % \end{syntax} % Removes any leading and trailing explicit space characters % from the \meta{token list} and leaves the result in the input -% stream. This process requires two expansions. +% stream. % \begin{texnote} % The result is returned within the \tn{unexpanded} % primitive (\cs{exp_not:n}), which means that the token @@ -793,78 +852,75 @@ % nothing is left in the input stream. % \end{function} % -% \begin{function}[updated = 2011-08-10, EXP,pTF]{\tl_if_head_eq_catcode:nN} +% \begin{function}[updated = 2012-07-09, EXP, pTF]{\tl_if_head_eq_catcode:nN} % \begin{syntax} % \cs{tl_if_head_eq_catcode_p:nN} \Arg{token list} \meta{test token} % \cs{tl_if_head_eq_catcode:nNTF} \Arg{token list} \meta{test token} % ~~\Arg{true code} \Arg{false code} % \end{syntax} -% Tests if the first \meta{token} in the \meta{token list} has the same -% category code as the \meta{test token}. In the case where -% \meta{token list} is empty, its head is considered to be \cs{q_nil}, -% and the test will be true if \meta{test token} is a control sequence. +% Tests if the first \meta{token} in the \meta{token list} has the +% same category code as the \meta{test token}. In the case where the +% \meta{token list} is empty, the test will always be \texttt{false}. % \end{function} % -% \begin{function}[updated = 2011-08-10, EXP,pTF] +% \begin{function}[updated = 2012-07-09, EXP, pTF] % {\tl_if_head_eq_charcode:nN, \tl_if_head_eq_charcode:fN} % \begin{syntax} % \cs{tl_if_head_eq_charcode_p:nN} \Arg{token list} \meta{test token} % \cs{tl_if_head_eq_charcode:nNTF} \Arg{token list} \meta{test token} % ~~\Arg{true code} \Arg{false code} % \end{syntax} -% Tests if the first \meta{token} in the \meta{token list} has the same -% character code as the \meta{test token}. In the case where -% \meta{token list} is empty, its head is considered to be \cs{q_nil}, -% and the test will be true if \meta{test token} is a control sequence. +% Tests if the first \meta{token} in the \meta{token list} has the +% same character code as the \meta{test token}. In the case where the +% \meta{token list} is empty, the test will always be \texttt{false}. % \end{function} % -% \begin{function}[updated = 2011-08-10, EXP,pTF]{\tl_if_head_eq_meaning:nN} +% \begin{function}[updated = 2012-07-09, EXP, pTF]{\tl_if_head_eq_meaning:nN} % \begin{syntax} % \cs{tl_if_head_eq_meaning_p:nN} \Arg{token list} \meta{test token} % \cs{tl_if_head_eq_meaning:nNTF} \Arg{token list} \meta{test token} % ~~\Arg{true code} \Arg{false code} % \end{syntax} -% Tests if the first \meta{token} in the \meta{token list} has the same -% meaning as the \meta{test token}. In the case where \meta{token list} -% is empty, its head is considered to be \cs{q_nil}, and the test will -% be true if \meta{test token} has the same meaning as \cs{q_nil}. +% Tests if the first \meta{token} in the \meta{token list} has the +% same meaning as the \meta{test token}. In the case where +% \meta{token list} is empty, the test will always be \texttt{false}. % \end{function} % -% \begin{function}[updated = 2011-08-11, EXP,pTF]{\tl_if_head_group:n} +% \begin{function}[added = 2012-07-08, EXP, pTF]{\tl_if_head_is_group:n} % \begin{syntax} -% \cs{tl_if_head_group_p:n} \Arg{token list} -% \cs{tl_if_head_group:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \cs{tl_if_head_is_group_p:n} \Arg{token list} +% \cs{tl_if_head_is_group:nTF} \Arg{token list} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the first \meta{token} in the \meta{token list} % is an explicit begin-group character (with category code~1 % and any character code), in other words, if the \meta{token list} -% starts with a brace group. In particular, the test is false +% starts with a brace group. In particular, the test is \texttt{false} % if the \meta{token list} starts with an implicit token such as % \cs{c_group_begin_token}, or if it empty. % This function is useful to implement actions on token lists on % a token by token basis. % \end{function} % -% \begin{function}[added = 2011-08-11,EXP,pTF]{\tl_if_head_N_type:n} +% \begin{function}[added = 2012-07-08, EXP, pTF]{\tl_if_head_is_N_type:n} % \begin{syntax} -% \cs{tl_if_head_N_type_p:n} \Arg{token list} -% \cs{tl_if_head_N_type:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \cs{tl_if_head_is_N_type_p:n} \Arg{token list} +% \cs{tl_if_head_is_N_type:nTF} \Arg{token list} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the first \meta{token} in the \meta{token list} % is a normal \texttt{N}-type argument. In other words, % it is neither an explicit space character (with category code~10 % and character code~32) nor an explicit begin-group character % (with category code~1 and any character code). An empty -% argument yields false, as it does not have a \enquote{normal} +% argument yields \texttt{false}, as it does not have a \enquote{normal} % first token. % This function is useful to implement actions on token lists on % a token by token basis. % \end{function} % -% \begin{function}[updated = 2011-08-11,EXP,pTF]{\tl_if_head_space:n} +% \begin{function}[updated = 2012-07-08, EXP, pTF]{\tl_if_head_is_space:n} % \begin{syntax} -% \cs{tl_if_head_space_p:n} \Arg{token list} -% \cs{tl_if_head_space:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \cs{tl_if_head_is_space_p:n} \Arg{token list} +% \cs{tl_if_head_is_space:nTF} \Arg{token list} \Arg{true code} \Arg{false code} % \end{syntax} %^^A We need to add a discussion of %^^A explicit vs implicit tokens somewhere in the doc. @@ -872,7 +928,7 @@ % is an explicit space character (with category code~$10$ % and character code~$32$). If \meta{token list} starts with % an implicit token such as \cs{c_space_token}, the test -% will yield false, as well as if the argument is empty. +% will yield \texttt{false}, as well as if the argument is empty. % This function is useful to implement actions on token lists on % a token by token basis. % \begin{texnote} @@ -942,89 +998,22 @@ % code and so should only be used for short-term storage. % \end{variable} % -% \section{Experimental token list functions} -% -% \begin{function}[added = 2012-01-08, EXP]{\tl_reverse_tokens:n} -% \begin{syntax} -% \cs{tl_reverse_tokens:n} \Arg{tokens} -% \end{syntax} -% This function, which works directly on \TeX{} tokens, reverses -% the order of the \meta{tokens}: the first will be the last and -% the last will become first. Spaces are preserved. The reversal -% also operates within brace groups, but the braces themselves -% are not exchanged, as this would lead to an unbalanced token -% list. For instance, \cs{tl_reverse_tokens:n} |{a~{b()}}| -% leaves |{)(b}~a| in the input stream. This function requires -% two steps of expansion. -% \begin{texnote} -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the token -% list will not expand further when appearing in an x-type -% argument expansion. -% \end{texnote} -% \end{function} -% -% \begin{function}[added = 2011-08-11, EXP]{\tl_length_tokens:n} -% \begin{syntax} -% \cs{tl_length_tokens:n} \Arg{tokens} -% \end{syntax} -% Counts the number of \TeX{} tokens in the \meta{tokens} and leaves -% this information in the input stream. Every token, including spaces and -% braces, contributes one to the total; thus for instance, the length of -% |a~{bc}| is $6$. -% This function requires three expansions, -% giving an \meta{integer denotation}. -% \end{function} -% -% \begin{function}[added = 2012-01-08, EXP] -% {\tl_expandable_uppercase:n,\tl_expandable_lowercase:n} -% \begin{syntax} -% \cs{tl_expandable_uppercase:n} \Arg{tokens} -% \cs{tl_expandable_lowercase:n} \Arg{tokens} -% \end{syntax} -% The \cs{tl_expandable_uppercase:n} function works through all of -% the \meta{tokens}, replacing characters in the range |a|--|z| -% (with arbitrary category code) by the corresponding letter -% in the range |A|--|Z|, with category code $11$ (letter). Similarly, -% \cs{tl_expandable_lowercase:n} replaces characters in the range -% |A|--|Z| by letters in the range |a|--|z|, and leaves other tokens -% unchanged. This function requires two steps of expansion. -% \begin{texnote} -% Begin-group and end-group characters are normalized and become -% |{| and |}|, respectively. -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the token -% list will not expand further when appearing in an x-type -% argument expansion. -% \end{texnote} -% \end{function} +% \section{Internal functions} % -% \begin{function}[added = 2011-11-21, updated = 2012-01-08, EXP] -% {\tl_item:nn, \tl_item:Nn, \tl_item:cn} +% \begin{function}{\__tl_trim_spaces:nn} % \begin{syntax} -% \cs{tl_item:nn} \Arg{token list} \Arg{integer expression} +% \cs{__tl_trim_spaces:nn} |{ \q_mark| \meta{token list} |}| \Arg{continuation} % \end{syntax} -% Indexing items in the \meta{token list} from $0$ on the left, this -% function will evaluate the \meta{integer expression} and leave the -% appropriate item from the \meta{token list} in the input stream. -% If the \meta{integer expression} is negative, indexing occurs from -% the right of the token list, starting at $-1$ for the right-most item. -% If the index is out of bounds, then thr function expands to nothing. -% \begin{texnote} -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the \meta{item} -% will not expand further when appearing in an x-type -% argument expansion. -% \end{texnote} +% This function removes all leading and trailing explicit space +% characters from the \meta{token list}, and expands to the +% \meta{continuation}, followed by a brace group containing +% \cs{use_none:n} \cs{q_mark} \meta{trimmed token list}. For +% instance, \cs{tl_trim_spaces:n} is implemented by taking the +% \meta{continuation} to be \cs{exp_not:o}, and the \texttt{o}-type +% expansion removes the \cs{q_mark}. This function is also used in +% \pkg{l3clist}. % \end{function} % -% \section{Internal functions} -% -% \begin{variable}{\q_tl_act_mark,\q_tl_act_stop} -% Quarks which are only used for the particular purposes of -% \cs{tl_act_...} functions. -% \end{variable} -% % \end{documentation} % % \begin{implementation} @@ -1036,10 +1025,14 @@ % \end{macrocode} % % \begin{macrocode} +%<@@=tl> +% \end{macrocode} +% +% \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -1055,7 +1048,7 @@ % \begin{macrocode} \cs_new_protected:Npn \tl_new:N #1 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \cs_gset_eq:NN #1 \c_empty_tl } \cs_generate_variant:Nn \tl_new:N { c } @@ -1067,12 +1060,12 @@ % \begin{macrocode} \cs_new_protected:Npn \tl_const:Nn #1#2 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } } \cs_new_protected:Npn \tl_const:Nx #1#2 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \cs_gset_nopar:Npx #1 {#2} } \cs_generate_variant:Nn \tl_const:Nn { c } @@ -1134,6 +1127,20 @@ % \end{macro} % \end{macro} % +% \begin{macro}{\tl_concat:NNN, \tl_concat:ccc} +% \begin{macro}{\tl_gconcat:NNN, \tl_gconcat:ccc} +% Concatenating token lists is easy. +% \begin{macrocode} +\cs_new_protected:Npn \tl_concat:NNN #1#2#3 + { \tl_set:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } } +\cs_new_protected:Npn \tl_gconcat:NNN #1#2#3 + { \tl_gset:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } } +\cs_generate_variant:Nn \tl_concat:NNN { ccc } +\cs_generate_variant:Nn \tl_gconcat:NNN { ccc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \begin{macro}[pTF]{\tl_if_exist:N, \tl_if_exist:c} % Copies of the \texttt{cs} functions defined in \pkg{l3basics}. % \begin{macrocode} @@ -1148,6 +1155,37 @@ % \end{macrocode} % \end{macro} % +% \subsection{Constant token lists} +% +% \begin{variable}{\c_job_name_tl} +% Inherited from the \LaTeX3 name for the primitive: this needs to +% actually contain the text of the job name rather than the name of +% the primitive, of course. \LuaTeX{} does not quote file names containing +% spaces, whereas \pdfTeX{} and \XeTeX{} do. So there may be a correction to +% make in the \LuaTeX{} case. +% \begin{macrocode} +%<*initex> +\tex_everyjob:D \exp_after:wN + { + \tex_the:D \tex_everyjob:D + \luatex_if_engine:T + { + \lua_now:x + { dofile ( assert ( kpse.find_file ("lualatexquotejobname.lua" ) ) ) } + } + } +%</initex> +\tl_const:Nx \c_job_name_tl { \tex_jobname:D } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_space_tl} +% A space as a token list (as opposed to as a character). +% \begin{macrocode} +\tl_const:Nn \c_space_tl { ~ } +% \end{macrocode} +% \end{variable} +% % \subsection{Adding to token list variables} % % \begin{macro} @@ -1273,7 +1311,7 @@ % % \subsection{Reassigning token list category codes} % -% \begin{variable}{\c_tl_rescan_marker_tl} +% \begin{variable}{\c_@@_rescan_marker_tl} % The rescanning code needs a special token list containing the same % character with two different category codes. This is set up here, % while the detail is described below. @@ -1286,7 +1324,7 @@ \tex_lowercase:D { \group_end: - \tl_const:Nn \c_tl_rescan_marker_tl { A B } + \tl_const:Nn \c_@@_rescan_marker_tl { A B } } % \end{macrocode} % \end{variable} @@ -1302,8 +1340,8 @@ % \tl_gset_rescan:cnn, \tl_gset_rescan:cno, \tl_gset_rescan:cnx % } % \begin{macro}{\tl_rescan:nn} -% \begin{macro}[aux]{\tl_set_rescan_aux:NNnn} -% \begin{macro}[aux]{\tl_rescan_aux:w} +% \begin{macro}[aux]{\@@_set_rescan:NNnn} +% \begin{macro}[aux]{\@@_rescan:w} % The idea here is to deal cleanly with the problem that % \tn{scantokens} treats the argument as a file, and without % the correct settings a \TeX{} error occurs: @@ -1322,15 +1360,15 @@ % \enquote{unprintable}. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_set_rescan:Nnn - { \tl_set_rescan_aux:NNnn \tl_set:Nn } + { \@@_set_rescan:NNnn \tl_set:Nn } \cs_new_protected_nopar:Npn \tl_gset_rescan:Nnn - { \tl_set_rescan_aux:NNnn \tl_gset:Nn } + { \@@_set_rescan:NNnn \tl_gset:Nn } \cs_new_protected_nopar:Npn \tl_rescan:nn - { \tl_set_rescan_aux:NNnn \prg_do_nothing: \use:n } -\cs_new_protected:Npn \tl_set_rescan_aux:NNnn #1#2#3#4 + { \@@_set_rescan:NNnn \prg_do_nothing: \use:n } +\cs_new_protected:Npn \@@_set_rescan:NNnn #1#2#3#4 { \group_begin: - \exp_args:No \etex_everyeof:D { \c_tl_rescan_marker_tl \exp_not:N } + \exp_args:No \etex_everyeof:D { \c_@@_rescan_marker_tl \exp_not:N } \tex_endlinechar:D \c_minus_one \tex_newlinechar:D \c_minus_one #3 @@ -1339,7 +1377,7 @@ \group_end: #1 \exp_not:N #2 { - \exp_after:wN \tl_rescan_aux:w + \exp_after:wN \@@_rescan:w \exp_after:wN \prg_do_nothing: \etex_scantokens:D {#4} } @@ -1347,8 +1385,8 @@ } \use:x { - \cs_new:Npn \exp_not:N \tl_rescan_aux:w ##1 - \c_tl_rescan_marker_tl + \cs_new:Npn \exp_not:N \@@_rescan:w ##1 + \c_@@_rescan_marker_tl { \exp_not:N \exp_not:o { ##1 } } } \cs_generate_variant:Nn \tl_set_rescan:Nnn { Nno , Nnx } @@ -1380,21 +1418,21 @@ % \begin{macro}{\tl_greplace_all:Nnn, \tl_greplace_all:cnn} % \begin{macro}{\tl_replace_once:Nnn, \tl_replace_once:cnn} % \begin{macro}{\tl_greplace_once:Nnn, \tl_greplace_once:cnn} -% \begin{macro}[aux]{\tl_replace_aux:NNNnn, \tl_replace_aux_ii:w} -% \begin{macro}[aux]{\tl_replace_all_aux:, \tl_replace_once_aux:} -% \begin{macro}[aux]{\tl_replace_once_aux_end:w} -% All of the replace functions are based on \cs{tl_replace_aux:NNNnn}, +% \begin{macro}[aux]{\@@_replace:NNNnn, \@@_replace:w} +% \begin{macro}[aux]{\@@_replace_all:, \@@_replace_once:} +% \begin{macro}[aux]{\@@_replace_once_end:w} +% All of the replace functions are based on \cs{@@_replace:NNNnn}, % whose arguments are: \meta{function}, \cs{tl_(g)set:Nx}, \meta{tl~var}, % \meta{search tokens}, \meta{replacement tokens}. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_replace_once:Nnn - { \tl_replace_aux:NNNnn \tl_replace_once_aux: \tl_set:Nx } + { \@@_replace:NNNnn \@@_replace_once: \tl_set:Nx } \cs_new_protected_nopar:Npn \tl_greplace_once:Nnn - { \tl_replace_aux:NNNnn \tl_replace_once_aux: \tl_gset:Nx } + { \@@_replace:NNNnn \@@_replace_once: \tl_gset:Nx } \cs_new_protected_nopar:Npn \tl_replace_all:Nnn - { \tl_replace_aux:NNNnn \tl_replace_all_aux: \tl_set:Nx } + { \@@_replace:NNNnn \@@_replace_all: \tl_set:Nx } \cs_new_protected_nopar:Npn \tl_greplace_all:Nnn - { \tl_replace_aux:NNNnn \tl_replace_all_aux: \tl_gset:Nx } + { \@@_replace:NNNnn \@@_replace_all: \tl_gset:Nx } \cs_generate_variant:Nn \tl_replace_once:Nnn { c } \cs_generate_variant:Nn \tl_greplace_once:Nnn { c } \cs_generate_variant:Nn \tl_replace_all:Nnn { c } @@ -1402,34 +1440,34 @@ % \end{macrocode} % The idea is easier to understand by considering the case of % \cs{tl_replace_all:Nnn}. The replacement happens within an -% \texttt{x}-type expansion. We use an auxiliary function \cs{tl_tmp:w}, +% \texttt{x}-type expansion. We use an auxiliary function \cs{@@_tmp:w}, % which essentially replaces the next \meta{search tokens} by % \meta{replacement tokens}. To avoid runaway arguments, -% we expand something like \cs{tl_tmp:w} \meta{token list} \cs{q_mark} +% we expand something like \cs{@@_tmp:w} \meta{token list} \cs{q_mark} % \meta{search tokens} \cs{q_stop}, repeating until the end. How do we % detect that we have reached the last occurrence of \meta{search tokens}? % The last replacement is characterized by the fact that the argument of -% \cs{tl_tmp:w} contains \cs{q_mark}. In the code below, -% \cs{tl_replace_aux_ii:w} takes an argument delimited by \cs{q_mark}, +% \cs{@@_tmp:w} contains \cs{q_mark}. In the code below, +% \cs{@@_replace:w} takes an argument delimited by \cs{q_mark}, % and removes the following token. Before we reach the end, this gobbles % \cs{q_mark} \cs{use_none_delimit_by_q_stop:w} which appear in the -% definition of \cs{tl_tmp:w}, and leaves the \meta{replacement tokens}, +% definition of \cs{@@_tmp:w}, and leaves the \meta{replacement tokens}, % passed to \cs{exp_not:n}, to be included in the \texttt{x}-expanding % definition. At the end, the first \cs{q_mark} is within the argument -% of \cs{tl_tmp:w}, and \cs{tl_replace_aux_ii:w} gobbles the second +% of \cs{@@_tmp:w}, and \cs{@@_replace:w} gobbles the second % \cs{q_mark} as well, leaving \cs{use_none_delimit_by_q_stop:w}, % which ends the recursion cleanly. % \begin{macrocode} -\cs_new_protected:Npn \tl_replace_aux:NNNnn #1#2#3#4#5 +\cs_new_protected:Npn \@@_replace:NNNnn #1#2#3#4#5 { \tl_if_empty:nTF {#4} { - \msg_kernel_error:nnx { tl } { empty-search-pattern } + \__msg_kernel_error:nnx { kernel } { empty-search-pattern } { \tl_to_str:n {#5} } } { \group_align_safe_begin: - \cs_set:Npx \tl_tmp:w ##1##2 #4 + \cs_set:Npx \@@_tmp:w ##1##2 #4 { ##2 \exp_not:N \q_mark @@ -1445,12 +1483,12 @@ } } } -\cs_new:Npn \tl_replace_aux_ii:w #1 \q_mark #2 { \exp_not:o {#1} } +\cs_new:Npn \@@_replace:w #1 \q_mark #2 { \exp_not:o {#1} } % \end{macrocode} -% The first argument of \cs{tl_tmp:w} is responsible for repeating +% The first argument of \cs{@@_tmp:w} is responsible for repeating % the replacement in the case of \texttt{replace_all}, and stopping % it early for \texttt{replace_once}. Note also that we build -% \cs{tl_tmp:w} within an \texttt{x}-expansion so that the +% \cs{@@_tmp:w} within an \texttt{x}-expansion so that the % \meta{replacement tokens} can contain |#|. The second % \cs{exp_not:n} ensures that the \meta{replacement tokens} % are not expanded by \cs{tl_(g)set:Nx}. @@ -1460,17 +1498,17 @@ % ensure that we don't lose braces in case the tokens between two % occurrences of the \meta{search tokens} form a brace group. % \begin{macrocode} -\cs_new:Npn \tl_replace_all_aux: +\cs_new_nopar:Npn \@@_replace_all: { - \exp_after:wN \tl_replace_aux_ii:w - \tl_tmp:w \tl_replace_all_aux: \prg_do_nothing: + \exp_after:wN \@@_replace:w + \@@_tmp:w \@@_replace_all: \prg_do_nothing: } -\cs_new_nopar:Npn \tl_replace_once_aux: +\cs_new_nopar:Npn \@@_replace_once: { - \exp_after:wN \tl_replace_aux_ii:w - \tl_tmp:w { \tl_replace_once_aux_end:w \prg_do_nothing: } \prg_do_nothing: + \exp_after:wN \@@_replace:w + \@@_tmp:w { \@@_replace_once_end:w \prg_do_nothing: } \prg_do_nothing: } -\cs_new:Npn \tl_replace_once_aux_end:w #1 \q_mark #2 \q_stop +\cs_new:Npn \@@_replace_once_end:w #1 \q_mark #2 \q_stop { \exp_not:o {#1} } % \end{macrocode} % \end{macro} @@ -1511,7 +1549,7 @@ % \subsection{Token list conditionals} % % \begin{macro}[pTF]{\tl_if_blank:n,\tl_if_blank:V,\tl_if_blank:o} -% \begin{macro}[aux]{\tl_if_blank_p_aux:NNw} +% \begin{macro}[aux]{\@@_if_blank_p:NNw} % \TeX{} skips spaces when reading a non-delimited arguments. Thus, % a \meta{token list} is blank if and only if \cs{use_none:n} % \meta{token list} |?| is empty. For performance reasons, we hard-code @@ -1525,7 +1563,7 @@ % while \tn{escapechar} is a space or is unprintable. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_blank:n #1 { p , T , F , TF } - { \tl_if_empty_return:o { \use_none:n #1 ? } } + { \@@_if_empty_return:o { \use_none:n #1 ? } } \cs_generate_variant:Nn \tl_if_blank_p:n { V } \cs_generate_variant:Nn \tl_if_blank:nT { V } \cs_generate_variant:Nn \tl_if_blank:nF { V } @@ -1561,14 +1599,15 @@ % \begin{macro}[pTF]{\tl_if_empty:n,\tl_if_empty:V} % It would be tempting to just use |\if_meaning:w \q_nil #1 \q_nil| as % a test since this works really well. However, it fails on a token -% list starting with |\q_nil| of course but more troubling is the -% case where argument is a complete conditional such as |\if_true:| -% a |\else:| b |\fi:| because then |\if_true:| is used by -% |\if_meaning:w|, the test turns out false, the |\else:| executes -% the false branch, the |\fi:| ends it and the |\q_nil| at the end +% list starting with \cs{q_nil} of course but more troubling is the +% case where argument is a complete conditional such as \cs{if_true:} +% a \cs{else:} b \cs{fi:} because then \cs{if_true:} is used by +% \cs{if_meaning:w}, the test turns out \texttt{false}, the \cs{else:} +% executes the \texttt{false} branch, the \cs{fi:} ends it and the +% \cs{q_nil} at the end % starts executing\dots{} A safer route is to convert the entire % token list into harmless characters first and then compare -% that. This way the test will even accept |\q_nil| as the first +% that. This way the test will even accept \cs{q_nil} as the first % token. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_empty:n #1 { p , TF , T , F } @@ -1587,8 +1626,8 @@ % \end{macro} % % \begin{macro}[pTF]{\tl_if_empty:o} -% \begin{macro}[EXP,aux]{\tl_if_empty_return:o} -% The auxiliary function \cs{tl_if_empty_return:o} is for use +% \begin{macro}[EXP,aux]{\@@_if_empty_return:o} +% The auxiliary function \cs{@@_if_empty_return:o} is for use % in conditionals on token lists, which mostly reduce to testing % if a given token list is empty after applying a simple function % to it. @@ -1598,7 +1637,7 @@ % Note that this works because \cs{tl_to_str:n} expands tokens % that follow until reading a catcode $1$ (begin-group) token. % \begin{macrocode} -\cs_new:Npn \tl_if_empty_return:o #1 +\cs_new:Npn \@@_if_empty_return:o #1 { \exp_after:wN \if_meaning:w \exp_after:wN \q_nil \tl_to_str:n \exp_after:wN {#1} \q_nil @@ -1608,7 +1647,7 @@ \fi: } \prg_new_conditional:Npnn \tl_if_empty:o #1 { p , TF , T , F } - { \tl_if_empty_return:o {#1} } + { \@@_if_empty_return:o {#1} } % \end{macrocode} % \end{macro} % \end{macro} @@ -1670,10 +1709,10 @@ % % \begin{macro}[TF]{\tl_if_in:nn, \tl_if_in:Vn, \tl_if_in:on, \tl_if_in:no} % Once more, the test relies on \cs{tl_to_str:n} for robustness. -% The function \cs{tl_tmp:w} removes tokens until the first occurrence +% The function \cs{@@_tmp:w} removes tokens until the first occurrence % of |#2|. If this does not appear in |#1|, then the final |#2| is removed, % leaving an empty token list. Otherwise some tokens remain, and the -% test is false. See \cs{tl_if_empty:n(TF)} for details on +% test is \texttt{false}. See \cs{tl_if_empty:n(TF)} for details on % the emptyness test. % % Special care is needed to treat correctly cases like @@ -1685,8 +1724,8 @@ % \begin{macrocode} \prg_new_protected_conditional:Npnn \tl_if_in:nn #1#2 { T , F , TF } { - \cs_set:Npn \tl_tmp:w ##1 #2 { } - \tl_if_empty:oTF { \tl_tmp:w #1 {} {} #2 } + \cs_set:Npn \@@_tmp:w ##1 #2 { } + \tl_if_empty:oTF { \@@_tmp:w #1 {} {} #2 } { \prg_return_false: } { \prg_return_true: } } \cs_generate_variant:Nn \tl_if_in:nnT { V , o , no } @@ -1695,27 +1734,73 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}[EXP,pTF]{\tl_if_single:N} +% Expand the token list and feed it to \cs{tl_if_single:n}. +% \begin{macrocode} +\cs_new:Npn \tl_if_single_p:N { \exp_args:No \tl_if_single_p:n } +\cs_new:Npn \tl_if_single:NT { \exp_args:No \tl_if_single:nT } +\cs_new:Npn \tl_if_single:NF { \exp_args:No \tl_if_single:nF } +\cs_new:Npn \tl_if_single:NTF { \exp_args:No \tl_if_single:nTF } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP,pTF]{\tl_if_single:n} +% A token list has exactly one item if it is either a single +% token surrounded by optional explicit spaces, or a single brace +% group surrounded by optional explicit spaces. The naive +% version of this test would do \cs{use_none:n} |#1|, and +% test if the result is empty. However, this will fail when +% the token list is empty. Furthermore, it does not allow optional +% trailing spaces. +% \begin{macrocode} +\prg_new_conditional:Npnn \tl_if_single:n #1 { p , T , F , TF } + { \__str_if_eq_x_return:nn { \exp_not:o { \use_none:nn #1 ?? } } {?} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\tl_case:Nnn, \tl_case:cnn} +% \begin{macro}[aux, EXP]{\@@_case:Nw} +% \begin{macro}[aux, EXP]{\@@_case_end:nw} +% \begin{macrocode} +\cs_new:Npn \tl_case:Nnn #1#2#3 + { + \tex_romannumeral:D + \@@_case:Nw #1 #2 #1 {#3} \q_recursion_stop + } +\cs_new:Npn \@@_case:Nw #1#2#3 + { + \tl_if_eq:NNTF #1 #2 + { \@@_case_end:nw {#3} } + { \@@_case:Nw #1 } + } +\cs_generate_variant:Nn \tl_case:Nnn { c } +\cs_new_eq:NN \@@_case_end:nw \__prg_case_end:nw +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% % \subsection{Mapping to token lists} % % \begin{macro}{\tl_map_function:nN} % \begin{macro}{\tl_map_function:NN, \tl_map_function:cN} -% \begin{macro}[aux]{\tl_map_function_aux:Nn} +% \begin{macro}[aux]{\@@_map_function:Nn} % Expandable loop macro for token lists. These have the advantage of not % needing to test if the argument is empty, because if it is, the stop % marker will be read immediately and the loop terminated. % \begin{macrocode} \cs_new:Npn \tl_map_function:nN #1#2 { - \tl_map_function_aux:Nn #2 #1 + \@@_map_function:Nn #2 #1 \q_recursion_tail - \prg_break_point:n { } + \__prg_break_point:Nn \tl_map_break: { } } \cs_new_nopar:Npn \tl_map_function:NN { \exp_args:No \tl_map_function:nN } -\cs_new:Npn \tl_map_function_aux:Nn #1#2 +\cs_new:Npn \@@_map_function:Nn #1#2 { - \quark_if_recursion_tail_break:n {#2} - #1 {#2} \tl_map_function_aux:Nn #1 + \__quark_if_recursion_tail_break:nN {#2} \tl_map_break: + #1 {#2} \@@_map_function:Nn #1 } \cs_generate_variant:Nn \tl_map_function:NN { c } % \end{macrocode} @@ -1726,19 +1811,18 @@ % \begin{macro}{\tl_map_inline:nn} % \begin{macro}{\tl_map_inline:Nn, \tl_map_inline:cn} % The inline functions are straight forward by now. We use a little -% trick with the counter \cs{g_prg_map_int} to make -% them nestable. We can also make use of \cs{tl_map_function_aux:Nn} +% trick with the counter \cs{g__prg_map_int} to make +% them nestable. We can also make use of \cs{@@_map_function:Nn} % from before. % \begin{macrocode} \cs_new_protected:Npn \tl_map_inline:nn #1#2 { - \int_gincr:N \g_prg_map_int - \cs_gset:cpn { tl_map_inline_ \int_use:N \g_prg_map_int :n } - ##1 {#2} - \exp_args:Nc \tl_map_function_aux:Nn - { tl_map_inline_ \int_use:N \g_prg_map_int :n } + \int_gincr:N \g__prg_map_int + \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2} + \exp_args:Nc \@@_map_function:Nn + { __prg_map_ \int_use:N \g__prg_map_int :w } #1 \q_recursion_tail - \prg_break_point:n { \int_gdecr:N \g_prg_map_int } + \__prg_break_point:Nn \tl_map_break: { \int_gdecr:N \g__prg_map_int } } \cs_new_protected:Npn \tl_map_inline:Nn { \exp_args:No \tl_map_inline:nn } @@ -1749,25 +1833,25 @@ % % \begin{macro}{\tl_map_variable:nNn} % \begin{macro}{\tl_map_variable:NNn, \tl_map_variable:cNn} -% \begin{macro}[aux]{\tl_map_variable_aux:Nnn} +% \begin{macro}[aux]{\@@_map_variable:Nnn} % \cs{tl_map_variable:nNn} \meta{token list} \meta{temp} \meta{action} % assigns % \meta{temp} to each element and executes \meta{action}. % \begin{macrocode} \cs_new_protected:Npn \tl_map_variable:nNn #1#2#3 { - \tl_map_variable_aux:Nnn #2 {#3} #1 + \@@_map_variable:Nnn #2 {#3} #1 \q_recursion_tail - \prg_break_point:n { } + \__prg_break_point:Nn \tl_map_break: { } } \cs_new_protected_nopar:Npn \tl_map_variable:NNn { \exp_args:No \tl_map_variable:nNn } -\cs_new_protected:Npn \tl_map_variable_aux:Nnn #1#2#3 +\cs_new_protected:Npn \@@_map_variable:Nnn #1#2#3 { \tl_set:Nn #1 {#3} - \quark_if_recursion_tail_break:N #1 + \__quark_if_recursion_tail_break:NN #1 \tl_map_break: \use:n {#2} - \tl_map_variable_aux:Nnn #1 {#2} + \@@_map_variable:Nnn #1 {#2} } \cs_generate_variant:Nn \tl_map_variable:NNn { c } % \end{macrocode} @@ -1777,10 +1861,12 @@ % % \begin{macro}{\tl_map_break:} % \begin{macro}{\tl_map_break:n} -% The break statements are simply copies. +% The break statements use the general \cs{__prg_map_break:Nn}. % \begin{macrocode} -\cs_new_eq:NN \tl_map_break: \prg_map_break: -\cs_new_eq:NN \tl_map_break:n \prg_map_break:n +\cs_new_nopar:Npn \tl_map_break: + { \__prg_map_break:Nn \tl_map_break: { } } +\cs_new_nopar:Npn \tl_map_break:n + { \__prg_map_break:Nn \tl_map_break: } % \end{macrocode} % \end{macro} % \end{macro} @@ -1811,7 +1897,7 @@ \cs_new:Npn \tl_use:N #1 { \tl_if_exist:NTF #1 {#1} - { \msg_expandable_kernel_error:nnn { kernel } { bad-var } {#1} } + { \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#1} } } \cs_generate_variant:Nn \tl_use:N { c } % \end{macrocode} @@ -1819,54 +1905,54 @@ % % \subsection{Working with the contents of token lists} % -% \begin{macro}{\tl_length:n, \tl_length:V, \tl_length:o} -% \begin{macro}{\tl_length:N, \tl_length:c} -% \begin{macro}[aux]{\tl_length_aux:n} +% \begin{macro}{\tl_count:n, \tl_count:V, \tl_count:o} +% \begin{macro}{\tl_count:N, \tl_count:c} +% \begin{macro}[aux]{\@@_count:n} % Count number of elements within a token list or token list % variable. Brace groups within the list are read as a single % element. Spaces are ignored. -% \cs{tl_length_aux:n} grabs the element and replaces it by |+1|. +% \cs{@@_count:n} grabs the element and replaces it by |+1|. % The |0| to ensure it works on an empty list. % \begin{macrocode} -\cs_new:Npn \tl_length:n #1 +\cs_new:Npn \tl_count:n #1 { \int_eval:n - { 0 \tl_map_function:nN {#1} \tl_length_aux:n } + { 0 \tl_map_function:nN {#1} \@@_count:n } } -\cs_new:Npn \tl_length:N #1 +\cs_new:Npn \tl_count:N #1 { \int_eval:n - { 0 \tl_map_function:NN #1 \tl_length_aux:n } + { 0 \tl_map_function:NN #1 \@@_count:n } } -\cs_new:Npn \tl_length_aux:n #1 { + \c_one } -\cs_generate_variant:Nn \tl_length:n { V , o } -\cs_generate_variant:Nn \tl_length:N { c } +\cs_new:Npn \@@_count:n #1 { + \c_one } +\cs_generate_variant:Nn \tl_count:n { V , o } +\cs_generate_variant:Nn \tl_count:N { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\tl_reverse_items:n} -% \begin{macro}[aux]{\tl_reverse_items_aux:nwNwn} -% \begin{macro}[aux]{\tl_reverse_items_aux:wn} +% \begin{macro}[aux]{\@@_reverse_items:nwNwn} +% \begin{macro}[aux]{\@@_reverse_items:wn} % Reversal of a token list is done by taking one item at a time % and putting it after \cs{q_stop}. % \begin{macrocode} \cs_new:Npn \tl_reverse_items:n #1 { - \tl_reverse_items_aux:nwNwn #1 ? - \q_mark \tl_reverse_items_aux:nwNwn - \q_mark \tl_reverse_items_aux:wn + \@@_reverse_items:nwNwn #1 ? + \q_mark \@@_reverse_items:nwNwn + \q_mark \@@_reverse_items:wn \q_stop { } } -\cs_new:Npn \tl_reverse_items_aux:nwNwn #1 #2 \q_mark #3 #4 \q_stop #5 +\cs_new:Npn \@@_reverse_items:nwNwn #1 #2 \q_mark #3 #4 \q_stop #5 { #3 #2 - \q_mark \tl_reverse_items_aux:nwNwn - \q_mark \tl_reverse_items_aux:wn + \q_mark \@@_reverse_items:nwNwn + \q_mark \@@_reverse_items:wn \q_stop { {#1} #5 } } -\cs_new:Npn \tl_reverse_items_aux:wn #1 \q_stop #2 +\cs_new:Npn \@@_reverse_items:wn #1 \q_stop #2 { \exp_not:o { \use_none:nn #2 } } % \end{macrocode} % \end{macro} @@ -1879,78 +1965,237 @@ % \tl_trim_spaces:N, \tl_trim_spaces:c, % \tl_gtrim_spaces:N, \tl_gtrim_spaces:c % } +% Trimming spaces from around the input is deferred to an internal +% function whose first argument is the token list to trim, augmented +% by an initial \cs{q_mark}, and whose second argument is a +% \meta{continuation}, which will receive as a braced argument +% \cs{use_none:n} \cs{q_mark} \meta{trimmed token list}. In the case +% at hand, we take \cs{exp_not:o} as our continuation, so that space +% trimming will behave correctly within an \texttt{x}-type expansion. +% \begin{macrocode} +\cs_new:Npn \tl_trim_spaces:n #1 + { \@@_trim_spaces:nn { \q_mark #1 } \exp_not:o } +\cs_new_protected:Npn \tl_trim_spaces:N #1 + { \tl_set:Nx #1 { \exp_args:No \tl_trim_spaces:n {#1} } } +\cs_new_protected:Npn \tl_gtrim_spaces:N #1 + { \tl_gset:Nx #1 { \exp_args:No \tl_trim_spaces:n {#1} } } +\cs_generate_variant:Nn \tl_trim_spaces:N { c } +\cs_generate_variant:Nn \tl_gtrim_spaces:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_trim_spaces:nn} % \begin{macro}[aux] % { -% \tl_trim_spaces_aux_i:w, \tl_trim_spaces_aux_ii:w -% \tl_trim_spaces_aux_iii:w, \tl_trim_spaces_aux_iv:w +% \@@_trim_spaces_i:w, \@@_trim_spaces_ii:w +% \@@_trim_spaces_iii:w, \@@_trim_spaces_iv:w % } % Trimming spaces from around the input is done using delimited % arguments and quarks, and to get spaces at odd places in the -% definitions, we nest those in \cs{tl_tmp:w}, which then receives +% definitions, we nest those in \cs{@@_tmp:w}, which then receives % a single space as its argument: |#1| is \verb*+ +. -% Removing leading spaces is done with \cs{tl_trim_spaces_aux_i:w}, +% Removing leading spaces is done with \cs{@@_trim_spaces_i:w}, % which loops until \cs{q_mark}\verb*+ + matches the end of the token % list: then |##1| is the token list and |##3| is -% \cs{tl_trim_spaces_aux_ii:w}. This hands the relevant tokens to the -% loop \cs{tl_trim_spaces_aux_iii:w}, responsible for trimming +% \cs{@@_trim_spaces_ii:w}. This hands the relevant tokens to the +% loop \cs{@@_trim_spaces_iii:w}, responsible for trimming % trailing spaces. The end is reached when \verb*+ + \cs{q_nil} % matches the one present in the definition of \cs{tl_trim_spacs:n}. -% Then \cs{tl_trim_spaces_aux_iv:w} puts the token list into a group, -% as the argument of the initial \tn{unexpanded}. -% The \tn{unexpanded} here is used so that space trimming will -% behave correctly within an \texttt{x}-type expansion. -% -% Some of the auxiliaries used in this code are also used -% in the \pkg{l3clist} module. Change with care. +% Then \cs{@@_trim_spaces_iv:w} puts the token list into a group, +% with \cs{use_none:n} placed there to gobble a lingering \cs{q_mark}, +% and feeds this to the \meta{continuation}. % \begin{macrocode} -\cs_set:Npn \tl_tmp:w #1 +\cs_set:Npn \@@_tmp:w #1 { - \cs_new:Npn \tl_trim_spaces:n ##1 + \cs_new:Npn \@@_trim_spaces:nn ##1 { - \etex_unexpanded:D - \tl_trim_spaces_aux_i:w - \q_mark + \@@_trim_spaces_i:w ##1 \q_nil \q_mark #1 { } - \q_mark \tl_trim_spaces_aux_ii:w - \tl_trim_spaces_aux_iii:w + \q_mark \@@_trim_spaces_ii:w + \@@_trim_spaces_iii:w #1 \q_nil - \tl_trim_spaces_aux_iv:w - \q_stop + \@@_trim_spaces_iv:w + \q_stop } - \cs_new:Npn \tl_trim_spaces_aux_i:w ##1 \q_mark #1 ##2 \q_mark ##3 + \cs_new:Npn \@@_trim_spaces_i:w ##1 \q_mark #1 ##2 \q_mark ##3 { ##3 - \tl_trim_spaces_aux_i:w + \@@_trim_spaces_i:w \q_mark ##2 \q_mark #1 {##1} } - \cs_new:Npn \tl_trim_spaces_aux_ii:w ##1 \q_mark \q_mark ##2 + \cs_new:Npn \@@_trim_spaces_ii:w + \@@_trim_spaces_i:w \q_mark \q_mark ##1 { - \tl_trim_spaces_aux_iii:w - ##2 + \@@_trim_spaces_iii:w + ##1 } - \cs_new:Npn \tl_trim_spaces_aux_iii:w ##1 #1 \q_nil ##2 + \cs_new:Npn \@@_trim_spaces_iii:w ##1 #1 \q_nil ##2 { ##2 ##1 \q_nil - \tl_trim_spaces_aux_iii:w + \@@_trim_spaces_iii:w } - \cs_new:Npn \tl_trim_spaces_aux_iv:w ##1 \q_nil ##2 \q_stop - { \exp_after:wN { \use_none:n ##1 } } + \cs_new:Npn \@@_trim_spaces_iv:w ##1 \q_nil ##2 \q_stop ##3 + { ##3 { \use_none:n ##1 } } } -\tl_tmp:w { ~ } -\cs_new_protected:Npn \tl_trim_spaces:N #1 - { \tl_set:Nx #1 { \exp_after:wN \tl_trim_spaces:n \exp_after:wN {#1} } } -\cs_new_protected:Npn \tl_gtrim_spaces:N #1 - { \tl_gset:Nx #1 { \exp_after:wN \tl_trim_spaces:n \exp_after:wN {#1} } } -\cs_generate_variant:Nn \tl_trim_spaces:N { c } -\cs_generate_variant:Nn \tl_gtrim_spaces:N { c } +\@@_tmp:w { ~ } % \end{macrocode} % \end{macro} % \end{macro} +% +% \subsection{Token by token changes} +% +% \begin{variable}{\q__@@_act_mark,\q__@@_act_stop} +% The \cs{tl_act} functions may be applied to any token list. +% Hence, we use two private quarks, to allow any token, even quarks, +% in the token list.^^A in particular critical for future \::e. +% Only \cs{q__@@_act_mark} and \cs{q__@@_act_stop} may not appear +% in the token lists manipulated by \cs{@@_act:NNNnn} functions. The quarks +% are effectively defined in \pkg{l3quark}. +% \end{variable} +% +% \begin{macro}[EXP,int]{\@@_act:NNNnn} +% \begin{macro}[EXP,aux]{\@@_act_output:n, \@@_act_reverse_output:n} +% \begin{macro}[EXP,aux]{\@@_act_loop:w} +% \begin{macro}[EXP,aux]{\@@_act_normal:NwnNNN} +% \begin{macro}[EXP,aux]{\@@_act_group:nwnNNN} +% \begin{macro}[EXP,aux]{\@@_act_space:wwnNNN} +% \begin{macro}[EXP,aux]{\@@_act_end:w} +% To help control the expansion, \cs{@@_act:NNNnn} should always +% be proceeded by \tn{romannumeral} and ends by producing \cs{c_zero} +% once the result has been obtained. Then loop over tokens, +% groups, and spaces in |#5|. The marker \cs{q__@@_act_mark} +% is used both to avoid losing outer braces and to detect the +% end of the token list more easily. The result is stored +% as an argument for the dummy function \cs{@@_act_result:n}. +% \begin{macrocode} +\cs_new:Npn \@@_act:NNNnn #1#2#3#4#5 + { + \group_align_safe_begin: + \@@_act_loop:w #5 \q__@@_act_mark \q__@@_act_stop + {#4} #1 #2 #3 + \@@_act_result:n { } + } +% \end{macrocode} +% In the loop, we check how the token list begins and act +% accordingly. In the \enquote{normal} case, we may have +% reached \cs{q__@@_act_mark}, the end of the list. Then +% leave \cs{c_zero} and the result in the input stream, +% to terminate the expansion of \tn{romannumeral}. +% Otherwise, apply the relevant function to the +% \enquote{arguments}, |#3| +% and to the head of the token list. Then repeat the loop. +% The scheme is the same if the token list starts with a +% group or with a space. Some extra work is needed to +% make \cs{@@_act_space:wwnNNN} gobble the space. +% \begin{macrocode} +\cs_new:Npn \@@_act_loop:w #1 \q__@@_act_stop + { + \tl_if_head_is_N_type:nTF {#1} + { \@@_act_normal:NwnNNN } + { + \tl_if_head_is_group:nTF {#1} + { \@@_act_group:nwnNNN } + { \@@_act_space:wwnNNN } + } + #1 \q__@@_act_stop + } +\cs_new:Npn \@@_act_normal:NwnNNN #1 #2 \q__@@_act_stop #3#4 + { + \if_meaning:w \q__@@_act_mark #1 + \exp_after:wN \@@_act_end:wn + \fi: + #4 {#3} #1 + \@@_act_loop:w #2 \q__@@_act_stop + {#3} #4 + } +\cs_new:Npn \@@_act_end:wn #1 \@@_act_result:n #2 + { \group_align_safe_end: \c_zero #2 } +\cs_new:Npn \@@_act_group:nwnNNN #1 #2 \q__@@_act_stop #3#4#5 + { + #5 {#3} {#1} + \@@_act_loop:w #2 \q__@@_act_stop + {#3} #4 #5 + } +\exp_last_unbraced:NNo + \cs_new:Npn \@@_act_space:wwnNNN \c_space_tl #1 \q__@@_act_stop #2#3#4#5 + { + #5 {#2} + \@@_act_loop:w #1 \q__@@_act_stop + {#2} #3 #4 #5 + } +% \end{macrocode} +% Typically, the output is done to the right of what was already output, +% using \cs{@@_act_output:n}, but for the \cs{@@_act_reverse} functions, +% it should be done to the left. +% \begin{macrocode} +\cs_new:Npn \@@_act_output:n #1 #2 \@@_act_result:n #3 + { #2 \@@_act_result:n { #3 #1 } } +\cs_new:Npn \@@_act_reverse_output:n #1 #2 \@@_act_result:n #3 + { #2 \@@_act_result:n { #1 #3 } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\tl_reverse:n, \tl_reverse:o, \tl_reverse:V} +% \begin{macro}[EXP,aux]{\@@_reverse_normal:nN} +% \begin{macro}[EXP,aux]{\@@_reverse_group_preserve:nn} +% \begin{macro}[EXP,aux]{\@@_reverse_space:n} +% The goal here is to reverse without losing spaces nor braces. +% This is done using the general internal function \cs{@@_act:NNNnn}. +% Spaces and \enquote{normal} tokens are output on the left of the current +% output. Grouped tokens are output to the left but without any reversal +% within the group. All of the internal functions here drop one argument: +% this is needed by \cs{@@_act:NNNnn} when changing case (to record +% which direction the change is in), but not when reversing the tokens. +% \begin{macrocode} +\cs_new:Npn \tl_reverse:n #1 + { + \etex_unexpanded:D \exp_after:wN + { + \tex_romannumeral:D + \@@_act:NNNnn + \@@_reverse_normal:nN + \@@_reverse_group_preserve:nn + \@@_reverse_space:n + { } + {#1} + } + } +\cs_generate_variant:Nn \tl_reverse:n { o , V } +\cs_new:Npn \@@_reverse_normal:nN #1#2 + { \@@_act_reverse_output:n {#2} } +\cs_new:Npn \@@_reverse_group_preserve:nn #1#2 + { \@@_act_reverse_output:n { {#2} } } +\cs_new:Npn \@@_reverse_space:n #1 + { \@@_act_reverse_output:n { ~ } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_reverse:N, \tl_reverse:c, \tl_greverse:N, \tl_greverse:c} +% This reverses the list, leaving \cs{exp_stop_f:} in front, +% which stops the \texttt{f}-expansion. +% \begin{macrocode} +\cs_new_protected:Npn \tl_reverse:N #1 + { \tl_set:Nx #1 { \exp_args:No \tl_reverse:n { #1 } } } +\cs_new_protected:Npn \tl_greverse:N #1 + { \tl_gset:Nx #1 { \exp_args:No \tl_reverse:n { #1 } } } +\cs_generate_variant:Nn \tl_reverse:N { c } +\cs_generate_variant:Nn \tl_greverse:N { c } +% \end{macrocode} % \end{macro} % % \subsection{The first token from a token list} @@ -1959,6 +2204,7 @@ % \begin{macro}{\tl_head:w} % \begin{macro}{\tl_tail:N, \tl_tail:n, \tl_tail:V, \tl_tail:v, \tl_tail:f} % \begin{macro}{\tl_tail:w} +% \begin{macro}[aux]{\@@_tail:w} % These functions pick up either the head or the tail of a list. The % empty brace groups in \cs{tl_head:n} and \cs{tl_tail:n} ensure that % a blank argument gives an empty result. The result is returned within @@ -1969,8 +2215,8 @@ \cs_new:Npn \tl_head:n #1 { \etex_unexpanded:D \exp_after:wN { \tl_head:w #1 { } \q_stop } } \cs_new:Npn \tl_tail:n #1 - { \etex_unexpanded:D \tl_tail_aux:w #1 \q_mark { } \q_mark \q_stop } -\cs_new:Npn \tl_tail_aux:w #1 #2 \q_mark #3 \q_stop { {#2} } + { \etex_unexpanded:D \@@_tail:w #1 \q_mark { } \q_mark \q_stop } +\cs_new:Npn \@@_tail:w #1 #2 \q_mark #3 \q_stop { {#2} } \cs_new_nopar:Npn \tl_head:N { \exp_args:No \tl_head:n } \cs_generate_variant:Nn \tl_head:n { V , v , f } \cs_new_nopar:Npn \tl_tail:N { \exp_args:No \tl_tail:n } @@ -1980,46 +2226,47 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\str_head:n, \str_tail:n} -% \begin{macro}[aux]{\str_head_aux:w} -% \begin{macro}[aux]{\str_tail_aux:w} +% \begin{macro}[aux]{\__str_head:w} +% \begin{macro}[aux]{\__str_tail:w} % After \cs{tl_to_str:n}, we have a list of character tokens, % all with category code 12, except the space, which has category % code 10. Directly using \cs{tl_head:w} would thus lose leading spaces. % Instead, we take an argument delimited by an explicit space, and % then only use \cs{tl_head:w}. If the string started with a -% space, then the argument of \cs{str_head_aux:w} is empty, and +% space, then the argument of \cs{__str_head:w} is empty, and % the function correctly returns a space character. Otherwise, % it returns the first token of |#1|, which is the first token % of the string. If the string is empty, we return an empty result. % % To remove the first character of \cs{tl_to_str:n} |{#1}|, % we test it using \cs{if_charcode:w} \cs{scan_stop:}, -% always false for characters. If the argument was non-empty, -% then \cs{str_tail_aux:w} returns everything until the first +% always \texttt{false} for characters. If the argument was non-empty, +% then \cs{__str_tail:w} returns everything until the first % \texttt{X} (with category code letter, no risk of confusing % with the user input). If the argument was empty, the first % \texttt{X} is taken by \cs{if_charcode:w}, and nothing % is returned. We use \texttt{X} as a \meta{marker}, rather than % a quark because the test \cs{if_charcode:w} \cs{scan_stop:} -% \meta{marker} has to be false. +% \meta{marker} has to be \texttt{false}. % \begin{macrocode} \cs_new:Npn \str_head:n #1 { - \exp_after:wN \str_head_aux:w + \exp_after:wN \__str_head:w \tl_to_str:n {#1} { { } } ~ \q_stop } -\cs_new:Npn \str_head_aux:w #1 ~ % +\cs_new:Npn \__str_head:w #1 ~ % { \tl_head:w #1 { ~ } } \cs_new:Npn \str_tail:n #1 { - \exp_after:wN \str_tail_aux:w + \exp_after:wN \__str_tail:w \reverse_if:N \if_charcode:w \scan_stop: \tl_to_str:n {#1} X X \q_stop } -\cs_new:Npn \str_tail_aux:w #1 X #2 \q_stop { \fi: #1 } +\cs_new:Npn \__str_tail:w #1 X #2 \q_stop { \fi: #1 } % \end{macrocode} % \end{macro} % \end{macro} @@ -2029,32 +2276,39 @@ % \begin{macro}[pTF]{\tl_if_head_eq_charcode:nN} % \begin{macro}[pTF]{\tl_if_head_eq_charcode:fN} % \begin{macro}[pTF]{\tl_if_head_eq_catcode:nN} -% Accessing the first token of a token list is tricky in two cases: -% when it has category code $1$ (begin-group token), or when it is -% an explicit space, with category code $10$ and character code $32$. -% -% Forgetting temporarily about this issue we would use the -% following test in \cs{tl_if_head_eq_charcode:nN}. Here, -% an empty |#1| argument yields \cs{q_nil}, otherwise the -% first token of the token list. +% Accessing the first token of a token list is tricky in three cases: +% when it has category code $1$ (begin-group token), when it is an +% explicit space, with category code $10$ and character code $32$, or +% when the token list is empty (obviously). +% +% Forgetting temporarily about this issue we would use the following +% test in \cs{tl_if_head_eq_charcode:nN}. Here, \cs{tl_head:w} yields +% the first token of the token list, then passed to \cs{exp_not:N}. % \begin{verbatim} % \if_charcode:w % \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop % \exp_not:N #2 % \end{verbatim} -% The special cases are detected using \cs{tl_if_head_N_type:n} -% (the extra |?| takes care of empty arguments). -% In those cases, the first token is a character, and -% since we only care about its character code, we can -% use \cs{str_head:n} to access it (this works even if -% it is a space character). +% The two first special cases are detected by testing if the token +% list starts with an \texttt{N}-type token (the extra |?| sends empty +% token lists to the \texttt{true} branch of this test). In those +% cases, the first token is a character, and since we only care about +% its character code, we can use \cs{str_head:n} to access it (this +% works even if it is a space character). An empty argument will +% result in \cs{tl_head:w} leaving two tokens: |?| which is taken in +% the \cs{if_charcode:w} test, and \cs{use_none:nn}, which ensures +% that \cs{prg_return_false:} is returned regardless of whether the +% charcode test was \texttt{true} or \texttt{false}. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_head_eq_charcode:nN #1#2 { p , T , F , TF } { \if_charcode:w \exp_not:N #2 - \tl_if_head_N_type:nTF { #1 ? } - { \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop } + \tl_if_head_is_N_type:nTF { #1 ? } + { + \exp_after:wN \exp_not:N + \tl_head:w #1 { ? \use_none:nn } \q_stop + } { \str_head:n {#1} } \prg_return_true: \else: @@ -2066,20 +2320,26 @@ \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNT { f } \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNF { f } % \end{macrocode} -% For \cs{tl_if_head_eq_catcode:nN}, again we detect special -% cases with a \cs{tl_if_head_N_type}. Then we need to test -% if the first token is a begin-group token or an explicit -% space token, and produce the relevant token, either -% \cs{c_group_begin_token} or \cs{c_space_token}. +% For \cs{tl_if_head_eq_catcode:nN}, again we detect special cases +% with a \cs{tl_if_head_is_N_type:n}. Then we need to test if the +% first token is a begin-group token or an explicit space token, and +% produce the relevant token, either \cs{c_group_begin_token} or +% \cs{c_space_token}. Again, for an empty argument, a hack is used, +% removing \cs{prg_return_true:} and \cs{else:} with \cs{use_none:nn} +% in case the catcode test with the (arbitrarily chosen) |?| is +% \texttt{true}. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_head_eq_catcode:nN #1 #2 { p , T , F , TF } { \if_catcode:w \exp_not:N #2 - \tl_if_head_N_type:nTF { #1 ? } - { \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop } + \tl_if_head_is_N_type:nTF { #1 ? } { - \tl_if_head_group:nTF {#1} + \exp_after:wN \exp_not:N + \tl_head:w #1 { ? \use_none:nn } \q_stop + } + { + \tl_if_head_is_group:nTF {#1} { \c_group_begin_token } { \c_space_token } } @@ -2089,29 +2349,34 @@ \fi: } % \end{macrocode} -% For \cs{tl_if_head_eq_meaning:nN}, again, detect special cases. -% In the normal case, use \cs{tl_head:w}, with no \cs{exp_not:N} -% this time, since \cs{if_meaning:w} causes no expansion. +% For \cs{tl_if_head_eq_meaning:nN}, again, detect special cases. In +% the normal case, use \cs{tl_head:w}, with no \cs{exp_not:N} this +% time, since \cs{if_meaning:w} causes no expansion. With an empty +% argument, the test is \texttt{true}, and \cs{use_none:nnn} removes +% |#2| and the usual \cs{prg_return_true:} and \cs{else:}. % In the special cases, we know that the first token is a character, % hence \cs{if_charcode:w} and \cs{if_catcode:w} together are enough. % We combine them in some order, hopefully faster than the reverse. +% Tests are not nested because the arguments may contain unmatched +% primitive conditionals. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_head_eq_meaning:nN #1#2 { p , T , F , TF } { - \tl_if_head_N_type:nTF { #1 ? } - { \tl_if_head_eq_meaning_aux_normal:nN } - { \tl_if_head_eq_meaning_aux_special:nN } + \tl_if_head_is_N_type:nTF { #1 ? } + { \@@_if_head_eq_meaning_normal:nN } + { \@@_if_head_eq_meaning_special:nN } {#1} #2 } -\cs_new:Npn \tl_if_head_eq_meaning_aux_normal:nN #1 #2 +\cs_new:Npn \@@_if_head_eq_meaning_normal:nN #1 #2 { - \exp_after:wN \if_meaning:w \tl_head:w #1 \q_nil \q_stop #2 + \exp_after:wN \if_meaning:w + \tl_head:w #1 { ?? \use_none:nnn } \q_stop #2 \prg_return_true: \else: \prg_return_false: \fi: } -\cs_new:Npn \tl_if_head_eq_meaning_aux_special:nN #1 #2 +\cs_new:Npn \@@_if_head_eq_meaning_special:nN #1 #2 { \if_charcode:w \str_head:n {#1} \exp_not:N #2 \exp_after:wN \use:n @@ -2121,7 +2386,7 @@ \fi: { \if_catcode:w \exp_not:N #2 - \tl_if_head_group:nTF {#1} + \tl_if_head_is_group:nTF {#1} { \c_group_begin_token } { \c_space_token } \prg_return_true: @@ -2136,7 +2401,7 @@ % \end{macro} % \end{macro} % -% \begin{macro}[pTF]{\tl_if_head_N_type:n} +% \begin{macro}[pTF]{\tl_if_head_is_N_type:n} % The first token of a token list can be either an N-type argument, % a begin-group token (catcode 1), or an explicit space token % (catcode 10 and charcode 32). These two cases are characterized @@ -2145,16 +2410,16 @@ % string representation). The extra brace group covers the case of % an empty argument, whose head is not \enquote{normal}. % \begin{macrocode} -\prg_new_conditional:Npnn \tl_if_head_N_type:n #1 { p , T , F , TF } +\prg_new_conditional:Npnn \tl_if_head_is_N_type:n #1 { p , T , F , TF } { - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { \exp_not:o { \use:n #1 { } } } { \exp_not:n { #1 { } } } } % \end{macrocode} % \end{macro} % -% \begin{macro}[EXP,pTF]{\tl_if_head_group:n} +% \begin{macro}[EXP,pTF]{\tl_if_head_is_group:n} % Pass the first token of |#1| through \cs{token_to_str:N}, % then check for the brace balance. The extra \texttt{?} % caters for an empty argument.\footnote{Bruno: this could @@ -2163,7 +2428,7 @@ % to happen in one step of expansion, keeping the token % list brace balanced at all times.} % \begin{macrocode} -\prg_new_conditional:Npnn \tl_if_head_group:n #1 { p , T , F , TF } +\prg_new_conditional:Npnn \tl_if_head_is_group:n #1 { p , T , F , TF } { \if_catcode:w * \exp_after:wN \use_none:n @@ -2181,22 +2446,22 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[EXP,pTF]{\tl_if_head_space:n} -% \begin{macro}[EXP,aux]{\tl_if_head_space_aux:w} +% \begin{macro}[EXP,pTF]{\tl_if_head_is_space:n} +% \begin{macro}[EXP,aux]{\@@_if_head_is_space:w} % If the first token of the token list is an explicit space, i.e., % a character token with character code $32$ and category code $10$, -% then this test will be \meta{true}. It is \meta{false} if the token +% then this test will be \texttt{true}. It is \texttt{false} if the token % list is empty, if the first token is an implicit space token, % such as \cs{c_space_token}, or any token other than an explicit space. % The slightly convoluted approach with \tn{romannumeral} ensures that % each expansion step gives a balanced token list. % \begin{macrocode} -\prg_new_conditional:Npnn \tl_if_head_space:n #1 { p , T , F , TF } +\prg_new_conditional:Npnn \tl_if_head_is_space:n #1 { p , T , F , TF } { \tex_romannumeral:D \if_false: { \fi: - \tl_if_head_space_aux:w ? #1 ? ~ } + \@@_if_head_is_space:w ? #1 ? ~ } } -\cs_new:Npn \tl_if_head_space_aux:w #1 ~ +\cs_new:Npn \@@_if_head_is_space:w #1 ~ { \tl_if_empty:oTF { \use_none:n #1 } { \exp_after:wN \c_zero \exp_after:wN \prg_return_true: } @@ -2225,37 +2490,6 @@ % \end{macrocode} %\end{macro} % -% \subsection{Constant token lists} -% -% \begin{variable}{\c_job_name_tl} -% Inherited from the \LaTeX3 name for the primitive: this needs to -% actually contain the text of the job name rather than the name of -% the primitive, of course. \LuaTeX{} does not quote file names containing -% spaces, whereas \pdfTeX{} and \XeTeX{} do. So there may be a correction to -% make in the \LuaTeX{} case. -% \begin{macrocode} -%<*initex> -\tex_everyjob:D \exp_after:wN - { - \tex_the:D \tex_everyjob:D - \luatex_if_engine:T - { - \lua_now:x - { dofile ( assert ( kpse.find_file ("lualatexquotejobname.lua" ) ) ) } - } - } -%</initex> -\tl_const:Nx \c_job_name_tl { \tex_jobname:D } -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_space_tl} -% A space as a token list (as opposed to as a character). -% \begin{macrocode} -\tl_const:Nn \c_space_tl { ~ } -% \end{macrocode} -% \end{variable} -% % \subsection{Scratch token lists} % % \begin{variable}{\g_tmpa_tl, \g_tmpb_tl} @@ -2279,398 +2513,6 @@ % \end{macrocode} % \end{variable} % -% \subsection{Experimental functions} -% -% \begin{macro}[EXP]{\str_if_eq_return:xx} -% It turns out that we often need to compare a token list -% with the result of applying some function to it, and -% return with \cs{prg_return_true/false:}. This test is -% similar to \cs{str_if_eq:nnTF}, but hard-coded for speed. -% \begin{macrocode} -\cs_new:Npn \str_if_eq_return:xx #1 #2 - { - \if_int_compare:w \pdftex_strcmp:D {#1} {#2} = \c_zero - \prg_return_true: - \else: - \prg_return_false: - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP,pTF]{\tl_if_single:N} -% Expand the token list and feed it to \cs{tl_if_single:n}. -% \begin{macrocode} -\cs_new:Npn \tl_if_single_p:N { \exp_args:No \tl_if_single_p:n } -\cs_new:Npn \tl_if_single:NT { \exp_args:No \tl_if_single:nT } -\cs_new:Npn \tl_if_single:NF { \exp_args:No \tl_if_single:nF } -\cs_new:Npn \tl_if_single:NTF { \exp_args:No \tl_if_single:nTF } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP,pTF]{\tl_if_single:n} -% A token list has exactly one item if it is either a single -% token surrounded by optional explicit spaces, or a single brace -% group surrounded by optional explicit spaces. The naive -% version of this test would do \cs{use_none:n} |#1|, and -% test if the result is empty. However, this will fail when -% the token list is empty. Furthermore, it does not allow optional -% trailing spaces. -% \begin{macrocode} -\prg_new_conditional:Npnn \tl_if_single:n #1 { p , T , F , TF } - { \str_if_eq_return:xx { \exp_not:o { \use_none:nn #1 ?? } } {?} } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP,pTF]{\tl_if_single_token:n} -% There are four cases: empty token list, token list starting with -% a normal token, with a brace group, or with a space token. -% If the token list starts with a normal token, remove it -% and check for emptyness. Otherwise, compare with a single -% space, only case where we have a single token. -% \begin{macrocode} -\prg_new_conditional:Npnn \tl_if_single_token:n #1 { p , T , F , TF } - { - \tl_if_head_N_type:nTF {#1} - { \str_if_eq_return:xx { \exp_not:o { \use_none:n #1 } } { } } - { \str_if_eq_return:xx { \exp_not:n {#1} } { ~ } } - } -% \end{macrocode} -% \end{macro} -% -% \begin{variable}{\q_tl_act_mark,\q_tl_act_stop} -% The \cs{tl_act} functions may be applied to any token list. -% Hence, we use two private quarks, to allow any token, even quarks, -% in the token list.^^A in particular critical for future \::e. -% Only \cs{q_tl_act_mark} and \cs{q_tl_act_stop} may not appear -% in the token lists manipulated by \cs{tl_act} functions. The quarks -% are effectively defined in \pkg{l3quark}. -% \end{variable} -% -% \begin{macro}[EXP]{\tl_act:NNNnn,\tl_act_aux:NNNnn} -% \begin{macro}[EXP]{\tl_act_output:n,\tl_act_reverse_output:n, -% \tl_act_group_recurse:Nnn} -% \begin{macro}[EXP,aux]{\tl_act_loop:w,\tl_act_normal:NwnNNN, -% \tl_act_group:nwnNNN,\tl_act_space:wwnNNN,\tl_act_end:w} -% To help control the expansion, \cs{tl_act:NNNnn} starts with -% \tn{romannumeral} and ends by producing \cs{c_zero} -% once the result has been obtained. Then loop over tokens, -% groups, and spaces in |#5|. The marker \cs{q_tl_act_mark} -% is used both to avoid losing outer braces and to detect the -% end of the token list more easily. The result is stored -% as an argument for the dummy function \cs{tl_act_result:n}. -% \begin{macrocode} -\cs_new:Npn \tl_act:NNNnn { \tex_romannumeral:D \tl_act_aux:NNNnn } -\cs_new:Npn \tl_act_aux:NNNnn #1 #2 #3 #4 #5 - { - \group_align_safe_begin: - \tl_act_loop:w #5 \q_tl_act_mark \q_tl_act_stop - {#4} #1 #2 #3 - \tl_act_result:n { } - } -% \end{macrocode} -% In the loop, we check how the token list begins and act -% accordingly. In the \enquote{normal} case, we may have -% reached \cs{q_tl_act_mark}, the end of the list. Then -% leave \cs{c_zero} and the result in the input stream, -% to terminate the expansion of \tn{romannumeral}. -% Otherwise, apply the relevant function to the -% \enquote{arguments}, |#3| -% and to the head of the token list. Then repeat the loop. -% The scheme is the same if the token list starts with a -% group or with a space. Some extra work is needed to -% make \cs{tl_act_space:wwnNNN} gobble the space. -% \begin{macrocode} -\cs_new:Npn \tl_act_loop:w #1 \q_tl_act_stop - { - \tl_if_head_N_type:nTF {#1} - { \tl_act_normal:NwnNNN } - { - \tl_if_head_group:nTF {#1} - { \tl_act_group:nwnNNN } - { \tl_act_space:wwnNNN } - } - #1 \q_tl_act_stop - } -\cs_new:Npn \tl_act_normal:NwnNNN #1 #2 \q_tl_act_stop #3#4 - { - \if_meaning:w \q_tl_act_mark #1 - \exp_after:wN \tl_act_end:wn - \fi: - #4 {#3} #1 - \tl_act_loop:w #2 \q_tl_act_stop - {#3} #4 - } -\cs_new:Npn \tl_act_end:wn #1 \tl_act_result:n #2 - { \group_align_safe_end: \c_zero #2 } -\cs_new:Npn \tl_act_group:nwnNNN #1 #2 \q_tl_act_stop #3#4#5 - { - #5 {#3} {#1} - \tl_act_loop:w #2 \q_tl_act_stop - {#3} #4 #5 - } -\exp_last_unbraced:NNo - \cs_new:Npn \tl_act_space:wwnNNN \c_space_tl #1 \q_tl_act_stop #2#3#4#5 - { - #5 {#2} - \tl_act_loop:w #1 \q_tl_act_stop - {#2} #3 #4 #5 - } -% \end{macrocode} -% Typically, the output is done to the right of what was already output, -% using \cs{tl_act_output:n}, but for the \cs{tl_act_reverse} functions, -% it should be done to the left. -% \begin{macrocode} -\cs_new:Npn \tl_act_output:n #1 #2 \tl_act_result:n #3 - { #2 \tl_act_result:n { #3 #1 } } -\cs_new:Npn \tl_act_reverse_output:n #1 #2 \tl_act_result:n #3 - { #2 \tl_act_result:n { #1 #3 } } -% \end{macrocode} -% In many applications of \cs{tl_act:NNNnn}, we need to recursively -% apply some transformation within brace groups, then output. In this -% code, |#1| is the output function, |#2| is the transformation, -% which should expand in two steps, and |#3| is the group. -% \begin{macrocode} -\cs_new:Npn \tl_act_group_recurse:Nnn #1#2#3 - { - \exp_args:Nf #1 - { \exp_after:wN \exp_after:wN \exp_after:wN { #2 {#3} } } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP]{\tl_reverse_tokens:n} -% \begin{macro}[EXP,aux]{\tl_act_reverse_normal:nN, -% \tl_act_reverse_group:nn, \tl_act_reverse_space:n} -% The goal is to reverse a token list. This is done by feeding -% \cs{tl_act_aux:NNNnn} three functions, an empty fourth argument -% (we don't use it for \cs{tl_act_reverse_tokens:n}), and as -% a fifth argument the token list to be reversed. -% Spaces and normal tokens are output to the left of the current -% output. For groups, we must recursively apply -% \cs{tl_act_reverse_tokens:n} to the group, and output, still -% on the left. Note that in all three cases, we throw one argument -% away: this \meta{parameter} is where for instance the -% upper/lowercasing action stores the information of whether it -% is uppercasing or lowercasing. -% \begin{macrocode} -\cs_new:Npn \tl_reverse_tokens:n #1 - { - \etex_unexpanded:D \exp_after:wN - { - \tex_romannumeral:D - \tl_act_aux:NNNnn - \tl_act_reverse_normal:nN - \tl_act_reverse_group:nn - \tl_act_reverse_space:n - { } - {#1} - } - } -\cs_new:Npn \tl_act_reverse_space:n #1 - { \tl_act_reverse_output:n {~} } -\cs_new:Npn \tl_act_reverse_normal:nN #1 #2 - { \tl_act_reverse_output:n {#2} } -\cs_new:Npn \tl_act_reverse_group:nn #1 - { - \tl_act_group_recurse:Nnn - \tl_act_reverse_output:n - { \tl_reverse_tokens:n } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP]{\tl_reverse:n,\tl_reverse:o,\tl_reverse:V} -% \begin{macro}[EXP,aux]{\tl_reverse_group_preserve:nn} -% The goal here is to reverse without losing spaces nor braces. -% The only difference with \cs{tl_reverse_tokens:n} is that -% we now simply output groups without entering them. -% \begin{macrocode} -\cs_new:Npn \tl_reverse:n #1 - { - \etex_unexpanded:D \exp_after:wN - { - \tex_romannumeral:D - \tl_act_aux:NNNnn - \tl_act_reverse_normal:nN - \tl_act_reverse_group_preserve:nn - \tl_act_reverse_space:n - { } - {#1} - } - } -\cs_new:Npn \tl_act_reverse_group_preserve:nn #1 #2 - { \tl_act_reverse_output:n { {#2} } } -\cs_generate_variant:Nn \tl_reverse:n { o , V } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\tl_reverse:N, \tl_reverse:c, \tl_greverse:N, \tl_greverse:c} -% This reverses the list, leaving \cs{exp_stop_f:} in front, -% which stops the \texttt{f}-expansion. -% \begin{macrocode} -\cs_new_protected:Npn \tl_reverse:N #1 - { \tl_set:Nx #1 { \exp_args:No \tl_reverse:n { #1 } } } -\cs_new_protected:Npn \tl_greverse:N #1 - { \tl_gset:Nx #1 { \exp_args:No \tl_reverse:n { #1 } } } -\cs_generate_variant:Nn \tl_reverse:N { c } -\cs_generate_variant:Nn \tl_greverse:N { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\tl_length_tokens:n} -% \begin{macro}[EXP,aux]{\tl_act_length_normal:nN, -% \tl_act_length_group:nn,\tl_act_length_space:n} -% The length is computed through an \cs{int_eval:n} construction. -% Each \texttt{1+} is output to the \emph{left}, into the integer -% expression, and the sum is ended by the \cs{c_zero} inserted by -% \cs{tl_act_end:wn}. Somewhat a hack. -% \begin{macrocode} -\cs_new:Npn \tl_length_tokens:n #1 - { - \int_eval:n - { - \tl_act_aux:NNNnn - \tl_act_length_normal:nN - \tl_act_length_group:nn - \tl_act_length_space:n - { } - {#1} - } - } -\cs_new:Npn \tl_act_length_normal:nN #1 #2 { 1 + } -\cs_new:Npn \tl_act_length_space:n #1 { 1 + } -\cs_new:Npn \tl_act_length_group:nn #1 #2 - { 2 + \tl_length_tokens:n {#2} + } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{variable}{\c_tl_act_uppercase_tl, \c_tl_act_lowercase_tl} -% These constants contain the correspondance between lowercase -% and uppercase letters, in the form |aAbBcC...| and |AaBbCc...| -% respectively. -% \begin{macrocode} -\tl_const:Nn \c_tl_act_uppercase_tl - { - aA bB cC dD eE fF gG hH iI jJ kK lL mM - nN oO pP qQ rR sS tT uU vV wW xX yY zZ - } -\tl_const:Nn \c_tl_act_lowercase_tl - { - Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm - Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz - } -% \end{macrocode} -% \end{variable} -% -% \begin{macro}[EXP]{\tl_expandable_uppercase:n,\tl_expandable_lowercase:n} -% \begin{macro}[EXP,aux]{\tl_act_case_normal:nN, -% \tl_act_case_group:nn,\tl_act_case_space:n} -% The only difference between uppercasing and lowercasing is -% the table of correspondance that is used. As for other -% token list actions, we feed \cs{tl_act_aux:NNNnn} three -% functions, and this time, we use the \meta{parameters} -% argument to carry which case-changing we are applying. -% A space is simply output. A normal token is compared -% to each letter in the alphabet using \cs{str_if_eq:nn} -% tests, and converted if necessary to upper/lowercase, -% before being output. For a group, we must perform the -% conversion within the group (the \cs{exp_after:wN} trigger -% \tn{romannumeral}, which expands fully to give the -% converted group), then output. -% \begin{macrocode} -\cs_new:Npn \tl_expandable_uppercase:n #1 - { - \etex_unexpanded:D \exp_after:wN - { - \tex_romannumeral:D - \tl_act_case_aux:nn { \c_tl_act_uppercase_tl } {#1} - } - } -\cs_new:Npn \tl_expandable_lowercase:n #1 - { - \etex_unexpanded:D \exp_after:wN - { - \tex_romannumeral:D - \tl_act_case_aux:nn { \c_tl_act_lowercase_tl } {#1} - } - } -\cs_new:Npn \tl_act_case_aux:nn - { - \tl_act_aux:NNNnn - \tl_act_case_normal:nN - \tl_act_case_group:nn - \tl_act_case_space:n - } -\cs_new:Npn \tl_act_case_space:n #1 { \tl_act_output:n {~} } -\cs_new:Npn \tl_act_case_normal:nN #1 #2 - { - \exp_args:Nf \tl_act_output:n - { - \exp_args:NNo \prg_case_str:nnn #2 {#1} - { \exp_stop_f: #2 } - } - } -\cs_new:Npn \tl_act_case_group:nn #1 #2 - { - \exp_after:wN \tl_act_output:n \exp_after:wN - { \exp_after:wN { \tex_romannumeral:D \tl_act_case_aux:nn {#1} {#2} } } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\tl_item:nn, \tl_item:Nn, \tl_item:cn} -% \begin{macro}[aux]{\tl_item_aux:nn} -% The idea here is to find the offset of the item from the left, then use -% a loop to grab the correct item. If the resulting offset is too large, -% then \cs{quark_if_recursion_tail_stop:n} terminates the loop, and returns -% nothing at all. -% \begin{macrocode} -\cs_new:Npn \tl_item:nn #1#2 - { - \exp_args:Nf \tl_item_aux:nn - { - \int_eval:n - { - \int_compare:nNnT {#2} < \c_zero - { \tl_length:n {#1} + } - #2 - } - } - #1 - \q_recursion_tail - \prg_break_point:n { } - } -\cs_new:Npn \tl_item_aux:nn #1#2 - { - \quark_if_recursion_tail_break:n {#2} - \int_compare:nNnTF {#1} = \c_zero - { \tl_map_break:n { \exp_not:n {#2} } } - { \exp_args:Nf \tl_item_aux:nn { \int_eval:n { #1 - 1 } } } - } -\cs_new_nopar:Npn \tl_item:Nn { \exp_args:No \tl_item:nn } -\cs_generate_variant:Nn \tl_item:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[pTF]{\tl_if_empty:x} -% We can test expandably the emptyness of an expanded token list -% thanks to the primitive \tn{pdfstrcmp} which expands its argument: -% a token list is empty if and only if its string representation is -% empty. -% \begin{macrocode} -\prg_new_conditional:Npnn \tl_if_empty:x #1 { p , T , F , TF } - { \str_if_eq_return:xx { } {#1} } -% \end{macrocode} -% \end{macro} -% % \subsection{Deprecated functions} % % \begin{macro}{\tl_new:Nn, \tl_new:cn, \tl_new:Nx} @@ -2751,11 +2593,11 @@ % Another renaming job. % \begin{macrocode} %<*deprecated> -\cs_new_eq:NN \tl_elt_count:n \tl_length:n -\cs_new_eq:NN \tl_elt_count:V \tl_length:V -\cs_new_eq:NN \tl_elt_count:o \tl_length:o -\cs_new_eq:NN \tl_elt_count:N \tl_length:N -\cs_new_eq:NN \tl_elt_count:c \tl_length:c +\cs_new_eq:NN \tl_elt_count:n \tl_count:n +\cs_new_eq:NN \tl_elt_count:V \tl_count:V +\cs_new_eq:NN \tl_elt_count:o \tl_count:o +\cs_new_eq:NN \tl_elt_count:N \tl_count:N +\cs_new_eq:NN \tl_elt_count:c \tl_count:c %</deprecated> % \end{macrocode} % \end{macro} @@ -2782,6 +2624,58 @@ % \end{macro} % \end{macro} % +% Deprecated on 2012-05-13 for removal by 2012-08-31. +% +% \begin{macro}{\tl_length_tokens:n} +% \begin{macrocode} +\cs_new_eq:NN \tl_length_tokens:n \tl_count_tokens:n +% \end{macrocode} +% \end{macro} +% +% Deprecated 2012-05-13 for removal by 2012-11-31. +% +% \begin{macro} +% {\tl_length:N, \tl_length:c, \tl_length:n, \tl_length:V, \tl_length:o} +% Renames. +% \begin{macrocode} +\cs_new_eq:NN \tl_length:N \tl_count:N +\cs_new_eq:NN \tl_length:c \tl_count:c +\cs_new_eq:NN \tl_length:n \tl_count:n +\cs_new_eq:NN \tl_length:V \tl_count:V +\cs_new_eq:NN \tl_length:o \tl_count:o +% \end{macrocode} +% \end{macro} +% +% Deprecated 2012-06-05 for removal after 2012-12-31. +% +% \begin{macro}[pTF]{\tl_if_empty:x} +% We can test expandably the emptiness of an expanded token list +% thanks to the primitive \tn{pdfstrcmp} which expands its argument: +% a token list is empty if and only if its string representation is +% empty. +% \begin{macrocode} +\prg_new_conditional:Npnn \tl_if_empty:x #1 { p , T , F , TF } + { \__str_if_eq_x_return:nn { } {#1} } +% \end{macrocode} +% \end{macro} +% +% Deprecated 2012-07-08 for removal after 2012-10-31. +% +% \begin{macro}[EXP, pTF]{\tl_if_head_group:n} +% \begin{macro}[EXP, pTF]{\tl_if_head_N_type:n} +% \begin{macro}[EXP, pTF]{\tl_if_head_space:n} +% \begin{macrocode} +\prg_new_eq_conditional:NNn \tl_if_head_group:n \tl_if_head_is_group:n + { p , T , F , TF } +\prg_new_eq_conditional:NNn \tl_if_head_N_type:n \tl_if_head_is_N_type:n + { p , T , F , TF } +\prg_new_eq_conditional:NNn \tl_if_head_space:n \tl_if_head_is_space:n + { p , T , F , TF } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx index b811e4a168a..6b1af27ca33 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx @@ -35,7 +35,7 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3token.dtx 3491 2012-03-04 06:13:18Z bruno $ +\GetIdInfo$Id: l3token.dtx 3986 2012-07-15 19:23:51Z joseph $ {L3 Experimental token manipulation} %</driver|package> %<*driver> @@ -78,8 +78,8 @@ % see if a certain character is present and maybe even remove it or % disregard other tokens while scanning. This module provides % functions for both and as such will have two primary function -% categories: |\token| for anything that deals with tokens and -% |\peek| for looking ahead in the token stream. +% categories: |\token_| for anything that deals with tokens and +% |\peek_| for looking ahead in the token stream. % % Most of the time we will be using the term \enquote{token} but most of the % time the function we're describing can equally well by used on a @@ -206,8 +206,8 @@ % \cs{char_set_lcode:nn} \Arg{intexpr_1} \Arg{intexpr_2} % \end{syntax} % This function set up the behaviour of \meta{character} when -% found inside \cs{tl_to_lowercase:n}, such that \meta{character1} -% will be converted into \meta{character2}. The two \meta{characters} +% found inside \cs{tl_to_lowercase:n}, such that \meta{character_1} +% will be converted into \meta{character_2}. The two \meta{characters} % may be specified using an \meta{integer expression} for the character code % concerned. This may include the \TeX{} |`|\meta{character} % method for converting a single character into its character @@ -243,8 +243,8 @@ % \cs{char_set_uccode:nn} \Arg{intexpr_1} \Arg{intexpr_2} % \end{syntax} % This function set up the behaviour of \meta{character} when -% found inside \cs{tl_to_uppercase:n}, such that \meta{character1} -% will be converted into \meta{character2}. The two \meta{characters} +% found inside \cs{tl_to_uppercase:n}, such that \meta{character_1} +% will be converted into \meta{character_2}. The two \meta{characters} % may be specified using an \meta{integer expression} for the character code % concerned. This may include the \TeX{} |`|\meta{character} % method for converting a single character into its character @@ -354,10 +354,10 @@ % % \begin{function}{\token_new:Nn} % \begin{syntax} -% \cs{token_new:Nn} \meta{token1} \Arg{token_2} +% \cs{token_new:Nn} \meta{token_1} \Arg{token_2} % \end{syntax} -% Defines \meta{token1} to globally be a snapshot of \meta{token2}. -% This will be an implicit representation of \meta{token2}. +% Defines \meta{token_1} to globally be a snapshot of \meta{token_2}. +% This will be an implicit representation of \meta{token_2}. % \end{function} % % ^^A Because it's late I can't figure out a better way to handle this: @@ -540,24 +540,24 @@ % % \begin{function}[EXP,pTF]{\token_if_eq_catcode:NN} % \begin{syntax} -% \cs{token_if_eq_catcode_p:NN} \meta{token1} \meta{token2} \\ -% \cs{token_if_eq_catcode:NNTF} \meta{token1} \meta{token2} \Arg{true code} \Arg{false code} +% \cs{token_if_eq_catcode_p:NN} \meta{token_1} \meta{token_2} \\ +% \cs{token_if_eq_catcode:NNTF} \meta{token_1} \meta{token_2} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the two \meta{tokens} have the same category code. % \end{function} % % \begin{function}[EXP,pTF]{\token_if_eq_charcode:NN} % \begin{syntax} -% \cs{token_if_eq_charcode_p:NN} \meta{token1} \meta{token2} \\ -% \cs{token_if_eq_charcode:NNTF} \meta{token1} \meta{token2} \Arg{true code} \Arg{false code} +% \cs{token_if_eq_charcode_p:NN} \meta{token_1} \meta{token_2} \\ +% \cs{token_if_eq_charcode:NNTF} \meta{token_1} \meta{token_2} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the two \meta{tokens} have the same character code. % \end{function} % % \begin{function}[EXP,pTF]{\token_if_eq_meaning:NN} % \begin{syntax} -% \cs{token_if_eq_meaning_p:NN} \meta{token1} \meta{token2} \\ -% \cs{token_if_eq_meaning:NNTF} \meta{token1} \meta{token2} \Arg{true code} \Arg{false code} +% \cs{token_if_eq_meaning_p:NN} \meta{token_1} \meta{token_2} \\ +% \cs{token_if_eq_meaning:NNTF} \meta{token_1} \meta{token_2} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the two \meta{tokens} have the same meaning when expanded. % \end{function} @@ -941,79 +941,6 @@ % not a macro then \cs{scan_stop:} will be left in the input stream % \end{function} % -% \section{Experimental token functions} -% -% \begin{function}[added = 2011-12-27] -% {\char_set_active:Npn, \char_set_active:Npx} -% \begin{syntax} -% \cs{char_set_active:Npn} \meta{char} \meta{parameters} \Arg{code} -% \end{syntax} -% Makes \meta{char} an active character to expand to \meta{code} as -% replacement text. -% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, -% \emph{etc.}) will be replaced by those absorbed. The \meta{char} is -% made active within the current \TeX{} group level, and the definition -% is also local. -% \end{function} -% -% \begin{function}[added = 2011-12-27] -% {\char_gset_active:Npn, \char_gset_active:Npx} -% \begin{syntax} -% \cs{char_gset_active:Npn} \meta{char} \meta{parameters} \Arg{code} -% \end{syntax} -% Makes \meta{char} an active character to expand to \meta{code} as -% replacement text. -% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, -% \emph{etc.}) will be replaced by those absorbed. The \meta{char} is -% made active within the current \TeX{} group level, but the definition -% is global. This function is therefore suited to cases where an active -% character definition should be applied only in some context (where the -% \meta{char} is again made active). -% \end{function} -% -% \begin{function}[added = 2011-12-27] -% {\char_set_active_eq:NN} -% \begin{syntax} -% \cs{char_set_active_eq:NN} \meta{char} \meta{function} -% \end{syntax} -% Makes \meta{char} an active character equivalent in meaning to the -% \meta{function} (which may itself be an active character). The \meta{char} -% is made active within the current \TeX{} group level, and the definition -% is also local. -% \end{function} -% -% \begin{function}[added = 2011-12-27] -% {\char_gset_active_eq:NN} -% \begin{syntax} -% \cs{char_gset_active_eq:NN} \meta{char} \meta{function} -% \end{syntax} -% Makes \meta{char} an active character equivalent in meaning to the -% \meta{function} (which may itself be an active character). The \meta{char} -% is made active within the current \TeX{} group level, but the definition -% is global. This function is therefore suited to cases where an active -% character definition should be applied only in some context (where the -% \meta{char} is again made active). -% \end{function} -% -% \begin{function}[added = 2011-08-14,TF]{\peek_N_type:} -% \begin{syntax} -% \cs{peek_N_type:TF} \Arg{true code} \Arg{false code} -% \end{syntax} -% Tests if the next \meta{token} in the input stream can be safely -% grabbed as an \texttt{N}-type argument. The test will be \meta{false} -% if the next \meta{token} is either an explicit or implicit -% begin-group or end-group token (with any character code), or -% an explicit or implicit space character (with character code $32$ -% and category code $10$), and \meta{true} in all other cases. -% Note that a \meta{true} result ensures that the next \meta{token} is -% a valid \texttt{N}-type argument. However, if the next \meta{token} -% is for instance \cs{c_space_token}, the test will take the -% \meta{false} branch, even though the next \meta{token} is in fact -% a valid \texttt{N}-type argument. The \meta{token} will be left -% in the input stream after the \meta{true code} or \meta{false code} -% (as appropriate to the result of the test). -% \end{function} -% % \end{documentation} % % \begin{implementation} @@ -1023,12 +950,16 @@ % \begin{macrocode} %<*initex|package> % \end{macrocode} +% +% \begin{macrocode} +%<@@=token> +% \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -1040,11 +971,11 @@ % Category code changes. % \begin{macrocode} \cs_new_protected:Npn \char_set_catcode:nn #1#2 - { \tex_catcode:D #1 = \int_eval:w #2 \int_eval_end: } + { \tex_catcode:D #1 = \__int_eval:w #2 \__int_eval_end: } \cs_new:Npn \char_value_catcode:n #1 - { \tex_the:D \tex_catcode:D \int_eval:w #1\int_eval_end: } + { \tex_the:D \tex_catcode:D \__int_eval:w #1\__int_eval_end: } \cs_new_protected:Npn \char_show_value_catcode:n #1 - { \tex_showthe:D \tex_catcode:D \int_eval:w #1 \int_eval_end: } + { \tex_showthe:D \tex_catcode:D \__int_eval:w #1 \__int_eval_end: } % \end{macrocode} % \end{macro} % \end{macro} @@ -1175,29 +1106,29 @@ % Pretty repetitive, but necessary! % \begin{macrocode} \cs_new_protected:Npn \char_set_mathcode:nn #1#2 - { \tex_mathcode:D #1 = \int_eval:w #2 \int_eval_end: } + { \tex_mathcode:D #1 = \__int_eval:w #2 \__int_eval_end: } \cs_new:Npn \char_value_mathcode:n #1 - { \tex_the:D \tex_mathcode:D \int_eval:w #1\int_eval_end: } + { \tex_the:D \tex_mathcode:D \__int_eval:w #1\__int_eval_end: } \cs_new_protected:Npn \char_show_value_mathcode:n #1 - { \tex_showthe:D \tex_mathcode:D \int_eval:w #1 \int_eval_end: } + { \tex_showthe:D \tex_mathcode:D \__int_eval:w #1 \__int_eval_end: } \cs_new_protected:Npn \char_set_lccode:nn #1#2 - { \tex_lccode:D #1 = \int_eval:w #2 \int_eval_end: } + { \tex_lccode:D #1 = \__int_eval:w #2 \__int_eval_end: } \cs_new:Npn \char_value_lccode:n #1 - { \tex_the:D \tex_lccode:D \int_eval:w #1\int_eval_end: } + { \tex_the:D \tex_lccode:D \__int_eval:w #1\__int_eval_end: } \cs_new_protected:Npn \char_show_value_lccode:n #1 - { \tex_showthe:D \tex_lccode:D \int_eval:w #1 \int_eval_end: } + { \tex_showthe:D \tex_lccode:D \__int_eval:w #1 \__int_eval_end: } \cs_new_protected:Npn \char_set_uccode:nn #1#2 - { \tex_uccode:D #1 = \int_eval:w #2 \int_eval_end: } + { \tex_uccode:D #1 = \__int_eval:w #2 \__int_eval_end: } \cs_new:Npn \char_value_uccode:n #1 - { \tex_the:D \tex_uccode:D \int_eval:w #1\int_eval_end: } + { \tex_the:D \tex_uccode:D \__int_eval:w #1\__int_eval_end: } \cs_new_protected:Npn \char_show_value_uccode:n #1 - { \tex_showthe:D \tex_uccode:D \int_eval:w #1 \int_eval_end: } + { \tex_showthe:D \tex_uccode:D \__int_eval:w #1 \__int_eval_end: } \cs_new_protected:Npn \char_set_sfcode:nn #1#2 - { \tex_sfcode:D #1 = \int_eval:w #2 \int_eval_end: } + { \tex_sfcode:D #1 = \__int_eval:w #2 \__int_eval_end: } \cs_new:Npn \char_value_sfcode:n #1 - { \tex_the:D \tex_sfcode:D \int_eval:w #1\int_eval_end: } + { \tex_the:D \tex_sfcode:D \__int_eval:w #1\__int_eval_end: } \cs_new_protected:Npn \char_show_value_sfcode:n #1 - { \tex_showthe:D \tex_sfcode:D \int_eval:w #1 \int_eval_end: } + { \tex_showthe:D \tex_sfcode:D \__int_eval:w #1 \__int_eval_end: } % \end{macrocode} % \end{macro} % \end{macro} @@ -1288,13 +1219,13 @@ \use:nn { \group_end: - \seq_set_from_clist:Nn \l_char_active_seq + \seq_set_split:Nnn \l_char_active_seq { } } } - { { " , $ , & , ^ , _ , ~ } } %$ + { { " $ & ^ _ ~ } } %$ \seq_new:N \l_char_special_seq -\seq_set_from_clist:Nn \l_char_special_seq - { \ , \" , \# , \$ , \% , \& , \\ , \^ , \_ , \{ , \} , \~ } +\seq_set_split:Nnn \l_char_special_seq { } + { \ \" \# \$ \% \& \\ \^ \_ \{ \} \~ } % \end{macrocode} % \end{variable} % @@ -1302,7 +1233,7 @@ % % \begin{macro}[pTF]{\token_if_group_begin:N} % Check if token is a begin group token. We use the constant -% |\c_group_begin_token| for this. +% \cs{c_group_begin_token} for this. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_group_begin:N #1 { p , T , F , TF } { @@ -1314,7 +1245,7 @@ % % \begin{macro}[pTF]{\token_if_group_end:N} % Check if token is a end group token. We use the constant -% |\c_group_end_token| for this. +% \cs{c_group_end_token} for this. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_group_end:N #1 { p , T , F , TF } { @@ -1326,7 +1257,7 @@ % % \begin{macro}[pTF]{\token_if_math_toggle:N} % Check if token is a math shift token. We use the constant -% |\c_math_toggle_token| for this. +% \cs{c_math_toggle_token} for this. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_math_toggle:N #1 { p , T , F , TF } { @@ -1338,7 +1269,7 @@ % % \begin{macro}[pTF]{\token_if_alignment:N} % Check if token is an alignment tab token. We use the constant -% |\c_alignment_tab_token| for this. +% \cs{c_alignment_token} for this. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_alignment:N #1 { p , T , F , TF } { @@ -1350,7 +1281,7 @@ % % \begin{macro}[pTF]{\token_if_parameter:N} % Check if token is a parameter token. We use the constant -% |\c_parameter_token| for this. We have to trick \TeX{} a bit to +% \cs{c_parameter_token} for this. We have to trick \TeX{} a bit to % avoid an error message: within a group we prevent % \cs{c_parameter_token} from behaving like a macro parameter character. % The definitions of \cs{prg_new_conditional:Npnn} are global, so they @@ -1369,7 +1300,7 @@ % % \begin{macro}[pTF]{\token_if_math_superscript:N} % Check if token is a math superscript token. We use the constant -% |\c_superscript_token| for this. +% \cs{c_math_superscript_token} for this. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_math_superscript:N #1 { p , T , F , TF } { @@ -1381,7 +1312,7 @@ % % \begin{macro}[pTF]{\token_if_math_subscript:N} % Check if token is a math subscript token. We use the constant -% |\c_subscript_token| for this. +% \cs{c_math_subscript_token} for this. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_math_subscript:N #1 { p , T , F , TF } { @@ -1393,7 +1324,7 @@ % % \begin{macro}[pTF]{\token_if_space:N} % Check if token is a space token. We use the constant -% |\c_space_token| for this. +% \cs{c_space_token} for this. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_space:N #1 { p , T , F , TF } { @@ -1405,7 +1336,7 @@ % % \begin{macro}[pTF]{\token_if_letter:N} % Check if token is a letter token. We use the constant -% |\c_letter_token| for this. +% \cs{c_catcode_letter_token} for this. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_letter:N #1 { p , T , F , TF } { @@ -1417,7 +1348,7 @@ % % \begin{macro}[pTF]{\token_if_other:N} % Check if token is an other char token. We use the constant -% |\c_other_char_token| for this. +% \cs{c_catcode_other_token} for this. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_other:N #1 { p , T , F , TF } { @@ -1429,8 +1360,8 @@ % % \begin{macro}[pTF]{\token_if_active:N} % Check if token is an active char token. We use the constant -% |\c_active_char_tl| for this. A technical point is that -% \cs{c_active_char_tl} is in fact a macro expanding to +% \cs{c_catcode_active_tl} for this. A technical point is that +% \cs{c_catcode_active_tl} is in fact a macro expanding to % |\exp_not:N *|, where |*| is active. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_active:N #1 { p , T , F , TF } @@ -1475,8 +1406,8 @@ % \end{macro} % % \begin{macro}[pTF]{\token_if_macro:N} -% \begin{macro}[aux]{\token_if_macro_p_aux:w} -% When a token is a macro, |\token_to_meaning:N| will always output +% \begin{macro}[aux]{\@@_if_macro_p:w} +% When a token is a macro, \cs{token_to_meaning:N} will always output % something like |\long macro:#1->#1| so we could naively check to % see if the meaning contains |->|. However, this can fail the five % \tn{...mark} primitives, whose meaning has the form @@ -1513,10 +1444,10 @@ \group_end: \prg_new_conditional:Npnn \token_if_macro:N #1 { p , T , F , TF } { - \exp_after:wN \token_if_macro_p_aux:w + \exp_after:wN \@@_if_macro_p:w \token_to_meaning:N #1 MA; \q_stop } - \cs_new:Npn \token_if_macro_p_aux:w #1 MA #2 ; #3 \q_stop + \cs_new:Npn \@@_if_macro_p:w #1 MA #2 ; #3 \q_stop { \if_int_compare:w \pdftex_strcmp:D { #2 } { cro } = \c_zero \prg_return_true: @@ -1532,7 +1463,7 @@ % \begin{macro}[pTF]{\token_if_cs:N} % Check if token has same catcode as a control sequence. This % follows the same pattern as for \cs{token_if_letter:N} \emph{etc.} -% We use |\scan_stop:| for this. +% We use \cs{scan_stop:} for this. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_cs:N #1 { p , T , F , TF } { @@ -1544,17 +1475,23 @@ % % \begin{macro}[pTF]{\token_if_expandable:N} % Check if token is expandable. We use the fact that \TeX{} will -% temporarily convert |\exp_not:N| \meta{token} into |\scan_stop:| if -% \meta{token} is expandable. +% temporarily convert \cs{exp_not:N} \meta{token} into \cs{scan_stop:} +% if \meta{token} is expandable. An \texttt{undefined} token is not +% considered as expandable. No problem nesting the conditionals, +% since the third |#1| is only skipped if it is non-expandable (hence +% not part of \TeX{}'s conditional apparatus). % \begin{macrocode} \prg_new_conditional:Npnn \token_if_expandable:N #1 { p , T , F , TF } { - \cs_if_exist:NTF #1 - { - \exp_after:wN \if_meaning:w \exp_not:N #1 #1 - \prg_return_false: \else: \prg_return_true: \fi: - } - { \prg_return_false: } + \exp_after:wN \if_meaning:w \exp_not:N #1 #1 + \prg_return_false: + \else: + \if_cs_exist:N #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + \fi: } % \end{macrocode} % \end{macro} @@ -1570,18 +1507,18 @@ % } % \begin{macro}[aux] % { -% \token_if_chardef_aux:w, -% \token_if_dim_register_aux:w, -% \token_if_int_register_aux:w, -% \token_if_muskip_register_aux:w, -% \token_if_skip_register_aux:w, -% \token_if_toks_register_aux:w, -% \token_if_protected_macro_aux:w, -% \token_if_long_macro_aux:w, +% \@@_if_chardef:w, +% \@@_if_dim_register:w, +% \@@_if_int_register:w, +% \@@_if_muskip_register:w, +% \@@_if_skip_register:w, +% \@@_if_toks_register:w, +% \@@_if_protected_macro:w, +% \@@_if_long_macro:w, % } % Most of these functions have to check the meaning of the token in % question so we need to do some checkups on which characters are -% output by |\token_to_meaning:N|. As usual, these characters have +% output by \cs{token_to_meaning:N}. As usual, these characters have % catcode 12 so we must do some serious substitutions in the code % below\dots % \begin{macrocode} @@ -1613,23 +1550,23 @@ % \begin{macrocode} \prg_new_conditional:Npnn \token_if_chardef:N #1 { p , T , F , TF } { - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { - \exp_after:wN \token_if_chardef_aux:w + \exp_after:wN \@@_if_chardef:w \token_to_meaning:N #1 CHAR" \q_stop } { \token_to_str:N \char } } \prg_new_conditional:Npnn \token_if_mathchardef:N #1 { p , T , F , TF } { - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { - \exp_after:wN \token_if_chardef_aux:w + \exp_after:wN \@@_if_chardef:w \token_to_meaning:N #1 CHAR" \q_stop } { \token_to_str:N \mathchar } } - \cs_new:Npn \token_if_chardef_aux:w #1 CHAR" #2 \q_stop { #1 CHAR } + \cs_new:Npn \@@_if_chardef:w #1 CHAR" #2 \q_stop { #1 CHAR } % \end{macrocode} % % Dim registers are a little more difficult since their \tn{meaning} @@ -1644,16 +1581,16 @@ \if_meaning:w \tex_dimendef:D #1 \prg_return_false: \else: - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { - \exp_after:wN \token_if_dim_register_aux:w + \exp_after:wN \@@_if_dim_register:w \token_to_meaning:N #1 ZIMEX \q_stop } { \token_to_str:N \ } \fi: \fi: } - \cs_new:Npn \token_if_dim_register_aux:w #1 ZIMEX #2 \q_stop { #1 ~ } + \cs_new:Npn \@@_if_dim_register:w #1 ZIMEX #2 \q_stop { #1 ~ } % \end{macrocode} % Integer registers are one step harder since constants are implemented % differently from variables, and we also have to take care of the @@ -1671,9 +1608,9 @@ \if_meaning:w \tex_countdef:D #1 \prg_return_false: \else: - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { - \exp_after:wN \token_if_int_register_aux:w + \exp_after:wN \@@_if_int_register:w \token_to_meaning:N #1 COUXY \q_stop } { \token_to_str:N \ } @@ -1682,7 +1619,7 @@ % } % } } - \cs_new:Npn \token_if_int_register_aux:w #1 COUXY #2 \q_stop { #1 ~ } + \cs_new:Npn \@@_if_int_register:w #1 COUXY #2 \q_stop { #1 ~ } % \end{macrocode} % Muskip registers are done the same way as the dimension registers. % \begin{macrocode} @@ -1694,16 +1631,16 @@ \if_meaning:w \tex_muskipdef:D #1 \prg_return_false: \else: - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { - \exp_after:wN \token_if_muskip_register_aux:w + \exp_after:wN \@@_if_muskip_register:w \token_to_meaning:N #1 MUSKIP \q_stop } { \token_to_str:N \ } \fi: \fi: } - \cs_new:Npn \token_if_muskip_register_aux:w #1 MUSKIP #2 \q_stop { #1 ~ } + \cs_new:Npn \@@_if_muskip_register:w #1 MUSKIP #2 \q_stop { #1 ~ } % \end{macrocode} % Skip registers. % \begin{macrocode} @@ -1715,16 +1652,16 @@ \if_meaning:w \tex_skipdef:D #1 \prg_return_false: \else: - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { - \exp_after:wN \token_if_skip_register_aux:w + \exp_after:wN \@@_if_skip_register:w \token_to_meaning:N #1 SKIP \q_stop } { \token_to_str:N \ } \fi: \fi: } - \cs_new:Npn \token_if_skip_register_aux:w #1 SKIP #2 \q_stop { #1 ~ } + \cs_new:Npn \@@_if_skip_register:w #1 SKIP #2 \q_stop { #1 ~ } % \end{macrocode} % Toks registers. % \begin{macrocode} @@ -1736,39 +1673,39 @@ \if_meaning:w \tex_toksdef:D #1 \prg_return_false: \else: - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { - \exp_after:wN \token_if_toks_register_aux:w + \exp_after:wN \@@_if_toks_register:w \token_to_meaning:N #1 YOKS \q_stop } { \token_to_str:N \ } \fi: \fi: } - \cs_new:Npn \token_if_toks_register_aux:w #1 YOKS #2 \q_stop { #1 ~ } + \cs_new:Npn \@@_if_toks_register:w #1 YOKS #2 \q_stop { #1 ~ } % \end{macrocode} % Protected macros. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_protected_macro:N #1 { p , T , F , TF } { - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { - \exp_after:wN \token_if_protected_macro_aux:w + \exp_after:wN \@@_if_protected_macro:w \token_to_meaning:N #1 PROYECYEZ~MACRO \q_stop } { \token_to_str:N \ } } - \cs_new:Npn \token_if_protected_macro_aux:w + \cs_new:Npn \@@_if_protected_macro:w #1 PROYECYEZ~MACRO #2 \q_stop { #1 ~ } % \end{macrocode} % Long macros and protected long macros share an auxiliary. % \begin{macrocode} \prg_new_conditional:Npnn \token_if_long_macro:N #1 { p , T , F , TF } { - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { - \exp_after:wN \token_if_long_macro_aux:w + \exp_after:wN \@@_if_long_macro:w \token_to_meaning:N #1 LOXG~MACRO \q_stop } { \token_to_str:N \ } @@ -1776,16 +1713,16 @@ \prg_new_conditional:Npnn \token_if_protected_long_macro:N #1 { p , T , F , TF } { - \str_if_eq_return:xx + \__str_if_eq_x_return:nn { - \exp_after:wN \token_if_long_macro_aux:w + \exp_after:wN \@@_if_long_macro:w \token_to_meaning:N #1 LOXG~MACRO \q_stop } { \token_to_str:N \protected \token_to_str:N \ } } - \cs_new:Npn \token_if_long_macro_aux:w #1 LOXG~MACRO #2 \q_stop { #1 ~ } + \cs_new:Npn \@@_if_long_macro:w #1 LOXG~MACRO #2 \q_stop { #1 ~ } % \end{macrocode} -% Finally the |\tl_to_lowercase:n| ends! +% Finally the \cs{tl_to_lowercase:n} ends! % \begin{macrocode} } % \end{macrocode} @@ -1793,12 +1730,12 @@ % \end{macro} % % \begin{macro}[pTF]{\token_if_primitive:N} -% \begin{macro}[aux]{\token_if_primitive_aux:NNw, -% \token_if_primitive_aux_space:w, -% \token_if_primitive_aux_nullfont:N, -% \token_if_primitive_aux_loop:N, -% \token_if_primitive_auxii:Nw, -% \token_if_primitive_aux_undefined:N} +% \begin{macro}[aux]{\@@_if_primitive:NNw, +% \@@_if_primitive_space:w, +% \@@_if_primitive_nullfont:N, +% \@@_if_primitive_loop:N, +% \@@_if_primitive:Nw, +% \@@_if_primitive_undefined:N} %^^A See http://groups.google.com/group/comp.text.tex/browse_thread/thread/0a72666873f8753d# % % We filter out macros first, because they cause endless trouble later @@ -1857,19 +1794,19 @@ \token_if_macro:NTF #1 \prg_return_false: { - \exp_after:wN \token_if_primitive_aux:NNw + \exp_after:wN \@@_if_primitive:NNw \token_to_meaning:N #1 ; ; ; \q_stop #1 } } - \cs_new:Npn \token_if_primitive_aux:NNw #1#2 #3 ; #4 \q_stop + \cs_new:Npn \@@_if_primitive:NNw #1#2 #3 ; #4 \q_stop { - \tl_if_empty:oTF { \token_if_primitive_aux_space:w #3 ~ } - { \token_if_primitive_aux_loop:N #3 ; \q_stop } - { \token_if_primitive_aux_nullfont:N } + \tl_if_empty:oTF { \@@_if_primitive_space:w #3 ~ } + { \@@_if_primitive_loop:N #3 ; \q_stop } + { \@@_if_primitive_nullfont:N } } } -\cs_new:Npn \token_if_primitive_aux_space:w #1 ~ { } -\cs_new:Npn \token_if_primitive_aux_nullfont:N #1 +\cs_new:Npn \@@_if_primitive_space:w #1 ~ { } +\cs_new:Npn \@@_if_primitive_nullfont:N #1 { \if_meaning:w \tex_nullfont:D #1 \prg_return_true: @@ -1877,25 +1814,25 @@ \prg_return_false: \fi: } -\cs_new:Npn \token_if_primitive_aux_loop:N #1 +\cs_new:Npn \@@_if_primitive_loop:N #1 { - \if_num:w `#1 < \c_token_A_int % - \exp_after:wN \token_if_primitive_auxii:Nw + \if_int_compare:w `#1 < \c_token_A_int % + \exp_after:wN \@@_if_primitive:Nw \exp_after:wN #1 \else: - \exp_after:wN \token_if_primitive_aux_loop:N + \exp_after:wN \@@_if_primitive_loop:N \fi: } -\cs_new:Npn \token_if_primitive_auxii:Nw #1 #2 \q_stop +\cs_new:Npn \@@_if_primitive:Nw #1 #2 \q_stop { \if:w : #1 - \exp_after:wN \token_if_primitive_aux_undefined:N + \exp_after:wN \@@_if_primitive_undefined:N \else: \prg_return_false: \exp_after:wN \use_none:n \fi: } -\cs_new:Npn \token_if_primitive_aux_undefined:N #1 +\cs_new:Npn \@@_if_primitive_undefined:N #1 { \if_cs_exist:N #1 \prg_return_true: @@ -1908,6 +1845,10 @@ % \end{macro} % % \subsection{Peeking ahead at the next token} +% +% \begin{macrocode} +%<@@=peek> +% \end{macrocode} % % Peeking ahead is implemented using a two part mechanism. The % outer level provides a defined interface to the lower level material. @@ -1930,35 +1871,35 @@ % \end{variable} % \end{variable} % -% \begin{variable}{\l_peek_search_token} +% \begin{variable}{\l_@@_search_token} % The token to search for as an implicit token: -% \emph{cf.}~\cs{l_peek_search_tl}. +% \emph{cf.}~\cs{l_@@_search_tl}. % \begin{macrocode} -\cs_new_eq:NN \l_peek_search_token ? +\cs_new_eq:NN \l_@@_search_token ? % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_peek_search_tl} +% \begin{variable}{\l_@@_search_tl} % The token to search for as an explicit token: -% \emph{cf.}~\cs{l_peek_search_token}. +% \emph{cf.}~\cs{l_@@_search_token}. % \begin{macrocode} -\tl_new:N \l_peek_search_tl +\tl_new:N \l_@@_search_tl % \end{macrocode} % \end{variable} % % \begin{macro}[aux] -% {\peek_true:w, \peek_true_aux:w, \peek_false:w, \peek_tmp:w} +% {\@@_true:w, \@@_true_aux:w, \@@_false:w, \@@_tmp:w} % Functions used by the branching and space-stripping code. % \begin{macrocode} -\cs_new_nopar:Npn \peek_true:w { } -\cs_new_nopar:Npn \peek_true_aux:w { } -\cs_new_nopar:Npn \peek_false:w { } -\cs_new:Npn \peek_tmp:w { } +\cs_new_nopar:Npn \@@_true:w { } +\cs_new_nopar:Npn \@@_true_aux:w { } +\cs_new_nopar:Npn \@@_false:w { } +\cs_new:Npn \@@_tmp:w { } % \end{macrocode} % \end{macro} % % \begin{macro}{\peek_after:Nw} -% \begin{macro}{\peek_after:Nw} +% \begin{macro}{\peek_gafter:Nw} % Simple wrappers for \tn{futurelet}: no arguments absorbed % here. % \begin{macrocode} @@ -1970,34 +1911,34 @@ % \end{macro} % \end{macro} % -% \begin{macro}[aux]{\peek_true_remove:w} +% \begin{macro}[aux]{\@@_true_remove:w} % A function to remove the next token and then regain control. % \begin{macrocode} -\cs_new_protected:Npn \peek_true_remove:w +\cs_new_protected:Npn \@@_true_remove:w { \group_align_safe_end: - \tex_afterassignment:D \peek_true_aux:w - \cs_set_eq:NN \peek_tmp:w + \tex_afterassignment:D \@@_true_aux:w + \cs_set_eq:NN \@@_tmp:w } % \end{macrocode} % \end{macro} % -% \begin{macro}[TF]{\peek_token_generic:NN} +% \begin{macro}[TF]{\@@_token_generic:NN} % The generic function stores the test token in both implicit and % explicit modes, and the \texttt{true} and \texttt{false} code as % token lists, more or less. The two branches have to be absorbed here % as the input stream needs to be cleared for the peek function itself. % \begin{macrocode} -\cs_new_protected:Npn \peek_token_generic:NNTF #1#2#3#4 +\cs_new_protected:Npn \@@_token_generic:NNTF #1#2#3#4 { - \cs_set_eq:NN \l_peek_search_token #2 - \tl_set:Nn \l_peek_search_tl {#2} - \cs_set_nopar:Npx \peek_true:w + \cs_set_eq:NN \l_@@_search_token #2 + \tl_set:Nn \l_@@_search_tl {#2} + \cs_set_nopar:Npx \@@_true:w { \exp_not:N \group_align_safe_end: \exp_not:n {#3} } - \cs_set_nopar:Npx \peek_false:w + \cs_set_nopar:Npx \@@_false:w { \exp_not:N \group_align_safe_end: \exp_not:n {#4} @@ -2005,24 +1946,24 @@ \group_align_safe_begin: \peek_after:Nw #1 } -\cs_new_protected:Npn \peek_token_generic:NNT #1#2#3 - { \peek_token_generic:NNTF #1 #2 {#3} { } } -\cs_new_protected:Npn \peek_token_generic:NNF #1#2#3 - { \peek_token_generic:NNTF #1 #2 { } {#3} } +\cs_new_protected:Npn \@@_token_generic:NNT #1#2#3 + { \@@_token_generic:NNTF #1 #2 {#3} { } } +\cs_new_protected:Npn \@@_token_generic:NNF #1#2#3 + { \@@_token_generic:NNTF #1 #2 { } {#3} } % \end{macrocode} % \end{macro} % -% \begin{macro}[TF]{\peek_token_remove_generic:NN} +% \begin{macro}[TF]{\@@_token_remove_generic:NN} % For token removal there needs to be a call to the auxiliary % function which does the work. % \begin{macrocode} -\cs_new_protected:Npn \peek_token_remove_generic:NNTF #1#2#3#4 +\cs_new_protected:Npn \@@_token_remove_generic:NNTF #1#2#3#4 { - \cs_set_eq:NN \l_peek_search_token #2 - \tl_set:Nn \l_peek_search_tl {#2} - \cs_set_eq:NN \peek_true:w \peek_true_remove:w - \cs_set_nopar:Npx \peek_true_aux:w { \exp_not:n {#3} } - \cs_set_nopar:Npx \peek_false:w + \cs_set_eq:NN \l_@@_search_token #2 + \tl_set:Nn \l_@@_search_tl {#2} + \cs_set_eq:NN \@@_true:w \@@_true_remove:w + \cs_set_nopar:Npx \@@_true_aux:w { \exp_not:n {#3} } + \cs_set_nopar:Npx \@@_false:w { \exp_not:N \group_align_safe_end: \exp_not:n {#4} @@ -2030,45 +1971,45 @@ \group_align_safe_begin: \peek_after:Nw #1 } -\cs_new_protected:Npn \peek_token_remove_generic:NNT #1#2#3 - { \peek_token_remove_generic:NNTF #1 #2 {#3} { } } -\cs_new_protected:Npn \peek_token_remove_generic:NNF #1#2#3 - { \peek_token_remove_generic:NNTF #1 #2 { } {#3} } +\cs_new_protected:Npn \@@_token_remove_generic:NNT #1#2#3 + { \@@_token_remove_generic:NNTF #1 #2 {#3} { } } +\cs_new_protected:Npn \@@_token_remove_generic:NNF #1#2#3 + { \@@_token_remove_generic:NNTF #1 #2 { } {#3} } % \end{macrocode} % \end{macro} % % \begin{macro} -% {\peek_execute_branches_catcode:, \peek_execute_branches_meaning:} +% {\@@_execute_branches_catcode:, \@@_execute_branches_meaning:} % The category code and meaning tests are straight forward. % \begin{macrocode} -\cs_new_nopar:Npn \peek_execute_branches_catcode: +\cs_new_nopar:Npn \@@_execute_branches_catcode: { \if_catcode:w - \exp_not:N \l_peek_token \exp_not:N \l_peek_search_token - \exp_after:wN \peek_true:w + \exp_not:N \l_peek_token \exp_not:N \l_@@_search_token + \exp_after:wN \@@_true:w \else: - \exp_after:wN \peek_false:w + \exp_after:wN \@@_false:w \fi: } -\cs_new_nopar:Npn \peek_execute_branches_meaning: +\cs_new_nopar:Npn \@@_execute_branches_meaning: { - \if_meaning:w \l_peek_token \l_peek_search_token - \exp_after:wN \peek_true:w + \if_meaning:w \l_peek_token \l_@@_search_token + \exp_after:wN \@@_true:w \else: - \exp_after:wN \peek_false:w + \exp_after:wN \@@_false:w \fi: } % \end{macrocode} % \end{macro} % -% \begin{macro}{\peek_execute_branches_charcode:} -% \begin{macro}[aux]{\peek_execute_branches_charcode:NN} +% \begin{macro}{\@@_execute_branches_charcode:} +% \begin{macro}[aux]{\@@_execute_branches_charcode:NN} % First the character code test there is a need to worry about \TeX{} % grabbing brace group or skipping spaces. These are all tested for % using a category code check before grabbing what must be a real % single token and doing the comparison. % \begin{macrocode} -\cs_new_nopar:Npn \peek_execute_branches_charcode: +\cs_new_nopar:Npn \@@_execute_branches_charcode: { \bool_if:nTF { @@ -2076,18 +2017,18 @@ || \token_if_eq_catcode_p:NN \l_peek_token \c_group_end_token || \token_if_eq_meaning_p:NN \l_peek_token \c_space_token } - { \peek_false:w } + { \@@_false:w } { - \exp_after:wN \peek_execute_branches_charcode_aux:NN - \l_peek_search_tl + \exp_after:wN \@@_execute_branches_charcode_aux:NN + \l_@@_search_tl } } -\cs_new:Npn \peek_execute_branches_charcode_aux:NN #1#2 +\cs_new:Npn \@@_execute_branches_charcode_aux:NN #1#2 { \if:w \exp_not:N #1 \exp_not:N #2 - \exp_after:wN \peek_true:w + \exp_after:wN \@@_true:w \else: - \exp_after:wN \peek_false:w + \exp_after:wN \@@_false:w \fi: #2 } @@ -2095,46 +2036,46 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\peek_ignore_spaces_execute_branches:} -% \begin{macro}[aux]{\peek_ignore_spaces_execute_branches_aux:} +% \begin{macro}{\@@_ignore_spaces_execute_branches:} +% \begin{macro}[aux]{\@@_ignore_spaces_execute_branches_aux:} % This function removes one token at a time with a mechanism that can % be applied to things other than spaces. % \begin{macrocode} -\cs_new_protected_nopar:Npn \peek_ignore_spaces_execute_branches: +\cs_new_protected_nopar:Npn \@@_ignore_spaces_execute_branches: { \token_if_eq_meaning:NNTF \l_peek_token \c_space_token { - \tex_afterassignment:D \peek_ignore_spaces_execute_branches_aux: - \cs_set_eq:NN \peek_tmp:w + \tex_afterassignment:D \@@_ignore_spaces_execute_branches_aux: + \cs_set_eq:NN \@@_tmp:w } - { \peek_execute_branches: } + { \@@_execute_branches: } } -\cs_new_protected_nopar:Npn \peek_ignore_spaces_execute_branches_aux: - { \peek_after:Nw \peek_ignore_spaces_execute_branches: } +\cs_new_protected_nopar:Npn \@@_ignore_spaces_execute_branches_aux: + { \peek_after:Nw \@@_ignore_spaces_execute_branches: } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[aux]{\peek_def:nnnn} -% \begin{macro}[aux]{\peek_def_aux:nnnnn} +% \begin{macro}[aux]{\@@_def:nnnn} +% \begin{macro}[aux]{\@@_def:nnnnn} % The public functions themselves cannot be defined using % \cs{prg_new_conditional:Npnn} and so a couple of auxiliary functions % are used. As a result, everything is done inside a group. As a result % things are a bit complicated. % \begin{macrocode} \group_begin: - \cs_set:Npn \peek_def:nnnn #1#2#3#4 + \cs_set:Npn \@@_def:nnnn #1#2#3#4 { - \peek_def_aux:nnnnn {#1} {#2} {#3} {#4} { TF } - \peek_def_aux:nnnnn {#1} {#2} {#3} {#4} { T } - \peek_def_aux:nnnnn {#1} {#2} {#3} {#4} { F } + \@@_def:nnnnn {#1} {#2} {#3} {#4} { TF } + \@@_def:nnnnn {#1} {#2} {#3} {#4} { T } + \@@_def:nnnnn {#1} {#2} {#3} {#4} { F } } - \cs_set:Npn \peek_def_aux:nnnnn #1#2#3#4#5 + \cs_set:Npn \@@_def:nnnnn #1#2#3#4#5 { \cs_new_nopar:cpx { #1 #5 } { \tl_if_empty:nF {#2} - { \exp_not:n { \cs_set_eq:NN \peek_execute_branches: #2 } } + { \exp_not:n { \cs_set_eq:NN \@@_execute_branches: #2 } } \exp_not:c { #3 #5 } \exp_not:n {#4} } @@ -2150,22 +2091,22 @@ % With everything in place the definitions can take place. First for % category codes. % \begin{macrocode} - \peek_def:nnnn { peek_catcode:N } + \@@_def:nnnn { peek_catcode:N } { } - { peek_token_generic:NN } - { \peek_execute_branches_catcode: } - \peek_def:nnnn { peek_catcode_ignore_spaces:N } - { \peek_execute_branches_catcode: } - { peek_token_generic:NN } - { \peek_ignore_spaces_execute_branches: } - \peek_def:nnnn { peek_catcode_remove:N } + { @@_token_generic:NN } + { \@@_execute_branches_catcode: } + \@@_def:nnnn { peek_catcode_ignore_spaces:N } + { \@@_execute_branches_catcode: } + { @@_token_generic:NN } + { \@@_ignore_spaces_execute_branches: } + \@@_def:nnnn { peek_catcode_remove:N } { } - { peek_token_remove_generic:NN } - { \peek_execute_branches_catcode: } - \peek_def:nnnn { peek_catcode_remove_ignore_spaces:N } - { \peek_execute_branches_catcode: } - { peek_token_remove_generic:NN } - { \peek_ignore_spaces_execute_branches: } + { @@_token_remove_generic:NN } + { \@@_execute_branches_catcode: } + \@@_def:nnnn { peek_catcode_remove_ignore_spaces:N } + { \@@_execute_branches_catcode: } + { @@_token_remove_generic:NN } + { \@@_ignore_spaces_execute_branches: } % \end{macrocode} % \end{macro} % \begin{macro}[TF] @@ -2175,22 +2116,22 @@ % } % Then for character codes. % \begin{macrocode} - \peek_def:nnnn { peek_charcode:N } + \@@_def:nnnn { peek_charcode:N } { } - { peek_token_generic:NN } - { \peek_execute_branches_charcode: } - \peek_def:nnnn { peek_charcode_ignore_spaces:N } - { \peek_execute_branches_charcode: } - { peek_token_generic:NN } - { \peek_ignore_spaces_execute_branches: } - \peek_def:nnnn { peek_charcode_remove:N } + { @@_token_generic:NN } + { \@@_execute_branches_charcode: } + \@@_def:nnnn { peek_charcode_ignore_spaces:N } + { \@@_execute_branches_charcode: } + { @@_token_generic:NN } + { \@@_ignore_spaces_execute_branches: } + \@@_def:nnnn { peek_charcode_remove:N } { } - { peek_token_remove_generic:NN } - { \peek_execute_branches_charcode: } - \peek_def:nnnn { peek_charcode_remove_ignore_spaces:N } - { \peek_execute_branches_charcode: } - { peek_token_remove_generic:NN } - { \peek_ignore_spaces_execute_branches: } + { @@_token_remove_generic:NN } + { \@@_execute_branches_charcode: } + \@@_def:nnnn { peek_charcode_remove_ignore_spaces:N } + { \@@_execute_branches_charcode: } + { @@_token_remove_generic:NN } + { \@@_ignore_spaces_execute_branches: } % \end{macrocode} % \end{macro} % \begin{macro}[TF] @@ -2201,22 +2142,22 @@ % Finally for meaning, with the group closed to remove the temporary % definition functions. % \begin{macrocode} - \peek_def:nnnn { peek_meaning:N } + \@@_def:nnnn { peek_meaning:N } { } - { peek_token_generic:NN } - { \peek_execute_branches_meaning: } - \peek_def:nnnn { peek_meaning_ignore_spaces:N } - { \peek_execute_branches_meaning: } - { peek_token_generic:NN } - { \peek_ignore_spaces_execute_branches: } - \peek_def:nnnn { peek_meaning_remove:N } + { @@_token_generic:NN } + { \@@_execute_branches_meaning: } + \@@_def:nnnn { peek_meaning_ignore_spaces:N } + { \@@_execute_branches_meaning: } + { @@_token_generic:NN } + { \@@_ignore_spaces_execute_branches: } + \@@_def:nnnn { peek_meaning_remove:N } { } - { peek_token_remove_generic:NN } - { \peek_execute_branches_meaning: } - \peek_def:nnnn { peek_meaning_remove_ignore_spaces:N } - { \peek_execute_branches_meaning: } - { peek_token_remove_generic:NN } - { \peek_ignore_spaces_execute_branches: } + { @@_token_remove_generic:NN } + { \@@_execute_branches_meaning: } + \@@_def:nnnn { peek_meaning_remove_ignore_spaces:N } + { \@@_execute_branches_meaning: } + { @@_token_remove_generic:NN } + { \@@_ignore_spaces_execute_branches: } \group_end: % \end{macrocode} % \end{macro} @@ -2226,7 +2167,7 @@ % \begin{macro}{\token_get_prefix_spec:N} % \begin{macro}{\token_get_arg_spec:N} % \begin{macro}{\token_get_replacement_spec:N} -% \begin{macro}[aux]{\token_get_prefix_arg_replacement_aux:wN} +% \begin{macro}[aux]{\@@_get_prefix_arg_replacement:wN} % We sometimes want to test if a % control sequence can be expanded to reveal a hidden % value. However, we cannot just expand the macro blindly as it may @@ -2234,18 +2175,18 @@ % these functions to pick either the prefix(es), the argument % specification, or the replacement text from a macro. All of this % information is returned as characters with catcode~$12$. If the -% token in question isn't a macro, the token |\scan_stop:| is +% token in question isn't a macro, the token \cs{scan_stop:} is % returned instead. % \begin{macrocode} \exp_args:Nno \use:nn - { \cs_new:Npn \token_get_prefix_arg_replacement_aux:wN #1 } + { \cs_new:Npn \@@_get_prefix_arg_replacement:wN #1 } { \tl_to_str:n { macro : } #2 -> #3 \q_stop #4 } { #4 {#1} {#2} {#3} } \cs_new:Npn \token_get_prefix_spec:N #1 { \token_if_macro:NTF #1 { - \exp_after:wN \token_get_prefix_arg_replacement_aux:wN + \exp_after:wN \@@_get_prefix_arg_replacement:wN \token_to_meaning:N #1 \q_stop \use_i:nnn } { \scan_stop: } @@ -2254,7 +2195,7 @@ { \token_if_macro:NTF #1 { - \exp_after:wN \token_get_prefix_arg_replacement_aux:wN + \exp_after:wN \@@_get_prefix_arg_replacement:wN \token_to_meaning:N #1 \q_stop \use_ii:nnn } { \scan_stop: } @@ -2263,7 +2204,7 @@ { \token_if_macro:NTF #1 { - \exp_after:wN \token_get_prefix_arg_replacement_aux:wN + \exp_after:wN \@@_get_prefix_arg_replacement:wN \token_to_meaning:N #1 \q_stop \use_iii:nnn } { \scan_stop: } @@ -2274,66 +2215,6 @@ % \end{macro} % \end{macro} % -% \subsection{Experimental token functions} -% -% \begin{macro}{\char_set_active:Npn,\char_set_active:Npx} -% \begin{macro}{\char_set_active:Npn,\char_set_active:Npx} -% \begin{macro}{\char_set_active_eq:NN,\char_gset_active_eq:NN} -% \begin{macrocode} -\group_begin: - \char_set_catcode_active:N \^^@ - \cs_set:Npn \char_tmp:NN #1#2 - { - \cs_new:Npn #1 ##1 - { - \char_set_catcode_active:n { `##1 } - \group_begin: - \char_set_lccode:nn { `\^^@ } { `##1 } - \tl_to_lowercase:n { \group_end: #2 ^^@ } - } - } - \char_tmp:NN \char_set_active:Npn \cs_set:Npn - \char_tmp:NN \char_set_active:Npx \cs_set:Npx - \char_tmp:NN \char_gset_active:Npn \cs_gset:Npn - \char_tmp:NN \char_gset_active:Npx \cs_gset:Npx - \char_tmp:NN \char_set_active_eq:NN \cs_set_eq:NN - \char_tmp:NN \char_gset_active_eq:NN \cs_gset_eq:NN -\group_end: -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}[TF]{\peek_N_type:} -% \begin{macro}{\peek_execute_branches_N_type:} -% The next token is normal if it is neither a begin-group token, -% nor an end-group token, nor a charcode-$32$ space token. -% Note that implicit begin-group tokens, end-group tokens, and -% spaces are also recognized as non-\texttt{N}-type. -% Here, there is no \meta{search token}, so we feed a dummy -% \cs{scan_stop:} to the \cs{peek_token_generic::NN} functions. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \peek_execute_branches_N_type: - { - \bool_if:nTF - { - \token_if_eq_catcode_p:NN \l_peek_token \c_group_begin_token || - \token_if_eq_catcode_p:NN \l_peek_token \c_group_end_token || - \token_if_eq_meaning_p:NN \l_peek_token \c_space_token - } - { \peek_false:w } - { \peek_true:w } - } -\cs_new_protected_nopar:Npn \peek_N_type:TF - { \peek_token_generic:NNTF \peek_execute_branches_N_type: \scan_stop: } -\cs_new_protected_nopar:Npn \peek_N_type:T - { \peek_token_generic:NNT \peek_execute_branches_N_type: \scan_stop: } -\cs_new_protected_nopar:Npn \peek_N_type:F - { \peek_token_generic:NNF \peek_execute_branches_N_type: \scan_stop: } -% \end{macrocode} -% \end{macro} -% \end{macro} -% % \subsection{Deprecated functions} % % Deprecated on 2011-05-27, for removal by 2011-08-31. |