diff options
author | Karl Berry <karl@freefriends.org> | 2023-10-24 17:51:37 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2023-10-24 17:51:37 +0000 |
commit | 0bfadba8b4e7062c64d16b4ff197dd8adaa54be5 (patch) | |
tree | 1b646413f7f5827654e1c48ff82bf11c061dfa7d /Master/texmf-dist/source/latex | |
parent | 640cf00679c57a79632e597d833d3197aeb9e045 (diff) |
l3kernel (23oct23)
git-svn-id: svn://tug.org/texlive/trunk@68632 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex')
61 files changed, 2227 insertions, 801 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx index ea13fbeacf1..09e21e47109 100644 --- a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx @@ -24,7 +24,7 @@ % %<*driver|generic|package|2ekernel> %</driver|generic|package|2ekernel> -\def\ExplFileDate{2023-10-10}% +\def\ExplFileDate{2023-10-23}% %<*driver> \documentclass[full]{l3doc} \usepackage{graphicx} @@ -51,7 +51,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -311,9 +311,8 @@ % or private. % % To allow clear separation of these two cases, the following convention -% is used. In private functions and variables, two |_| characters are -% added to the start of the module name. On the other hand, public -% interfaces to not have these two |_| character. Thus +% is used. To denote a private function or a private variable (of the module), +% two |_| characters are used in front of the module name, e.g. % \begin{verbatim} % \module_foo:nnn % \end{verbatim} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3.ins b/Master/texmf-dist/source/latex/l3kernel/l3.ins index 52c65e4c8e2..24f11d8f7b6 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3.ins +++ b/Master/texmf-dist/source/latex/l3kernel/l3.ins @@ -92,6 +92,9 @@ and all files in that bundle must be distributed together. \from{l3fp-trig.dtx} {package} \from{l3fp-convert.dtx} {package} \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/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx index 6b484105fe5..00e159d8176 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -1045,7 +1045,7 @@ % \end{texnote} % \end{function} % -% \begin{function}[EXP, added = 2018-06-18]{\use:e} +% \begin{function}[EXP, added = 2018-06-18, updated = 2023-07-05]{\use:e} % \begin{syntax} % \cs{use:e} \Arg{expandable tokens} % \end{syntax} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx index e300bccc67e..a42f358ae89 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx index dfa6b3c451e..57576531682 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx index 6e455b099c8..567969d5450 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx b/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx index 4192ec029a3..794b53b5f49 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx index 8fc2f6870bd..bd8082cf340 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx b/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx index 94824400de0..cf046706b69 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3color.dtx b/Master/texmf-dist/source/latex/l3kernel/l3color.dtx index 3d225b2d223..2cdf604d02c 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3color.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3color.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -330,7 +330,7 @@ % % \subsection{Coloring math mode material} % -% Coloring math mode material using \cs{color_select:nn(n)} has some restrictions +% Coloring math mode material using \cs[no-index]{color_select:nn(n)} has some restrictions % and often leads to spacing issues and/or poor input syntax. Avoiding generating % \tn{mathord} atoms whilst coloring only those parts of the input which are % required needs careful handling. The functionality here covers this important @@ -341,7 +341,7 @@ % \cs{color_math:nn} \Arg{color expression}\Arg{content} % \cs{color_math:nnn} \Arg{model(s)} \Arg{value(s)} \Arg{content} % \end{syntax} -% Works as for \cs{color_select:n(n)} but applies color only to the math mode +% Works as for \cs[no-index]{color_select:n(n)} but applies color only to the math mode % \meta{content}. The function does not generate a group and the \meta{content} % therefore retains its math atom states. Sub/superscripts are also properly % handled. diff --git a/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx b/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx index 8efdc986ccc..c351529d858 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx b/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx index c9564f4080a..98d8df40e54 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -549,6 +549,21 @@ % \end{macrocode} % \end{macro} % +% \subsection{Deprecated \pkg{l3text} functions} +% +% \begin{macro}[EXP]{\text_titlecase:n} +% \begin{macro}[EXP]{\text_titlecase:nn} +% \begin{macrocode} +\__kernel_patch_deprecation:nnNNpn { 2023-07-08 } { \text_titlecase_first:n } +\cs_gset:Npn \text_titlecase:n #1 + { \text_titlecase_first:n { \text_lowercase:n {#1} } } +\__kernel_patch_deprecation:nnNNpn { 2023-07-08 } { \text_titlecase_first:nn } +\cs_gset:Npn \text_titlecase:nn #1#2 + { \text_titlecase_first:nn {#1} { \text_lowercase:n {#2} } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \subsection{Deprecated \pkg{l3tl} functions} % % \begin{macrocode} @@ -574,12 +589,12 @@ \__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_uppercase:nn } \cs_gset:Npn \tl_upper_case:nn #1#2 { \text_uppercase:nn {#1} {#2} } -\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase:n } +\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase_first:n } \cs_gset:Npn \tl_mixed_case:n #1 - { \text_titlecase:n {#1} } -\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase:nn } + { \text_titlecase_first:n {#1} } +\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase_first:nn } \cs_gset:Npn \tl_mixed_case:nn #1#2 - { \text_titlecase:nn {#1} {#2} } + { \text_titlecase_first:nn {#1} {#2} } % \end{macrocode} % \end{macro} % @@ -608,7 +623,7 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[EXP]{\char_to_nfd:Nm, \char_to_nfd:n} +% \begin{macro}[EXP]{\char_to_nfd:N, \char_to_nfd:n} % \begin{macrocode} \__kernel_patch_deprecation:nnNNpn { 2022-10-09 } { \codepoint_to_nfd:n } \cs_gset:Npn \char_to_nfd:N #1 { \codepoint_to_nfd:n {`#1} } @@ -629,8 +644,8 @@ \cs_gset:Npn \char_lower_case:N { \text_lowercase:n } \__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_uppercase:n } \cs_gset:Npn \char_upper_case:N { \text_uppercase:n } -\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase:n } -\cs_gset:Npn \char_mixed_case:N { \text_titlecase:n } +\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase_first:n } +\cs_gset:Npn \char_mixed_case:N { \text_titlecase_first:n } \__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_casefold:n } \cs_gset:Npn \char_fold_case:N { \str_casefold:n } \__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_lowercase:n } diff --git a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx index ed675106ba1..789095d1046 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx @@ -85,7 +85,7 @@ and all files in that bundle must be distributed together. % require you to do updates, if the class changes.}} % % \author{\Team} -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % \maketitle % \tableofcontents % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx b/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx index df2b7c63abe..59bd089ae65 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx @@ -2,7 +2,7 @@ % %% File l3dosctrip.dtx % -% Copyright (C) 2012,2014-2023 The LaTeX Project +% Copyright (C) 2012-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 @@ -63,7 +63,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx index d4fe6b3a30a..3bf2bd61536 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx index 2d2ae6a183f..af83fe4e088 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx b/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx index 637da52ee78..278c71f27c1 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx index da05eafa395..17d75d10459 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % \maketitle % % \begin{documentation} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx index 3db65c9d29f..ccd5e63ac17 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx index 3c5ad9195bf..b79950c2677 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx @@ -2,7 +2,7 @@ % %% File: l3fp-basics.dtx % -% Copyright (C) 2011-2014,2016-2023 The LaTeX Project +% Copyright (C) 2011-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 @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx index 835f9c43414..70983272ddf 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx index 5ac216bf4c4..f0e691f310b 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx index b83b37335bd..e374e7e2881 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-functions.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-functions.dtx new file mode 100644 index 00000000000..a899f3493ae --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-functions.dtx @@ -0,0 +1,282 @@ +% \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@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2023-10-23} +% +% \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:Npe \@@_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:Ne \@@_clear_variable:n + { _ \tex_romannumeral:D \l_@@_function_arg_int } + \fp_clear_variable:n {##1} + \cs_set_nopar:cpe { 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:e + { + \exp_not:n { \cs_gset:Npn \@@_tmp:w ##1 } + { \exp_not:o { \l_@@_symbolic_fp } } + } + \use:e + { + \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} +% +% \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/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx index 2f439c2925b..5e98d6b62c2 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -163,7 +163,7 @@ % \end{macro} % \end{macro} % -% \begin{macro}[EXP]{\@@_compare_back_any:ww, \@@_compare_back:ww, \@@_compare_nan:w} +% \begin{macro}[EXP]{\@@_compare_back:ww, \@@_bcmp:ww, \@@_compare_back_any:ww, \@@_compare_nan:w} % \begin{quote} % \cs{@@_compare_back_any:ww} \meta{y} |;| \meta{x} |;| % \end{quote} @@ -178,6 +178,17 @@ % a different type, the highest type is a larger number. Finally, if % $y\leq 0$, then $x>y$, unless both are zero. % \begin{macrocode} +\cs_new:Npn \@@_compare_back:ww #1#2; #3#4; + { + \cs:w + @@ + \@@_type_from_scan:N #1 + _bcmp + \@@_type_from_scan:N #3 + :ww + \cs_end: + #1#2; #3#4; + } \cs_new:Npn \@@_compare_back_any:ww #1#2; #3 { \@@_if_type_fp:NTwFw @@ -195,7 +206,7 @@ } #1#2 ; #3 } -\cs_new:Npn \@@_compare_back:ww +\cs_new:Npn \@@_bcmp:ww \s_@@ \@@_chk:w #1 #2 #3; \s_@@ \@@_chk:w #4 #5 #6; { diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx index 418974d8263..58fc4f1f2a2 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx index 3e3b5cfdfc2..3cff0bdc1a1 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx index f0853f59995..901cb5ba340 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-symbolic.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-symbolic.dtx new file mode 100644 index 00000000000..277ecfabf55 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-symbolic.dtx @@ -0,0 +1,673 @@ +% \iffalse +% +%% File l3fp-symbolic.dtx (C) Copyright 2012-2015,2017,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-symbolic} package\\ Symbolic expressions^^A +% } +% +% \author{^^A +% The \LaTeX{} Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2023-10-23} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-symbolic} implementation} +% +% \begin{macrocode} +%<*package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{Misc} +% +% \begin{variable}{\l_@@_symbolic_fp} +% Scratch floating point. +% \begin{macrocode} +\fp_new:N \l_@@_symbolic_fp +% \end{macrocode} +% \end{variable} +% +% \subsection{Building blocks for expressions} +% +% Every symbolic expression has the form \cs{s_@@_symbolic} +% \cs{@@_symbolic_chk:w} \meta{operation} |,| \Arg{operands} \meta{junk} +% |;| where the \meta{operation} is a list of \texttt{N}-type tokens, +% the \meta{operands} is an array of floating point objects, and the +% \meta{junk} is to be discarded. If the outermost operator (last to be +% evaluated) is unary, the expression has the form +% \begin{quote} +% \cs{s_@@_symbolic} \cs{@@_symbolic_chk:w} \\ +% \cs{@@_types_unary:NNw} |\__fp_|\meta{op}|_o:w| \meta{token} |,| \\ +% |{| \meta{operand} |}| \meta{junk} |;| +% \end{quote} +% where the \meta{op} is a unary operation (|set_sign|, |cos|, +% \ldots{}), and the \meta{token} and \meta{operand} are used as +% arguments for \cs{@@_\meta{op}_o:w} (or the type-specific analog of +% this function). If the outermost operator is binary, the expression +% has the form +% \begin{quote} +% \cs{s_@@_symbolic} \cs{@@_symbolic_chk:w} \\ +% \cs{@@_types_binary:Nww} |\__fp_|\meta{op}|_o:ww| |,| \\ +% |{| \meta{operand_1} \meta{operand_2} |}| \meta{junk} |;| +% \end{quote} +% where the \meta{op} is an operation (|+|, |&|, \ldots{}), and +% |\__fp_|\meta{op}|_o:ww| receives the \meta{operands} as arguments. +% If the expression consists of a single variable, it is stored as +% \begin{quote} +% \cs{s_@@_symbolic} \cs{@@_symbolic_chk:w} \\ +% \cs{@@_variable_o:w} \meta{identifier} |,| \\ +% |{| |}| \meta{junk} |;| +% \end{quote} +% +% Symbolic expressions are stored in a prefix form. When encountering a +% symbolic expression in a floating point computation, we attempt to +% evaluate the operands as much as possible, and if that yields floating +% point numbers rather than expressions, we apply the operator which +% follows (if the function is known). +% +% For instance, the expression |a + b * sin(c)| is stored as +% \begin{verbatim} +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_types_binary:Nww \__fp_+_o:ww , +% { +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_variable_o:w a , { } ; +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_types_binary:Nww \__fp_*_o:ww , +% { +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_variable_o:w b , { } ; +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_types_unary:NNw \__fp_sin_o:w \use_i:nn , +% { +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_variable_o:w c , { } ; +% } ; +% } ; +% } ; +% \end{verbatim} +% +% \begin{variable}{\s_@@_symbolic} +% Scan mark indicating the start of a symbolic expression. +% \begin{macrocode} +\scan_new:N \s_@@_symbolic +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_symbolic_chk:w} +% Analog of \cs{@@_chk:w} for symbolic expressions. +% \begin{macrocode} +\cs_new_protected:Npn \@@_symbolic_chk:w #1,#2#3; + { + \msg_error:nne { fp } { misused-fp } + { + \@@_to_tl_dispatch:w + \s_@@_symbolic \@@_symbolic_chk:w #1,{#2}; + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Expanding after a symbolic expression} +% +% \begin{macro}[EXP] +% {\@@_if_has_symbolic:nTF, \@@_if_has_symbolic_aux:w} +% Tests if |#1| contains \cs{s_@@_symbolic} at top-level. This test +% should be precise enough to determine if a given an array contains a +% symbolic expression or only consists in floating points. Used in +% \cs{@@_exp_after_symbolic_f:nw}. +% \begin{macrocode} +\cs_new:Npn \@@_if_has_symbolic:nTF #1 + { + \@@_if_has_symbolic_aux:w + #1 \s_@@_mark \use_i:nn + \s_@@_symbolic \s_@@_mark \use_ii:nn + \s_@@_stop + } +\cs_new:Npn \@@_if_has_symbolic_aux:w + #1 \s_@@_symbolic #2 \s_@@_mark #3#4 \s_@@_stop { #3 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_exp_after_symbolic_f:nw} +% \begin{macro}[EXP] +% {\@@_exp_after_symbolic_aux:w, \@@_exp_after_symbolic_loop:N} +% This function does two things: trigger an \texttt{f}-expansion of +% the argument~|#1| after the following symbolic expression, and +% evaluate all pieces of the expression which can be evaluated. +% \begin{macrocode} +\cs_new:Npn \@@_exp_after_symbolic_f:nw + #1 \s_@@_symbolic \@@_symbolic_chk:w #2, #3#4; + { + \exp_after:wN \@@_exp_after_symbolic_aux:w + \exp:w + \@@_exp_after_symbolic_loop:N #2 + { , \exp:w \use_none:nn } + \exp_after:wN \exp_end: \exp_after:wN + { + \exp:w \exp_end_continue_f:w + \@@_exp_after_array_f:w #3 \s_@@_expr_stop + \exp_after:wN + } + \exp_after:wN ; + \exp:w \exp_end_continue_f:w #1 + } +\cs_new:Npn \@@_exp_after_symbolic_aux:w #1, #2; + { + \@@_if_has_symbolic:nTF {#2} + { \s_@@_symbolic \@@_symbolic_chk:w #1, {#2} ; } + { #1 #2 @ \prg_do_nothing: } + } +\cs_new:Npn \@@_exp_after_symbolic_loop:N #1 + { + \exp_after:wN \exp_end: + \exp_after:wN #1 + \exp:w + \@@_exp_after_symbolic_loop:N + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Applying infix operators to expressions} +% +% \begin{macro}[EXP]{\@@_symbolic_binary_o:Nww} +% Used when applying infix operators to expressions. +% \begin{macrocode} +\cs_new:Npn \@@_symbolic_binary_o:Nww #1 #2; #3; + { + \@@_exp_after_symbolic_f:nw { \exp_after:wN \exp_stop_f: } + \s_@@_symbolic \@@_symbolic_chk:w + \@@_types_binary:Nww #1 , { #2; #3; } ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{@makeother}{^} %^^A Hack! +% \begin{@makeother}{|} %^^A Hack! +% \begin{@makeother}{&} %^^A Hack! +% \begin{macro}[EXP] +% { +% \@@_symbolic_+_symbolic_o:ww, +% \@@_symbolic_+_o:ww, +% \@@_+_symbolic_o:ww, +% \@@_symbolic_-_symbolic_o:ww, +% \@@_symbolic_-_o:ww, +% \@@_-_symbolic_o:ww, +% \@@_symbolic_*_symbolic_o:ww, +% \@@_symbolic_*_o:ww, +% \@@_*_symbolic_o:ww, +% \@@_symbolic_/_symbolic_o:ww, +% \@@_symbolic_/_o:ww, +% \@@_/_symbolic_o:ww, +% \@@_symbolic_^_symbolic_o:ww, +% \@@_symbolic_^_o:ww, +% \@@_^_symbolic_o:ww, +% \@@_symbolic_|_symbolic_o:ww, +% \@@_symbolic_|_o:ww, +% \@@_|_symbolic_o:ww, +% \@@_symbolic_&_symbolic_o:ww, +% \@@_symbolic_&_o:ww, +% \@@_&_symbolic_o:ww, +% } +% \begin{macrocode} +\cs_set:Npn \@@_tmp:w #1#2 + { + \cs_new_nopar:cpn + { @@_symbolic_#2_symbolic_o:ww } + { \@@_symbolic_binary_o:Nww #1 } + \cs_new_eq:cc + { @@_symbolic_#2 _o:ww } + { @@_symbolic_#2_symbolic_o:ww } + \cs_new_eq:cc + { @@ _#2_symbolic_o:ww } + { @@_symbolic_#2_symbolic_o:ww } + } +\tl_map_inline:nn { + - * / ^ & | } + { \exp_args:Nc \@@_tmp:w { @@_#1_o:ww } {#1} } +% \end{macrocode} +% \end{macro} +% \end{@makeother} +% \end{@makeother} +% \end{@makeother} +% +% \subsection{Applying prefix functions to expressions} +% +% \begin{macro}[aux, EXP]{\@@_symbolic_unary_o:NNw} +% Used when applying infix operators to expressions. +% \begin{macrocode} +\cs_new:Npn \@@_symbolic_unary_o:NNw #1#2#3; @ + { + \@@_exp_after_symbolic_f:nw { \exp_after:wN \exp_stop_f: } + \s_@@_symbolic \@@_symbolic_chk:w + \@@_types_unary:NNw #1#2 , { #3; } ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP] +% { +% \@@_symbolic_acos_o:w , +% \@@_symbolic_acsc_o:w , +% \@@_symbolic_asec_o:w , +% \@@_symbolic_asin_o:w , +% \@@_symbolic_cos_o:w , +% \@@_symbolic_cot_o:w , +% \@@_symbolic_csc_o:w , +% \@@_symbolic_exp_o:w , +% \@@_symbolic_ln_o:w , +% \@@_symbolic_not_o:w , +% \@@_symbolic_sec_o:w , +% \@@_symbolic_set_sign_o:w , +% \@@_symbolic_sin_o:w , +% \@@_symbolic_tan_o:w , +% } +% \begin{macrocode} +\tl_map_inline:nn + { + {acos} {acsc} {asec} {asin} {cos} {cot} {csc} {exp} {ln} + {not} {sec} {set_sign} {sin} {sqrt} {tan} + } + { + \cs_new_nopar:cpe { @@_symbolic_#1_o:w } + { + \exp_not:N \@@_symbolic_unary_o:NNw + \exp_not:c { @@_#1_o:w } + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Conversions} +% +% \begin{macro}[EXP] +% { +% \@@_symbolic_to_decimal:w, +% \@@_symbolic_to_int:w, +% \@@_symbolic_to_scientific:w +% } +% \begin{macro}[EXP]{\@@_symbolic_convert:wnnN} +% Symbolic expressions cannot be converted to decimal, integer, or +% scientific notation unless they can be reduced to +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1#2#3 + { + \cs_new_nopar:cpn { @@_symbolic_to_#1:w } + { + \exp_after:wN \@@_symbolic_convert:wnnN + \exp:w \exp_end_continue_f:w + \@@_exp_after_symbolic_f:nw { { #2 } { fp_to_#1 } #3 } + } + } +\@@_tmp:w { decimal } { 0 } \@@_to_decimal_dispatch:w +\@@_tmp:w { int } { 0 } \@@_to_int_dispatch:w +\@@_tmp:w { scientific } { nan } \@@_to_scientific_dispatch:w +\cs_new:Npn \@@_symbolic_convert:wnnN #1#2; #3#4#5 + { + \str_if_eq:nnTF {#1} { \s_@@_symbolic } + { \@@_invalid_operation:nnw {#3} {#4} #1#2; } + { #5 #1#2; } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP] +% {\@@_symbolic_cs_arg_to_fn:NN, \@@_symbolic_op_arg_to_fn:nN} +% \begin{macrocode} +\cs_new:Npn \@@_symbolic_cs_arg_to_fn:NN #1 + { + \exp_args:Nf \@@_symbolic_op_arg_to_fn:nN + { \@@_types_cs_to_op:N #1 } + } +\cs_new:Npn \@@_symbolic_op_arg_to_fn:nN #1#2 + { + \str_case:nnF { #1 #2 } + { + { not ? } { ! } + { set_sign 0 } { abs } + { set_sign 2 } { - } + } + { + \token_if_eq_meaning:NNTF #2 \use_ii:nn + { #1 d } {#1} + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_symbolic_to_tl:w} +% \begin{macro}[rEXP] +% { +% \@@_symbolic_unary_to_tl:NNw, +% \@@_symbolic_binary_to_tl:Nww +% } +% Converting a symbolic expression to a token list is possible. +% \begin{macrocode} +\cs_new:Npn \@@_symbolic_to_tl:w + \s_@@_symbolic \@@_symbolic_chk:w #1#2, #3#4; + { + \str_case:nnTF {#1} + { + { \@@_types_unary:NNw } { \@@_symbolic_unary_to_tl:NNw } + { \@@_types_binary:Nww } { \@@_symbolic_binary_to_tl:Nww } + { \@@_function_o:w } { \@@_symbolic_function_to_tl:Nw } + } + { #2, #3 @ } + { \tl_to_str:n {#2} } + } +\cs_new:Npn \@@_symbolic_unary_to_tl:NNw #1#2 , #3 @ + { + \use:e + { + \@@_symbolic_cs_arg_to_fn:NN #1#2 + ( \@@_to_tl_dispatch:w #3 ) + } + } +\cs_new:Npn \@@_symbolic_binary_to_tl:Nww #1, #2; #3; @ + { + \use:e + { + ( \@@_to_tl_dispatch:w #2; ) + \@@_types_cs_to_op:N #1 + ( \@@_to_tl_dispatch:w #3; ) + } + } +\cs_new:Npn \@@_symbolic_function_to_tl:Nw #1, #2@ + { + \use:e + { + \@@_types_cs_to_op:N #1 + ( \@@_array_to_clist:n {#2} ) + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Identifiers} +% +% Functions defined here are not necessarily tied to symbolic +% expressions. +% +% \begin{macro}[TF]{\@@_id_if_invalid:n} +% \begin{macro}[EXP]{\@@_id_if_invalid_aux:N} +% If |#1| contains a space, it is not a valid identifier. Otherwise, +% loop through letters in |#1|: if it is not a letter, break the loop +% and return \texttt{true}. If the end of the loop is reached +% without finding any non-letter, return \texttt{false}. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn + \@@_id_if_invalid:n #1 { T , F , TF } + { + \tl_if_empty:nTF {#1} + { \prg_return_true: } + { + \tl_if_in:onTF { \tl_to_str:n {#1} } { ~ } + { \prg_return_true: } + { + \exp_after:wN \@@_id_if_invalid_aux:N \tl_to_str:n {#1} + { ? \prg_break:n \prg_return_false: } + \prg_break_point: + } + } + } +\cs_new:Npn \@@_id_if_invalid_aux:N #1 + { + \use_none:n #1 + \int_compare:nF { `a <= `#1 <= `z } + { + \int_compare:nF { `A <= `#1 <= `Z } + { \prg_break:n \prg_return_true: } + } + \@@_id_if_invalid_aux:N + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Declaring variables and assigning values} +% +% \begin{macro}[EXP]{\@@_variable_o:w} +% We do not use \cs{exp_last_unbraced:Nv} to extract the value of +% |\l__fp_variable_#1_fp| because in \cs{fp_set_variable:nn} we define +% this \texttt{fp} variable to be something which \texttt{f}-expands +% to an actual floating point, rather than a genuine floating point. +% \begin{macrocode} +\cs_new:Npn \@@_variable_o:w #1 @ #2 + { + \fp_if_exist:cTF { l_@@_variable_#1_fp } + { + \exp_last_unbraced:Nf \@@_exp_after_array_f:w + { \use:c { l_@@_variable_#1_fp } } \s_@@_expr_stop + \exp_after:wN \exp_stop_f: #2 + } + { + \token_if_eq_meaning:NNTF #2 \prg_do_nothing: + { + \s_@@_symbolic \@@_symbolic_chk:w + \@@_variable_o:w #1 , { } ; + } + { + \exp_after:wN \s_@@_symbolic + \exp_after:wN \@@_symbolic_chk:w + \exp_after:wN \@@_variable_o:w + \exp:w + \@@_exp_after_symbolic_loop:N #1 + { , \exp:w \use_none:nn } + \exp_after:wN \exp_end: + \exp_after:wN { \exp_after:wN } \exp_after:wN ; + #2 + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% {\@@_variable_set_parsing:Nn, \@@_variable_set_parsing_aux:NNn} +% \begin{macrocode} +\cs_new:Npn \@@_variable_set_parsing:Nn #1#2 + { + \cs_set_nopar:Npn \@@_tmp:w + { + \@@_exp_after_symbolic_f:nw { \@@_parse_infix:NN } + \s_@@_symbolic \@@_symbolic_chk:w + \@@_variable_o:w #2 , { } ; + } + \exp_args:NNc \@@_variable_set_parsing_aux:NNn #1 + { @@_parse_word_#2:N } {#2} + } +\cs_new:Npn \@@_variable_set_parsing_aux:NNn #1#2#3 + { + \cs_if_eq:NNF #2 \@@_tmp:w + { + \cs_if_exist:NTF #2 + { + \msg_warning:nnnn + { fp } { id-used-elsewhere } {#3} { variable } + #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}{\fp_clear_variable:n} +% \begin{macro}{\@@_clear_variable:n} +% \begin{macrocode} +\cs_new_protected:Npn \fp_clear_variable:n #1 + { + \@@_id_if_invalid:nTF {#1} + { \msg_error:nnn { fp } { id-invalid } {#1} } + { \exp_args:No \@@_clear_variable:n { \tl_to_str:n {#1} } } + } +\cs_new_protected:Npn \@@_clear_variable:n #1 + { + \cs_undefine:c { l_@@_variable_#1_fp } + \@@_variable_set_parsing:Nn \cs_set_eq:NN {#1} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_new_variable:n} +% \begin{macro}{\@@_new_variable:n} +% Check that |#1| is a valid identifier. If the identifier is already +% in use, complain. Then set |\__fp_parse_word_#1:N| to use +% |\__fp_variable_o:w|. +% \begin{macrocode} +\cs_new_protected:Npn \fp_new_variable:n #1 + { + \@@_id_if_invalid:nTF {#1} + { \msg_error:nnn { fp } { id-invalid } {#1} } + { \exp_args:No \@@_new_variable:n { \tl_to_str:n {#1} } } + } +\cs_new_protected:Npn \@@_new_variable:n #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 { l_@@_variable_#1_fp } + } + \@@_variable_set_parsing:Nn \cs_gset_eq:NN {#1} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_set_variable:nn} +% \begin{macro}{\@@_set_variable:nn} +% Refuse invalid identifiers. If the variable does not exist yet, +% define it just as in \cs{fp_new_variable:n} (but without unnecessary +% checks). Then evaluate~|#2|. If the result contains the +% identifier~|#1|, we would later get a loop in cases such as +% \begin{quote} +% \cs{fp_set_variable:nn} |{A}| |{A}|\\ +% \cs{fp_show:n} |{A}| +% \end{quote} +% To detect this, define |\l__fp_variable_#1_fp| to raise an +% internal flag and evaluate to \texttt{nan}. Then re-evaluate +% \cs{l_@@_symbolic_fp}, and store the result in~|#1|. If the flag is +% raised, |#1|~was present in \cs{l_@@_symbolic_fp}. In all cases, +% the |#1|-free result ends up in |\l__fp_variable_#1_fp|. +% \begin{macrocode} +\flag_new:n { @@_symbolic } +\cs_new_protected:Npn \fp_set_variable:nn #1 + { + \@@_id_if_invalid:nTF {#1} + { \msg_error:nnn { fp } { id-invalid } {#1} } + { \exp_args:No \@@_set_variable:nn { \tl_to_str:n {#1} } } + } +\cs_new_protected:Npn \@@_set_variable:nn #1#2 + { + \@@_variable_set_parsing:Nn \cs_set_eq:NN {#1} + \fp_set:Nn \l_@@_symbolic_fp {#2} + \cs_set_nopar:cpn { l_@@_variable_#1_fp } + { \flag_ensure_raised:n { @@_symbolic } \c_nan_fp } + \flag_clear:n { @@_symbolic } + \fp_set:cn { l_@@_variable_#1_fp } { \l_@@_symbolic_fp } + \flag_if_raised:nT { @@_symbolic } + { + \msg_error:nneee { fp } { id-loop } + { \tl_to_str:n {#1} } + { \tl_to_str:n {#2} } + { \fp_to_tl:N \l_@@_symbolic_fp } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Messages} +% +% \begin{macrocode} +\msg_new:nnnn { fp } { id-invalid } + { Floating~point~identifier~'#1'~invalid. } + { + LaTeX~has~been~asked~to~create~a~new~floating~point~identifier~'#1'~ + but~this~may~only~contain~ASCII~letters. + } +\msg_new:nnnn { fp } { id-already-defined } + { Floating~point~identifier~'#1'~already~defined. } + { + LaTeX~has~been~asked~to~create~a~new~floating~point~identifier~'#1'~ + but~this~name~has~already~been~used~elsewhere. + } +\msg_new:nnnn { fp } { id-used-elsewhere } + { Floating~point~identifier~'#1'~already~used~for~something~else. } + { + LaTeX~has~been~asked~to~create~a~new~floating~point~identifier~'#1'~ + but~this~name~is~used,~and~is~not~a~user-defined~#2. + } +\msg_new:nnnn { fp } { id-loop } + { Variable~'#1'~used~in~the~definition~of~'#1'. } + { + LaTeX~has~been~asked~to~set~the~floating~point~identifier~'#1'~ + to~the~expression~'#2'.~Evaluating~this~expression~yields~'#3',~ + which~contains~'#1'~itself. + } +% \end{macrocode} +% +% \subsection{Road-map} +% +% The following functions are not implemented: |min|, |max|, |?:|, +% comparisons, |round|, |atan|, |acot|. +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx index 674ecdfd2db..1bdece9ba76 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx @@ -2,7 +2,7 @@ % %% File: l3fp-traps.dtx % -% Copyright (C) 2011-2014,2016-2023 The LaTeX Project +% Copyright (C) 2011-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 @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % \maketitle % % \begin{documentation} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx index b7bc6c19cec..c49383a1787 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-types.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-types.dtx new file mode 100644 index 00000000000..693cec5cccf --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-types.dtx @@ -0,0 +1,184 @@ +% \iffalse +% +%% File l3fp-types.dtx (C) Copyright 2012-2015,2017,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-types} package\\ Floating point types^^A +% } +% +% \author{^^A +% The \LaTeX{} Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2023-10-23} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-types} implementation} +% +% \begin{macrocode} +%<*package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{Support for types} +% +% Despite lack of documentation, the \pkg{l3fp} internals support types. +% Each additional type must define +% \begin{itemize} +% \item |\s__fp_|\meta{type} and |\__fp_|\meta{type}|_chk:w|; +% \item |\__fp_exp_after_|\meta{type}|_f:nw|; +% \item |\__fp_|\meta{type}|_to_|\meta{out}|:w| for \meta{out} among +% |decimal|, |scientific|, |tl|; +% \end{itemize} +% and may define +% \begin{itemize} +% \item |\__fp_|\meta{type}|_to_int:w| and |\__fp_|\meta{type}|_to_dim:w|; +% \item |\__fp_|\meta{op}|_|\meta{type}|_o:w| for any of the \meta{op} +% that the type implements, among |acos|, |acsc|, |asec|, |asin|, +% |cos|, |cot|, |csc|, |exp|, |ln|, |not|, |sec|, |set_sign|, |sin|, +% |tan|; +% \item |\__fp_|\meta{type_1}|_|\meta{op}|_|\meta{type_2}|_o:ww| for +% \meta{op} among |^*/-+&|\verb"|" and for every pair of types; +% \item |\__fp_|\meta{type_1}|_bcmp_|\meta{type_2}|:ww| for every +% pair of types. +% \end{itemize} +% The latter is set up in \pkg{l3fp-logic}. +% +% \subsection{Dispatch according to the type} +% +% \begin{macro}[EXP] +% {\@@_types_cs_to_op:N, \@@_types_cs_to_op_auxi:wwwn} +% From |\__fp_|\meta{op}|_o:w| produce \meta{op}, otherwise~|?|. +% \begin{macrocode} +\cs_new:Npe \@@_types_cs_to_op:N #1 + { + \exp_not:N \exp_after:wN \exp_not:N \@@_types_cs_to_op_auxi:wwwn + \exp_not:N \token_to_str:N #1 \s_@@_mark + \exp_not:N \@@_use_i_delimit_by_s_stop:nw + \tl_to_str:n { @@_ _o:w } \s_@@_mark + { \exp_not:N \@@_use_i_delimit_by_s_stop:nw ? } + \s_@@_stop + } +\use:e + { + \cs_new:Npn \exp_not:N \@@_types_cs_to_op_auxi:wwwn + #1 \tl_to_str:n { @@_ } #2 + \tl_to_str:n { _o:w } #3 \s_@@_mark #4 { #4 {#2} } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_types_unary:NNw} +% \begin{macro}[EXP] +% {\@@_types_unary_auxi:nNw, \@@_types_unary_auxii:NnNw} +% \begin{syntax} +% \cs{@@_types_unary:NNw} |\__fp_|\meta{function}|_o:w| +% ~~\meta{token} \meta{operand} |@| +% \end{syntax} +% \begin{macrocode} +\cs_new:Npn \@@_types_unary:NNw #1 + { + \exp_args:Nf \@@_types_unary_auxi:nNw + { \@@_types_cs_to_op:N #1 } + } +\cs_new:Npn \@@_types_unary_auxi:nNw #1#2#3 + { + \exp_after:wN \@@_types_unary_auxii:NnNw + \cs:w @@_#1 \@@_type_from_scan:N #3 _o:w \cs_end: + {#1} + #2#3 + } +\cs_new:Npn \@@_types_unary_auxii:NnNw #1#2#3 + { + \token_if_eq_meaning:NNTF \scan_stop: #1 + { \@@_invalid_operation_o:nw {#2} } + { #1 #3 } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_types_binary:Nww} +% \begin{macro}[EXP] +% {\@@_types_binary_auxi:Nww, \@@_types_binary_auxii:NNww} +% \begin{syntax} +% \cs{@@_types_binary:Nww} |\__fp_|\meta{binop}|_o:ww| +% ~~\meta{operand_1} \meta{operand_2} |@| +% \end{syntax} +% \begin{macrocode} +\cs_new:Npn \@@_types_binary:Nww #1 + { + \exp_last_unbraced:Nf \@@_types_binary_auxi:Nww + { \@@_types_cs_to_op:N #1 } + } +\cs_new:Npn \@@_types_binary_auxi:Nww #1#2#3; #4#5; @ + { + \exp_after:wN \@@_types_binary_auxii:NNww + \cs:w + @@ + \@@_type_from_scan:N #2 + _#1 + \@@_type_from_scan:N #4 + _o:ww + \cs_end: + #1 #2#3; #4#5; + } +\cs_new:Npn \@@_types_binary_auxii:NNww #1#2 + { + \token_if_eq_meaning:NNTF \scan_stop: #1 + { \@@_invalid_operation_o:Nww #2 } + {#1} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx index 60a7b7534fd..578d568978f 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx @@ -49,7 +49,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -658,6 +658,138 @@ % the \meta{code} should make use of the \meta{tl~var}. % \end{function} % +% \section{Symbolic expressions} +% +% Floating point expressions support variables: these can only be set locally, +% so act like standard \cs[no-index]{l_\dots} variables. +% \begin{quote}\let\obeyedline=\newline\obeylines^^A +% \cs{fp_new_variable:n} |{ A }| +% \cs{fp_set:Nn} \cs{l_tmpb_fp} |{ 1 * sin(A) + 3**2 }| +% \cs{fp_show:n} |{| \cs{l_tmpb_fp} |}| +% \cs{fp_show:N} \cs{l_tmpb_fp} +% \cs{fp_set_variable:nn} |{ A }| |{ pi/2 }| +% \cs{fp_show:n} |{| \cs{l_tmpb_fp} |}| +% \cs{fp_show:N} \cs{l_tmpb_fp} +% \cs{fp_set_variable:nn} |{ A }| |{ 0 }| +% \cs{fp_show:n} |{| \cs{l_tmpb_fp} |}| +% \cs{fp_show:N} \cs{l_tmpb_fp} +% \end{quote} +% defines~|A| to be a variable, then defines \cs{l_tmpb_fp} to stand for +% |1*sin(A)+9| (note that |3**2| is evaluated, but the |1*|~product is +% not simplified away). Until \cs{l_tmpb_fp} is changed, \cs{fp_show:N} +% \cs{l_tmpb_fp} will show |((1*sin(A))+9)| regardless of the value +% of~|A|. The next step defines~|A| to be equal to~|pi/2|: then +% \cs{fp_show:n} |{| \cs{l_tmpb_fp} |}| will evaluate \cs{l_tmpb_fp} and +% show~|10|. We then redefine~|A| to be~|0|: since \cs{l_tmpb_fp} still +% stands for |1*sin(A)+9|, the value shown is then~|9|. Variables can +% be set with \cs{fp_set_variable:nn} to arbitrary floating point +% expressions including other variables. +% +% \begin{function}[added = 2023-10-19]{\fp_new_variable:n} +% \begin{syntax} +% \cs{fp_new_variable:n} \Arg{identifier} +% \end{syntax} +% Declares the \meta{identifier} as a variable, which allows it to be +% used in floating point expressions. For instance, +% \begin{quote} +% \cs{fp_new_variable:n} |{ A }| \\ +% \cs{fp_show:n} |{ A**2 - A + 1 }| +% \end{quote} +% shows |(((A^2)-A)+1)|. 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 among +% |[a-zA-Z]|. +% \end{function} +% +% \begin{function}[added = 2023-10-19]{\fp_set_variable:nn} +% \begin{syntax} +% \cs{fp_set_variable:nn} \Arg{identifier} \Arg{fp expr} +% \end{syntax} +% Defines the \meta{identifier} to stand in any further expression for +% the result of evaluating the \meta{floating point expression} as +% much as possible. The result may contain other variables, which are +% then replaced by their values if they have any. For instance, +% \begin{quote}\let\obeyedline=\newline\obeylines^^A +% \cs{fp_new_variable:n} |{ A }| +% \cs{fp_new_variable:n} |{ B }| +% \cs{fp_new_variable:n} |{ C }| +% \cs{fp_set_variable:nn} |{ A } { 3 }| +% \cs{fp_set_variable:nn} |{ C } { A ** 2 + B * 1 }| +% \cs{fp_show:n} |{ C + 4 }| +% \cs{fp_set_variable:nn} |{ A } { 4 }| +% \cs{fp_show:n} |{ C + 4 }| +% \end{quote} +% shows |((9+(B*1))+4)| twice: changing the value of~|A| to~|4| does +% not alter~|C| because |A|~was replaced by its value~|3| when +% evaluating |A**2+B*1|. +% \end{function} +% +% \begin{function}[added = 2023-10-19]{\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}\let\obeyedline=\newline\obeylines^^A +% \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{function} +% +% \section{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-10-19]{\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 'foo'}}. +% The \meta{identifier} must consist entirely of Latin letters |[a-zA-Z]|. +% \end{function} +% +% \begin{function}[added = 2023-10-19]{\fp_set_function:nnn} +% \begin{syntax} +% \cs{fp_set_function:nnn} \Arg{identifier} \Arg{vars} \Arg{fp expr} +% \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-10-19]{\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} @@ -1417,7 +1549,7 @@ % \begin{function}[EXP, added = 2012-09-26, tested = m3fp-convert003] % {\fp_max:nn, \fp_min:nn} % \begin{syntax} -% \cs{fp_max:nn} \Arg{fp expression 1} \Arg{fp expression 2} +% \cs{fp_max:nn} \Arg{fp expr_1} \Arg{fp expr_2} % \end{syntax} % Evaluates the \meta{fp exprs} as described for % \cs{fp_eval:n} and leaves the resulting larger (\texttt{max}) or diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx index 9929135baa5..36d84a593dc 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx index e012e191d21..c1dc697e718 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -94,7 +94,7 @@ % \int_show:n { \l_my_tl + \l_my_int * 3 - ( 3 + 4 * 5 ) } % \end{verbatim} % show the same result $-6$ because \cs[no-index]{l_my_tl} expands to -% the integer denotation~|5| while the integer variable \cs{l_my_int} +% the integer denotation~|5| while the integer variable \cs[no-index]{l_my_int} % takes the value~$4$. As the \meta{integer expression} is fully % expanded from left to right during evaluation, fully expandable and % restricted-expandable functions can both be used, and \cs{exp_not:n} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx b/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx index 10458ad602f..cbfdc48666c 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx b/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx index d517f72a228..ce3ab209700 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx index 95ddcd0a383..9fea120c910 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -385,10 +385,10 @@ % \begin{syntax} % \meta{key} .legacy_if_set:n = \meta{switch} % \end{syntax} -% Defines \meta{key} to set legacy \cs{if} \meta{switch} to \meta{value} +% Defines \meta{key} to set legacy \cs[no-index]{if\meta{switch}} to \meta{value} % (which must be either \enquote{\texttt{true}} or \enquote{\texttt{false}}). % The \meta{switch} is the name of the switch \emph{without the leading -% \cs{if}}. +% \texttt{if}}. % % The \texttt{inverse} versions will set the \meta{switch} to the logical % opposite of the \meta{value}. @@ -740,16 +740,12 @@ % \end{function} % % \begin{variable}[updated = 2020-02-08] -% {\l_keys_key_str, \l_keys_path_str, \l_keys_value_tl} +% {\l_keys_path_str, \l_keys_key_str, \l_keys_value_tl} % For each key processed, information of the full \emph{path} of the % key, the \emph{name} of the key and the \emph{value} of the key is % available within two string and one token list variables. % These may be used within the code of the key. % -% The \emph{value} is everything after the \texttt{=}, which may be -% empty if no value was given. This is stored in \cs{l_keys_value_tl}, and -% is not processed in any way by \cs{keys_set:nn}. -% % The \emph{path} of the key is a \enquote{full} description of the key, % and is unique for each key. It consists of the module and full key name, % thus for example @@ -767,6 +763,10 @@ % \texttt{/}, and thus is not unique. In the preceding examples, both keys % have name \texttt{key-a} despite having different paths. This information % is stored in \cs{l_keys_key_str}. +% +% The \emph{value} is everything after the \texttt{=}, which may be +% empty if no value was given. This is stored in \cs{l_keys_value_tl}, and +% is not processed in any way by \cs{keys_set:nn}. % \end{variable} % % \section{Handling of unknown keys} @@ -788,10 +788,10 @@ % { % \keys_set_known:nn, \keys_set_known:nV, % \keys_set_known:nv, \keys_set_known:ne, -% \keys_set_known:no +% \keys_set_known:no, % \keys_set_known:nnN, \keys_set_known:nVN, % \keys_set_known:nvN, \keys_set_known:neN, -% \keys_set_known:noN +% \keys_set_known:noN, % \keys_set_known:nnnN, \keys_set_known:nVnN, % \keys_set_known:nvnN, \keys_set_known:nenN, % \keys_set_known:nonN diff --git a/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx b/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx index 92b8cdb971f..78adefa2dae 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -60,7 +60,7 @@ % \cs{legacy_if:nTF} \Arg{name} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the \LaTeXe{}/plain \TeX{} conditional (generated by \tn{newif}) -% if \texttt{true} or \texttt{false} and branches accordingly. The +% is \texttt{true} or \texttt{false} and branches accordingly. The % \meta{name} of the conditional should \emph{omit} the leading \texttt{if}. % \end{function} % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx b/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx index c7832c892df..c0ec4f69a04 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx index 4feb4115a10..382aab68ddd 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3names.dtx b/Master/texmf-dist/source/latex/l3kernel/l3names.dtx index f299b215791..e85262831f2 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3names.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3names.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx b/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx index f583b393ca4..9c6172caafc 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx index e3f09d90d31..c676e7343e6 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -581,7 +581,7 @@ % \begin{syntax} % \cs{bool_until_do:Nn} \meta{boolean} \Arg{code} % \end{syntax} -% This function firsts checks the logical value of the \meta{boolean}. +% This function first checks the logical value of the \meta{boolean}. % If it is \texttt{false} the \meta{code} is placed in the input stream % and expanded. After the completion of the \meta{code} the truth % of the \meta{boolean} is re-evaluated. The process then loops @@ -592,7 +592,7 @@ % \begin{syntax} % \cs{bool_while_do:Nn} \meta{boolean} \Arg{code} % \end{syntax} -% This function firsts checks the logical value of the \meta{boolean}. +% This function first checks the logical value of the \meta{boolean}. % If it is \texttt{true} the \meta{code} is placed in the input stream % and expanded. After the completion of the \meta{code} the truth % of the \meta{boolean} is re-evaluated. The process then loops @@ -627,7 +627,7 @@ % \begin{syntax} % \cs{bool_until_do:nn} \Arg{boolean expression} \Arg{code} % \end{syntax} -% This function firsts checks the logical value of the +% This function first checks the logical value of the % \meta{boolean expression} (as described for \cs{bool_if:nTF}). % If it is \texttt{false} the \meta{code} is placed in the input stream % and expanded. After the completion of the \meta{code} the truth @@ -639,7 +639,7 @@ % \begin{syntax} % \cs{bool_while_do:nn} \Arg{boolean expression} \Arg{code} % \end{syntax} -% This function firsts checks the logical value of the +% This function first checks the logical value of the % \meta{boolean expression} (as described for \cs{bool_if:nTF}). % If it is \texttt{true} the \meta{code} is placed in the input stream % and expanded. After the completion of the \meta{code} the truth @@ -808,7 +808,8 @@ % \cs{prg_break:n} \Arg{code} \ldots{} \cs{prg_break_point:} % \end{syntax} % Breaks a recursion which has no \meta{ending code} and which is not -% a user-breakable mapping (see for instance \cs{prop_get:Nn}), and +% a user-breakable mapping (see for instance +% implementation of \cs{int_step_function:nnnN}), and % inserts the \meta{code} in the input stream. % \end{function} % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx index 69cafe1cff4..8fb7648af53 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -60,7 +60,7 @@ % Each entry in a property list must have a unique \meta{key}: if an entry is % added to a property list which already contains the \meta{key} then the new % entry overwrites the existing one. The \meta{keys} are compared on a -% string basis, using the same method as \cs{str_if_eq:nn}. +% string basis, using the same method as \cs{str_if_eq:nnTF}. % % Property lists are intended for storing key-based information for use within % code. This is in contrast to key--value lists, which are a form of diff --git a/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx index 1a1e1aaf1ff..d5152295827 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx b/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx index 87dfcec47b1..cd7bd9f33b0 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -921,7 +921,7 @@ % \item Optimize states with a single \cs[no-index]{__regex_action_free:n}. % \item Optimize the use of \cs[no-index]{__regex_action_success:} by inserting it % in state $2$ directly instead of having an extra transition. -% \item Optimize the use of \cs{int_step_...} functions. +% \item Optimize the use of \cs[no-index]{int_step_...} functions. % \item Groups don't capture within regexes for csnames; optimize and % document. % \item Better \enquote{show} for anchors, properties, and catcode tests. @@ -930,7 +930,7 @@ % numbers. % \item Instead of checking whether the character is special or % alphanumeric using its character code, check if it is special in -% regexes with \cs{cs_if_exist} tests. +% regexes with \cs[no-index]{cs_if_exist} tests. % \end{itemize} % % The following features are likely to be implemented at some point diff --git a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx index 9572261d466..56662dc6235 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx index 0371b7ecad4..3130ef85970 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx b/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx index 6837e7fb0ea..0a987712f32 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx b/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx index f4bfaf2c2c1..c4fc416d428 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3str.dtx b/Master/texmf-dist/source/latex/l3kernel/l3str.dtx index 300a779bd1f..99c0f980a51 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3str.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3str.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -752,7 +752,7 @@ % \item Case changing text for typesetting: see the % \cs[index=text_lowercase:n]{text_lowercase:n(n)}, % \cs[index=text_uppercase:n]{text_uppercase:n(n)} and -% \cs[index=text_titlecase:n]{text_titlecase:n(n)} functions which +% \cs[index=text_titlecase_all:n]{text_titlecase_(all|once):n(n)} functions which % correctly deal with context-dependence and other factors appropriate % to text case changing. % \end{itemize} @@ -1138,7 +1138,7 @@ % \end{macro} % % \begin{macro}[EXP]{\@@_if_eq:nn} -% String comparisons rely on the primitive \cs[index=pdfstrcmp]{(pdf)strcmp}, +% String comparisons rely on the primitive \tn[index=pdfstrcmp]{(pdf)strcmp}, % so we define a new name for it. % \begin{macrocode} \cs_new_eq:NN \@@_if_eq:nn \tex_strcmp:D diff --git a/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx index 5e57590767f..577e4daa199 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -299,7 +299,7 @@ % enabled. This returns false if unrestricted shell escape is % enabled. Unrestricted shell escape is not considered a superset % of restricted shell escape in this case. To find whether any -% shell escape is enabled use \cs{sys_if_shell:}. +% shell escape is enabled use \cs{sys_if_shell:TF}. % \end{function} % % \begin{function}[added = 2017-05-27] diff --git a/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx b/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx index 0e20a797f09..e34e9043a54 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -77,16 +77,17 @@ % { % \text_lowercase:n, % \text_uppercase:n, -% \text_titlecase:n, +% \text_titlecase_all:n, % \text_titlecase_first:n % } % \begin{macro}[EXP] % { % \text_lowercase:nn, % \text_uppercase:nn, -% \text_titlecase:nn, +% \text_titlecase_all:nn, % \text_titlecase_first:nn % } +% \begin{macro}[EXP]{\@@_change_case:nnn} % The user level functions here are all wrappers around the internal % functions for case changing. % \begin{macrocode} @@ -94,31 +95,34 @@ { \@@_change_case:nnn { lower } { } {#1} } \cs_new:Npn \text_uppercase:n #1 { \@@_change_case:nnn { upper } { } {#1} } -\cs_new:Npn \text_titlecase:n #1 +\cs_new:Npn \text_titlecase_all:n #1 { \@@_change_case:nnn { title } { } {#1} } \cs_new:Npn \text_titlecase_first:n #1 - { \@@_change_case:nnn { titleonly } { } {#1} } + { \@@_change_case:nnnn { title } { break } { } {#1} } \cs_new:Npn \text_lowercase:nn #1#2 { \@@_change_case:nnn { lower } {#1} {#2} } \cs_new:Npn \text_uppercase:nn #1#2 { \@@_change_case:nnn { upper } {#1} {#2} } -\cs_new:Npn \text_titlecase:nn #1#2 +\cs_new:Npn \text_titlecase_all:nn #1#2 { \@@_change_case:nnn { title } {#1} {#2} } \cs_new:Npn \text_titlecase_first:nn #1#2 - { \@@_change_case:nnn { titleonly } {#1} {#2} } + { \@@_change_case:nnnn { title } { break } {#1} {#2} } +\cs_new:Npn \@@_change_case:nnn #1#2#3 + { \@@_change_case:nnnn {#1} {#1} {#2} {#3} } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}[EXP] % { -% \@@_change_case:nnn , -% \@@_change_case_auxi:nnn , -% \@@_change_case_auxii:nnn +% \@@_change_case:nnnn , +% \@@_change_case_auxi:nnnn , +% \@@_change_case_auxii:nnnn % } -% \begin{macro}[EXP]{\@@_change_case_BCP:nnn} -% \begin{macro}[EXP]{\@@_change_case_BCP:nnw} -% \begin{macro}[EXP]{\@@_change_case_BCP:nnnnw} +% \begin{macro}[EXP]{\@@_change_case_BCP:nnnn} +% \begin{macro}[EXP]{\@@_change_case_BCP:nnnw} +% \begin{macro}[EXP]{\@@_change_case_BCP:nnnnnw} % \begin{macro}[EXP] % { % \@@_change_case_store:n, \@@_change_case_store:o, @@ -128,74 +132,69 @@ % \begin{macro}[EXP]{\@@_change_case_store:nw} % \begin{macro}[EXP]{\@@_change_case_result:n} % \begin{macro}[EXP]{\@@_change_case_end:w} -% \begin{macro}[EXP]{\@@_change_case_loop:nnw} -% \begin{macro}[EXP]{\@@_change_case_break:w} +% \begin{macro}[EXP]{\@@_change_case_loop:nnnw} +% \begin{macro}[EXP]{\@@_change_case_break:w, \@@_change_case_break_aux:w} % \begin{macro}[EXP] % { -% \@@_change_case_group_lower:nnn , -% \@@_change_case_group_upper:nnn , -% \@@_change_case_group_title:nnn , -% \@@_change_case_group_titleonly:nnn +% \@@_change_case_group_lower:nnnn , +% \@@_change_case_group_upper:nnnn , +% \@@_change_case_group_title:nnnn % } -% \begin{macro}[EXP]{\@@_change_case_space:nnw} % \begin{macro}[EXP] -% {\@@_change_case_N_type:nnN, \@@_change_case_N_type_aux:nnN} -% \begin{macro}[EXP]{\@@_change_case_N_type:nnnN} -% \begin{macro}[EXP]{\@@_change_case_math_search:nnNNN} -% \begin{macro}[EXP]{\@@_change_case_math_loop:nnNw} -% \begin{macro}[EXP]{\@@_change_case_math_N_type:nnNN} -% \begin{macro}[EXP]{\@@_change_case_math_group:nnNn} -% \begin{macro}[EXP]{\@@_change_case_math_space:nnNw} -% \begin{macro}[EXP]{\@@_change_case_cs_check:nnN} -% \begin{macro}[EXP]{\@@_change_case_exclude:nnN} -% \begin{macro}[EXP]{\@@_change_case_exclude:nnnN} -% \begin{macro}[EXP]{\@@_change_case_exclude:nnNN} -% \begin{macro}[EXP]{\@@_change_case_exclude:nnNw} -% \begin{macro}[EXP]{\@@_change_case_exclude:nnNnn} -% \begin{macro}[EXP]{\@@_change_case_replace:nnN} -% \begin{macro}[EXP]{\@@_change_case_replace:nnn, \@@_change_case_replace:vnn} -% \begin{macro}[EXP]{\@@_change_case_switch:nnN} +% {\@@_change_case_space:nnnw, \@@_change_case_space_break:nnnw} % \begin{macro}[EXP] -% { -% \@@_change_case_switch_lower:nnNnnnn , -% \@@_change_case_switch_upper:nnNnnnn , -% \@@_change_case_switch_title:nnNnnnn , -% \@@_change_case_switch_titleonly:nnNnnnn -% } +% {\@@_change_case_N_type:nnnN, \@@_change_case_N_type_aux:nnnN} +% \begin{macro}[EXP]{\@@_change_case_N_type:nnnnN} +% \begin{macro}[EXP]{\@@_change_case_math_search:nnnNNN} +% \begin{macro}[EXP]{\@@_change_case_math_loop:nnnNw} +% \begin{macro}[EXP]{\@@_change_case_math_N_type:nnnNN} +% \begin{macro}[EXP]{\@@_change_case_math_group:nnnNn} +% \begin{macro}[EXP]{\@@_change_case_math_space:nnnNw} +% \begin{macro}[EXP]{\@@_change_case_cs_check:nnnN} +% \begin{macro}[EXP]{\@@_change_case_exclude:nnnN} +% \begin{macro}[EXP]{\@@_change_case_exclude:nnnnN} +% \begin{macro}[EXP]{\@@_change_case_exclude:nnnNN} +% \begin{macro}[EXP]{\@@_change_case_exclude:nnnNw} +% \begin{macro}[EXP]{\@@_change_case_exclude:nnnNnn} +% \begin{macro}[EXP]{\@@_change_case_replace:nnnN} +% \begin{macro}[EXP]{\@@_change_case_replace:nnnn, \@@_change_case_replace:vnnn} +% \begin{macro}[EXP]{\@@_change_case_switch:nnnN} % \begin{macro}[EXP] % { -% \@@_change_case_letterlike_lower:nnN , -% \@@_change_case_letterlike_upper:nnN , -% \@@_change_case_letterlike_title:nnN , -% \@@_change_case_letterlike_titleonly:nnN +% \@@_change_case_switch_lower:nnnNnnnn , +% \@@_change_case_switch_upper:nnnNnnnn , +% \@@_change_case_switch_title:nnnNnnnn % } -% \begin{macro}[EXP]{\@@_change_case_letterlike:nnnnN} +% \begin{macro}[EXP]{\@@_change_case_skip:nnw} +% \begin{macro}[EXP]{\@@_change_case_skip_N_type:nnN} +% \begin{macro}[EXP]{\@@_change_case_skip_group:nnn} +% \begin{macro}[EXP]{\@@_change_case_skip_space:nnw} % \begin{macro}[EXP] % { -% \@@_change_case_custom_lower:nnn , -% \@@_change_case_custom_title:nnn , -% \@@_change_case_custom_upper:nnn , -% \@@_change_case_custom_titleonly:nnn +% \@@_change_case_letterlike_lower:nnnN , +% \@@_change_case_letterlike_upper:nnnN , +% \@@_change_case_letterlike_title:nnnN % } -% \begin{macro}[EXP]{\@@_change_case_custom:nnn} +% \begin{macro}[EXP]{\@@_change_case_letterlike:nnnnnN} % \begin{macro}[EXP] % { -% \@@_change_case_codepoint_lower:nnn , -% \@@_change_case_codepoint_upper:nnn , -% \@@_change_case_codepoint_title:nnn , -% \@@_change_case_codepoint_titleonly:nnn +% \@@_change_case_custom_lower:nnnn , +% \@@_change_case_custom_title:nnnn , +% \@@_change_case_custom_upper:nnnn % } -% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnn} -% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnw} -% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnN} +% \begin{macro}[EXP]{\@@_change_case_custom:nnnnn} % \begin{macro}[EXP] % { -% \@@_change_case_codepoint_title:nn , -% \@@_change_case_codepoint_titleonly:nn +% \@@_change_case_codepoint_lower:nnnn , +% \@@_change_case_codepoint_upper:nnnn , +% \@@_change_case_codepoint_title:nnnn % } -% \begin{macro}[EXP]{\@@_change_case_codepoint_title:nnnn} -% \begin{macro}[EXP] -% {\@@_change_case_codepoint:nnnn, \@@_change_case_codepoint_aux:nnnn} +% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnnn} +% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnnw} +% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnnN} +% \begin{macro}[EXP]{\@@_change_case_codepoint_title:nnn} +% \begin{macro}[EXP]{\@@_change_case_codepoint_title:nnnnn} +% \begin{macro}[EXP]{\@@_change_case_codepoint:nnnnn} % \begin{macro}[EXP]{\@@_change_case_codepoint:nn} % \begin{macro}[EXP] % { @@ -203,13 +202,15 @@ % \@@_change_case_codepoint:fnn , % \@@_change_case_codepoint_aux:nnn % } +% \begin{macro}[EXP]{\@@_change_case_codepoint_aux:nnn} +% \begin{macro}[EXP]{\@@_change_case_codepoint_aux:nn} +% \begin{macro}[EXP]{\@@_change_case_catcode:nn} % \begin{macro}[EXP] % { -% \@@_change_case_next_lower:nn , -% \@@_change_case_next_upper:nn , -% \@@_change_case_next_title:nn , -% \@@_change_case_next_titleonly:nn , -% \@@_change_case_next_end:nn +% \@@_change_case_next_lower:nnn , +% \@@_change_case_next_upper:nnn , +% \@@_change_case_next_title:nnn , +% \@@_change_case_next_end:nnn % } % As for the expansion code, the business end of case changing is the % handling of \texttt{N}-type tokens. First, we expand the input fully @@ -231,45 +232,50 @@ % wrap the entire result in exactly one \cs{exp_not:n}, or rather in the % kernel version. % \begin{macrocode} -\cs_new:Npn \@@_change_case:nnn #1#2#3 +\cs_new:Npn \@@_change_case:nnnn #1#2#3#4 { \__kernel_exp_not:w \exp_after:wN { \exp:w - \exp_args:Ne \@@_change_case_auxi:nnn - { \text_expand:n {#3} } - {#1} {#2} + \exp_args:Ne \@@_change_case_auxi:nnnn + { \text_expand:n {#4} } + {#1} {#2} {#3} } } -\cs_new:Npn \@@_change_case_auxi:nnn #1#2#3 - { \exp_args:No \@@_change_case_BCP:nnn { \tl_to_str:n {#3} } {#1} {#2} } -\cs_new:Npe \@@_change_case_BCP:nnn #1#2#3 +\cs_new:Npn \@@_change_case_auxi:nnnn #1#2#3#4 { - \exp_not:N \@@_change_case_BCP:nnw - {#2} {#3} #1 \tl_to_str:n { -x- -x- } \exp_not:N \q_@@_stop + \exp_args:No \@@_change_case_BCP:nnnn + { \tl_to_str:n {#4} } {#1} {#2} {#3} + } +\cs_new:Npe \@@_change_case_BCP:nnnn #1#2#3#4 + { + \exp_not:N \@@_change_case_BCP:nnnw + {#2} {#3} {#4} #1 \tl_to_str:n { -x- -x- } \exp_not:N \q_@@_stop } \use:e { - \cs_new:Npn \exp_not:N \@@_change_case_BCP:nnw - #1#2#3 \tl_to_str:n { -x- } #4 \tl_to_str:n { -x- } #5 + \cs_new:Npn \exp_not:N \@@_change_case_BCP:nnnw + #1#2#3#4 \tl_to_str:n { -x- } #5 \tl_to_str:n { -x- } #6 \exp_not:N \q_@@_stop } - { \@@_change_case_BCP:nnnnw {#1} {#2} {#4} {#3} #3 - - \q_@@_stop } -\cs_new:Npn \@@_change_case_BCP:nnnnw #1#2#3#4#5 - #6 - #7 \q_@@_stop + { \@@_change_case_BCP:nnnnnw {#1} {#2} {#3} {#5} {#4} #4 - \q_@@_stop } +\cs_new:Npn \@@_change_case_BCP:nnnnnw #1#2#3#4#5#6 - #7 \q_@@_stop { - \cs_if_exist:cTF { @@_change_case_ #2 _ #5 -x- #3 :nnnn } - { \@@_change_case_auxii:nnn {#1} {#2} { #5 -x- #3 } } + \bool_lazy_or:nnTF + { \cs_if_exist_p:c { @@_change_case_ #2 _ #6 -x- #4 :nnnnn } } + { \tl_if_exist_p:c { l_@@_ #2 case_special_ #6 -x- #4 _tl } } + { \@@_change_case_auxii:nnnn {#1} {#2} {#3} { #6 -x- #4 } } { - \cs_if_exist:cTF { @@_change_case_ #2 _ #5 :nnnn } - { \@@_change_case_auxii:nnn {#1} {#2} {#5} } - { \@@_change_case_auxii:nnn {#1} {#2} {#4} } + \cs_if_exist:cTF { @@_change_case_ #2 _ #6 :nnnnn } + { \@@_change_case_auxii:nnnn {#1} {#2} {#3} {#6} } + { \@@_change_case_auxii:nnnn {#1} {#2} {#3} {#5} } } } -\cs_new:Npn \@@_change_case_auxii:nnn #1#2#3 +\cs_new:Npn \@@_change_case_auxii:nnnn #1#2#3#4 { \group_align_safe_begin: - \cs_if_exist_use:c { @@_change_case_boundary_ #2 _ #3 :Nnnw } - \@@_change_case_loop:nnw {#2} {#3} #1 + \cs_if_exist_use:c { @@_change_case_boundary_ #2 _ #4 :Nnnnw } + \@@_change_case_loop:nnnw {#2} {#3} {#4} #1 \q_@@_recursion_tail \q_@@_recursion_stop \@@_change_case_result:n { } } @@ -290,20 +296,23 @@ % \end{macrocode} % The main loop is the standard \texttt{tl action} type. % \begin{macrocode} -\cs_new:Npn \@@_change_case_loop:nnw #1#2#3 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_loop:nnnw #1#2#3#4 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#3} - { \@@_change_case_N_type:nnN } + \tl_if_head_is_N_type:nTF {#4} + { \@@_change_case_N_type:nnnN } { - \tl_if_head_is_group:nTF {#3} - { \use:c { @@_change_case_group_ #1 :nnn } } - { \@@_change_case_space:nnw } + \tl_if_head_is_group:nTF {#4} + { \use:c { @@_change_case_group_ #1 :nnnn } } + { \@@_change_case_space:nnnw } } - {#1} {#2} #3 \q_@@_recursion_stop + {#1} {#2} {#3} #4 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_break:w #1 \q_@@_recursion_tail \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_break:w + { \@@_change_case_break_aux:w \prg_do_nothing: } +\cs_new:Npn \@@_change_case_break_aux:w + #1 \q_@@_recursion_tail \q_@@_recursion_stop { - \@@_change_case_store:n {#1} + \@@_change_case_store:o {#1} \@@_change_case_end:w } % \end{macrocode} @@ -315,53 +324,47 @@ % having too much testing, we use a two-step process here to allow the % titlecase functions to be separate. % \begin{macrocode} -\cs_new:Npn \@@_change_case_group_lower:nnn #1#2#3 +\cs_new:Npn \@@_change_case_group_lower:nnnn #1#2#3#4 { \@@_change_case_store:o { \exp_after:wN { \exp:w - \@@_change_case_auxii:nnn {#3} {#1} {#2} + \@@_change_case_auxii:nnnn {#4} {#1} {#2} {#3} } } - \@@_change_case_loop:nnw {#1} {#2} + \@@_change_case_loop:nnnw {#1} {#2} {#3} } -\cs_new_eq:NN \@@_change_case_group_upper:nnn - \@@_change_case_group_lower:nnn -\cs_new:Npn \@@_change_case_group_title:nnn #1#2#3 +\cs_new_eq:NN \@@_change_case_group_upper:nnnn + \@@_change_case_group_lower:nnnn +\cs_new:Npn \@@_change_case_group_title:nnnn #1#2#3#4 { \@@_change_case_store:o { \exp_after:wN { \exp:w - \@@_change_case_auxii:nnn {#3} {#1} {#2} + \@@_change_case_auxii:nnnn {#4} {#1} {#2} {#3} } } - \@@_change_case_loop:nnw { lower } {#2} - } -\cs_new:Npn \@@_change_case_group_titleonly:nnn #1#2#3 - { - \@@_change_case_store:o - { - \exp_after:wN - { - \exp:w - \@@_change_case_auxii:nnn {#3} {#1} {#2} - } - } - \@@_change_case_break:w + \@@_change_case_skip:nnw {#2} {#3} } \use:e { - \cs_new:Npn \exp_not:N \@@_change_case_space:nnw #1#2 \c_space_tl + \cs_new:Npn \exp_not:N \@@_change_case_space:nnnw #1#2#3 \c_space_tl } { \@@_change_case_store:n { ~ } - \cs_if_exist_use:c { @@_change_case_boundary_ #1 _ #2 :Nnnw } - \@@_change_case_loop:nnw {#1} {#2} + \cs_if_exist_use:cF { @@_change_case_space_ #2 :nnn } + { + \cs_if_exist_use:c { @@_change_case_boundary_ #1 _ #3 :Nnnnw } + \@@_change_case_loop:nnnw + } + {#2} {#2} {#3} } +\cs_new:Npn \@@_change_case_space_break:nnn #1#2#3 + { \@@_change_case_break:w } % \end{macrocode} % The first step of handling \texttt{N}-type tokens is to filter out the % end-of-loop. That has to be done separately from the first real step @@ -371,85 +374,85 @@ % (i.e.~there is no assumption of \enquote{well-behaved} input in terms of % math mode). % \begin{macrocode} -\cs_new:Npn \@@_change_case_N_type:nnN #1#2#3 +\cs_new:Npn \@@_change_case_N_type:nnnN #1#2#3#4 { - \@@_if_q_recursion_tail_stop_do:Nn #3 + \@@_if_q_recursion_tail_stop_do:Nn #4 { \@@_change_case_end:w } - \@@_change_case_N_type_aux:nnN {#1} {#2} #3 + \@@_change_case_N_type_aux:nnnN {#1} {#2} {#3} #4 } -\cs_new:Npn \@@_change_case_N_type_aux:nnN #1#2#3 +\cs_new:Npn \@@_change_case_N_type_aux:nnnN #1#2#3#4 { - \exp_args:NV \@@_change_case_N_type:nnnN - \l_text_math_delims_tl {#1} {#2} #3 + \exp_args:NV \@@_change_case_N_type:nnnnN + \l_text_math_delims_tl {#1} {#2} {#3} #4 } -\cs_new:Npn \@@_change_case_N_type:nnnN #1#2#3#4 +\cs_new:Npn \@@_change_case_N_type:nnnnN #1#2#3#4#5 { - \@@_change_case_math_search:nnNNN {#2} {#3} #4 #1 + \@@_change_case_math_search:nnnNNN {#2} {#3} {#4} #5 #1 \q_@@_recursion_tail \q_@@_recursion_tail \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_math_search:nnNNN #1#2#3#4#5 +\cs_new:Npn \@@_change_case_math_search:nnnNNN #1#2#3#4#5#6 { - \@@_if_q_recursion_tail_stop_do:Nn #4 - { \@@_change_case_cs_check:nnN {#1} {#2} #3 } - \token_if_eq_meaning:NNTF #3 #4 + \@@_if_q_recursion_tail_stop_do:Nn #5 + { \@@_change_case_cs_check:nnnN {#1} {#2} {#3} #4 } + \token_if_eq_meaning:NNTF #4 #5 { \@@_use_i_delimit_by_q_recursion_stop:nw { - \@@_change_case_store:n {#3} - \@@_change_case_math_loop:nnNw {#1} {#2} #5 + \@@_change_case_store:n {#4} + \@@_change_case_math_loop:nnnNw {#1} {#2} {#3} #6 } } - { \@@_change_case_math_search:nnNNN {#1} {#2} #3 } + { \@@_change_case_math_search:nnnNNN {#1} {#2} {#3} #4 } } -\cs_new:Npn \@@_change_case_math_loop:nnNw #1#2#3#4 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_math_loop:nnnNw #1#2#3#4#5 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#4} - { \@@_change_case_math_N_type:nnNN } + \tl_if_head_is_N_type:nTF {#5} + { \@@_change_case_math_N_type:nnnNN } { - \tl_if_head_is_group:nTF {#4} - { \@@_change_case_math_group:nnNn } - { \@@_change_case_math_space:nnNw } + \tl_if_head_is_group:nTF {#5} + { \@@_change_case_math_group:nnnNn } + { \@@_change_case_math_space:nnnNw } } - {#1} {#2} #3 #4 \q_@@_recursion_stop + {#1} {#2} {#3} #4 #5 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_math_N_type:nnNN #1#2#3#4 +\cs_new:Npn \@@_change_case_math_N_type:nnnNN #1#2#3#4#5 { - \@@_if_q_recursion_tail_stop_do:Nn #4 + \@@_if_q_recursion_tail_stop_do:Nn #5 { \@@_change_case_end:w } - \@@_change_case_store:n {#4} - \token_if_eq_meaning:NNTF #4 #3 - { \@@_change_case_loop:nnw {#1} {#2} } - { \@@_change_case_math_loop:nnNw {#1} {#2} #3 } + \@@_change_case_store:n {#5} + \token_if_eq_meaning:NNTF #5 #4 + { \@@_change_case_loop:nnnw {#1} {#2} {#3} } + { \@@_change_case_math_loop:nnnNw {#1} {#2} {#3} #4 } } -\cs_new:Npn \@@_change_case_math_group:nnNn #1#2#3#4 +\cs_new:Npn \@@_change_case_math_group:nnnNn #1#2#3#4#5 { - \@@_change_case_store:n { {#4} } - \@@_change_case_math_loop:nnNw {#1} {#2} #3 + \@@_change_case_store:n { {#5} } + \@@_change_case_math_loop:nnnNw {#1} {#2} {#3} #4 } \use:e { - \cs_new:Npn \exp_not:N \@@_change_case_math_space:nnNw #1#2#3 + \cs_new:Npn \exp_not:N \@@_change_case_math_space:nnnNw #1#2#3#4 \c_space_tl } { \@@_change_case_store:n { ~ } - \@@_change_case_math_loop:nnNw {#1} {#2} #3 + \@@_change_case_math_loop:nnnNw {#1} {#2} {#3} #4 } % \end{macrocode} % Once potential math-mode cases are filtered out the next stage is to % test if the token grabbed is a control sequence: the two routes the code % may take are then very different. % \begin{macrocode} -\cs_new:Npn \@@_change_case_cs_check:nnN #1#2#3 +\cs_new:Npn \@@_change_case_cs_check:nnnN #1#2#3#4 { - \token_if_cs:NTF #3 - { \@@_change_case_exclude:nnN {#1} {#2} } + \token_if_cs:NTF #4 + { \@@_change_case_exclude:nnnN {#1} {#2} {#3} } { \@@_codepoint_process:nN - { \use:c { @@_change_case_custom_ #1 :nnn } {#1} {#2} } + { \use:c { @@_change_case_custom_ #1 :nnnn } {#1} {#2} {#3} } } - #3 + #4 } % \end{macrocode} % To deal with a control sequence there is first a need to test if it is @@ -457,92 +460,115 @@ % done using a loop as for the other special cases. If a hit is found then % the argument is grabbed and passed through as-is. % \begin{macrocode} -\cs_new:Npn \@@_change_case_exclude:nnN #1#2#3 +\cs_new:Npn \@@_change_case_exclude:nnnN #1#2#3#4 { - \exp_args:Ne \@@_change_case_exclude:nnnN + \exp_args:Ne \@@_change_case_exclude:nnnnN { \exp_not:V \l_text_math_arg_tl \exp_not:V \l_text_case_exclude_arg_tl } - {#1} {#2} #3 + {#1} {#2} {#3} #4 } -\cs_new:Npn \@@_change_case_exclude:nnnN #1#2#3#4 +\cs_new:Npn \@@_change_case_exclude:nnnnN #1#2#3#4#5 { - \@@_change_case_exclude:nnNN {#2} {#3} #4 #1 + \@@_change_case_exclude:nnnNN {#2} {#3} {#4} #5 #1 \q_@@_recursion_tail \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_exclude:nnNN #1#2#3#4 +\cs_new:Npn \@@_change_case_exclude:nnnNN #1#2#3#4#5 { - \@@_if_q_recursion_tail_stop_do:Nn #4 - { \@@_change_case_replace:nnN {#1} {#2} #3 } - \str_if_eq:nnTF {#3} {#4} + \@@_if_q_recursion_tail_stop_do:Nn #5 + { \@@_change_case_replace:nnnN {#1} {#2} {#3} #4 } + \str_if_eq:nnTF {#4} {#5} { \@@_use_i_delimit_by_q_recursion_stop:nw - { \@@_change_case_exclude:nnNw {#1} {#2} #3 } + { \@@_change_case_exclude:nnnNw {#1} {#2} {#3} #4 } } - { \@@_change_case_exclude:nnNN {#1} {#2} #3 } + { \@@_change_case_exclude:nnnNN {#1} {#2} {#3} #4 } } -\cs_new:Npn \@@_change_case_exclude:nnNw #1#2#3#4# - { \@@_change_case_exclude:nnNnn {#1} {#2} {#3} {#4} } -\cs_new:Npn \@@_change_case_exclude:nnNnn #1#2#3#4#5 +\cs_new:Npn \@@_change_case_exclude:nnnNw #1#2#3#4#5# + { \@@_change_case_exclude:nnnNnn {#1} {#2} {#3} {#4} {#5} } +\cs_new:Npn \@@_change_case_exclude:nnnNnn #1#2#3#4#5#6 { - \tl_if_blank:nTF {#4} - { \@@_change_case_store:n { #3 {#5} } } + \tl_if_blank:nTF {#5} + { \@@_change_case_store:n { #4 {#6} } } { \@@_change_case_store:o { - \exp_after:wN #3 - \exp:w \@@_change_case_auxii:nnn {#4} {#1} {#2} - {#5} + \exp_after:wN #4 + \exp:w \@@_change_case_auxii:nnnn {#5} {#1} {#2} {#3} + {#6} } } - \@@_change_case_loop:nnw {#1} {#2} + \@@_change_case_loop:nnnw {#1} {#2} {#3} } % \end{macrocode} % Deal with any specialist replacement for case changing. % \begin{macrocode} -\cs_new:Npn \@@_change_case_replace:nnN #1#2#3 +\cs_new:Npn \@@_change_case_replace:nnnN #1#2#3#4 { - \cs_if_exist:cTF { l_@@_case_ \token_to_str:N #3 _tl } + \cs_if_exist:cTF { l_@@_case_ \token_to_str:N #4 _tl } { - \@@_change_case_replace:vnn - { l_@@_case_ \token_to_str:N #3 _tl } {#1} {#2} + \@@_change_case_replace:vnnn + { l_@@_case_ \token_to_str:N #4 _tl } {#1} {#2} {#3} } - { \@@_change_case_switch:nnN {#1} {#2} #3 } + { \@@_change_case_switch:nnnN {#1} {#2} {#3} #4 } } -\cs_new:Npn \@@_change_case_replace:nnn #1#2#3 - { \@@_change_case_loop:nnw {#2} {#3} #1 } -\cs_generate_variant:Nn \@@_change_case_replace:nnn { v } +\cs_new:Npn \@@_change_case_replace:nnnn #1#2#3#4 + { \@@_change_case_loop:nnnw {#2} {#3} {#4} #1 } +\cs_generate_variant:Nn \@@_change_case_replace:nnnn { v } % \end{macrocode} % Allow for manually-controlled case switching. % \begin{macrocode} -\cs_new:Npn \@@_change_case_switch:nnN #1#2#3 +\cs_new:Npn \@@_change_case_switch:nnnN #1#2#3#4 + { + \cs_if_eq:NNTF #4 \text_case_switch:nnnn + { \use:c { @@_change_case_switch_ #1 :nnnNnnnn } } + { \use:c { @@_change_case_letterlike_ #1 :nnnN } } + {#1} {#2} {#3} #4 + } +\cs_new:Npn \@@_change_case_switch_lower:nnnNnnnn #1#2#3#4#5#6#7#8 { - \cs_if_eq:NNTF #3 \text_case_switch:nnnn - { \use:c { @@_change_case_switch_ #1 :nnNnnnn } } - { \use:c { @@_change_case_letterlike_ #1 :nnN } } - {#1} {#2} #3 + \@@_change_case_store:n {#7} + \@@_change_case_loop:nnnw {#1} {#2} {#3} } -\cs_new:Npn \@@_change_case_switch_lower:nnNnnnn #1#2#3#4#5#6#7 +\cs_new:Npn \@@_change_case_switch_upper:nnnNnnnn #1#2#3#4#5#6#7#8 { \@@_change_case_store:n {#6} - \@@_change_case_loop:nnw {#1} {#2} + \@@_change_case_loop:nnnw {#1} {#2} {#3} } -\cs_new:Npn \@@_change_case_switch_upper:nnNnnnn #1#2#3#4#5#6#7 +\cs_new:Npn \@@_change_case_switch_title:nnnNnnnn #1#2#3#4#5#6#7#8 { - \@@_change_case_store:n {#5} - \@@_change_case_loop:nnw {#1} {#2} + \@@_change_case_store:n {#8} + \@@_change_case_skip:nnw {#2} {#3} } -\cs_new:Npn \@@_change_case_switch_title:nnNnnnn #1#2#3#4#5#6#7 +% \end{macrocode} +% Skip over material quickly after titlecase-first-only initials +% \begin{macrocode} +\cs_new:Npn \@@_change_case_skip:nnw #1#2#3 \q_@@_recursion_stop { - \@@_change_case_store:n {#7} - \@@_change_case_loop:nnw {#1} {#2} + \tl_if_head_is_N_type:nTF {#3} + { \@@_change_case_skip_N_type:nnN } + { + \tl_if_head_is_group:nTF {#3} + { \@@_change_case_skip_group:nnn } + { \@@_change_case_skip_space:nnw } + } + {#1} {#2} #3 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_switch_titleonly:nnNnnnn #1#2#3#4#5#6#7 +\cs_new:Npn \@@_change_case_skip_N_type:nnN #1#2#3 { - \@@_change_case_store:n {#7} - \@@_change_case_break:w + \@@_if_q_recursion_tail_stop_do:Nn #3 + { \@@_change_case_end:w } + \@@_change_case_store:n {#3} + \@@_change_case_skip:nnw {#1} {#2} + } +\cs_new:Npn \@@_change_case_skip_group:nnn #1#2#3 + { + \@@_change_case_store:n { {#3} } + \@@_change_case_skip:nnw {#1} {#2} } +\cs_new:Npn \@@_change_case_skip_space:nnw #1#2 + { \@@_change_case_space:nnnw {#1} {#1} {#2} } % \end{macrocode} % Letter-like commands may still be present: they are set up using a simple % lookup approach, so can easily be handled with no loop. If there is no @@ -550,68 +576,64 @@ % are all available only in upper- and lowercase, so titlecasing maps to the % uppercase version. % \begin{macrocode} -\cs_new:Npn \@@_change_case_letterlike_lower:nnN #1#2#3 - { \@@_change_case_letterlike:nnnnN {#1} {#1} {#1} {#2} #3 } -\cs_new_eq:NN \@@_change_case_letterlike_upper:nnN - \@@_change_case_letterlike_lower:nnN -\cs_new:Npn \@@_change_case_letterlike_title:nnN #1#2#3 - { \@@_change_case_letterlike:nnnnN { upper } { lower } {#1} {#2} #3 } -\cs_new:Npn \@@_change_case_letterlike_titleonly:nnN #1#2#3 - { \@@_change_case_letterlike:nnnnN { upper } { end } {#1} {#2} #3 } -\cs_new:Npn \@@_change_case_letterlike:nnnnN #1#2#3#4#5 - { - \cs_if_exist:cTF { c_@@_ #1 case_ \token_to_str:N #5 _tl } +\cs_new:Npn \@@_change_case_letterlike_lower:nnnN #1#2#3#4 + { \@@_change_case_letterlike:nnnnnN {#1} {#1} {#1} {#2} {#3} #4 } +\cs_new_eq:NN \@@_change_case_letterlike_upper:nnnN + \@@_change_case_letterlike_lower:nnnN +\cs_new:Npn \@@_change_case_letterlike_title:nnnN #1#2#3#4 + { \@@_change_case_letterlike:nnnnnN { upper } { end } {#1} {#2} {#3} #4 } +\cs_new:Npn \@@_change_case_letterlike:nnnnnN #1#2#3#4#5#6 + { + \cs_if_exist:cTF { c_@@_ #1 case_ \token_to_str:N #6 _tl } { \@@_change_case_store:v - { c_@@_ #1 case_ \token_to_str:N #5 _tl } - \use:c { @@_change_case_next_ #2 :nn } {#2} {#4} + { c_@@_ #1 case_ \token_to_str:N #6 _tl } + \use:c { @@_change_case_next_ #2 :nnn } {#2} {#4} {#5} } { - \@@_change_case_store:n {#5} + \@@_change_case_store:n {#6} \cs_if_exist:cTF { c_@@_ \str_if_eq:nnTF {#1} { lower } { upper } { lower } - case_ \token_to_str:N #5 _tl + case_ \token_to_str:N #6 _tl } - { \use:c { @@_change_case_next_ #2 :nn } {#2} {#4} } - { \@@_change_case_loop:nnw {#3} {#4} } + { \use:c { @@_change_case_next_ #2 :nnn } {#2} {#4} {#5} } + { \@@_change_case_loop:nnnw {#3} {#4} {#5} } } } % \end{macrocode} % Check for a customised codepoint result. % \begin{macrocode} -\cs_new:Npn \@@_change_case_custom_lower:nnn #1#2#3 +\cs_new:Npn \@@_change_case_custom_lower:nnnn #1#2#3#4 { - \@@_change_case_custom:nnnnn {#1} {#2} {#3} {#1} - { \use:c { @@_change_case_codepoint_ #1 :nnn } {#1} {#2} {#3} } + \@@_change_case_custom:nnnnnn {#1} {#1} {#2} {#3} {#4} + { \use:c { @@_change_case_codepoint_ #1 :nnnn } {#1} {#2} {#3} {#4} } } -\cs_new_eq:NN \@@_change_case_custom_upper:nnn - \@@_change_case_custom_lower:nnn -\cs_new:Npn \@@_change_case_custom_title:nnn #1#2#3 +\cs_new_eq:NN \@@_change_case_custom_upper:nnnn + \@@_change_case_custom_lower:nnnn +\cs_new:Npn \@@_change_case_custom_title:nnnn #1#2#3#4 { - \@@_change_case_custom:nnnnn { title } {#2} {#3} {#1} + \@@_change_case_custom:nnnnnn { title } {#1} {#2} {#3} {#4} { - \@@_change_case_custom:nnnnn { upper } {#2} {#3} {#1} - { \use:c { @@_change_case_codepoint_ #1 :nnn } {#1} {#2} {#3} } + \@@_change_case_custom:nnnnnn { upper } {#1} {#2} {#3} {#4} + { \use:c { @@_change_case_codepoint_ #1 :nnnn } {#1} {#2} {#3} {#4} } } } -\cs_new_eq:NN \@@_change_case_custom_titleonly:nnn - \@@_change_case_custom_title:nnn -\cs_new:Npn \@@_change_case_custom:nnnnn #1#2#3#4#5 +\cs_new:Npn \@@_change_case_custom:nnnnnn #1#2#3#4#5#6 { - \tl_if_exist:cTF { l_@@_ #1 case _ \tl_to_str:n {#3} _ #2 _tl } + \tl_if_exist:cTF { l_@@_ #1 case _ \tl_to_str:n {#5} _ #4 _tl } { - \@@_change_case_replace:vnn - { l_@@_ #1 case _ \tl_to_str:n {#3} _ #2 _tl } {#4} {#2} + \@@_change_case_replace:vnnn + { l_@@_ #1 case _ \tl_to_str:n {#5} _ #4 _tl } {#2} {#3} {#4} } { - \tl_if_exist:cTF { l_@@_ #1 case _ \tl_to_str:n {#3} _tl } + \tl_if_exist:cTF { l_@@_ #1 case _ \tl_to_str:n {#5} _tl } { - \@@_change_case_replace:vnn - { l_@@_ #1 case _ \tl_to_str:n {#3} _tl } {#4} {#2} + \@@_change_case_replace:vnnn + { l_@@_ #1 case _ \tl_to_str:n {#5} _tl } {#2} {#3} {#4} } - {#5} + {#6} } } % \end{macrocode} @@ -620,17 +642,17 @@ % is there the special case of a terminal sigma. If not, then we pass to % a simple codepoint mapping. % \begin{macrocode} -\cs_new:Npn \@@_change_case_codepoint_lower:nnn #1#2#3 +\cs_new:Npn \@@_change_case_codepoint_lower:nnnn #1#2#3#4 { - \cs_if_exist_use:cF { @@_change_case_lower_ #2 :nnnn } - { \@@_change_case_lower_sigma:nnnn } - {#1} {#1} {#2} {#3} + \cs_if_exist_use:cF { @@_change_case_lower_ #3 :nnnnn } + { \@@_change_case_lower_sigma:nnnnn } + {#1} {#1} {#2} {#3} {#4} } -\cs_new:Npn \@@_change_case_codepoint_upper:nnn #1#2#3 +\cs_new:Npn \@@_change_case_codepoint_upper:nnnn #1#2#3#4 { - \cs_if_exist_use:cF { @@_change_case_upper_ #2 :nnnn } - { \@@_change_case_codepoint:nnnn } - {#1} {#1} {#2} {#3} + \cs_if_exist_use:cF { @@_change_case_upper_ #3 :nnnnn } + { \@@_change_case_codepoint:nnnnn } + {#1} {#1} {#2} {#3} {#4} } % \end{macrocode} % If the current character is an uppercase sigma, the a check is made on the @@ -638,91 +660,87 @@ % then there is a look-ahead phase: the logic here is simply based on letters % or actives (to cover $8$-bit engines). % \begin{macrocode} -\cs_new:Npn \@@_change_case_lower_sigma:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_lower_sigma:nnnnn #1#2#3#4#5 { - \@@_codepoint_compare:nNnTF {#4} = { "03A3 } - { \@@_change_case_lower_sigma:nnnw {#2} } - { \@@_change_case_codepoint:nnnn {#1} {#2} } - {#3} {#4} + \@@_codepoint_compare:nNnTF {#5} = { "03A3 } + { \@@_change_case_lower_sigma:nnnnw {#2} } + { \@@_change_case_codepoint:nnnnn {#1} {#2} } + {#3} {#4} {#5} } -\cs_new:Npn \@@_change_case_lower_sigma:nnnw #1#2#3#4 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_lower_sigma:nnnnw #1#2#3#4#5 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#4} - { \@@_change_case_lower_sigma:nnnN {#3} } + \tl_if_head_is_N_type:nTF {#5} + { \@@_change_case_lower_sigma:nnnnN {#4} } { \@@_change_case_store:e - { \codepoint_generate:nn { "03C2 } { \@@_char_catcode:N #3 } } - \@@_change_case_loop:nnw + { \codepoint_generate:nn { "03C2 } { \@@_char_catcode:N #4 } } + \@@_change_case_loop:nnnw } - {#1} {#2} #4 \q_@@_recursion_stop + {#1} {#2} {#3} #5 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_lower_sigma:nnnN #1#2#3#4 +\cs_new:Npn \@@_change_case_lower_sigma:nnnnN #1#2#3#4#5 { \@@_change_case_store:e { \bool_lazy_or:nnTF - { \token_if_letter_p:N #4 } + { \token_if_letter_p:N #5 } { \bool_lazy_and_p:nn - { \token_if_active_p:N #4 } - { \int_compare_p:nNn {`#4} > { "80 } } + { \token_if_active_p:N #5 } + { \int_compare_p:nNn {`#5} > { "80 } } } { \codepoint_generate:nn { "03C3 } { \@@_char_catcode:N #1 } } { \codepoint_generate:nn { "03C2 } { \@@_char_catcode:N #1 } } } - \@@_change_case_loop:nnw {#2} {#3} #4 + \@@_change_case_loop:nnnw {#2} {#3} {#4} #5 } % \end{macrocode} % For titlecasing, we need to fully expand the new character to see if it % is a letter (or active). % \begin{macrocode} -\cs_new:Npn \@@_change_case_codepoint_title:nnn #1#2#3 +\cs_new:Npn \@@_change_case_codepoint_title:nnnn #1#2#3#4 { \bool_if:NTF \l_text_titlecase_check_letter_bool { - \tl_if_single:nTF {#3} + \tl_if_single:nTF {#4} { \bool_lazy_or:nnTF - { \token_if_letter_p:N #3 } + { \token_if_letter_p:N #4 } { \bool_lazy_and_p:nn - { \token_if_active_p:N #3 } - { ! \int_compare_p:nNn {`#3} < { "80 } } + { \token_if_active_p:N #4 } + { ! \int_compare_p:nNn {`#4} < { "80 } } } - { \use:c { @@_change_case_codepoint_ #1 :nn } } - { \@@_change_case_codepoint_title:nnnn { title } {#1} } + { \@@_change_case_codepoint_title:nnn } + { \@@_change_case_codepoint_title:nnnnn { title } {#1} } } - { \use:c { @@_change_case_codepoint_ #1 :nn } } + { \@@_change_case_codepoint_title:nnn } } - { \use:c { @@_change_case_codepoint_ #1 :nn } } - {#2} {#3} + { \@@_change_case_codepoint_title:nnn } + {#2} {#3} {#4} } -\cs_new_eq:NN \@@_change_case_codepoint_titleonly:nnn - \@@_change_case_codepoint_title:nnn -\cs_new:Npn \@@_change_case_codepoint_title:nn #1#2 - { \@@_change_case_codepoint_title:nnnn { title } { lower } {#1} {#2} } -\cs_new:Npn \@@_change_case_codepoint_titleonly:nn #1#2 - { \@@_change_case_codepoint_title:nnnn { title } { end } {#1} {#2} } -\cs_new:Npn \@@_change_case_codepoint_title:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_codepoint_title:nnn #1#2#3 + { \@@_change_case_codepoint_title:nnnnn { title } { end } {#1} {#2} {#3} } +\cs_new:Npn \@@_change_case_codepoint_title:nnnnn #1#2#3#4#5 { - \cs_if_exist_use:cF { @@_change_case_title_ #3 :nnnn } + \cs_if_exist_use:cF { @@_change_case_title_ #4 :nnnnn } { - \cs_if_exist_use:cF { @@_change_case_upper_ #3 :nnnn } - { \@@_change_case_codepoint:nnnn } + \cs_if_exist_use:cF { @@_change_case_upper_ #4 :nnnnn } + { \@@_change_case_codepoint:nnnnn } } - {#1} {#2} {#3} {#4} + {#1} {#2} {#3} {#4} {#5} } -\cs_new:Npn \@@_change_case_codepoint:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_codepoint:nnnnn #1#2#3#4#5 { \bool_lazy_and:nnTF - { \tl_if_single_p:n {#4} } - { \token_if_active_p:N #4 } - { \@@_change_case_store:n {#4} } + { \tl_if_single_p:n {#5} } + { \token_if_active_p:N #5 } + { \@@_change_case_store:n {#5} } { \@@_change_case_store:e - { \@@_change_case_codepoint:nn {#1} {#4} } + { \@@_change_case_codepoint:nn {#1} {#5} } } - \use:c { @@_change_case_next_ #2 :nn } {#2} {#3} + \use:c { @@_change_case_next_ #2 :nnn } {#2} {#3} {#4} } \cs_new:Npn \@@_change_case_codepoint:nn #1#2 { @@ -799,16 +817,14 @@ } } } -\cs_new:Npn \@@_change_case_next_lower:nn #1#2 - { \@@_change_case_loop:nnw {#1} {#2} } -\cs_new_eq:NN \@@_change_case_next_upper:nn - \@@_change_case_next_lower:nn -\cs_new_eq:NN \@@_change_case_next_title:nn - \@@_change_case_next_lower:nn -\cs_new_eq:NN \@@_change_case_next_titleonly:nn - \@@_change_case_next_lower:nn -\cs_new:Npn \@@_change_case_next_end:nn #1#2 - { \@@_change_case_break:w } +\cs_new:Npn \@@_change_case_next_lower:nnn #1#2#3 + { \@@_change_case_loop:nnnw {#1} {#2} {#3} } +\cs_new_eq:NN \@@_change_case_next_upper:nnn + \@@_change_case_next_lower:nnn +\cs_new_eq:NN \@@_change_case_next_title:nnn + \@@_change_case_next_lower:nnn +\cs_new:Npn \@@_change_case_next_end:nnn #1#2#3 + { \@@_change_case_skip:nnw {#2} {#3} } % \end{macrocode} % \end{macro} % \end{macro} @@ -853,6 +869,13 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\text_declare_case_equivalent:Nn} % Create equivalents to allow replacement. @@ -914,6 +937,7 @@ { \tl_clear_new:c { l_@@_ #2 case _ #1 _ #3 _tl } \tl_set:cn { l_@@_ #2 case _ #1 _ #3 _ tl } {#4} + \tl_clear_new:c { l_@@_ #2 case_special_ #3 _tl } } % \end{macrocode} % \end{macro} @@ -944,55 +968,58 @@ % \end{macro} % % \begin{macro}[EXP] -% {\@@_change_case_upper_de-x-eszett:nnnn, \@@_change_case_upper_de-alt:nnnn} +% { +% \@@_change_case_upper_de-x-eszett:nnnnn, +% \@@_change_case_upper_de-alt:nnnnn +% } % A simple alternative version for German. % \begin{macrocode} -\cs_new:cpn { @@_change_case_upper_de-x-eszett:nnnn } #1#2#3#4 +\cs_new:cpn { @@_change_case_upper_de-x-eszett:nnnnn } #1#2#3#4#5 { - \@@_codepoint_compare:nNnTF {#4} = { "00DF } + \@@_codepoint_compare:nNnTF {#5} = { "00DF } { \@@_change_case_store:e { \codepoint_generate:nn { "1E9E } - { \@@_change_case_catcode:nn {#4} { "1E9E } } + { \@@_change_case_catcode:nn {#5} { "1E9E } } } - \use:c { @@_change_case_next_ #2 :nn } - {#2} {#3} + \use:c { @@_change_case_next_ #2 :nnn } + {#2} {#3} {#4} } - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } } -\cs_new_eq:cc { @@_change_case_upper_de-alt:nnnn } - { @@_change_case_upper_de-x-eszett:nnnn } +\cs_new_eq:cc { @@_change_case_upper_de-alt:nnnnn } + { @@_change_case_upper_de-x-eszett:nnnnn } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] % { -% \@@_change_case_upper_el:nnnn , -% \@@_change_case_upper_el_aux:nnnn , -% \@@_change_case_upper_el-x-iota:nnnn +% \@@_change_case_upper_el:nnnnn , +% \@@_change_case_upper_el-x-iota:nnnnn , +% \@@_change_case_upper_el_aux:nnnnn % } -% \begin{macro}[EXP]{\@@_change_case_upper_el:nnn} -% \begin{macro}[EXP]{\@@_change_case_upper_el:nnnw} +% \begin{macro}[EXP]{\@@_change_case_upper_el:nnnn} +% \begin{macro}[EXP]{\@@_change_case_upper_el:nnnnw} % \begin{macro}[EXP] -% {\@@_change_case_upper_el:nnnN, \@@_change_case_upper_el_aux:nnnN} -% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnw} -% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnN} -% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnn} -% \begin{macro}[EXP]{\@@_change_case_upper_el_dialytika:nnn} +% {\@@_change_case_upper_el:nnnnN, \@@_change_case_upper_el_aux:nnnnN} +% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnnw} +% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnnN} +% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnnn} +% \begin{macro}[EXP]{\@@_change_case_upper_el_dialytika:nnnn} % \begin{macro}[EXP]{\@@_change_case_upper_el_dialytika:n} -% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnw} -% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnN} -% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnn} +% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnnw} +% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnnN} +% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnnn} % \begin{macro}[EXP] % { % \@@_change_case_upper_el_ypogegrammeni:n , % \@@_change_case_upper_el-x-iota_ypogegrammeni:n % } % \begin{macro}[EXP]{\@@_change_case_upper_el_stress:nn} -% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnw} -% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnN} -% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnn} +% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnnw} +% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnnN} +% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnnn} % \begin{macro}[EXP,noTF] % { % \@@_change_case_if_greek:n , @@ -1017,65 +1044,65 @@ % for \pdfTeX{} so is best left unchanged, and the latter has issues concerning % how \texttt{LGR} outputs the input and output (differently!). % \begin{macrocode} -\cs_new:Npn \@@_change_case_upper_el:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_upper_el:nnnnn #1#2#3#4#5 { \bool_lazy_and:nnTF - { \@@_change_case_if_greek_p:n {#4} } + { \@@_change_case_if_greek_p:n {#5} } { ! \bool_lazy_or_p:nn - { \@@_codepoint_compare_p:nNn {#4} = { "0374 } } - { \@@_codepoint_compare_p:nNn {#4} = { "037E } } + { \@@_codepoint_compare_p:nNn {#5} = { "0374 } } + { \@@_codepoint_compare_p:nNn {#5} = { "037E } } } { - \@@_change_case_if_greek_spacing_diacritic:nTF {#4} + \@@_change_case_if_greek_spacing_diacritic:nTF {#5} { - \@@_change_case_store:n {#4} - \@@_change_case_loop:nnw + \@@_change_case_store:n {#5} + \@@_change_case_loop:nnnw } { - \exp_args:Ne \@@_change_case_upper_el:nnn + \exp_args:Ne \@@_change_case_upper_el:nnnn { \codepoint_to_nfd:n - { \@@_codepoint_from_chars:Nw #4 } + { \@@_codepoint_from_chars:Nw #5 } } } - {#2} {#3} + {#2} {#3} {#4} } { - \@@_codepoint_compare:nNnTF {#4} = { "0345 } + \@@_codepoint_compare:nNnTF {#5} = { "0345 } { \@@_change_case_store:e { \codepoint_generate:nn { "0399 } { \char_value_catcode:n { "0399 } } } - \@@_change_case_loop:nnw {#2} {#3} + \@@_change_case_loop:nnnw {#2} {#3} {#4} } - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } } } -\cs_new_eq:cN { @@_change_case_upper_el-x-iota:nnnn } - \@@_change_case_upper_el:nnnn -\cs_new:Npn \@@_change_case_upper_el:nnn #1#2#3 +\cs_new_eq:cN { @@_change_case_upper_el-x-iota:nnnnn } + \@@_change_case_upper_el:nnnnn +\cs_new:Npn \@@_change_case_upper_el:nnnn #1#2#3#4 { \@@_codepoint_process:nN - { \@@_change_case_upper_el:nnnw {#2} {#3} } #1 + { \@@_change_case_upper_el:nnnnw {#2} {#3} {#4} } #1 } % \end{macrocode} % At this stage we have the first NFD codepoint as |#3|. What we need to know % is whether after that we have another character, either from the NFD or % directly in the input. If not, we store the changed character at this stage. % \begin{macrocode} -\cs_new:Npn \@@_change_case_upper_el:nnnw #1#2#3#4 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_upper_el:nnnnw #1#2#3#4#5 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#4} - { \@@_change_case_upper_el:nnnN {#3} } + \tl_if_head_is_N_type:nTF {#5} + { \@@_change_case_upper_el:nnnnN {#4} } { \@@_change_case_store:e - { \@@_change_case_codepoint:nn { upper } {#3} } - \@@_change_case_loop:nnw + { \@@_change_case_codepoint:nn { upper } {#4} } + \@@_change_case_loop:nnnw } - {#1} {#2} #4 \q_@@_recursion_stop + {#1} {#2} {#3} #5 \q_@@_recursion_stop } % \end{macrocode} % Now, we check the detail of the next codepoint: again we filter out the @@ -1085,99 +1112,99 @@ % to move any ypogegrammeni to after accents (in case the input is not % normalised). The ypogegrammeni itself is handled separately. % \begin{macrocode} -\cs_new:Npn \@@_change_case_upper_el:nnnN #1#2#3#4 +\cs_new:Npn \@@_change_case_upper_el:nnnnN #1#2#3#4#5 { - \token_if_cs:NTF #4 + \token_if_cs:NTF #5 { \@@_change_case_store:e { \@@_change_case_codepoint:nn { upper } {#1} } - \@@_change_case_loop:nnw {#2} {#3} #4 + \@@_change_case_loop:nnnw {#2} {#3} {#4} #5 } { \@@_change_case_if_takes_ypogegrammeni:nTF {#1} { - \@@_change_case_upper_el_ypogegrammeni:nnnnnw - {#1} {#2} {#3} { } { } #4 + \@@_change_case_upper_el_ypogegrammeni:nnnnnnw + {#1} {#2} {#3} {#4} { } { } #5 } - { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4 } + { \@@_change_case_upper_el_aux:nnnnN {#1} {#2} {#3} {#4} #5 } } } -\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnw - #1#2#3#4#5#6 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnnw + #1#2#3#4#5#6#7 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#6} + \tl_if_head_is_N_type:nTF {#7} { - \@@_change_case_upper_el_ypogegrammeni:nnnnnN - {#1} {#2} {#3} {#4} {#5} + \@@_change_case_upper_el_ypogegrammeni:nnnnnnN + {#1} {#2} {#3} {#4} {#5} {#6} } - { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4#5 } - #6 \q_@@_recursion_stop + { \@@_change_case_upper_el_aux:nnnnN {#1} {#2} {#3} {#4} #5#6 } + #7 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnN #1#2#3#4#5#6 +\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnnN #1#2#3#4#5#6#7 { - \token_if_cs:NTF #6 - { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4#5 } + \token_if_cs:NTF #7 + { \@@_change_case_upper_el_aux:nnnnN {#1} {#2} {#3} {#4} #5#6 } { \@@_codepoint_process:nN { - \@@_change_case_upper_el_ypogegrammeni:nnnnnn - {#1} {#2} {#3} {#4} {#5} + \@@_change_case_upper_el_ypogegrammeni:nnnnnnn + {#1} {#2} {#3} {#4} {#5} {#6} } } - #6 + #7 } -\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnn #1#2#3#4#5#6 +\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnnn #1#2#3#4#5#6#7 { - \@@_codepoint_compare:nNnTF {#6} = { "0345 } + \@@_codepoint_compare:nNnTF {#7} = { "0345 } { - \@@_change_case_upper_el_ypogegrammeni:nnnnnw - {#1} {#2} {#3} {#4} {#6} + \@@_change_case_upper_el_ypogegrammeni:nnnnnnw + {#1} {#2} {#3} {#4} {#5} {#7} } { \bool_lazy_or:nnTF - { \@@_change_case_if_greek_accent_p:n {#6} } - { \@@_change_case_if_greek_breathing_p:n {#6} } + { \@@_change_case_if_greek_accent_p:n {#7} } + { \@@_change_case_if_greek_breathing_p:n {#7} } { - \@@_change_case_upper_el_ypogegrammeni:nnnnnw - {#1} {#2} {#3} {#4#6} {#5} + \@@_change_case_upper_el_ypogegrammeni:nnnnnnw + {#1} {#2} {#3} {#4} {#5#7} {#6} } - { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4#5 #6 } + { \@@_change_case_upper_el_aux:nnnnN {#1} {#2} {#3} {#4} #5#6 #7 } } } -\cs_new:Npn \@@_change_case_upper_el_aux:nnnN #1#2#3#4 +\cs_new:Npn \@@_change_case_upper_el_aux:nnnnN #1#2#3#4#5 { \@@_codepoint_process:nN - { \@@_change_case_upper_el_aux:nnnn {#1} {#2} {#3} } #4 + { \@@_change_case_upper_el_aux:nnnnn {#1} {#2} {#3} {#4} } #5 } -\cs_new:Npn \@@_change_case_upper_el_aux:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_upper_el_aux:nnnnn #1#2#3#4#5 { - \@@_codepoint_compare:nNnTF {#4} = { "0308 } - { \@@_change_case_upper_el_dialytika:nnn {#2} {#3} {#1} } + \@@_codepoint_compare:nNnTF {#5} = { "0308 } + { \@@_change_case_upper_el_dialytika:nnnn {#2} {#3} {#4} {#1} } { - \@@_change_case_if_greek_accent:nTF {#4} - { \@@_change_case_upper_el_hiatus:nnnw {#2} {#3} {#1} } + \@@_change_case_if_greek_accent:nTF {#5} + { \@@_change_case_upper_el_hiatus:nnnnw {#2} {#3} {#4} {#1} } { - \@@_change_case_if_greek_breathing:nTF {#4} - { \@@_change_case_upper_el:nnn {#1} {#2} {#3} } + \@@_change_case_if_greek_breathing:nTF {#5} + { \@@_change_case_upper_el:nnnn {#1} {#2} {#3} {#4} } { - \@@_codepoint_compare:nNnTF {#4} = { "0345 } + \@@_codepoint_compare:nNnTF {#5} = { "0345 } { \@@_change_case_store:e - { \use:c { @@_change_case_upper_ #3 _ypogegrammeni:n } {#1} } - \@@_change_case_loop:nnw {#2} {#3} + { \use:c { @@_change_case_upper_ #4 _ypogegrammeni:n } {#1} } + \@@_change_case_loop:nnnw {#2} {#3} {#4} } { - \@@_change_case_if_greek_stress:nTF {#4} + \@@_change_case_if_greek_stress:nTF {#5} { \@@_change_case_store:e - { \@@_change_case_upper_el_stress:nn {#1} {#4} } - \@@_change_case_loop:nnw {#2} {#3} + { \@@_change_case_upper_el_stress:nn {#1} {#5} } + \@@_change_case_loop:nnnw {#2} {#3} {#4} } { \@@_change_case_store:e { \@@_change_case_codepoint:nn { upper } {#1} } - \@@_change_case_loop:nnw {#2} {#3} #4 + \@@_change_case_loop:nnnw {#2} {#3} {#4} #5 } } } @@ -1189,15 +1216,15 @@ % We know only two letters take it, so we can shortcut here on the second % part of the tests. % \begin{macrocode} -\cs_new:Npn \@@_change_case_upper_el_dialytika:nnn #1#2#3 +\cs_new:Npn \@@_change_case_upper_el_dialytika:nnnn #1#2#3#4 { - \@@_change_case_if_takes_dialytika:nTF {#3} - { \@@_change_case_upper_el_dialytika:n {#3} } + \@@_change_case_if_takes_dialytika:nTF {#4} + { \@@_change_case_upper_el_dialytika:n {#4} } { \@@_change_case_store:e - { \@@_change_case_codepoint:nn { upper } {#3} } + { \@@_change_case_codepoint:nn { upper } {#4} } } - \@@_change_case_upper_el_gobble:nnw {#1} {#2} + \@@_change_case_upper_el_gobble:nnnw {#1} {#2} {#3} } \cs_new:Npn \@@_change_case_upper_el_dialytika:n #1 { @@ -1220,41 +1247,41 @@ % Adding a hiatus needs some of the same ideas, but if there is not one we % skip this code point, hence needing a separate function. % \begin{macrocode} -\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnw - #1#2#3#4 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnnw + #1#2#3#4#5 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#4} - { \@@_change_case_upper_el_hiatus:nnnN {#3} } + \tl_if_head_is_N_type:nTF {#5} + { \@@_change_case_upper_el_hiatus:nnnnN {#4} } { \@@_change_case_store:e - { \@@_change_case_codepoint:nn { upper } {#3} } - \@@_change_case_loop:nnw + { \@@_change_case_codepoint:nn { upper } {#4} } + \@@_change_case_loop:nnnw } - {#1} {#2} #4 \q_@@_recursion_stop + {#1} {#2} {#3} #5 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnN #1#2#3#4 +\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnnN #1#2#3#4#5 { - \token_if_cs:NTF #4 + \token_if_cs:NTF #5 { \@@_change_case_store:e { \@@_change_case_codepoint:nn { upper } {#1} } - \@@_change_case_loop:nnw {#2} {#3} #4 + \@@_change_case_loop:nnnw {#2} {#3} {#4} #5 } { \@@_codepoint_process:nN - { \@@_change_case_upper_el_hiatus:nnnn {#1} {#2} {#3} } #4 + { \@@_change_case_upper_el_hiatus:nnnnn {#1} {#2} {#3} {#4} } #5 } } -\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnnn #1#2#3#4#5 { - \@@_change_case_if_takes_dialytika:nTF {#4} + \@@_change_case_if_takes_dialytika:nTF {#5} { \@@_change_case_store:e { \@@_change_case_codepoint:nn { upper } {#1} } - \@@_change_case_upper_el_dialytika:n {#4} - \@@_change_case_upper_el_gobble:nnw {#2} {#3} + \@@_change_case_upper_el_dialytika:n {#5} + \@@_change_case_upper_el_gobble:nnnw {#2} {#3} {#4} } - { \@@_change_case_upper_el:nnn {#1} {#2} {#3} #4 } + { \@@_change_case_upper_el:nnnn {#1} {#2} {#3} {#4} #5 } } % \end{macrocode} % Handling the \emph{ypogegrammeni} output depends on the selected approach @@ -1323,31 +1350,31 @@ % For clearing out trailing combining marks after we have dealt with % the first one. % \begin{macrocode} -\cs_new:Npn \@@_change_case_upper_el_gobble:nnw - #1#2#3 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_upper_el_gobble:nnnw + #1#2#3#4 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#3} - { \@@_change_case_upper_el_gobble:nnN } - { \@@_change_case_loop:nnw } - {#1} {#2} #3 \q_@@_recursion_stop + \tl_if_head_is_N_type:nTF {#4} + { \@@_change_case_upper_el_gobble:nnnN } + { \@@_change_case_loop:nnnw } + {#1} {#2} {#3} #4 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_upper_el_gobble:nnN #1#2#3 +\cs_new:Npn \@@_change_case_upper_el_gobble:nnnN #1#2#3#4 { - \token_if_cs:NTF #3 - { \@@_change_case_loop:nnw {#1} {#2} } + \token_if_cs:NTF #4 + { \@@_change_case_loop:nnnw {#1} {#2} {#3} } { \@@_codepoint_process:nN - { \@@_change_case_upper_el_gobble:nnn {#1} {#2} } + { \@@_change_case_upper_el_gobble:nnnn {#1} {#2} {#3} } } - #3 + #4 } -\cs_new:Npn \@@_change_case_upper_el_gobble:nnn #1#2#3 +\cs_new:Npn \@@_change_case_upper_el_gobble:nnnn #1#2#3#4 { \bool_lazy_or:nnTF - { \@@_change_case_if_greek_accent_p:n {#3} } - { \@@_change_case_if_greek_breathing_p:n {#3} } - { \@@_change_case_upper_el_gobble:nnw {#1} {#2} } - { \@@_change_case_loop:nnw {#1} {#2} #3 } + { \@@_change_case_if_greek_accent_p:n {#4} } + { \@@_change_case_if_greek_breathing_p:n {#4} } + { \@@_change_case_upper_el_gobble:nnnw {#1} {#2} {#3} } + { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 } } % \end{macrocode} % Luckily the Greek range is limited and clear. @@ -1597,98 +1624,101 @@ % \end{macro} % \end{macro} % \begin{macro}[EXP] -% {\@@_change_case_boundary_upper_el:Nnnw, \@@_change_case_boundary_upper_el-x-iota:Nnnw} -% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnN} -% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnn} -% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnw} +% { +% \@@_change_case_boundary_upper_el:Nnnnw, +% \@@_change_case_boundary_upper_el-x-iota:Nnnnw +% } +% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnN} +% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnn} +% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnnw} % There is one things that need special treatment at start start of % words in Greek. For an isolated accent \emph{eta}, % which is handled by seeing if we have exactly one of the affected % codepoints followed by a space or brace group. % \begin{macrocode} -\cs_new:Npn \@@_change_case_boundary_upper_el:Nnnw - #1#2#3#4 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_boundary_upper_el:Nnnnw + #1#2#3#4#5 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#4} - { \@@_change_case_boundary_upper_el:nnN } - { \@@_change_case_loop:nnw } - {#2} {#3} #4 \q_@@_recursion_stop + \tl_if_head_is_N_type:nTF {#5} + { \@@_change_case_boundary_upper_el:nnnN } + { \@@_change_case_loop:nnnw } + {#2} {#3} {#4} #5 \q_@@_recursion_stop } -\cs_new_eq:cN { @@_change_case_boundary_upper_el-x-iota:Nnnw } - \@@_change_case_boundary_upper_el:Nnnw -\cs_new:Npn \@@_change_case_boundary_upper_el:nnN #1#2#3 +\cs_new_eq:cN { @@_change_case_boundary_upper_el-x-iota:Nnnnw } + \@@_change_case_boundary_upper_el:Nnnnw +\cs_new:Npn \@@_change_case_boundary_upper_el:nnnN #1#2#3#4 { - \token_if_cs:NTF #3 - { \@@_change_case_loop:nnw {#1} {#2} } + \token_if_cs:NTF #4 + { \@@_change_case_loop:nnnw {#1} {#2} {#3} } { \@@_codepoint_process:nN - { \@@_change_case_boundary_upper_el:nnn {#1} {#2} } + { \@@_change_case_boundary_upper_el:nnnn {#1} {#2} {#3} } } - #3 + #4 } -\cs_new:Npn \@@_change_case_boundary_upper_el:nnn #1#2#3 +\cs_new:Npn \@@_change_case_boundary_upper_el:nnnn #1#2#3#4 { \bool_lazy_any:nTF { - { \@@_codepoint_compare_p:nNn {#3} = { "0389 } } - { \@@_codepoint_compare_p:nNn {#3} = { "03AE } } - { \@@_codepoint_compare_p:nNn {#3} = { "1F22 } } - { \@@_codepoint_compare_p:nNn {#3} = { "1F2A } } + { \@@_codepoint_compare_p:nNn {#4} = { "0389 } } + { \@@_codepoint_compare_p:nNn {#4} = { "03AE } } + { \@@_codepoint_compare_p:nNn {#4} = { "1F22 } } + { \@@_codepoint_compare_p:nNn {#4} = { "1F2A } } } - { \@@_change_case_boundary_upper_el:nnnw {#1} {#2} {#3} } - { \@@_change_case_breathing:nnn {#1} {#2} {#3} } + { \@@_change_case_boundary_upper_el:nnnnw {#1} {#2} {#3} {#4} } + { \@@_change_case_breathing:nnnn {#1} {#2} {#3} {#4} } } -\cs_new:Npn \@@_change_case_boundary_upper_el:nnnw - #1#2#3#4 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_boundary_upper_el:nnnnw + #1#2#3#4#5 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#4} - { \@@_change_case_loop:nnw {#1} {#2} #3 } + \tl_if_head_is_N_type:nTF {#5} + { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 } { \@@_change_case_store:e { \codepoint_generate:nn { "0389 } - { \@@_change_case_catcode:nn {#3} { "0389 } } + { \@@_change_case_catcode:nn {#4} { "0389 } } } - \@@_change_case_loop:nnw {#1} {#2} + \@@_change_case_loop:nnnw {#1} {#2} {#3} } - #4 \q_@@_recursion_stop + #5 \q_@@_recursion_stop } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} -% \begin{macro}[EXP]{\@@_change_case_breathing:nnn} % \begin{macro}[EXP]{\@@_change_case_breathing:nnnn} -% \begin{macro}[EXP]{\@@_change_case_breathing:nnnnw} +% \begin{macro}[EXP]{\@@_change_case_breathing:nnnnn} % \begin{macro}[EXP]{\@@_change_case_breathing:nnnnnw} -% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnnn} -% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnw} -% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnN} -% \begin{macro}[EXP]{\@@_change_case_breathing_dialytika:nnn} +% \begin{macro}[EXP]{\@@_change_case_breathing:nnnnnnw} +% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnnnn} +% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnnw} +% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnN} +% \begin{macro}[EXP]{\@@_change_case_breathing_dialytika:nnnn} % In Greek, breathing diacritics are normally dropped when uppercasing: % see the code for the general case. However, for the first character % of a word, if there is a breather \emph{and} the next character takes % a \emph{dialytika}, it needs to be added. We start by checking if % the current codepoint is in the Greek range, then decomposing. % \begin{macrocode} -\cs_new:Npn \@@_change_case_breathing:nnn #1#2#3 +\cs_new:Npn \@@_change_case_breathing:nnnn #1#2#3#4 { - \@@_change_case_if_greek:nTF {#3} + \@@_change_case_if_greek:nTF {#4} { - \exp_args:Ne \@@_change_case_breathing:nnnn + \exp_args:Ne \@@_change_case_breathing:nnnnn { \codepoint_to_nfd:n - { \@@_codepoint_from_chars:Nw #3 } + { \@@_codepoint_from_chars:Nw #4 } } - {#1} {#2} {#3} + {#1} {#2} {#3} {#4} } - { \@@_change_case_loop:nnw {#1} {#2} #3 } + { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 } } -\cs_new:Npn \@@_change_case_breathing:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_breathing:nnnnn #1#2#3#4#5 { \@@_codepoint_process:nN - { \@@_change_case_breathing:nnnnw {#2} {#3} {#4} } + { \@@_change_case_breathing:nnnnnw {#2} {#3} {#4} {#5} } #1 \q_mark } % \end{macrocode} @@ -1699,36 +1729,36 @@ % and second if the final resulting codepoint is one of the two we % care about. % \begin{macrocode} -\cs_new:Npn \@@_change_case_breathing:nnnnw #1#2#3#4#5 \q_mark +\cs_new:Npn \@@_change_case_breathing:nnnnnw #1#2#3#4#5#6 \q_mark { - \tl_if_blank:nTF {#5} - { \@@_change_case_loop:nnw {#1} {#2} #3 } + \tl_if_blank:nTF {#6} + { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 } { \@@_codepoint_process:nN - { \@@_change_case_breathing:nnnnnw {#1} {#2} {#3} {#4} } - #5 \q_mark + { \@@_change_case_breathing:nnnnnnw {#1} {#2} {#3} {#4} {#5} } + #6 \q_mark } } -\cs_new:Npn \@@_change_case_breathing:nnnnnw #1#2#3#4#5#6 \q_mark +\cs_new:Npn \@@_change_case_breathing:nnnnnnw #1#2#3#4#5#6#7 \q_mark { - \tl_if_blank:nTF {#6} + \tl_if_blank:nTF {#7} { - \@@_change_case_breathing_aux:nnnnn - {#1} {#2} {#3} {#4} {#5} + \@@_change_case_breathing_aux:nnnnnn + {#1} {#2} {#3} {#4} {#5} {#6} } { \@@_codepoint_process:nN - { \@@_change_case_breathing:nnnnnw {#1} {#2} {#3} {#4} } - #6 \q_mark + { \@@_change_case_breathing:nnnnnnw {#1} {#2} {#3} {#4} {#5} } + #7 \q_mark } } -\cs_new:Npn \@@_change_case_breathing_aux:nnnnn #1#2#3#4#5 +\cs_new:Npn \@@_change_case_breathing_aux:nnnnnn #1#2#3#4#5#6 { \bool_lazy_or:nnTF - { \@@_codepoint_compare_p:nNn {#5} = { "0313 } } - { \@@_codepoint_compare_p:nNn {#5} = { "0314 } } - { \@@_change_case_breathing_aux:nnnw {#1} {#2} {#4} } - { \@@_change_case_loop:nnw {#1} {#2} #3 } + { \@@_codepoint_compare_p:nNn {#6} = { "0313 } } + { \@@_codepoint_compare_p:nNn {#6} = { "0314 } } + { \@@_change_case_breathing_aux:nnnnw {#1} {#2} {#3} {#5} } + { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 } } % \end{macrocode} % Now the lookahead can be fired: check the next codepoint and assess @@ -1736,29 +1766,29 @@ % breathing mark or generate the \emph{dialytika}: the % latter is code shared with the general mechanism. % \begin{macrocode} -\cs_new:Npn \@@_change_case_breathing_aux:nnnw #1#2#3#4 +\cs_new:Npn \@@_change_case_breathing_aux:nnnnw #1#2#3#4#5 \q_@@_recursion_stop { \@@_change_case_store:e - { \@@_change_case_codepoint:nn { upper } {#3} } - \tl_if_head_is_N_type:nTF {#4} - { \@@_change_case_breathing_aux:nnN } - { \@@_change_case_loop:nnw } - {#1} {#2} #4 \q_@@_recursion_stop + { \@@_change_case_codepoint:nn { upper } {#4} } + \tl_if_head_is_N_type:nTF {#5} + { \@@_change_case_breathing_aux:nnnN } + { \@@_change_case_loop:nnnw } + {#1} {#2} {#3} #5 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_breathing_aux:nnN #1#2#3 +\cs_new:Npn \@@_change_case_breathing_aux:nnnN #1#2#3#4 { \@@_codepoint_process:nN - { \@@_change_case_breathing_dialytika:nnn {#1} {#2} } #3 + { \@@_change_case_breathing_dialytika:nnnn {#1} {#2} {#3} } #4 } -\cs_new:Npn \@@_change_case_breathing_dialytika:nnn #1#2#3 +\cs_new:Npn \@@_change_case_breathing_dialytika:nnnn #1#2#3#4 { - \@@_change_case_if_takes_dialytika:nTF {#3} + \@@_change_case_if_takes_dialytika:nTF {#4} { - \@@_change_case_upper_el_dialytika:n {#3} - \@@_change_case_loop:nnw {#1} {#2} + \@@_change_case_upper_el_dialytika:n {#4} + \@@_change_case_loop:nnnw {#1} {#2} {#3} } - { \@@_change_case_loop:nnw {#1} {#2} #3 } + { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 } } % \end{macrocode} % \end{macro} @@ -1769,88 +1799,88 @@ % \end{macro} % \end{macro} % \end{macro} -% \begin{macro}[EXP]{\@@_change_case_title_el:nnnn} +% \begin{macro}[EXP]{\@@_change_case_title_el:nnnnn} % Titlecasing retains accents, but to prevent the uppercasing code % from kicking in, there has to be an explicit function here. % \begin{macrocode} -\cs_new:Npn \@@_change_case_title_el:nnnn #1#2#3#4 - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } +\cs_new:Npn \@@_change_case_title_el:nnnnn #1#2#3#4#5 + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] % { -% \@@_change_case_upper_hy:nnnn , -% \@@_change_case_title_hy:nnnn , -% \@@_change_case_upper_hy-x-yiwn:nnnn , -% \@@_change_case_title_hy-x-yiwn:nnnn +% \@@_change_case_upper_hy:nnnnn , +% \@@_change_case_title_hy:nnnnn , +% \@@_change_case_upper_hy-x-yiwn:nnnnn , +% \@@_change_case_title_hy-x-yiwn:nnnnn % } % See \url{https://www.unicode.org/L2/L2020/20143-armenian-ech-yiwn.pdf}. % \begin{macrocode} -\cs_new:Npn \@@_change_case_upper_hy:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_upper_hy:nnnnn #1#2#3#4#5 { - \@@_codepoint_compare:nNnTF {#4} = { "0587 } + \@@_codepoint_compare:nNnTF {#5} = { "0587 } { \@@_change_case_store:e { \codepoint_generate:nn { "0535 } - { \@@_change_case_catcode:nn {#4} { "0535 } } + { \@@_change_case_catcode:nn {#5} { "0535 } } \codepoint_generate:nn { "054E } - { \@@_change_case_catcode:nn {#4} { "054E } } + { \@@_change_case_catcode:nn {#5} { "054E } } } - \use:c { @@_change_case_next_ #2 :nn } - {#2} {#3} + \use:c { @@_change_case_next_ #2 :nnn } + {#2} {#3} {#4} } - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } } -\cs_new:Npn \@@_change_case_title_hy:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_title_hy:nnnnn #1#2#3#4#5 { - \@@_codepoint_compare:nNnTF {#4} = { "0587 } + \@@_codepoint_compare:nNnTF {#5} = { "0587 } { \@@_change_case_store:e { \codepoint_generate:nn { "0535 } - { \@@_change_case_catcode:nn {#4} { "0535 } } + { \@@_change_case_catcode:nn {#5} { "0535 } } \codepoint_generate:nn { "057E } - { \@@_change_case_catcode:nn {#4} { "057E } } + { \@@_change_case_catcode:nn {#5} { "057E } } } - \use:c { @@_change_case_next_ #2 :nn } - {#2} {#3} + \use:c { @@_change_case_next_ #2 :nnn } + {#2} {#3} {#4} } - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } } -\cs_new:cpn { @@_change_case_upper_hy-x-yiwn:nnnn } #1#2#3#4 - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } -\cs_new_eq:cc { @@_change_case_title_hy-x-yiwn:nnnn } - { @@_change_case_upper_hy-x-yiwn:nnnn } +\cs_new:cpn { @@_change_case_upper_hy-x-yiwn:nnnnn } #1#2#3#4#5 + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } +\cs_new_eq:cc { @@_change_case_title_hy-x-yiwn:nnnnn } + { @@_change_case_upper_hy-x-yiwn:nnnnn } % \end{macrocode} % \end{macro} % -% \begin{macro}[EXP]{\@@_change_case_lower_la-x-medieval:nnnn} -% \begin{macro}[EXP]{\@@_change_case_upper_la-x-medieval:nnnn} +% \begin{macro}[EXP]{\@@_change_case_lower_la-x-medieval:nnnnn} +% \begin{macro}[EXP]{\@@_change_case_upper_la-x-medieval:nnnnn} % Simply swaps of characters. % \begin{macrocode} -\cs_new:cpn { @@_change_case_lower_la-x-medieval:nnnn } #1#2#3#4 +\cs_new:cpn { @@_change_case_lower_la-x-medieval:nnnnn } #1#2#3#4#5 { - \@@_codepoint_compare:nNnTF {#4} = { "0056 } + \@@_codepoint_compare:nNnTF {#5} = { "0056 } { \@@_change_case_store:e - { \char_generate:nn { "0075 } { \@@_char_catcode:N #4 } } - \use:c { @@_change_case_next_ #2 :nn } - {#2} {#3} + { \char_generate:nn { "0075 } { \@@_char_catcode:N #5 } } + \use:c { @@_change_case_next_ #2 :nnn } + {#2} {#3} {#4} } - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } } -\cs_new:cpn { @@_change_case_upper_la-x-medieval:nnnn } #1#2#3#4 +\cs_new:cpn { @@_change_case_upper_la-x-medieval:nnnnn } #1#2#3#4#5 { - \@@_codepoint_compare:nNnTF {#4} = { "0075 } + \@@_codepoint_compare:nNnTF {#5} = { "0075 } { \@@_change_case_store:e - { \char_generate:nn { "0056 } { \@@_char_catcode:N #4 } } - \use:c { @@_change_case_next_ #2 :nn } - {#2} {#3} + { \char_generate:nn { "0056 } { \@@_char_catcode:N #5 } } + \use:c { @@_change_case_next_ #2 :nnn } + {#2} {#3} {#4} } - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } } % \end{macrocode} % \end{macro} @@ -1858,62 +1888,62 @@ % % \begin{macro}[EXP] % { -% \@@_change_cases_lower_lt:nnnn , -% \@@_change_cases_lower_lt_auxi:nnnn , -% \@@_change_cases_lower_lt_auxii:nnnn +% \@@_change_cases_lower_lt:nnnnn , +% \@@_change_cases_lower_lt_auxi:nnnnn , +% \@@_change_cases_lower_lt_auxii:nnnnn % } -% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnw} -% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnN} -% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnn} +% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnnw} +% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnnN} +% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnnn} % For Lithuanian, the issue to be dealt with is dots over lower case % letters: these should be present if there is another accent. The first step % is a simple match attempt: look for the three uppercase accented letters % which should gain a dot-above char in their lowercase form. % \begin{macrocode} -\cs_new:Npn \@@_change_case_lower_lt:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_lower_lt:nnnnn #1#2#3#4#5 { - \exp_args:Ne \@@_change_case_lower_lt_auxi:nnnn + \exp_args:Ne \@@_change_case_lower_lt_auxi:nnnnn { - \int_case:nn { \@@_codepoint_from_chars:Nw #4 } + \int_case:nn { \@@_codepoint_from_chars:Nw #5 } { { "00CC } { "0300 } { "00CD } { "0301 } { "0128 } { "0303 } } } - {#2} {#3} {#4} + {#2} {#3} {#4} {#5} } % \end{macrocode} % If there was a hit, output the result with the dot-above and move on. % Otherwise, look for one of the three letters that can take a combining % accent: I, J nd I-ogonek. % \begin{macrocode} -\cs_new:Npn \@@_change_case_lower_lt_auxi:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_lower_lt_auxi:nnnnn #1#2#3#4#5 { \tl_if_blank:nTF {#1} { - \exp_args:Ne \@@_change_case_lower_lt_auxii:nnnn + \exp_args:Ne \@@_change_case_lower_lt_auxii:nnnnn { - \int_case:nn { \@@_codepoint_from_chars:Nw #4 } + \int_case:nn { \@@_codepoint_from_chars:Nw #5 } { { "0049 } { "0069 } { "004A } { "006A } { "012E } { "012F } } } - {#2} {#3} {#4} + {#2} {#3} {#4} {#5} } { \@@_change_case_store:e { \codepoint_generate:nn { "0069 } - { \@@_change_case_catcode:nn {#4} { "0069 } } + { \@@_change_case_catcode:nn {#5} { "0069 } } \codepoint_generate:nn { "0307 } - { \@@_change_case_catcode:nn {#4} { "0307 } } + { \@@_change_case_catcode:nn {#5} { "0307 } } \codepoint_generate:nn {#1} - { \@@_change_case_catcode:nn {#4} {#1} } + { \@@_change_case_catcode:nn {#5} {#1} } } - \@@_change_case_loop:nnw {#2} {#3} + \@@_change_case_loop:nnnw {#2} {#3} {#4} } } % \end{macrocode} @@ -1921,55 +1951,55 @@ % then need to look for a combining accent: as usual, we need to be aware of % the loop situation. % \begin{macrocode} -\cs_new:Npn \@@_change_case_lower_lt_auxii:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_lower_lt_auxii:nnnnn #1#2#3#4#5 { \tl_if_blank:nTF {#1} - { \@@_change_case_codepoint:nnnn {#2} {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn {#2} {#2} {#3} {#4} {#5} } { \@@_change_case_store:e { \codepoint_generate:nn {#1} - { \@@_change_case_catcode:nn {#4} {#1} } + { \@@_change_case_catcode:nn {#5} {#1} } } - \@@_change_case_lower_lt:nnw {#2} {#3} + \@@_change_case_lower_lt:nnnw {#2} {#3} {#4} } } -\cs_new:Npn \@@_change_case_lower_lt:nnw #1#2#3 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_lower_lt:nnnw #1#2#3#4 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#3} - { \@@_change_case_lower_lt:nnN } - { \@@_change_case_loop:nnw } - {#1} {#2} #3 \q_@@_recursion_stop + \tl_if_head_is_N_type:nTF {#4} + { \@@_change_case_lower_lt:nnnN } + { \@@_change_case_loop:nnnw } + {#1} {#2} {#3} #4 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_lower_lt:nnN #1#2#3 +\cs_new:Npn \@@_change_case_lower_lt:nnnN #1#2#3#4 { \@@_codepoint_process:nN - { \@@_change_case_lower_lt:nnn {#1} {#2} } #3 + { \@@_change_case_lower_lt:nnnn {#1} {#2} {#3} } #4 } -\cs_new:Npn \@@_change_case_lower_lt:nnn #1#2#3 +\cs_new:Npn \@@_change_case_lower_lt:nnnn #1#2#3#4 { \bool_lazy_and:nnT { \bool_lazy_or_p:nn - { ! \tl_if_single_p:n {#3} } - { ! \token_if_cs_p:N #3 } + { ! \tl_if_single_p:n {#4} } + { ! \token_if_cs_p:N #4 } } { \bool_lazy_any_p:n { - { \@@_codepoint_compare_p:nNn {#3} = { "0300 } } - { \@@_codepoint_compare_p:nNn {#3} = { "0301 } } - { \@@_codepoint_compare_p:nNn {#3} = { "0303 } } + { \@@_codepoint_compare_p:nNn {#4} = { "0300 } } + { \@@_codepoint_compare_p:nNn {#4} = { "0301 } } + { \@@_codepoint_compare_p:nNn {#4} = { "0303 } } } } { \@@_change_case_store:e { \codepoint_generate:nn { "0307 } - { \@@_change_case_catcode:nn {#3} { "0307 } } + { \@@_change_case_catcode:nn {#4} { "0307 } } } } - \@@_change_case_loop:nnw {#1} {#2} #3 + \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 } % \end{macrocode} % \end{macro} @@ -1978,64 +2008,64 @@ % \end{macro} % \begin{macro}[EXP] % { -% \@@_change_cases_upper_lt:nnnn , -% \@@_change_cases_upper_lt_aux:nnnn +% \@@_change_cases_upper_lt:nnnnn , +% \@@_change_cases_upper_lt_aux:nnnnn % } -% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnw} -% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnN} -% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnn} +% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnnw} +% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnnN} +% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnnn} % The uppercasing version: first find i/j/i-ogonek, then look for the % combining char: drop it if present. % \begin{macrocode} -\cs_new:Npn \@@_change_case_upper_lt:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_upper_lt:nnnnn #1#2#3#4#5 { - \exp_args:Ne \@@_change_case_upper_lt_aux:nnnn + \exp_args:Ne \@@_change_case_upper_lt_aux:nnnnn { - \int_case:nn { \@@_codepoint_from_chars:Nw #4 } + \int_case:nn { \@@_codepoint_from_chars:Nw #5 } { { "0069 } { "0049 } { "006A } { "004A } { "012F } { "012E } } } - {#2} {#3} {#4} + {#2} {#3} {#4} {#5} } -\cs_new:Npn \@@_change_case_upper_lt_aux:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_upper_lt_aux:nnnnn #1#2#3#4#5 { \tl_if_blank:nTF {#1} - { \@@_change_case_codepoint:nnnn { upper } {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn { upper } {#2} {#3} {#4} {#5} } { \@@_change_case_store:e { \codepoint_generate:nn {#1} - { \@@_change_case_catcode:nn {#4} {#1} } + { \@@_change_case_catcode:nn {#5} {#1} } } - \@@_change_case_upper_lt:nnw {#2} {#3} + \@@_change_case_upper_lt:nnnw {#2} {#3} {#4} } } -\cs_new:Npn \@@_change_case_upper_lt:nnw #1#2#3 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_upper_lt:nnnw #1#2#3#4 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#3} - { \@@_change_case_upper_lt:nnN } - { \use:c { @@_change_case_next_ #1 :nn } } - {#1} {#2} #3 \q_@@_recursion_stop + \tl_if_head_is_N_type:nTF {#4} + { \@@_change_case_upper_lt:nnnN } + { \use:c { @@_change_case_next_ #1 :nnn } } + {#1} {#2} {#3} #4 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_upper_lt:nnN #1#2#3 +\cs_new:Npn \@@_change_case_upper_lt:nnnN #1#2#3#4 { \@@_codepoint_process:nN - { \@@_change_case_upper_lt:nnn {#1} {#2} } #3 + { \@@_change_case_upper_lt:nnnn {#1} {#2} {#3} } #4 } -\cs_new:Npn \@@_change_case_upper_lt:nnn #1#2#3 +\cs_new:Npn \@@_change_case_upper_lt:nnnn #1#2#3#4 { \bool_lazy_and:nnTF { \bool_lazy_or_p:nn - { ! \tl_if_single_p:n {#3} } - { ! \token_if_cs_p:N #3 } + { ! \tl_if_single_p:n {#4} } + { ! \token_if_cs_p:N #4 } } - { \@@_codepoint_compare_p:nNn {#3} = { "0307 } } - { \use:c { @@_change_case_next_ #1 :nn } {#1} {#2} } - { \use:c { @@_change_case_next_ #1 :nn } {#1} {#2} #3 } + { \@@_codepoint_compare_p:nNn {#4} = { "0307 } } + { \use:c { @@_change_case_next_ #1 :nnn } {#1} {#2} {#3} } + { \use:c { @@_change_case_next_ #1 :nnn } {#1} {#2} {#3} #4 } } % \end{macrocode} % \end{macro} @@ -2044,84 +2074,84 @@ % \end{macro} % % \begin{macro}[EXP] -% {\@@_change_case_title_nl:nnnn, \@@_change_case_title_nl_aux:nnnn} -% \begin{macro}[EXP]{\@@_change_case_title_nl:nnw} -% \begin{macro}[EXP]{\@@_change_case_title_nl:nnN} +% {\@@_change_case_title_nl:nnnnn, \@@_change_case_title_nl_aux:nnnnn} +% \begin{macro}[EXP]{\@@_change_case_title_nl:nnnw} +% \begin{macro}[EXP]{\@@_change_case_title_nl:nnnN} % For Dutch, there is a single look-ahead test for \texttt{ij} when % title casing. If the appropriate letters are found, produce \texttt{IJ} % and gobble the \texttt{j}/\texttt{J}. % \begin{macrocode} -\cs_new:Npn \@@_change_case_title_nl:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_title_nl:nnnnn #1#2#3#4#5 { - \tl_if_single:nTF {#4} - { \@@_change_case_title_nl_aux:nnnn } - { \@@_change_case_codepoint:nnnn } - {#1} {#2} {#3} {#4} + \tl_if_single:nTF {#5} + { \@@_change_case_title_nl_aux:nnnnn } + { \@@_change_case_codepoint:nnnnn } + {#1} {#2} {#3} {#4} {#5} } -\cs_new:Npn \@@_change_case_title_nl_aux:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_title_nl_aux:nnnnn #1#2#3#4#5 { \bool_lazy_or:nnTF - { \int_compare_p:nNn {`#4} = { "0049 } } - { \int_compare_p:nNn {`#4} = { "0069 } } + { \int_compare_p:nNn {`#5} = { "0049 } } + { \int_compare_p:nNn {`#5} = { "0069 } } { \@@_change_case_store:e - { \char_generate:nn { "0049 } { \@@_char_catcode:N #4 } } - \@@_change_case_title_nl:nnw {#2} {#3} + { \char_generate:nn { "0049 } { \@@_char_catcode:N #5 } } + \@@_change_case_title_nl:nnnw {#2} {#3} {#4} } - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } } -\cs_new:Npn \@@_change_case_title_nl:nnw #1#2#3 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_title_nl:nnnw #1#2#3#4 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#3} - { \@@_change_case_title_nl:nnN } - { \use:c { @@_change_case_next_ #1 :nn } } - {#1} {#2} #3 \q_@@_recursion_stop + \tl_if_head_is_N_type:nTF {#4} + { \@@_change_case_title_nl:nnnN } + { \use:c { @@_change_case_next_ #1 :nnn } } + {#1} {#2} {#3} #4 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_title_nl:nnN #1#2#3 +\cs_new:Npn \@@_change_case_title_nl:nnnN #1#2#3#4 { \bool_lazy_and:nnTF - { ! \token_if_cs_p:N #3 } + { ! \token_if_cs_p:N #4 } { \bool_lazy_or_p:nn - { \int_compare_p:nNn {`#3} = { "004A } } - { \int_compare_p:nNn {`#3} = { "006A } } + { \int_compare_p:nNn {`#4} = { "004A } } + { \int_compare_p:nNn {`#4} = { "006A } } } { \@@_change_case_store:e - { \char_generate:nn { "004A } { \@@_char_catcode:N #3 } } - \use:c { @@_change_case_next_ #1 :nn } {#1} {#2} + { \char_generate:nn { "004A } { \@@_char_catcode:N #4 } } + \use:c { @@_change_case_next_ #1 :nnn } {#1} {#2} {#3} } - { \use:c { @@_change_case_next_ #1 :nn } {#1} {#2} #3 } + { \use:c { @@_change_case_next_ #1 :nnn } {#1} {#2} {#3} #4 } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % -% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnnn} -% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnNw} -% \begin{macro}[EXP]{\@@_change_case_lower_tr:NnnN} -% \begin{macro}[EXP]{\@@_change_case_lower_tr:Nnnn} +% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnnnn} +% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnnNw} +% \begin{macro}[EXP]{\@@_change_case_lower_tr:NnnnN} +% \begin{macro}[EXP]{\@@_change_case_lower_tr:Nnnnn} % The Turkic languages need special treatment for dotted-i and dotless-i. % The lower casing rule can be expressed in terms of searching first for % either a dotless-I or a dotted-I. In the latter case the mapping is % easy, but in the former there is a second stage search. % \begin{macrocode} -\cs_new:Npn \@@_change_case_lower_tr:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_lower_tr:nnnnn #1#2#3#4#5 { - \@@_codepoint_compare:nNnTF {#4} = { "0049 } - { \@@_change_case_lower_tr:nnNw {#1} {#3} #4 } + \@@_codepoint_compare:nNnTF {#5} = { "0049 } + { \@@_change_case_lower_tr:nnnNw {#1} {#3} {#4} #5 } { - \@@_codepoint_compare:nNnTF {#4} = { "0130 } + \@@_codepoint_compare:nNnTF {#5} = { "0130 } { \@@_change_case_store:e { \codepoint_generate:nn { "0069 } - { \@@_change_case_catcode:nn {#4} { "0069 } } + { \@@_change_case_catcode:nn {#5} { "0069 } } } - \@@_change_case_loop:nnw {#1} {#3} + \@@_change_case_loop:nnnw {#1} {#3} {#4} } - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } } } % \end{macrocode} @@ -2130,41 +2160,41 @@ % combination is found both the dotless-I and the dot-above char have to % be removed from the input. % \begin{macrocode} -\cs_new:Npn \@@_change_case_lower_tr:nnNw #1#2#3#4 \q_@@_recursion_stop +\cs_new:Npn \@@_change_case_lower_tr:nnnNw #1#2#3#4#5 \q_@@_recursion_stop { - \tl_if_head_is_N_type:nTF {#4} - { \@@_change_case_lower_tr:NnnN #3 {#1} {#2} } + \tl_if_head_is_N_type:nTF {#5} + { \@@_change_case_lower_tr:NnnnN #4 {#1} {#2} {#3} } { \@@_change_case_store:e { \codepoint_generate:nn { "0131 } - { \@@_change_case_catcode:nn {#3} { "0131 } } + { \@@_change_case_catcode:nn {#4} { "0131 } } } - \@@_change_case_loop:nnw {#1} {#2} + \@@_change_case_loop:nnnw {#1} {#2} {#3} } - #4 \q_@@_recursion_stop + #5 \q_@@_recursion_stop } -\cs_new:Npn \@@_change_case_lower_tr:NnnN #1#2#3#4 +\cs_new:Npn \@@_change_case_lower_tr:NnnnN #1#2#3#4#5 { \@@_codepoint_process:nN - { \@@_change_case_lower_tr:Nnnn #1 {#2} {#3} } #4 + { \@@_change_case_lower_tr:Nnnnn #1 {#2} {#3} {#4} } #5 } -\cs_new:Npn \@@_change_case_lower_tr:Nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_lower_tr:Nnnnn #1#2#3#4#5 { \bool_lazy_or:nnTF { \bool_lazy_and_p:nn - { \tl_if_single_p:n {#4} } - { \token_if_cs_p:N #4 } + { \tl_if_single_p:n {#5} } + { \token_if_cs_p:N #5 } } - { ! \@@_codepoint_compare_p:nNn {#4} = { "0307 } } + { ! \@@_codepoint_compare_p:nNn {#5} = { "0307 } } { \@@_change_case_store:e { \codepoint_generate:nn { "0131 } { \@@_change_case_catcode:nn {#1} { "0131 } } } - \@@_change_case_loop:nnw {#2} {#3} #4 + \@@_change_case_loop:nnnw {#2} {#3} {#4} #5 } { \@@_change_case_store:e @@ -2172,7 +2202,7 @@ \codepoint_generate:nn { "0069 } { \@@_change_case_catcode:nn {#1} { "0069 } } } - \@@_change_case_loop:nnw {#2} {#3} + \@@_change_case_loop:nnnw {#2} {#3} {#4} } } % \end{macrocode} @@ -2180,33 +2210,33 @@ % \end{macro} % \end{macro} % \end{macro} -% \begin{macro}[EXP]{\@@_change_case_upper_tr:nnnn} +% \begin{macro}[EXP]{\@@_change_case_upper_tr:nnnnn} % Uppercasing is easier: just one exception with no context. % \begin{macrocode} -\cs_new:Npn \@@_change_case_upper_tr:nnnn #1#2#3#4 +\cs_new:Npn \@@_change_case_upper_tr:nnnnn #1#2#3#4#5 { - \@@_codepoint_compare:nNnTF {#4} = { "0069 } + \@@_codepoint_compare:nNnTF {#5} = { "0069 } { \@@_change_case_store:e { \codepoint_generate:nn { "0130 } - { \@@_change_case_catcode:nn {#4} { "0130 } } + { \@@_change_case_catcode:nn {#5} { "0130 } } } - \use:c { @@_change_case_next_ #2 :nn } {#2} {#3} + \use:c { @@_change_case_next_ #2 :nnn } {#2} {#3} {#4} } - { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} } + { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} } } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] -% {\@@_change_case_lower_az:nnnn, \@@_change_case_upper_az:nnnn} +% {\@@_change_case_lower_az:nnnnn, \@@_change_case_upper_az:nnnnn} % Straight copies. % \begin{macrocode} -\cs_new_eq:NN \@@_change_case_lower_az:nnnn - \@@_change_case_lower_tr:nnnn -\cs_new_eq:NN \@@_change_case_upper_az:nnnn - \@@_change_case_upper_tr:nnnn +\cs_new_eq:NN \@@_change_case_lower_az:nnnnn + \@@_change_case_lower_tr:nnnnn +\cs_new_eq:NN \@@_change_case_upper_az:nnnnn + \@@_change_case_upper_tr:nnnnn % \end{macrocode} % \end{macro} % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx b/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx index 8b3ac6098c5..d863e51acef 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx @@ -2,7 +2,7 @@ % %% File: l3text-map.dtx % -% Copyright (C) 2022,2023 The LaTeX Project +% Copyright (C) 2022-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 @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx b/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx index 075b3707379..5770853cd72 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3text.dtx b/Master/texmf-dist/source/latex/l3kernel/l3text.dtx index 8df534cc84a..ea33b588557 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3text.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3text.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -94,18 +94,18 @@ % % \section{Case changing} % -% \begin{function}[EXP, added = 2019-11-20, updated = 2022-10-13] +% \begin{function}[EXP, added = 2019-11-20, updated = 2023-07-08] % { -% \text_lowercase:n, \text_uppercase:n, \text_titlecase:n, +% \text_lowercase:n, \text_uppercase:n, \text_titlecase_all:n, % \text_titlecase_first:n, -% \text_lowercase:nn, \text_uppercase:nn, \text_titlecase:nn, +% \text_lowercase:nn, \text_uppercase:nn, \text_titlecase_all:nn, % \text_titlecase_first:nn % } % \begin{syntax} % \cs{text_uppercase:n} \Arg{tokens} % \cs{text_uppercase:nn} \Arg{BCP-47} \Arg{tokens} % \end{syntax} -% Takes user input \meta{text} first applies \cs{text_expand}, then +% Takes user input \meta{text} first applies \cs{text_expand:n}, then % transforms the case of character tokens as specified by the % function name. The category code of letters are not changed by this % process when Unicode engines are used; in $8$-bit engines, case changed @@ -115,11 +115,13 @@ % % Upper- and lowercase have the obvious meanings. Titlecasing may be regarded % informally as converting the first character of the \meta{tokens} to -% uppercase and the rest to lowercase. However, the process is more complex +% uppercase. However, the process is more complex % than this as there are some situations where a single lowercase character % maps to a special form, for example \texttt{ij} in Dutch which becomes -% \texttt{IJ}. The \texttt{titlecase_first} variant does not attempt -% any case changing at all after the first letter has been processed. +% \texttt{IJ}. There are two functions available for titlecasing: one which +% applies the change to each \enquote{word} and a second which only applies +% at the start of the input. (Here, \enquote{word} boundaries are spaces: +% at present, full Unicode word breaking is not attempted.) % % Importantly, notice that these functions are intended for working with % user \emph{text for typesetting}. For case changing programmatic data see @@ -163,10 +165,7 @@ % I-dot and introduced when upper casing i-dotless. % \item German (\texttt{de-x-eszett}). % An alternative mapping for German in which the lowercase -% \emph{Eszett} maps to a \emph{gro\ss{}es Eszett}. Since there is -% a |T1| slot for the \emph{gro\ss{}es Eszett} in |T1|, this -% tailoring \emph{is} available with \pdfTeX{} as well as in the -% Unicode \TeX{} engines. +% \emph{Eszett} maps to a \emph{gro\ss{}es Eszett}. % \item Greek (\texttt{el}). % Removes accents from Greek letters when uppercasing; titlecasing % leaves accents in place. A variant \texttt{el-x-iota} is available @@ -185,25 +184,17 @@ % The characters |u| and |V| are interchanged on case changing. % \item Dutch (\texttt{nl}). % Capitalisation of \texttt{ij} at the beginning of titlecased -% input produces \texttt{IJ} rather than \texttt{Ij}. The output -% retains two separate letters, thus this transformation \emph{is} -% available using \pdfTeX{}. +% input produces \texttt{IJ} rather than \texttt{Ij}. % \end{itemize} % -% For titlecasing, note that there are two functions available. The -% function \cs{text_titlecase:n} applies (broadly) uppercasing to the first -% letter of the input, then lowercasing to the remainder. In contrast, -% \cs{text_titlecase_first:n} \emph{only} carries out the uppercasing operation, -% and leaves the balance of the input unchanged. Determining whether -% non-letter characters at the start of text should switch from upper- to -% lowercasing is controllable. When \cs{l_text_titlecase_check_letter_bool} is +% Determining whether non-letter characters at the start of text should count +% as the uppercase element is controllable. When \cs{l_text_titlecase_check_letter_bool} is % \texttt{true}, characters which are not letters (category code~$11$) are -% left unchanged and \enquote{skipped}: the first \emph{letter} is uppercased. +% \enquote{skipped}: the first \emph{letter} is uppercased. % (With $8$-bit engines, this is extended to active characters which form % part of a multi-byte letter codepoint.) When % \cs{l_text_titlecase_check_letter_bool} is \texttt{false}, the first -% character is uppercased, and the rest lowercased, irrespective of the nature -% of the character. +% character is uppercased, irrespective of the category code of the character. % % \begin{function}[added = 2022-07-04] % { diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx index 9cadf04e878..6336b0d0765 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -177,9 +177,6 @@ % by avoiding \cs{exp_not:n} for characters other than active and macro % parameters.) % -% ^^A todo: ask LuaTeX list for an \ifx\undefined <active char> -% ^^A which does not add the <active char> in memory. -% % \begin{macrocode} %<*package> % \end{macrocode} @@ -443,6 +440,42 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_analysis_disable_char:N} +% Similar to \cs{@@_analysis_disable:n}, but it receives a normal +% character token, tests if that token is active (by turning it into +% a space: the active space has been undefined at this point), and +% if so, disables it. Even if the character is active and set equal +% to a primitive conditional, nothing blows up. +% Again, in \pTeX{} and \upTeX{} we skip characters beyond $[0,255]$, +% which cannot be active anyways. +% \begin{macrocode} +\group_begin: + \char_set_catcode_active:N \^^@ + \cs_new_protected:Npn \@@_analysis_disable_char:N #1 + { + \tex_lccode:D `#1 = 32 \exp_stop_f: + \tex_lowercase:D { \if_meaning:w #1 } \tex_undefined:D + \tex_let:D #1 \tex_undefined:D + \fi: + } + \bool_lazy_or:nnT + { \sys_if_engine_ptex_p: } + { \sys_if_engine_uptex_p: } + { + \cs_gset_protected:Npn \@@_analysis_disable_char:N #1 + { + \if_int_compare:w 256 > `#1 \exp_stop_f: + \tex_lccode:D `#1 = 32 \exp_stop_f: + \tex_lowercase:D { \if_meaning:w #1 } \tex_undefined:D + \tex_let:D #1 \tex_undefined:D + \fi: + \fi: + } + } +\group_end: +% \end{macrocode} +% \end{macro} +% % \subsection{First pass} % % The goal of this pass is to detect special (non-\texttt{N}-type) tokens, @@ -737,7 +770,7 @@ \exp_after:wN \use_ii:nn \fi: { - \@@_analysis_disable:n { `#1 } + \@@_analysis_disable_char:N #1 \int_incr:N \l_@@_analysis_normal_int } { \@@_analysis_cs_space_count:NN \@@_analysis_a_cs:ww #1 } diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx index e606c3c5587..f3c52e2a0f0 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -187,7 +187,7 @@ % \tl_put_left:co, % \tl_gput_left:Nn, \tl_gput_left:NV, \tl_gput_left:Nv, \tl_gput_left:Ne, % \tl_gput_left:No, -% \tl_gput_left:cn, \tl_gput_left:cV, \tl_gput_left:cv, \tl_gput_left:ce +% \tl_gput_left:cn, \tl_gput_left:cV, \tl_gput_left:cv, \tl_gput_left:ce, % \tl_gput_left:co % } % \begin{syntax} @@ -205,7 +205,7 @@ % \tl_put_right:co, % \tl_gput_right:Nn, \tl_gput_right:NV, \tl_gput_right:Nv, \tl_gput_right:Ne, % \tl_gput_right:No, -% \tl_gput_right:cn, \tl_gput_right:cV, \tl_gput_right:cv, \tl_gput_right:ce +% \tl_gput_right:cn, \tl_gput_right:cV, \tl_gput_right:cv, \tl_gput_right:ce, % \tl_gput_right:co % } % \begin{syntax} @@ -592,8 +592,8 @@ % \begin{syntax} % \cs{tl_reverse_items:n} \Arg{token list} % \end{syntax} -% Reverses the order of the \meta{items} stored in \meta{tl~var}, -% so that \Arg{item_1}\Arg{item_2}\Arg{item_3} \ldots \Arg{item_n} +% Reverses the order of the \meta{items} in the \meta{token list}, +% so that \meta{item_1}\meta{item_2}\meta{item_3} \ldots \meta{item_n} % becomes \Arg{item_n} \ldots{} \Arg{item_3}\Arg{item_2}\Arg{item_1}. % This process removes any unprotected space within the % \meta{token list}. Braced token groups are copied without diff --git a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx index aedde780987..888ceb36012 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % @@ -481,6 +481,18 @@ % \end{texnote} % \end{function} % +% \begin{function}[EXP,added = 2023-10-15]{\token_to_catcode:N} +% \begin{syntax} +% \cs{token_to_catcode:N} \meta{token} +% \end{syntax} +% Converts the given \meta{token} into a number describing its category code. +% If \meta{token} is a control sequence this expands to $16$. This can't +% detect the categories $0$ (escape character), $5$ (end of line), $9$ +% (ignored character), $14$ (comment character), or $15$ (invalid character). +% Control sequences or active characters let to a token of one of the +% detectable category codes will yield that category. +% \end{function} +% % \section{Token conditionals} % % \begin{function}[EXP,pTF]{\token_if_group_begin:N} @@ -1022,7 +1034,7 @@ % For instance \cs{peek_regex:nTF} \verb"{ abc | [a-z] }" |{ } { }| % |abc| will only inspect the first token~|a| even though the first % branch |abc| of the alternative is preferred in functions such as -% \cs{peek_regex_remove_once:n}. This may have an effect on +% \cs{peek_regex_remove_once:nTF}. This may have an effect on % tokenization if the input stream has not yet been tokenized and % category codes are changed. % \end{texnote} @@ -1221,7 +1233,7 @@ % \end{syntax} % Converts the \meta{char} to the equivalent case-changed character % as detailed by the function name (see \cs{str_foldcase:n} -% and \cs{text_titlecase:n} for details of these terms). The case mapping +% and \cs{text_titlecase_all:n} for details of these terms). The case mapping % is carried out with no context-dependence (\emph{cf.}~\cs{text_uppercase:n}, % \emph{etc.}) The \texttt{str} versions always generate \enquote{other} % (category code $12$) characters, whilst the standard versions generate @@ -1873,6 +1885,66 @@ % \end{macro} % \end{macro} % +% \begin{macro}{\token_to_catcode:N} +% \begin{macro}{\@@_to_catcode:N} +% The macro works by comparing the input token with \cs{if_catcode:w} with all +% valid category codes. Since the most common tokens in an average argument +% list are of category $11$ or $12$ those are tested first. And since a space +% and braces are no ordinary |N|-type arguments, and only control sequences +% let to those categories can match them they are tested last. +% \begin{macrocode} +\cs_new:Npn \token_to_catcode:N + { \int_value:w \group_align_safe_begin: \@@_to_catcode:N } +\cs_new:Npn \@@_to_catcode:N #1 + { + \if_catcode:w \exp_not:N #1 \c_catcode_letter_token + 11 + \else: + \if_catcode:w \exp_not:N #1 \c_catcode_other_token + 12 + \else: + \if_catcode:w \exp_not:N #1 \c_math_toggle_token + 3 + \else: + \if_catcode:w \exp_not:N #1 \c_alignment_token + 4 + \else: + \if_catcode:w \exp_not:N #1 ## + 6 + \else: + \if_catcode:w \exp_not:N #1 \c_math_superscript_token + 7 + \else: + \if_catcode:w \exp_not:N #1 \c_math_subscript_token + 8 + \else: + \if_catcode:w \exp_not:N #1 \c_group_begin_token + 1 + \else: + \if_catcode:w \exp_not:N #1 \c_group_end_token + 2 + \else: + \if_catcode:w \exp_not:N #1 \c_space_token + 10 + \else: + \token_if_cs:NTF #1 { 16 } { 13 } + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: + \group_align_safe_end: + \exp_stop_f: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \begin{macro} % { % \c_group_begin_token, diff --git a/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx b/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx index 2161e0963ef..54486cc0faf 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2023-10-10} +% \date{Released 2023-10-23} % % \maketitle % |