[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.