[latex3-commits] [git/LaTeX3-latex3-latex3] l3text: Make \text_expand:n and \text_<type>case:n f-type expandable (81618b557)
Joseph Wright
joseph.wright at morningstar2.co.uk
Sat Dec 7 10:12:40 CET 2019
Repository : https://github.com/latex3/latex3
On branch : l3text
Link : https://github.com/latex3/latex3/commit/81618b557c1a86bbaad3ed3676870b81de3fe6fc
>---------------------------------------------------------------
commit 81618b557c1a86bbaad3ed3676870b81de3fe6fc
Author: Joseph Wright <joseph.wright at morningstar2.co.uk>
Date: Sat Dec 7 09:12:40 2019 +0000
Make \text_expand:n and \text_<type>case:n f-type expandable
User text can contain document commands which themselves take arguments.
With the e-type approach, when used in running text (no e/x-type
expanson), we end up with
\exp_not:n { \foo } \exp_not:n { { arg } }
or similar The first \exp_not:n is a no-op here, so \foo (assuming 1
agument) grabs \exp_not:n rather than the _result_ of applying it to
"{arg}". Depending on the exact details for implementation of \foo, all
sorts of crap then happens.
With f-type expansion, we get
\exp_not:n { \foo { arg } }
which is fine: the same no-op inserts exactly the tokens we want.
>---------------------------------------------------------------
81618b557c1a86bbaad3ed3676870b81de3fe6fc
l3kernel/l3text.dtx | 458 +++++++++++++++++++++++++++++++++-------------------
1 file changed, 292 insertions(+), 166 deletions(-)
diff --git a/l3kernel/l3text.dtx b/l3kernel/l3text.dtx
index 2530198ad..dcc654d5d 100644
--- a/l3kernel/l3text.dtx
+++ b/l3kernel/l3text.dtx
@@ -57,7 +57,7 @@
% here concern conversion of textual content for example in case changing,
% generation of bookmarks and extraction to tags.
%
-% \begin{function}[rEXP, added = 2019-11-20]{\text_expand:n}
+% \begin{function}[EXP, added = 2019-11-20]{\text_expand:n}
% \begin{syntax}
% \cs{text_expand:n} \Arg{text}
% \end{syntax}
@@ -74,7 +74,7 @@
% and \cs{l_text_letterlike_tl} are excluded from expansion.
% \end{function}
%
-% \begin{function}[rEXP, added = 2019-11-20]
+% \begin{function}[EXP, added = 2019-11-20]
% {
% \text_lowercase:n, \text_uppercase:n, \text_titlecase:n,
% \text_titlecase_first:n,
@@ -421,7 +421,6 @@
% \end{macrocode}
% \end{macro}
%
-%
% \subsection{Configuration variables}
%
% \begin{variable}{\l_text_accents_tl, \l_text_letterlike_tl}
@@ -500,48 +499,79 @@
% \end{variable}
% \end{variable}
%
-% \begin{macro}[rEXP]{\text_expand:n}
-% \begin{macro}[rEXP]{\@@_expand_loop:w}
-% \begin{macro}[rEXP]{\@@_expand_group:n}
-% \begin{macro}[rEXP]{\@@_expand_space:w}
-% \begin{macro}[rEXP]
+% \begin{macro}[EXP]{\text_expand:n, \@@_expand:n}
+% \begin{macro}[EXP]{\@@_expand_result:n}
+% \begin{macro}[EXP]{\@@_expand_store:n, \@@_expand_store:o}
+% \begin{macro}[EXP]{\@@_expand_store:nw}
+% \begin{macro}[EXP]{\@@_expand_end:w}
+% \begin{macro}[EXP]{\@@_expand_loop:w}
+% \begin{macro}[EXP]{\@@_expand_group:n}
+% \begin{macro}[EXP]{\@@_expand_space:w}
+% \begin{macro}[EXP]
% {
% \@@_expand_N_type:N ,
% \@@_expand_N_type_auxi:N ,
% \@@_expand_N_type_auxii:N ,
% \@@_expand_N_type_auxiii:N
% }
-% \begin{macro}[rEXP]{\@@_expand_math_search:NNN}
-% \begin{macro}[rEXP]{\@@_expand_math_loop:Nw}
-% \begin{macro}[rEXP]{\@@_expand_math_N_type:NN}
-% \begin{macro}[rEXP]{\@@_expand_math_group:Nn}
-% \begin{macro}[rEXP]{\@@_expand_math_space:Nw}
-% \begin{macro}[rEXP]{\@@_expand_exclude:N}
-% \begin{macro}[rEXP]{\@@_expand_exclude:nN}
-% \begin{macro}[rEXP]{\@@_expand_exclude:NN}
-% \begin{macro}[rEXP]{\@@_expand_exclude:Nn}
-% \begin{macro}[rEXP]{\@@_expand_letterlike:N}
-% \begin{macro}[rEXP]{\@@_expand_letterlike:NN}
-% \begin{macro}[rEXP]
+% \begin{macro}[EXP]{\@@_expand_math_search:NNN}
+% \begin{macro}[EXP]{\@@_expand_math_loop:Nw}
+% \begin{macro}[EXP]{\@@_expand_math_N_type:NN}
+% \begin{macro}[EXP]{\@@_expand_math_group:Nn}
+% \begin{macro}[EXP]{\@@_expand_math_space:Nw}
+% \begin{macro}[EXP]{\@@_expand_exclude:N}
+% \begin{macro}[EXP]{\@@_expand_exclude:nN}
+% \begin{macro}[EXP]{\@@_expand_exclude:NN}
+% \begin{macro}[EXP]{\@@_expand_exclude:Nn}
+% \begin{macro}[EXP]{\@@_expand_letterlike:N}
+% \begin{macro}[EXP]{\@@_expand_letterlike:NN}
+% \begin{macro}[EXP]
% {
% \@@_expand_implicit:N ,
% \@@_expand_explicit:N ,
% \@@_expand_cs:N ,
% \@@_expand_protect:N
% }
-% \begin{macro}[rEXP]{\@@_expand_protect:nN}
-% \begin{macro}[rEXP]{\@@_expand_protect:Nw}
-% \begin{macro}[rEXP]{\@@_expand_cs_expand:N}
+% \begin{macro}[EXP]{\@@_expand_protect:nN}
+% \begin{macro}[EXP]{\@@_expand_protect:Nw}
+% \begin{macro}[EXP]{\@@_expand_cs_expand:N}
% After precautions against |&| tokens, start a simple loop: that of
% course means that \enquote{text} cannot contain the two recursion
-% quarks.
+% quarks. The loop here must be \texttt{f}-type expandable; we have
+% arbitrary user commands which might be protected \emph{and} take
+% arguments, and if the expansion code is used in a typesetting
+% context, that will otherwise explode. (The same issue applies more
+% clearly to case changing: see the example there.)
% \begin{macrocode}
\cs_new:Npn \text_expand:n #1
{
+ \__kernel_exp_not:w \exp_after:wN
+ {
+ \exp:w
+ \@@_expand:n {#1}
+ }
+ }
+\cs_new:Npn \@@_expand:n #1
+ {
\group_align_safe_begin:
\@@_expand_loop:w #1
\q_recursion_tail \q_recursion_stop
+ \@@_expand_result:n { }
+ }
+% \end{macrocode}
+% The approach to making the code \texttt{f}-type expandable is to usee
+% a marker result token and to shuffle the collected tokens
+% \begin{macrocode}
+\cs_new:Npn \@@_expand_store:n #1
+ { \@@_expand_store:nw {#1} }
+\cs_generate_variant:Nn \@@_expand_store:n { o }
+\cs_new:Npn \@@_expand_store:nw #1#2 \@@_expand_result:n #3
+ { #2 \@@_expand_result:n { #3 #1 } }
+\cs_new:Npn \@@_expand_end:w #1 \@@_expand_result:n #2
+ {
\group_align_safe_end:
+ \exp_end:
+ #2
}
% \end{macrocode}
% The main loop is a standard \enquote{tl action}; groups are handled
@@ -561,15 +591,19 @@
}
\cs_new:Npn \@@_expand_group:n #1
{
- {
- \@@_expand_loop:w #1
- \q_recursion_tail \q_recursion_stop
- }
+ \@@_expand_store:o
+ {
+ \exp_after:wN
+ {
+ \exp:w
+ \@@_expand:n {#1}
+ }
+ }
\@@_expand_loop:w
}
\exp_last_unbraced:NNo \cs_new:Npn \@@_expand_space:w \c_space_tl
{
- \c_space_tl
+ \@@_expand_store:n { ~ }
\@@_expand_loop:w
}
% \end{macrocode}
@@ -581,7 +615,8 @@
% \begin{macrocode}
\cs_new:Npx \@@_expand_N_type:N #1
{
- \exp_not:N \quark_if_recursion_tail_stop:N #1
+ \exp_not:N \quark_if_recursion_tail_stop_do:Nn #1
+ { \exp_not:N \@@_expand_end:w }
\exp_not:N \bool_lazy_any:nTF
{
{ \exp_not:N \token_if_eq_meaning_p:NN #1 \c_space_token }
@@ -594,7 +629,7 @@
\c_@@_mathchardef_space_token
}
}
- { \exp_not:N \@@_expand_space:w \c_space_tl }
+ { \exp_not:N \@@_expand_space:w \c_space_tl }
{ \exp_not:N \@@_expand_N_type_auxi:N #1 }
}
% \end{macrocode}
@@ -610,7 +645,7 @@
{ \token_if_eq_meaning_p:NN #1 \c_@@_chardef_group_begin_token }
{ \token_if_eq_meaning_p:NN #1 \c_@@_mathchardef_group_begin_token }
{
- \c_left_brace_str
+ \@@_expand_store:o \c_left_brace_str
\@@_expand_loop:w
}
{
@@ -618,7 +653,7 @@
{ \token_if_eq_meaning_p:NN #1 \c_@@_chardef_group_end_token }
{ \token_if_eq_meaning_p:NN #1 \c_@@_mathchardef_group_end_token }
{
- \c_right_brace_str
+ \@@_expand_store:o \c_right_brace_str
\@@_expand_loop:w
}
{ \@@_expand_N_type_auxii:N #1 }
@@ -665,7 +700,7 @@
{
\use_i_delimit_by_q_recursion_stop:nw
{
- \exp_not:n {#1}
+ \@@_expand_store:n {#1}
\@@_expand_math_loop:Nw #3
}
}
@@ -684,21 +719,22 @@
}
\cs_new:Npn \@@_expand_math_N_type:NN #1#2
{
- \quark_if_recursion_tail_stop:N #2
- \exp_not:n {#2}
+ \quark_if_recursion_tail_stop_do:Nn #2
+ { \@@_expand_end:w }
+ \@@_expand_store:n {#2}
\token_if_eq_meaning:NNTF #2 #1
{ \@@_expand_loop:w }
{ \@@_expand_math_loop:Nw #1 }
}
\cs_new:Npn \@@_expand_math_group:Nn #1#2
{
- { \exp_not:n {#2} }
+ \@@_expand_store:n { {#2} }
\@@_expand_math_loop:Nw #1
}
\exp_after:wN \cs_new:Npn \exp_after:wN \@@_expand_math_space:Nw
\exp_after:wN # \exp_after:wN 1 \c_space_tl
{
- \c_space_tl
+ \@@_expand_store:n { ~ }
\@@_expand_math_loop:Nw #1
}
% \end{macrocode}
@@ -735,7 +771,7 @@
}
\cs_new:Npn \@@_expand_exclude:Nn #1#2
{
- \exp_not:n { #1 {#2} }
+ \@@_expand_store:n { #1 {#2} }
\@@_expand_loop:w
}
% \end{macrocode}
@@ -756,7 +792,7 @@
{
\use_i_delimit_by_q_recursion_stop:nw
{
- \exp_not:n {#1}
+ \@@_expand_store:n {#1}
\@@_expand_loop:w
}
}
@@ -781,7 +817,7 @@
\token_if_cs:NTF #1
{ \@@_expand_cs:N #1 }
{
- \exp_not:n {#1}
+ \@@_expand_store:n {#1}
\@@_expand_loop:w
}
}
@@ -809,10 +845,10 @@
\quark_if_nil:nTF {#4}
{
\cs_if_exist:cTF {#2}
- { \exp_not:c {#2} }
- { \exp_not:n { \protect #1 } }
+ { \exp_args:Ne \@@_expand_store:n { \exp_not:c {#2} } }
+ { \@@_expand_store:n { \protect #1 } }
}
- { \exp_not:n { \protect #1 } }
+ { \@@_expand_store:n { \protect #1 } }
\@@_expand_loop:w
}
% \end{macrocode}
@@ -824,7 +860,7 @@
\@@_if_expandable:NTF #1
{ \exp_after:wN \@@_expand_loop:w #1 }
{
- \exp_not:n {#1}
+ \@@_expand_store:n {#1}
\@@_expand_loop:w
}
}
@@ -849,17 +885,21 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
%
% \subsection{Case changing}
%
-% \begin{macro}[rEXP]
+% \begin{macro}[EXP]
% {
% \text_lowercase:n,
% \text_uppercase:n,
% \text_titlecase:n,
% \text_titlecase_first:n
% }
-% \begin{macro}[rEXP]
+% \begin{macro}[EXP]
% {
% \text_lowercase:nn,
% \text_uppercase:nn,
@@ -869,90 +909,134 @@
% The user level functions here are all wrappers around the internal
% functions for case changing.
% \begin{macrocode}
-\cs_new:Npn \text_lowercase:n { \@@_change_case:nnn { lower } { } }
-\cs_new:Npn \text_uppercase:n { \@@_change_case:nnn { upper } { } }
-\cs_new:Npn \text_titlecase:n { \@@_change_case:nnn { title } { } }
-\cs_new:Npn \text_titlecase_first:n { \@@_change_case:nnn { titleonly } { } }
-\cs_new:Npn \text_lowercase:nn { \@@_change_case:nnn { lower } }
-\cs_new:Npn \text_uppercase:nn { \@@_change_case:nnn { upper } }
-\cs_new:Npn \text_titlecase:nn { \@@_change_case:nnn { title } }
-\cs_new:Npn \text_titlecase_first:nn { \@@_change_case:nnn { titleonly } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[rEXP]{\@@_change_case:nnn, \@@_change_case_aux:nnn}
-% \begin{macro}[rEXP]{\@@_change_case_loop:nnw}
-% \begin{macro}[rEXP]{\@@_change_case_end:w}
-% \begin{macro}[rEXP]
+\cs_new:Npn \text_lowercase:n #1
+ { \@@_change_case:nnn { lower } { } {#1} }
+\cs_new:Npn \text_uppercase:n #1
+ { \@@_change_case:nnn { upper } { } {#1} }
+\cs_new:Npn \text_titlecase:n #1
+ { \@@_change_case:nnn { title } { } {#1} }
+\cs_new:Npn \text_titlecase_first:n #1
+ { \@@_change_case:nnn { titleonly } { } {#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
+ { \@@_change_case:nnn { title } {#1} {#2} }
+\cs_new:Npn \text_titlecase_first:nn #1#2
+ { \@@_change_case:nnn { titleonly } {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_change_case:nnn, \@@_change_case_aux:nnn}
+% \begin{macro}[EXP]{\@@_change_case_loop:nnw}
+% \begin{macro}[EXP]{\@@_change_case_break:w}
+% \begin{macro}[EXP]
% {
% \@@_change_case_group_lower:nnn ,
% \@@_change_case_group_upper:nnn ,
% \@@_change_case_group_title:nnn ,
% \@@_change_case_group_titleonly:nnn
% }
-% \begin{macro}[rEXP]{\@@_change_case_space:nnw}
-% \begin{macro}[rEXP]{\@@_change_case_N_type:nnN, \@@_change_case_N_type_aux:nnN}
-% \begin{macro}[rEXP]{\@@_change_case_N_type:nnnN}
-% \begin{macro}[rEXP]{\@@_change_case_math_search:nnNNN}
-% \begin{macro}[rEXP]{\@@_change_case_math_loop:nnNw}
-% \begin{macro}[rEXP]{\@@_change_case_math_N_type:nnNN}
-% \begin{macro}[rEXP]{\@@_change_case_math_group:nnNn}
-% \begin{macro}[rEXP]{\@@_change_case_math_space:nnNw}
-% \begin{macro}[rEXP]{\@@_change_case_cs_check:nnN}
-% \begin{macro}[rEXP]{\@@_change_case_exclude:nnN}
-% \begin{macro}[rEXP]{\@@_change_case_exclude:nnnN}
-% \begin{macro}[rEXP]{\@@_change_case_exclude:nnNN}
-% \begin{macro}[rEXP]{\@@_change_case_exclude:nnNn}
-% \begin{macro}[rEXP]
+% \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:nnNn}
+% \begin{macro}[EXP]
% {
% \@@_change_case_letterlike_lower:nnN ,
% \@@_change_case_letterlike_upper:nnN ,
% \@@_change_case_letterlike_title:nnN ,
% \@@_change_case_letterlike_titleonly:nnN
% }
-% \begin{macro}[rEXP]{\@@_change_case_letterlike:nnnnN}
-% \begin{macro}[rEXP]
+% \begin{macro}[EXP]{\@@_change_case_letterlike:nnnnN}
+% \begin{macro}[EXP]
% {\@@_change_case_char_lower:nnN, \@@_change_case_char_upper:nnN}
-% \begin{macro}[rEXP]{\@@_change_case_lower_sigma:nnnN}
-% \begin{macro}[rEXP]{\@@_change_case_lower_sigma:nnNw}
-% \begin{macro}[rEXP]{\@@_change_case_lower_sigma:NnnN}
-% \begin{macro}[rEXP]
+% \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_char_title:nnN, \@@_change_case_char_titleonly:nnN}
-% \begin{macro}[rEXP]
+% \begin{macro}[EXP]
% {\@@_change_case_char_title:nN, \@@_change_case_char_titleonly:nN}
-% \begin{macro}[rEXP]{\@@_change_case_char_title:nnnN}
-% \begin{macro}[rEXP]{\@@_change_case_char_char:nnnN}
-% \begin{macro}[rEXP]{\@@_change_case_char_UTFviii:nnnNN}
-% \begin{macro}[rEXP]{\@@_change_case_char_UTFviii:nnnNNN}
-% \begin{macro}[rEXP]{\@@_change_case_char_UTFviii:nnnNNNNN}
-% \begin{macro}[rEXP]{\@@_change_case_char_UTFviii:nnnn}
-% \begin{macro}[rEXP]
+% \begin{macro}[EXP]{\@@_change_case_char_title:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_char_char:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nnnNN}
+% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nnnNNN}
+% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nnnNNNNN}
+% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nnnn}
+% \begin{macro}[EXP]
% {
% \@@_change_case_char_next_lower:nn ,
% \@@_change_case_char_next_upper:nn ,
% \@@_change_case_char_next_title:nn ,
% \@@_change_case_char_next_titleonly:nn
% }
-% \begin{macro}[rEXP]{\@@_change_case_char_next_end:nn}
+% \begin{macro}[EXP]{\@@_change_case_char_next_end:nn}
% 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
% (so the loops here don't need to worry about awkward look-aheads and the
% like). Then we split into the different paths.
+%
+% The code here needs to be \texttt{f}-type expandable to deal with the
+% situation where case changing is applied in running text. There, we
+% might have case changing as a document command and the text containing
+% other non-expandable document commands.
+% \begin{verbatim}
+% \cs_set_eq:NN \MakeLowercase \text_lowercase
+% ...
+% \MakeLowercase{\enquote*{A} text}
+% \end{verbatim}
+% If we use an \texttt{e}-type expansion and wrap each token in
+% \cs{exp_not:n}, that would explode: the document command grabs
+% \cs{exp_not:n} as an argument, and things go badly wrong. So we have to
+% 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
{
- \group_align_safe_begin:
- \exp_args:Ne \@@_change_case_aux:nnn
- { \text_expand:n {#3} }
- {#1} {#2}
- \group_align_safe_end:
+ \__kernel_exp_not:w \exp_after:wN
+ {
+ \exp:w
+ \exp_args:Ne \@@_change_case_aux:nnn
+ { \text_expand:n {#3} }
+ {#1} {#2}
+ }
}
\cs_new:Npn \@@_change_case_aux:nnn #1#2#3
{
+ \group_align_safe_begin:
\@@_change_case_loop:nnw {#2} {#3} #1
\q_recursion_tail \q_recursion_stop
+ \@@_change_case_result:n { }
+ }
+% \end{macrocode}
+% As for expansion, collect up the tokens for future use.
+% \begin{macrocode}
+\cs_new:Npn \@@_change_case_store:n #1
+ { \@@_change_case_store:nw {#1} }
+\cs_generate_variant:Nn \@@_change_case_store:n { o , e , V , v }
+\cs_new:Npn \@@_change_case_store:nw #1#2 \@@_change_case_result:n #3
+ { #2 \@@_change_case_result:n { #3 #1 } }
+\cs_new:Npn \@@_change_case_end:w #1 \@@_change_case_result:n #2
+ {
+ \group_align_safe_end:
+ \exp_end:
+ #2
}
+% \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
{
\tl_if_head_is_N_type:nTF {#3}
@@ -964,7 +1048,7 @@
}
{#1} {#2} #3 \q_recursion_stop
}
-\cs_new:Npn \@@_change_case_end:w #1 \q_recursion_tail \q_recursion_stop
+\cs_new:Npn \@@_change_case_break:w #1 \q_recursion_tail \q_recursion_stop
{ \exp_not:n {#1} }
% \end{macrocode}
% For a group, we \emph{could} worry about whether this contains a character
@@ -977,36 +1061,48 @@
% \begin{macrocode}
\cs_new:Npn \@@_change_case_group_lower:nnn #1#2#3
{
- {
- \@@_change_case_loop:nnw {#1} {#2} #3
- \q_recursion_tail \q_recursion_stop
- }
+ \@@_change_case_store:o
+ {
+ \exp_after:wN
+ {
+ \exp:w
+ \@@_change_case_aux:nnn {#3} {#1} {#2}
+ }
+ }
\@@_change_case_loop:nnw {#1} {#2}
}
\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
{
- {
- \@@_change_case_loop:nnw {#1} {#2} #3
- \q_recursion_tail \q_recursion_stop
- }
+ \@@_change_case_store:o
+ {
+ \exp_after:wN
+ {
+ \exp:w
+ \@@_change_case_aux:nnn {#3} {#1} {#2}
+ }
+ }
\@@_change_case_loop:nnw { lower } {#2}
}
\cs_new:Npn \@@_change_case_group_titleonly:nnn #1#2#3
{
- {
- \@@_change_case_loop:nnw {#1} {#2} #3
- \q_recursion_tail \q_recursion_stop
- }
- \@@_change_case_end:w
+ \@@_change_case_store:o
+ {
+ \exp_after:wN
+ {
+ \exp:w
+ \@@_change_case_aux:nnn {#3} {#1} {#2}
+ }
+ }
+ \@@_change_case_break:w
}
\use:x
{
\cs_new:Npn \exp_not:N \@@_change_case_space:nnw ##1##2 \c_space_tl
}
{
- \c_space_tl
+ \@@_change_case_store:n { ~ }
\@@_change_case_loop:nnw {#1} {#2}
}
% \end{macrocode}
@@ -1020,7 +1116,8 @@
% \begin{macrocode}
\cs_new:Npn \@@_change_case_N_type:nnN #1#2#3
{
- \quark_if_recursion_tail_stop:N #3
+ \quark_if_recursion_tail_stop_do:Nn #3
+ { \@@_change_case_end:w }
\@@_change_case_N_type_aux:nnN {#1} {#2} #3
}
\cs_new:Npn \@@_change_case_N_type_aux:nnN #1#2#3
@@ -1042,7 +1139,7 @@
{
\use_i_delimit_by_q_recursion_stop:nw
{
- \exp_not:n {#3}
+ \@@_change_case_store:n {#3}
\@@_change_case_math_loop:nnNw {#1} {#2} #5
}
}
@@ -1061,15 +1158,16 @@
}
\cs_new:Npn \@@_change_case_math_N_type:nnNN #1#2#3#4
{
- \quark_if_recursion_tail_stop:N #4
- \exp_not:n {#4}
+ \quark_if_recursion_tail_stop_do:Nn #4
+ { \@@_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 }
}
\cs_new:Npn \@@_change_case_math_group:nnNn #1#2#3#4
{
- { \exp_not:n {#4} }
+ \@@_change_case_store:n { {#4} }
\@@_change_case_math_loop:nnNw {#1} {#2} #3
}
\use:x
@@ -1078,7 +1176,7 @@
\c_space_tl
}
{
- \c_space_tl
+ \@@_change_case_store:n { ~ }
\@@_change_case_math_loop:nnNw {#1} {#2} #3
}
% \end{macrocode}
@@ -1127,7 +1225,7 @@
}
\cs_new:Npn \@@_change_case_exclude:nnNn #1#2#3#4
{
- \exp_not:n { #3 {#4} }
+ \@@_change_case_store:n { #3 {#4} }
\@@_change_case_loop:nnw {#1} {#2}
}
% \end{macrocode}
@@ -1149,12 +1247,12 @@
{
\cs_if_exist:cTF { c_@@_ #1 case_ \token_to_str:N #5 _tl }
{
- \exp_not:v
+ \@@_change_case_store:v
{ c_@@_ #1 case_ \token_to_str:N #5 _tl }
\use:c { @@_change_case_char_next_ #2 :nn } {#2} {#4}
}
{
- \exp_not:n {#5}
+ \@@_change_case_store:n {#5}
\cs_if_exist:cTF
{
c_@@_
@@ -1210,16 +1308,20 @@
\tl_if_head_is_N_type:nTF {#4}
{ \@@_change_case_lower_sigma:NnnN #3 }
{
- \char_generate:nn { "03C2 } { \@@_char_catcode:N #3 }
+ \@@_change_case_store:e
+ { \char_generate:nn { "03C2 } { \@@_char_catcode:N #3 } }
\@@_change_case_loop:nnw
}
{#1} {#2} #4 \q_recursion_stop
}
\cs_new:Npn \@@_change_case_lower_sigma:NnnN #1#2#3#4
{
- \token_if_letter:NTF #4
- { \char_generate:nn { "03C3 } { \@@_char_catcode:N #1 } }
- { \char_generate:nn { "03C2 } { \@@_char_catcode:N #1 } }
+ \@@_change_case_store:e
+ {
+ \token_if_letter:NTF #4
+ { \char_generate:nn { "03C3 } { \@@_char_catcode:N #1 } }
+ { \char_generate:nn { "03C2 } { \@@_char_catcode:N #1 } }
+ }
\@@_change_case_loop:nnw {#2} {#3} #4
}
}
@@ -1276,7 +1378,8 @@
{
\cs_new:Npn \@@_change_case_char:nnnN #1#2#3#4
{
- \use:c { char_ #1 case :N } #4
+ \@@_change_case_store:e
+ { \use:c { char_ #1 case :N } #4 }
\use:c { @@_change_case_char_next_ #2 :nn } {#2} {#3}
}
}
@@ -1295,7 +1398,7 @@
{#1} {#2} {#3} #4
}
{
- \use:c { char_ #1 case :N } #4
+ \@@_change_case_store:e{ \use:c { char_ #1 case :N } #4 }
\use:c { @@_change_case_char_next_ #2 :nn } {#2} {#3}
}
}
@@ -1309,10 +1412,10 @@
{
\cs_if_exist:cTF { c_@@_ #1 case_ \tl_to_str:n {#4} _tl }
{
- \exp_not:v
+ \@@_change_case_store:v
{ c_@@_ #1 case_ \tl_to_str:n {#4} _tl }
}
- { \exp_not:n {#4} }
+ { \@@_change_case_store:n {#4} }
\use:c { @@_change_case_char_next_ #2 :nn } {#2} {#3}
}
}
@@ -1325,7 +1428,7 @@
\cs_new_eq:NN \@@_change_case_char_next_titleonly:nn
\@@_change_case_char_next_lower:nn
\cs_new:Npn \@@_change_case_char_next_end:nn #1#2
- { \@@_change_case_end:w }
+ { \@@_change_case_break:w }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1361,7 +1464,7 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\@@_change_case_upper_de-alt:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_de-alt:nnnN}
% A simple alternative version for German.
% \begin{macrocode}
\bool_lazy_or:nnT
@@ -1372,7 +1475,8 @@
{
\int_compare:nNnTF { `#4 } = { "00DF }
{
- \char_generate:nn { "1E9E } { \@@_char_catcode:N #4 }
+ \@@_change_case_store:e
+ { \char_generate:nn { "1E9E } { \@@_char_catcode:N #4 } }
\use:c { @@_change_case_char_next_ #2 :nn }
{#2} {#3}
}
@@ -1382,11 +1486,11 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[rEXP]{\@@_change_case_upper_el:nnnN}
-% \begin{macro}[rEXP]{\@@_change_case_upper_el:nnnn}
-% \begin{macro}[rEXP]{\@@_change_case_upper_el_aux:nnnN}
-% \begin{macro}[rEXP]{\@@_change_case_upper_el_loop:nnw}
-% \begin{macro}[rEXP]{\@@_change_case_upper_el:nnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_el:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_el:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_aux:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_loop:nnw}
+% \begin{macro}[EXP]{\@@_change_case_upper_el:nnN}
% \begin{macro}[EXP]{\@@_change_case_if_greek:nTF}
% For Greek uppercasing, we need to know if characters \emph{in the Greek
% range} have accents. That means doing a \textsc{nfd} conversion first, then
@@ -1434,7 +1538,7 @@
{
\int_compare:nNnTF { `#3 } = { "0308 }
{
- \exp_not:n {#3}
+ \@@_change_case_store:n {#3}
\@@_change_case_upper_el_loop:nnw {#1} {#2}
}
{
@@ -1456,8 +1560,11 @@
{
\int_compare:nNnTF { `#3 } = { "0344 }
{
- \char_generate:nn { "0308 }
- { \@@_char_catcode:N #3 }
+ \@@_change_case_store:e
+ {
+ \char_generate:nn { "0308 }
+ { \@@_char_catcode:N #3 }
+ }
\@@_change_case_upper_el_loop:nnw {#1} {#2}
}
{
@@ -1497,7 +1604,7 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \begin{macro}[rEXP]{\@@_change_case_title_el:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_title_el:nnnN}
% Titlecasing retains accents, but to prevent the uppercasing code
% from kicking in, there has to be an explicit function here.
% \begin{macrocode}
@@ -1511,7 +1618,7 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[rEXP]
+% \begin{macro}[EXP]
% {
% \@@_change_cases_lower_lt:nnnN ,
% \@@_change_cases_lower_lt_auxi:nnnN ,
@@ -1562,9 +1669,12 @@
{#2} {#3} #4
}
{
- \char_generate:nn { "0069 } { \@@_char_catcode:N #4 }
- \char_generate:nn { "0307 } { \@@_char_catcode:N #4 }
- \char_generate:nn {#1} { \@@_char_catcode:N #4 }
+ \@@_change_case_store:e
+ {
+ \char_generate:nn { "0069 } { \@@_char_catcode:N #4 }
+ \char_generate:nn { "0307 } { \@@_char_catcode:N #4 }
+ \char_generate:nn {#1} { \@@_char_catcode:N #4 }
+ }
\@@_change_case_loop:nnw {#2} {#3}
}
}
@@ -1601,7 +1711,10 @@
{ \int_compare_p:nNn { `#3 } = { "0303 } }
}
}
- { \char_generate:nn { "0307 } { \@@_char_catcode:N #3 } }
+ {
+ \@@_change_case_store:e
+ { \char_generate:nn { "0307 } { \@@_char_catcode:N #3 } }
+ }
\@@_change_case_loop:nnw {#1} {#2} #3
}
}
@@ -1609,7 +1722,7 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \begin{macro}[rEXP]
+% \begin{macro}[EXP]
% {
% \@@_change_cases_upper_lt:nnnN ,
% \@@_change_cases_upper_lt_aux:nnnN
@@ -1641,7 +1754,8 @@
\tl_if_blank:nTF {#1}
{ \@@_change_case_char:nnnN { upper } {#2} {#3} #4 }
{
- \char_generate:nn {#1} { \@@_char_catcode:N #4 }
+ \@@_change_case_store:e
+ { \char_generate:nn {#1} { \@@_char_catcode:N #4 } }
\@@_change_case_upper_lt:nnw {#2} {#3}
}
}
@@ -1666,9 +1780,9 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}[rEXP]{\@@_change_case_title_nl:nnnN}
-% \begin{macro}[rEXP]{\@@_change_case_title_nl:nnw}
-% \begin{macro}[rEXP]{\@@_change_case_title_nl:nnN}
+% \begin{macro}[EXP]{\@@_change_case_title_nl:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_title_nl:nnw}
+% \begin{macro}[EXP]{\@@_change_case_title_nl:nnN}
% 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}.
@@ -1701,7 +1815,8 @@
{ \int_compare_p:nNn { `#3 } = { "006A } }
}
{
- \char_generate:nn { "004A } { \@@_char_catcode:N #3 }
+ \@@_change_case_store:e
+ { \char_generate:nn { "004A } { \@@_char_catcode:N #3 } }
\use:c { @@_change_case_char_next_ #1 :nn } {#1} {#2}
}
{ \use:c { @@_change_case_char_next_ #1 :nn } {#1} {#2} #3 }
@@ -1711,10 +1826,10 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}[rEXP]{\@@_change_case_lower_tr:nnnN}
-% \begin{macro}[rEXP]{\@@_change_case_lower_tr:nnNw}
-% \begin{macro}[rEXP]{\@@_change_case_lower_tr:nnN}
-% \begin{macro}[rEXP]{\@@_change_case_lower_tr:nnnNN}
+% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnNw}
+% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnN}
+% \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
@@ -1731,7 +1846,8 @@
{
\int_compare:nNnTF { `#4 } = { "0130 }
{
- \char_generate:nn { "0069 } { \@@_char_catcode:N #4 }
+ \@@_change_case_store:e
+ { \char_generate:nn { "0069 } { \@@_char_catcode:N #4 } }
\@@_change_case_loop:nnw {#1} {#3}
}
{ \@@_change_case_lower_sigma:nnnN {#1} {#2} {#3} #4 }
@@ -1748,7 +1864,8 @@
\tl_if_head_is_N_type:nTF {#4}
{ \@@_change_case_lower_tr:nnN }
{
- \char_generate:nn { "0131 } { \@@_char_catcode:N #3 }
+ \@@_change_case_store:e
+ { \char_generate:nn { "0131 } { \@@_char_catcode:N #3 } }
\@@_change_case_loop:nnw
}
{#1} {#2} #4 \q_recursion_stop
@@ -1759,11 +1876,13 @@
{ \token_if_cs_p:N #3 }
{ ! \int_compare_p:nNn { `#3 } = { "0307 } }
{
- \char_generate:nn { "0131 } { \@@_char_catcode:N #3 }
+ \@@_change_case_store:e
+ { \char_generate:nn { "0131 } { \@@_char_catcode:N #3 } }
\@@_change_case_loop:nnw {#1} {#2} #3
}
{
- \char_generate:nn { "0069 } { \@@_char_catcode:N #3 }
+ \@@_change_case_store:e
+ { \char_generate:nn { "0069 } { \@@_char_catcode:N #3 } }
\@@_change_case_loop:nnw {#1} {#2}
}
}
@@ -1783,7 +1902,7 @@
{
\int_compare:nNnTF { `#4 } = { "0049 }
{
- \exp_not:V \c_@@_dotless_i_tl
+ \@@_change_case_store:V \c_@@_dotless_i_tl
\@@_change_case_loop:nnw {#1} {#3}
}
{
@@ -1796,7 +1915,11 @@
{
\int_compare:nNnTF { `#5 } = { "00B0 }
{
- \char_generate:nn { "0069 } { \char_value_catcode:n { "0069 } }
+ \@@_change_case_store:e
+ {
+ \char_generate:nn { "0069 }
+ { \char_value_catcode:n { "0069 } }
+ }
\@@_change_case_loop:nnw {#1} {#3}
}
{ \@@_change_case_char:nnnN {#1} {#2} {#3} #4#5 }
@@ -1807,7 +1930,7 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \begin{macro}[rEXP]{\@@_change_case_upper_tr:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_tr:nnnN}
% Uppercasing is easier: just one exception with no context.
% \begin{macrocode}
\cs_new:Npx \@@_change_case_upper_tr:nnnN #1#2#3#4
@@ -1822,7 +1945,7 @@
{ \exp_not:N \@@_char_catcode:N #4 }
}
{
- \exp_not:N \exp_not:V
+ \exp_not:N \@@_change_case_store:V
\exp_not:N \c_@@_dotted_I_tl
}
\exp_not:N \use:c { @@_change_case_char_next_ #2 :nn } {#2} {#3}
@@ -1832,7 +1955,8 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_change_case_lower_az:nnnN, \@@_change_case_upper_az:nnnN}
+% \begin{macro}[EXP]
+% {\@@_change_case_lower_az:nnnN, \@@_change_case_upper_az:nnnN}
% Straight copies.
% \begin{macrocode}
\cs_new_eq:NN \@@_change_case_lower_az:nnnN
@@ -2119,7 +2243,9 @@
% \begin{macro}[rEXP]{\@@_purify_replace:n}
% \begin{macro}[rEXP]{\@@_purify_expand:N, \@@_purify_protect:N}
% As in the other parts of the module, we start off with a standard
-% \enquote{action} loop, with expansion applied up-front.
+% \enquote{action} loop, with expansion applied up-front. Here, as there
+% will be no text commands left in the output, there is no concern about
+% using \cs{exp_not:n} and \texttt{e}-type expansion.
% \begin{macrocode}
\cs_new:Npn \text_purify:n #1
{
More information about the latex3-commits
mailing list