diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx | 418 |
1 files changed, 418 insertions, 0 deletions
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 |