[latex3-commits] [latex3/latex3] fp-func: Move l3fp-functions to kernel (9fc8a2a70)

github at latex-project.org github at latex-project.org
Wed Jul 5 22:05:35 CEST 2023


Repository : https://github.com/latex3/latex3
On branch  : fp-func
Link       : https://github.com/latex3/latex3/commit/9fc8a2a70dc64058e9ed1dbe19c3a51e770e322a

>---------------------------------------------------------------

commit 9fc8a2a70dc64058e9ed1dbe19c3a51e770e322a
Author: Joseph Wright <joseph.wright at morningstar2.co.uk>
Date:   Wed Jul 5 21:03:50 2023 +0100

    Move l3fp-functions to kernel


>---------------------------------------------------------------

9fc8a2a70dc64058e9ed1dbe19c3a51e770e322a
 l3kernel/CHANGELOG.md                              |   2 +
 l3kernel/doc/source3body.tex                       |   3 +-
 l3kernel/l3.ins                                    |   1 +
 l3kernel/l3fp-functions.dtx                        | 296 ++++++++++++++++
 l3kernel/l3fp.dtx                                  |  50 +++
 l3kernel/testfiles/m3fp-functions001.lvt           |  50 +++
 l3kernel/testfiles/m3fp-functions001.tlg           |  31 ++
 l3trial/l3fp-extras/l3fp-extras.ins                |   1 -
 l3trial/l3fp-extras/l3fp-functions.dtx             | 378 ---------------------
 .../l3fp-extras/testfiles/m3fp-functions001.lvt    |  52 ---
 .../l3fp-extras/testfiles/m3fp-functions001.tlg    |  31 --
 .../l3fp-extras/testfiles/m3fp-functions002.lvt    |  88 -----
 .../l3fp-extras/testfiles/m3fp-functions002.tlg    |  43 ---
 13 files changed, 432 insertions(+), 594 deletions(-)

diff --git a/l3kernel/CHANGELOG.md b/l3kernel/CHANGELOG.md
index 316e75a1c..e9870a095 100644
--- a/l3kernel/CHANGELOG.md
+++ b/l3kernel/CHANGELOG.md
@@ -11,6 +11,8 @@ this project uses date-based 'snapshot' version identifiers.
 - `\use:ee`, `\use:eee`, etc. up to `\use:eeeeeeeee`
 - Support for symbolic variables in fp input:
   `\fp_new_variable:n`, `\fp_set_variable:nn` and `\fp_clear_variable:n`
+- Support for user-defined functions in fp expressions:
+  `\fp_new_function:n`, `\fp_set_function:nnn` and `\fp_clear_function:n`
 
 ## [2023-06-30]
 
diff --git a/l3kernel/doc/source3body.tex b/l3kernel/doc/source3body.tex
index 5a0eb5bdc..e20f02602 100644
--- a/l3kernel/doc/source3body.tex
+++ b/l3kernel/doc/source3body.tex
@@ -575,7 +575,8 @@ used on top of \LaTeXe{} if \cs{outer} tokens are used in the arguments.
     l3fp-convert.dtx ,
     l3fp-random.dtx ,
     l3fp-types.dtx ,
-    l3fp-symbolic.dtx
+    l3fp-symbolic.dtx ,
+    l3fp-functions.dtx
   }
 \ExplSyntaxOff
 
diff --git a/l3kernel/l3.ins b/l3kernel/l3.ins
index b671f08ca..24f11d8f7 100644
--- a/l3kernel/l3.ins
+++ b/l3kernel/l3.ins
@@ -94,6 +94,7 @@ and all files in that bundle must be distributed together.
         \from{l3fp-random.dtx}  {package}
         \from{l3fp-types.dtx}   {package}
         \from{l3fp-symbolic.dtx}{package}
+        \from{l3fp-functions.dtx}{package}
         \from{l3fparray.dtx}    {package}
         \from{l3cctab.dtx}      {package}
         \from{l3sort.dtx}       {package}
diff --git a/l3kernel/l3fp-functions.dtx b/l3kernel/l3fp-functions.dtx
new file mode 100644
index 000000000..f2472def9
--- /dev/null
+++ b/l3kernel/l3fp-functions.dtx
@@ -0,0 +1,296 @@
+% \iffalse
+%
+%% File l3fp-functions.dtx (C) Copyright 2012-2018,2020,2021,2023 The LaTeX 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 development version of the bundle can be found at
+%
+%    https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\documentclass[full]{l3doc}
+\usepackage{amsmath}
+\begin{document}
+  \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+%   The \pkg{l3fp-functions} package\\ Floating point functions^^A
+% }
+%
+% \author{^^A
+%  The \LaTeX{} Project\thanks
+%    {^^A
+%      E-mail:
+%        \href{mailto:latex-team at latex-project.org}
+%          {latex-team at latex-project.org}^^A
+%    }^^A
+% }
+%
+% \date{Released 2018-04-30}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3fp-functions} implementation}
+%
+%    \begin{macrocode}
+%<*package>
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=fp>
+%    \end{macrocode}
+%
+% \subsection{Declaring functions}
+%
+% \begin{macro}{\fp_new_function:n}
+% \begin{macro}{\@@_new_function:n}
+%    \begin{macrocode}
+\cs_new_protected:Npn \fp_new_function:n #1
+  { \exp_args:No \@@_new_function:n { \tl_to_str:n {#1} } }
+\cs_new_protected:Npn \@@_new_function:n #1
+  {
+    \@@_id_if_invalid:nTF {#1}
+      { \msg_error:nnn { fp } { invalid-identifier } {#1} }
+      {
+        \cs_if_exist:cT { @@_parse_word_#1:N }
+          {
+            \msg_error:nnn
+              { fp } { id-already-defined } {#1}
+            \cs_undefine:c { @@_parse_word_#1:N }
+            \cs_undefine:c { @@_#1_o:w }
+          }
+        \@@_function_set_parsing:Nn \cs_gset_eq:NN {#1}
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+%   {\@@_function_set_parsing:Nn, \@@_function_set_parsing_aux:NNn}
+%    \begin{macrocode}
+\cs_new:Npn \@@_function_set_parsing:Nn #1#2
+  {
+    \exp_args:NNc \@@_function_set_parsing_aux:NNn #1
+      { @@_parse_word_#2:N } {#2}
+  }
+\cs_new:Npn \@@_function_set_parsing_aux:NNn #1#2#3
+  {
+    \cs_set:Npx \@@_tmp:w
+      {
+        \exp_not:N \@@_parse_function:NNN
+        \exp_not:N \@@_function_o:w
+        \exp_not:c { @@_#3_o:w }
+      }
+    \cs_if_eq:NNF #2 \@@_tmp:w
+      {
+        \cs_if_exist:NTF #2
+          {
+            \msg_warning:nnnn
+              { fp } { id-used-elsewhere } {#3} { function }
+            #1 #2 \@@_tmp:w
+          }
+          {
+            \cs_new_eq:NN #2 \scan_stop: % to declare the function
+            #1 #2 \@@_tmp:w
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_function_o:w}
+%    \begin{macrocode}
+\cs_new:Npn \@@_function_o:w #1#2 @
+  {
+    \cs_if_exist:NTF #1
+      { #1 #2 @ }
+      {
+        \exp_after:wN \s_@@_symbolic
+        \exp_after:wN \@@_symbolic_chk:w
+        \exp_after:wN \@@_function_o:w
+        \exp_after:wN #1
+        \exp_after:wN ,
+        \exp_after:wN {
+          \exp:w \exp_end_continue_f:w
+          \@@_exp_after_array_f:w #2 \s_@@_expr_stop
+          \exp_after:wN
+        }
+        \exp_after:wN ;
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \subsection{Defining functions by their expression}
+%
+% \begin{variable}{\l_@@_function_arg_int}
+%   Labels the arguments of a function being defined.
+%    \begin{macrocode}
+\int_new:N \l_@@_function_arg_int
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\fp_set_function:nnn}
+% \begin{macro}{\@@_set_function:Nnnn}
+%   \begin{syntax}
+%     \cs{fp_set_function:nnn} \Arg{identifier}
+%       \Arg{comma-list of variables} \Arg{expression}
+%   \end{syntax}
+%   Defines the \meta{identifier} to stand for a function which expects
+%   some arguments defined by the \meta{comma-list of variables}, and
+%   evaluates to the \meta{expression}.
+%    \begin{macrocode}
+\cs_new_protected:Npn \fp_set_function:nnn #1
+  {
+    \exp_args:NNo \@@_set_function:Nnnn \cs_set_eq:cN
+      { \tl_to_str:n {#1} }
+  }
+\cs_new_protected:Npn \@@_set_function:Nnnn #1#2#3#4
+  {
+    \@@_id_if_invalid:nTF {#2}
+      { \msg_error:nnn { fp } { invalid-identifier } {#2} }
+      {
+        \cs_if_exist:cF { @@_parse_word_#2:N }
+          { \@@_function_set_parsing:Nn \cs_set_eq:NN {#2} }
+        \group_begin:
+          \int_zero:N \l_@@_function_arg_int
+          \exp_args:No \clist_map_inline:nn { \tl_to_str:n {#3} }
+            {
+              \int_incr:N \l_@@_function_arg_int
+              \exp_args:Nx \@@_clear_variable:n
+                { _ \tex_romannumeral:D \l_@@_function_arg_int }
+              \fp_clear_variable:n {##1}
+              \cs_set_nopar:cpx { l_@@_variable_##1_fp }
+                {
+                  \exp_not:N \s__fp_symbolic
+                  \exp_not:N \@@_symbolic_chk:w
+                  \exp_not:N \@@_function_arg_o:w
+                  \int_use:N \l_@@_function_arg_int
+                  ########1 , { } ;
+                }
+            }
+          \cs_set:Npn \@@_function_arg_o:w ##1 @
+            {
+              \exp_after:wN \s_@@_symbolic
+              \exp_after:wN \@@_symbolic_chk:w
+              \exp_after:wN \@@_function_arg_o:w
+              \tex_romannumeral:D
+              \@@_exp_after_symbolic_loop:N ##1
+                { , \tex_romannumeral:D \use_none:nn }
+              \exp_after:wN \c_zero_int
+              \exp_after:wN { \exp_after:wN } \exp_after:wN ;
+            }
+          \fp_set:Nn \l_@@_symbolic_fp {#4}
+          \use:x
+            {
+              \exp_not:n { \cs_gset:Npn \@@_tmp:w ##1 }
+                { \exp_not:o { \l_@@_symbolic_fp } }
+            }
+          \use:x
+            {
+              \exp_not:n { \cs_gset:Npn \@@_tmp:w ##1 @ }
+                {
+                  \exp_not:N \@@_exp_after_symbolic_f:nw
+                  \exp_not:n { { \exp_after:wN \exp_stop_f: } }
+                  \exp_not:o { \@@_tmp:w { . , {##1} } }
+                }
+            }
+        \group_end:
+        #1 { @@_#2_o:w } \@@_tmp:w
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+%   {
+%     \@@_function_arg_o:w,
+%     \@@_function_arg_few:w,
+%     \@@_function_arg_get:w
+%   }
+%    \begin{macrocode}
+\cs_new:Npn \@@_function_arg_o:w #1. #2
+  {
+    \if_meaning:w @ #2
+      \exp_after:wN \@@_function_arg_few:w
+    \fi:
+    \if_int_compare:w #1 = \c_one_int
+      \exp_after:wN \@@_function_arg_get:w% \begin{macro}[added = 2023-07-05]{\fp_clear_variable:n}
+%   \begin{syntax}
+%     \cs{fp_clear_variable:n} \Arg{identifier}
+%   \end{syntax}
+%   Removes any value given by \cs{fp_set_variable:nn} to the variable
+%   with this \meta{identifier}.  For instance,
+%   \begin{quote}
+%     \cs{fp_new_variable:n} |{ A }|
+%     \cs{fp_set_variable:nn} |{ A } { 3 }|
+%     \cs{fp_show:n} |{ A ^ 2 }|
+%     \cs{fp_clear_variable:n} |{ A }|
+%     \cs{fp_show:n} |{ A ^ 2 }|
+%   \end{quote}
+%   shows~|9|, then~|(A^2)|.
+% \end{macro}
+    \fi:
+    \@@_use_i_until_s:nw
+      {
+        \exp_after:wN \@@_function_arg_o:w
+        \int_value:w \int_eval:n { #1 - 1 } .
+      }
+      #2
+  }
+\cs_new:Npn \@@_function_arg_few:w #1 @ { \exp_after:wN \c_nan_fp }
+\cs_new:Npn \@@_function_arg_get:w #1#2#3; #4 @
+  {
+    \@@_exp_after_array_f:w #3; \s_@@_expr_stop
+    \exp_after:wN \exp_stop_f:
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\fp_clear_function:n}
+% \begin{macro}{\@@_clear_function:n}
+%    \begin{macrocode}
+\cs_new_protected:Npn \fp_clear_function:n #1
+  { \exp_args:No \@@_clear_function:n { \tl_to_str:n {#1} } }
+\cs_new_protected:Npn \@@_clear_function:n #1
+  {
+    \cs_undefine:c { @@_parse_word_ #1 :N }
+    \@@_function_set_parsing:Nn \cs_set_eq:NN {#1}
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% ^^A todo: add check for number of args
+%
+%    \begin{macrocode}
+%</package>
+%    \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/l3kernel/l3fp.dtx b/l3kernel/l3fp.dtx
index fb573e783..322215bae 100644
--- a/l3kernel/l3fp.dtx
+++ b/l3kernel/l3fp.dtx
@@ -739,6 +739,56 @@
 %   shows~|9|, then~|(A^2)|.
 % \end{function}
 %
+% \subsection{User-defined functions}
+%
+% It is possible to define new user functions which can be used inside
+% the argument to \cs{fp_eval:n}, etc. These functions may take one or
+% more named arguments, and should be implemented using expansion methods
+% only.
+%
+% \begin{function}[added = 2023-07-05]{\fp_new_function:n}
+%   \begin{syntax}
+%     \cs{fp_new_function:n} \Arg{identifier}
+%   \end{syntax}
+%   Declares the \meta{identifier} as a function, which allows it to be
+%   used in floating point expressions.  For instance,
+%   \begin{quote}
+%      \cs{fp_new_function:n} |{ foo }| \\
+%      \cs{fp_show:n} |{ foo ( 1 + 2 , foo(3), A ) ** 2 } }|
+%   \end{quote}
+%   shows |(foo(3, foo(3), A))^(2)|.  If the declaration was missing,
+%   the parser would complain about an \enquote{\texttt{Unknown fp word 'A'}}.
+%   The \meta{identifier} must consist entirely of Latin letters |[a-zA-Z]|.
+% \end{function}
+%
+% \begin{function}[added = 2023-07-05]{\fp_set_function:nnn}
+%   \begin{syntax}
+%     \cs{fp_set_function:nnn} \Arg{identifier} \Arg{vars} \Arg{fpexpr}
+%   \end{syntax}
+%   Defines the \meta{identifier} to stand in any further expression for
+%   the result of evaluating the \meta{floating point expression}, with
+%   the \meta{identifier} accepting the \meta{vars} (a comma list).
+%   The result may contain other functions, which are
+%   then replaced by their results if they have any.  For instance,
+%   \begin{quote}
+%     \cs{fp_new_function:n} |{ foo }| \\
+%     \cs{fp_set_function:nnn} |{ npow } { a,b } { a**b }| \\
+%     \cs{fp_show:n} |{ npow(16,0.25) } }|
+%   \end{quote}
+%   shows |2|. The names of the \meta{vars} must
+%   consist entirely of Latin letters |[a-zA-Z]|, but are otherwise not
+%   restricted: in particular, they are independent of any variables
+%   declared by \cs{fp_new_variable:n}.
+% \end{function}
+%
+% \begin{function}[added = 2023-07-05]{\fp_clear_function:n}
+%   \begin{syntax}
+%     \cs{fp_clear_function:n} \Arg{identifier}
+%   \end{syntax}
+%   Removes any definition given by \cs{fp_set_function:nnn} to the function
+%   with this \meta{identifier}.
+% \end{function}
+%
 % \section{Some useful constants, and scratch variables}
 %
 % \begin{variable}[added = 2012-05-08, module = fp]{\c_zero_fp, \c_minus_zero_fp}
diff --git a/l3kernel/testfiles/m3fp-functions001.lvt b/l3kernel/testfiles/m3fp-functions001.lvt
new file mode 100644
index 000000000..de0fb5099
--- /dev/null
+++ b/l3kernel/testfiles/m3fp-functions001.lvt
@@ -0,0 +1,50 @@
+%
+% Copyright (C) The LaTeX Project
+%
+
+\documentclass{minimal}
+\input{regression-test}
+
+\ExplSyntaxOn
+\debug_on:n { check-declarations , deprecation , log-functions }
+\ExplSyntaxOff
+
+\begin{document}
+\START
+\AUTHOR{Bruno Le Floch}
+\ExplSyntaxOn
+
+\OMIT
+\fp_new_variable:n { A }
+\fp_new_variable:n { B }
+\TIMO
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\TEST { Declaring~a~function }
+  {
+    \fp_new_function:n { foo }
+    \iow_term:x { \fp_to_tl:n { foo ( 1 + 2 , foo(3), A ) ** 2 } }
+  }
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\TEST { Defining~fourthroot }
+  {
+    \fp_set_function:nnn { fourthroot } { a } { a**.25 }
+    \fp_set_variable:nn { a } { pi } % does not affect results
+    \iow_term:x { \fp_to_tl:n { fourthroot(16) } }
+    \iow_term:x { \fp_to_tl:n { fourthroot(.0625) } }
+    \iow_term:x { \fp_to_tl:n { fourthroot(B) } }
+    \iow_term:x { \fp_to_tl:n { fourthroot(1,2) } }
+  }
+
+\TEST { Defining~npow }
+  {
+    \fp_set_function:nnn { npow } { a,b } { a**b }
+    \iow_term:x { \fp_to_tl:n { npow(16,0.25) } }
+  }
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\END
diff --git a/l3kernel/testfiles/m3fp-functions001.tlg b/l3kernel/testfiles/m3fp-functions001.tlg
new file mode 100644
index 000000000..1dc7f2fdf
--- /dev/null
+++ b/l3kernel/testfiles/m3fp-functions001.tlg
@@ -0,0 +1,31 @@
+This is a generated file for the LaTeX (2e + expl3) validation system.
+Don't change this file in any respect.
+Author: Bruno Le Floch
+============================================================
+TEST 1: Declaring a function
+============================================================
+Defining \__fp_parse_word_foo:N on line ...
+(foo(3, foo(3), A))^(2)
+============================================================
+============================================================
+TEST 2: Defining fourthroot
+============================================================
+Defining \__fp_parse_word_fourthroot:N on line ...
+Defining \__fp_parse_word__i:N on line ...
+Defining \__fp_parse_word_a:N on line ...
+Defining \__fp_parse_word_a:N on line ...
+2
+0.5
+(1.)^(0.25)
+1
+============================================================
+============================================================
+TEST 3: Defining npow
+============================================================
+Defining \__fp_parse_word_npow:N on line ...
+Defining \__fp_parse_word__i:N on line ...
+Defining \__fp_parse_word_a:N on line ...
+Defining \__fp_parse_word__ii:N on line ...
+Defining \__fp_parse_word_b:N on line ...
+2
+============================================================
diff --git a/l3trial/l3fp-extras/l3fp-extras.ins b/l3trial/l3fp-extras/l3fp-extras.ins
index 7f5af3703..35c8f8439 100644
--- a/l3trial/l3fp-extras/l3fp-extras.ins
+++ b/l3trial/l3fp-extras/l3fp-extras.ins
@@ -41,7 +41,6 @@ Do not distribute a modified version of this file.
       {%
         \from{l3fp-extras.dtx}{package}%
         \from{l3fp-types-extras.dtx}{package}%
-        \from{l3fp-functions.dtx}{package}%
         \from{l3fp-interchange.dtx}{package}%
       }%
   }
diff --git a/l3trial/l3fp-extras/l3fp-functions.dtx b/l3trial/l3fp-extras/l3fp-functions.dtx
deleted file mode 100644
index 5d61c8199..000000000
--- a/l3trial/l3fp-extras/l3fp-functions.dtx
+++ /dev/null
@@ -1,378 +0,0 @@
-% \iffalse
-%
-%% File l3fp-functions.dtx (C) Copyright 2012-2018,2020,2021,2023 The LaTeX 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 "l3trial bundle" (The Work in LPPL)
-% and all files in that bundle must be distributed together.
-%
-% -----------------------------------------------------------------------
-%
-% The development version of the bundle can be found at
-%
-%    https://github.com/latex3/latex3
-%
-% for those people who are interested.
-%
-%<*driver|package>
-\RequirePackage{expl3}
-%</driver|package>
-%<*driver>
-\documentclass[full]{l3doc}
-\usepackage{amsmath}
-\begin{document}
-  \DocInput{\jobname.dtx}
-\end{document}
-%</driver>
-% \fi
-%
-% \title{^^A
-%   The \pkg{l3fp-functions} package\\ Floating point functions^^A
-% }
-%
-% \author{^^A
-%  The \LaTeX{} Project\thanks
-%    {^^A
-%      E-mail:
-%        \href{mailto:latex-team at latex-project.org}
-%          {latex-team at latex-project.org}^^A
-%    }^^A
-% }
-%
-% \date{Released 2018-04-30}
-%
-% \maketitle
-%
-% \begin{documentation}
-%
-% \end{documentation}
-%
-% \begin{implementation}
-%
-% \section{\pkg{l3fp-functions} implementation}
-%
-%    \begin{macrocode}
-%<*package>
-%    \end{macrocode}
-%
-%    \begin{macrocode}
-%<@@=fp>
-%    \end{macrocode}
-%
-% \subsection{Previously in \pkg{l3fp}: defining new \pkg{l3fp} functions}
-%
-% \begin{macro}[EXP]{\fp_function:Nw}
-%   Parse the argument of the function~|#1| using
-%   \cs{@@_parse_operand:Nw} with a precedence of~$16$, and pass the
-%   function and argument to \cs{@@_function_apply:nw}.
-%    \begin{macrocode}
-\cs_new:Npn \fp_function:Nw #1
-  {
-    \exp_after:wN \@@_function_apply:nw
-    \exp_after:wN #1
-    \exp:w
-      \@@_parse_operand:Nw \c_@@_prec_func_int \@@_parse_expand:w
-  }
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\fp_new_function:Npn}
-% \begin{macro}{\@@_new_function:NNnnn, \@@_new_function:Ncfnn}
-% \begin{macro}{\@@_function_args:Nwn}
-%   Save the code provided by the user in the control sequence
-%   |\__fp_user_#1|.  Define |#1| to call \cs{@@_function_apply:nw}
-%   after parsing one operand using \cs{@@_parse_operand:Nw} with
-%   precedence~$16$.  The auxiliary \cs{@@_function_args:Nwn} receives
-%   the user function and the number of arguments (half of the number of
-%   tokens in the parameter text~|#2|), followed by the operand (as a
-%   token list of floating points).  It checks the number of arguments,
-%   and applies the user function to the arguments (without the outer
-%   brace group).
-%    \begin{macrocode}
-\cs_new_protected:Npn \fp_new_function:Npn #1#2#
-  {
-    \@@_new_function:Ncfnn #1
-      { @@_user_ \cs_to_str:N #1 }
-      { \int_eval:n { \tl_count:n {#2} / 2 } }
-      {#2}
-  }
-\cs_new_protected:Npn \@@_new_function:NNnnn #1#2#3#4#5
-  {
-    \cs_new:Npn #1
-      {
-        \exp_after:wN \@@_function_apply:nw \exp_after:wN
-          {
-            \exp_after:wN \@@_function_args:Nwn
-            \exp_after:wN #2
-            \int_value:w #3 \exp_after:wN ; \exp_after:wN
-          }
-        \exp:w
-          \@@_parse_operand:Nw \c_@@_prec_func_int \@@_parse_expand:w
-      }
-    \cs_new:Npn #2 #4 {#5}
-  }
-\cs_generate_variant:Nn \@@_new_function:NNnnn { Ncf }
-\cs_new:Npn \@@_function_args:Nwn #1#2; #3
-  {
-    \int_compare:nNnTF { \tl_count:n {#3} } = {#2}
-      { #1 #3 }
-      {
-        \msg_expandable_error:nnnnn
-          { fp } { num-args } { #1() } {#2} {#2}
-        \c_nan_fp
-      }
-  }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]
-%   {
-%     \@@_function_apply:nw,
-%     \@@_function_store:wwNwnn,
-%     \@@_function_store_end:wnnn
-%   }
-%   The auxiliary \cs{@@_function_apply:nw} is called after parsing an
-%   operand, so it receives some code~|#1|, then the operand ending
-%   with~|@|, then a function such as \cs{@@_parse_infix_+:N} (but not
-%   always of this form, see comparisons for instance).  Package the
-%   operand (an array) into a token list with floating point items: this
-%   is the role of \cs{@@_function_store:wwNwnn} and
-%   \cs{@@_function_store_end:wnnn}.  Then apply \cs{@@_parse:n} to the
-%   code~|#1| followed by a brace group with this token list.  This
-%   results in a floating point result, which is then correctly parsed
-%   as the next operand of whatever was looking for one.  The trailing
-%   \cs{s_@@_expr_mark} is used as a special infix operator to indicate
-%   that the next token has already gone through \cs{@@_parse_infix:NN}.
-%    \begin{macrocode}
-\cs_new:Npn \@@_function_apply:nw #1#2 @
-  {
-    \@@_parse:n
-      {
-        \@@_function_store:wwNwnn #2
-          \s_@@_expr_mark \@@_function_store:wwNwnn ;
-          \s_@@_expr_mark \@@_function_store_end:wnnn
-        \s_@@_expr_stop { } { } {#1}
-      }
-    \s_@@_expr_mark
-  }
-\cs_new:Npn \@@_function_store:wwNwnn
-    #1; #2 \s_@@_expr_mark #3#4 \s_@@_expr_stop #5#6
-  { #3 #2 \s_@@_expr_mark #3#4 \s_@@_expr_stop { #5 #6 } { { #1; } } }
-\cs_new:Npn \@@_function_store_end:wnnn
-    #1 \s_@@_expr_stop #2#3#4
-  { #4 {#2} }
-%    \end{macrocode}
-% \end{macro}
-%
-% \subsection{Declaring functions}
-%
-% \begin{macro}{\fp_new_function:n}
-% \begin{macro}{\@@_new_function:n}
-%    \begin{macrocode}
-\cs_new_protected:Npn \fp_new_function:n #1
-  { \exp_args:No \@@_new_function:n { \tl_to_str:n {#1} } }
-\cs_new_protected:Npn \@@_new_function:n #1
-  {
-    \@@_id_if_invalid:nTF {#1}
-      { \msg_error:nnn { fp } { invalid-identifier } {#1} }
-      {
-        \cs_if_exist:cT { @@_parse_word_#1:N }
-          {
-            \msg_error:nnn
-              { fp } { id-already-defined } {#1}
-            \cs_undefine:c { @@_parse_word_#1:N }
-            \cs_undefine:c { @@_#1_o:w }
-          }
-        \@@_function_set_parsing:Nn \cs_gset_eq:NN {#1}
-      }
-  }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-%   {\@@_function_set_parsing:Nn, \@@_function_set_parsing_aux:NNn}
-%    \begin{macrocode}
-\cs_new:Npn \@@_function_set_parsing:Nn #1#2
-  {
-    \exp_args:NNc \@@_function_set_parsing_aux:NNn #1
-      { @@_parse_word_#2:N } {#2}
-  }
-\cs_new:Npn \@@_function_set_parsing_aux:NNn #1#2#3
-  {
-    \cs_set:Npx \@@_tmp:w
-      {
-        \exp_not:N \@@_parse_function:NNN
-        \exp_not:N \@@_function_o:w
-        \exp_not:c { @@_#3_o:w }
-      }
-    \cs_if_eq:NNF #2 \@@_tmp:w
-      {
-        \cs_if_exist:NTF #2
-          {
-            \msg_warning:nnnn
-              { fp } { id-used-elsewhere } {#3} { function }
-            #1 #2 \@@_tmp:w
-          }
-          {
-            \cs_new_eq:NN #2 \scan_stop: % to declare the function
-            #1 #2 \@@_tmp:w
-          }
-      }
-  }
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_function_o:w}
-%    \begin{macrocode}
-\cs_new:Npn \@@_function_o:w #1#2 @
-  {
-    \cs_if_exist:NTF #1
-      { #1 #2 @ }
-      {
-        \exp_after:wN \s_@@_symbolic
-        \exp_after:wN \@@_symbolic_chk:w
-        \exp_after:wN \@@_function_o:w
-        \exp_after:wN #1
-        \exp_after:wN ,
-        \exp_after:wN {
-          \exp:w \exp_end_continue_f:w
-          \@@_exp_after_array_f:w #2 \s_@@_expr_stop
-          \exp_after:wN
-        }
-        \exp_after:wN ;
-      }
-  }
-%    \end{macrocode}
-% \end{macro}
-%
-% \subsection{Defining functions by their expression}
-%
-% \begin{variable}{\l_@@_function_arg_int}
-%   Labels the arguments of a function being defined.
-%    \begin{macrocode}
-\int_new:N \l_@@_function_arg_int
-%    \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}{\fp_set_function:nnn}
-% \begin{macro}{\@@_set_function:Nnnn}
-%   \begin{syntax}
-%     \cs{fp_set_function:nnn} \Arg{identifier}
-%       \Arg{comma-list of variables} \Arg{expression}
-%   \end{syntax}
-%   Defines the \meta{identifier} to stand for a function which expects
-%   some arguments defined by the \meta{comma-list of variables}, and
-%   evaluates to the \meta{expression}.
-%    \begin{macrocode}
-\cs_new_protected:Npn \fp_set_function:nnn #1
-  {
-    \exp_args:NNo \@@_set_function:Nnnn \cs_set_eq:cN
-      { \tl_to_str:n {#1} }
-  }
-\cs_new_protected:Npn \@@_set_function:Nnnn #1#2#3#4
-  {
-    \@@_id_if_invalid:nTF {#2}
-      { \msg_error:nnn { fp } { invalid-identifier } {#2} }
-      {
-        \cs_if_exist:cF { @@_parse_word_#2:N }
-          { \@@_function_set_parsing:Nn \cs_set_eq:NN {#2} }
-        \group_begin:
-          \int_zero:N \l_@@_function_arg_int
-          \exp_args:No \clist_map_inline:nn { \tl_to_str:n {#3} }
-            {
-              \int_incr:N \l_@@_function_arg_int
-              \exp_args:Nx \@@_clear_variable:n
-                { _ \tex_romannumeral:D \l_@@_function_arg_int }
-              \fp_clear_variable:n {##1}
-              \cs_set_nopar:cpx { l_@@_variable_##1_fp }
-                {
-                  \exp_not:N \s__fp_symbolic
-                  \exp_not:N \@@_symbolic_chk:w
-                  \exp_not:N \@@_function_arg_o:w
-                  \int_use:N \l_@@_function_arg_int
-                  ########1 , { } ;
-                }
-            }
-          \cs_set:Npn \@@_function_arg_o:w ##1 @
-            {
-              \exp_after:wN \s_@@_symbolic
-              \exp_after:wN \@@_symbolic_chk:w
-              \exp_after:wN \@@_function_arg_o:w
-              \tex_romannumeral:D
-              \@@_exp_after_symbolic_loop:N ##1
-                { , \tex_romannumeral:D \use_none:nn }
-              \exp_after:wN \c_zero_int
-              \exp_after:wN { \exp_after:wN } \exp_after:wN ;
-            }
-          \fp_set:Nn \l_@@_symbolic_fp {#4}
-          \use:x
-            {
-              \exp_not:n { \cs_gset:Npn \@@_tmp:w ##1 }
-                { \exp_not:o { \l_@@_symbolic_fp } }
-            }
-          \use:x
-            {
-              \exp_not:n { \cs_gset:Npn \@@_tmp:w ##1 @ }
-                {
-                  \exp_not:N \@@_exp_after_symbolic_f:nw
-                  \exp_not:n { { \exp_after:wN \exp_stop_f: } }
-                  \exp_not:o { \@@_tmp:w { . , {##1} } }
-                }
-            }
-        \group_end:
-        #1 { @@_#2_o:w } \@@_tmp:w
-      }
-  }
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]
-%   {
-%     \@@_function_arg_o:w,
-%     \@@_function_arg_few:w,
-%     \@@_function_arg_get:w
-%   }
-%    \begin{macrocode}
-\cs_new:Npn \@@_function_arg_o:w #1. #2
-  {
-    \if_meaning:w @ #2
-      \exp_after:wN \@@_function_arg_few:w
-    \fi:
-    \if_int_compare:w #1 = \c_one_int
-      \exp_after:wN \@@_function_arg_get:w
-    \fi:
-    \@@_use_i_until_s:nw
-      {
-        \exp_after:wN \@@_function_arg_o:w
-        \int_value:w \int_eval:n { #1 - 1 } .
-      }
-      #2
-  }
-\cs_new:Npn \@@_function_arg_few:w #1 @ { \exp_after:wN \c_nan_fp }
-\cs_new:Npn \@@_function_arg_get:w #1#2#3; #4 @
-  {
-    \@@_exp_after_array_f:w #3; \s_@@_expr_stop
-    \exp_after:wN \exp_stop_f:
-  }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% ^^A todo: add check for number of args
-%
-%    \begin{macrocode}
-%</package>
-%    \end{macrocode}
-%
-% \end{implementation}
-%
-% \PrintIndex
diff --git a/l3trial/l3fp-extras/testfiles/m3fp-functions001.lvt b/l3trial/l3fp-extras/testfiles/m3fp-functions001.lvt
deleted file mode 100644
index 536132567..000000000
--- a/l3trial/l3fp-extras/testfiles/m3fp-functions001.lvt
+++ /dev/null
@@ -1,52 +0,0 @@
-%
-% Copyright (C) The LaTeX Project
-%
-
-\documentclass{minimal}
-\input{regression-test}
-
-\RequirePackage{expl3}
-\RequirePackage{l3fp-extras}
-\ExplSyntaxOn
-\debug_on:n { check-declarations , deprecation , log-functions }
-\ExplSyntaxOff
-
-\begin{document}
-\START
-\AUTHOR{Bruno Le Floch}
-\ExplSyntaxOn
-
-\OMIT
-\fp_new_variable:n { A }
-\fp_new_variable:n { B }
-\TIMO
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\TEST { Declaring~a~function }
-  {
-    \fp_new_function:n { foo }
-    \iow_term:x { \fp_to_tl:n { foo ( 1 + 2 , foo(3), A ) ** 2 } }
-  }
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\TEST { Defining~fourthroot }
-  {
-    \fp_set_function:nnn { fourthroot } { a } { a**.25 }
-    \fp_set_variable:nn { a } { pi } % does not affect results
-    \iow_term:x { \fp_to_tl:n { fourthroot(16) } }
-    \iow_term:x { \fp_to_tl:n { fourthroot(.0625) } }
-    \iow_term:x { \fp_to_tl:n { fourthroot(B) } }
-    \iow_term:x { \fp_to_tl:n { fourthroot(1,2) } }
-  }
-
-\TEST { Defining~npow }
-  {
-    \fp_set_function:nnn { npow } { a,b } { a**b }
-    \iow_term:x { \fp_to_tl:n { npow(16,0.25) } }
-  }
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\END
diff --git a/l3trial/l3fp-extras/testfiles/m3fp-functions001.tlg b/l3trial/l3fp-extras/testfiles/m3fp-functions001.tlg
deleted file mode 100644
index 1dc7f2fdf..000000000
--- a/l3trial/l3fp-extras/testfiles/m3fp-functions001.tlg
+++ /dev/null
@@ -1,31 +0,0 @@
-This is a generated file for the LaTeX (2e + expl3) validation system.
-Don't change this file in any respect.
-Author: Bruno Le Floch
-============================================================
-TEST 1: Declaring a function
-============================================================
-Defining \__fp_parse_word_foo:N on line ...
-(foo(3, foo(3), A))^(2)
-============================================================
-============================================================
-TEST 2: Defining fourthroot
-============================================================
-Defining \__fp_parse_word_fourthroot:N on line ...
-Defining \__fp_parse_word__i:N on line ...
-Defining \__fp_parse_word_a:N on line ...
-Defining \__fp_parse_word_a:N on line ...
-2
-0.5
-(1.)^(0.25)
-1
-============================================================
-============================================================
-TEST 3: Defining npow
-============================================================
-Defining \__fp_parse_word_npow:N on line ...
-Defining \__fp_parse_word__i:N on line ...
-Defining \__fp_parse_word_a:N on line ...
-Defining \__fp_parse_word__ii:N on line ...
-Defining \__fp_parse_word_b:N on line ...
-2
-============================================================
diff --git a/l3trial/l3fp-extras/testfiles/m3fp-functions002.lvt b/l3trial/l3fp-extras/testfiles/m3fp-functions002.lvt
deleted file mode 100644
index bbada7f76..000000000
--- a/l3trial/l3fp-extras/testfiles/m3fp-functions002.lvt
+++ /dev/null
@@ -1,88 +0,0 @@
-%
-% Copyright (C) The LaTeX Project
-%
-
-\documentclass{minimal}
-\input{regression-test}
-
-\RequirePackage{expl3}
-\RequirePackage{l3fp-extras}
-\ExplSyntaxOn
-\debug_on:n { check-declarations , deprecation , log-functions }
-\ExplSyntaxOff
-
-\begin{document}
-\START
-\AUTHOR{Bruno Le Floch}
-\ExplSyntaxOn
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\OMIT
-\cs_new_nopar:Npn \log:w
-  { \fp_function:Nw \__log:n }
-\cs_new:Npn \__log:n #1
-  {
-    \int_case:nnF { \tl_count:n {#1} }
-      {
-        { 1 } { \__log_aux:nn #1 { 10 } }
-        { 2 } { \__log_aux:nn #1 }
-      }
-      { \ERROR \c_nan_fp }
-  }
-\cs_new:Npn \__log_aux:nn #1#2 { ln(#1) / ln(#2) }
-\TIMO
-\TESTEXP { fp_function:Nw }
-  {
-    \fp_to_tl:n { \log:w (8, 2) ** 2 + \log:w (1e11) } \NEWLINE
-    \fp_to_tl:n { \log:w (1, 2, 3) } \NEWLINE
-    \fp_to_tl:n { \log:w (1sp, 2) } \NEWLINE
-  }
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\TEST { fp_new_function:Npn }
-  {
-    \fp_new_function:Npn \sqrt:w #1 { #1^.5 }
-    \fp_new_function:Npn \veclen:w #1#2
-      { \sqrt:w ( #1^2 + #2^2 ) }
-    \fp_log:n { \veclen:w ( 42 / 7 , 2 * 4 - 0 ) }
-    \fp_log:n { \veclen:w ( -1 , \c_minus_inf_fp ) }
-  }
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\OMIT
-\cs_new_nopar:Npn \veclenii:w
-  { \fp_function:Nw \__veclenii:n }
-\cs_new:Npn \__veclenii:n #1
-  { \sqrt:w ( \tl_map_function:nN {#1} \__veclenii_aux:n ) }
-\cs_new:Npn \__veclenii_aux:n #1 { + #1^2 }
-\TIMO
-\TESTEXP { Vector~length }
-  {
-    \fp_to_tl:n { \veclenii:w ( -1 ) }
-    \NEWLINE
-    \fp_to_tl:n
-      { \veclenii:w ( -1 \prg_replicate:nn { 8 } { , -1 } ) }
-    \NEWLINE
-    \fp_to_tl:n
-      {
-        \veclenii:w
-          ( 0 \int_step_function:nnN { 10 } { 20 } , )
-      }
-    \NEWLINE
-  }
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\OMIT
-\cs_new_nopar:Npn \first:w { \fp_function:Nw \__first:n }
-\cs_new:Npn \__first:n #1 { 1 + \tl_head:n { #1 \c_nan_fp } - 1 }
-\TIMO
-\TESTEXP { fp_function:Nw }
-  {
-    \fp_to_tl:n { \first:w (1, 2, 3) } \NEWLINE
-    \fp_to_tl:n
-      { \first:w 8 = \first:w (4, 2) * 2 ? \first:w (3, 7) : 5 }
-    \NEWLINE
-    \fp_to_tl:n { 2 ** \first:w 3 ** 2 } \NEWLINE
-  }
-
-\END
diff --git a/l3trial/l3fp-extras/testfiles/m3fp-functions002.tlg b/l3trial/l3fp-extras/testfiles/m3fp-functions002.tlg
deleted file mode 100644
index dbb34a275..000000000
--- a/l3trial/l3fp-extras/testfiles/m3fp-functions002.tlg
+++ /dev/null
@@ -1,43 +0,0 @@
-This is a generated file for the LaTeX (2e + expl3) validation system.
-Don't change this file in any respect.
-Author: Bruno Le Floch
-============================================================
-TEST 1: fp_function:Nw
-============================================================
-! Undefined control sequence.
-<argument> \ERROR 
-                  \c_nan_fp 
-l. ...  }
-The control sequence at the end of the top line
-of your error message was never \def'ed. If you have
-misspelled it (e.g., `\hobx'), type `I' and the correct
-spelling (e.g., `I\hbox'). Otherwise just continue,
-and I'll forget about whatever was undefined.
-20
-nan
--15.99999999999999
-============================================================
-============================================================
-TEST 2: fp_new_function:Npn
-============================================================
-Defining \sqrt:w on line ...
-Defining \__fp_user_sqrt:w on line ...
-Defining \veclen:w on line ...
-Defining \__fp_user_veclen:w on line ...
-> \veclen:w (42/7,2*4-0)=10.
-> \veclen:w (-1,\c_minus_inf_fp )=inf.
-============================================================
-============================================================
-TEST 3: Vector length
-============================================================
-1
-3
-50.84289527554465
-============================================================
-============================================================
-TEST 4: fp_function:Nw
-============================================================
-1
-3
-512
-============================================================





More information about the latex3-commits mailing list.