summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2012-07-23 17:15:00 +0000
committerKarl Berry <karl@freefriends.org>2012-07-23 17:15:00 +0000
commit134349701bddf7cbbacf6030c6b9f9838aff96fa (patch)
treeec1140c46e1c0347a671a6fa3cf8af5a79e95f93 /Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
parentf7855c12c18bb97b7b9e49ab685ee558d8c0b47b (diff)
l3kernel 3990 (17jul12)
git-svn-id: svn://tug.org/texlive/trunk@27108 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx418
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