[latex3-commits] [git/LaTeX3-latex3-latex3] master: Implement token_case_catcode/charcode/meaning (a34439fd5)
Joseph Wright
joseph.wright at morningstar2.co.uk
Thu Dec 3 17:40:50 CET 2020
Repository : https://github.com/latex3/latex3
On branch : master
Link : https://github.com/latex3/latex3/commit/a34439fd5434efa662743d14802542fcb93acad1
>---------------------------------------------------------------
commit a34439fd5434efa662743d14802542fcb93acad1
Author: Bruno Le Floch <bruno at le-floch.fr>
Date: Sun Apr 29 23:55:18 2018 -0400
Implement token_case_catcode/charcode/meaning
>---------------------------------------------------------------
a34439fd5434efa662743d14802542fcb93acad1
l3kernel/CHANGELOG.md | 2 +
l3kernel/l3token.dtx | 95 ++++++++++++++++++++++++++++++++++++++-
l3kernel/testfiles/m3quark001.tlg | 1 +
l3kernel/testfiles/m3token005.lvt | 76 +++++++++++++++++++++++++++++++
l3kernel/testfiles/m3token005.tlg | 14 ++++++
5 files changed, 187 insertions(+), 1 deletion(-)
diff --git a/l3kernel/CHANGELOG.md b/l3kernel/CHANGELOG.md
index 2aee70aa1..20133bda3 100644
--- a/l3kernel/CHANGELOG.md
+++ b/l3kernel/CHANGELOG.md
@@ -11,6 +11,8 @@ this project uses date-based 'snapshot' version identifiers.
- `\peek_analysis_map_inline:n`
- `\peek_regex:nTF`, `\peek_regex_remove_once:nTF`, and
`\peek_regex_replace_once:nnTF`
+- `\token_case_catcode:NnTF`, `\token_case_charcode:NnTF`, and
+ `\token_case_meaning:NnTF`
### Changed
- Extend `\text_expand:n` to cover `\@protected at testopt`
diff --git a/l3kernel/l3token.dtx b/l3kernel/l3token.dtx
index 798b7b160..dea6ab4d0 100644
--- a/l3kernel/l3token.dtx
+++ b/l3kernel/l3token.dtx
@@ -754,6 +754,32 @@
% this includes primitive-like commands defined using |{token.set_lua}|.
% \end{function}
%
+% \begin{function}[added = 2020-07-16, EXP, noTF]
+% {\token_case_catcode:Nn, \token_case_charcode:Nn, \token_case_meaning:Nn}
+% \begin{syntax}
+% \cs{token_case_meaning:NnTF} \meta{test token} \\
+% ~~"{" \\
+% ~~~~\meta{token case_1} \Arg{code case_1} \\
+% ~~~~\meta{token case_2} \Arg{code case_2} \\
+% ~~~~\ldots \\
+% ~~~~\meta{token case_n} \Arg{code case_n} \\
+% ~~"}" \\
+% ~~\Arg{true code}
+% ~~\Arg{false code}
+% \end{syntax}
+% This function compares the \meta{test token} in turn with each of
+% the \meta{token cases}. If the two are equal (as described for
+% \cs{token_if_eq_catcode:NNTF}, \cs{token_if_eq_charcode:NNTF} and
+% \cs{token_if_eq_meaning:NNTF}, respectively) then the associated
+% \meta{code} is left in the input stream and other cases are
+% discarded. If any of the cases are matched, the \meta{true code} is
+% also inserted into the input stream (after the code for the
+% appropriate case), while if none match then the \meta{false code} is
+% inserted. The functions \cs{token_case_catcode:Nn},
+% \cs{token_case_charcode:Nn}, and \cs{token_case_meaning:Nn}, which
+% do nothing if there is no match, are also available.
+% \end{function}
+%
% \section{Peeking ahead at the next token}
%
% There is often a need to look ahead at the next token in the input
@@ -2021,9 +2047,10 @@
%<@@=token>
% \end{macrocode}
%
-% \begin{variable}{\s_@@_stop}
+% \begin{variable}{\s_@@_mark, \s_@@_stop}
% Internal scan marks.
% \begin{macrocode}
+\scan_new:N \s_@@_mark
\scan_new:N \s_@@_stop
% \end{macrocode}
% \end{variable}
@@ -2690,6 +2717,72 @@ end
% \end{macro}
% \end{macro}
%
+% \begin{macro}[EXP, noTF]
+% {\token_case_catcode:Nn, \token_case_charcode:Nn, \token_case_meaning:Nn}
+% \begin{macro}[EXP]{\@@_case:NNnTF, \@@_case:NNw, \@@_case_end:nw}
+% The aim here is to allow the case statement to be evaluated
+% using a known number of expansion steps (two), and without
+% needing to use an explicit \enquote{end of recursion} marker.
+% That is achieved by using the test input as the final case,
+% as this is always true. The trick is then to tidy up
+% the output such that the appropriate case code plus either
+% the \texttt{true} or \texttt{false} branch code is inserted.
+% \begin{macrocode}
+\cs_new:Npn \token_case_catcode:Nn #1#2
+ { \exp:w \@@_case:NNnTF \token_if_eq_catcode:NNTF #1 {#2} { } { } }
+\cs_new:Npn \token_case_catcode:NnT #1#2#3
+ { \exp:w \@@_case:NNnTF \token_if_eq_catcode:NNTF #1 {#2} {#3} { } }
+\cs_new:Npn \token_case_catcode:NnF #1#2
+ { \exp:w \@@_case:NNnTF \token_if_eq_catcode:NNTF #1 {#2} { } }
+\cs_new:Npn \token_case_catcode:NnTF
+ { \exp:w \@@_case:NNnTF \token_if_eq_catcode:NNTF }
+\cs_new:Npn \token_case_charcode:Nn #1#2
+ { \exp:w \@@_case:NNnTF \token_if_eq_charcode:NNTF #1 {#2} { } { } }
+\cs_new:Npn \token_case_charcode:NnT #1#2#3
+ { \exp:w \@@_case:NNnTF \token_if_eq_charcode:NNTF #1 {#2} {#3} { } }
+\cs_new:Npn \token_case_charcode:NnF #1#2
+ { \exp:w \@@_case:NNnTF \token_if_eq_charcode:NNTF #1 {#2} { } }
+\cs_new:Npn \token_case_charcode:NnTF
+ { \exp:w \@@_case:NNnTF \token_if_eq_charcode:NNTF }
+\cs_new:Npn \token_case_meaning:Nn #1#2
+ { \exp:w \@@_case:NNnTF \token_if_eq_meaning:NNTF #1 {#2} { } { } }
+\cs_new:Npn \token_case_meaning:NnT #1#2#3
+ { \exp:w \@@_case:NNnTF \token_if_eq_meaning:NNTF #1 {#2} {#3} { } }
+\cs_new:Npn \token_case_meaning:NnF #1#2
+ { \exp:w \@@_case:NNnTF \token_if_eq_meaning:NNTF #1 {#2} { } }
+\cs_new:Npn \token_case_meaning:NnTF
+ { \exp:w \@@_case:NNnTF \token_if_eq_meaning:NNTF }
+\cs_new:Npn \@@_case:NNnTF #1#2#3#4#5
+ {
+ \@@_case:NNw #1 #2 #3 #2 { }
+ \s_@@_mark {#4}
+ \s_@@_mark {#5}
+ \s_@@_stop
+ }
+\cs_new:Npn \@@_case:NNw #1#2#3#4
+ {
+ #1 #2 #3
+ { \@@_case_end:nw {#4} }
+ { \@@_case:NNw #1 #2 }
+ }
+% \end{macrocode}
+% To tidy up the recursion, there are two outcomes. If there was a hit to
+% one of the cases searched for, then |#1| is the code to insert,
+% |#2| is the \emph{next} case to check on and |#3| is all of
+% the rest of the cases code. That means that |#4| is the \texttt{true}
+% branch code, and |#5| tidies up the spare \cs{s_@@_mark} and the
+% \texttt{false} branch. On the other hand, if none of the cases matched
+% then we arrive here using the \enquote{termination} case of comparing
+% the search with itself. That means that |#1| is empty, |#2| is
+% the first \cs{s_@@_mark} and so |#4| is the \texttt{false} code (the
+% \texttt{true} code is mopped up by |#3|).
+% \begin{macrocode}
+\cs_new:Npn \@@_case_end:nw #1#2#3 \s_@@_mark #4#5 \s_@@_stop
+ { \exp_end: #1 #4 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \subsection{Peeking ahead at the next token}
%
% \begin{macrocode}
diff --git a/l3kernel/testfiles/m3quark001.tlg b/l3kernel/testfiles/m3quark001.tlg
index a86a55bba..10446d7d2 100644
--- a/l3kernel/testfiles/m3quark001.tlg
+++ b/l3kernel/testfiles/m3quark001.tlg
@@ -96,6 +96,7 @@ already been used for a scan mark.
\s__clist_mark
\s__clist_stop
\s__char_stop
+\s__token_mark
\s__token_stop
\s__peek_mark
\s__peek_stop
diff --git a/l3kernel/testfiles/m3token005.lvt b/l3kernel/testfiles/m3token005.lvt
index 32890f37a..27bf03b0a 100644
--- a/l3kernel/testfiles/m3token005.lvt
+++ b/l3kernel/testfiles/m3token005.lvt
@@ -60,4 +60,80 @@
\tl_rescan:nn { \char_set_catcode_active:N \D } { \cs_log:N D }
}
+\TEST { Token~case }
+ {
+ \token_case_catcode:Nn \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ & { \ERROR }
+ }
+ \token_case_catcode:NnT \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ & { \ERROR }
+ } { \ERROR }
+ \token_case_catcode:NnF \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ & { \ERROR }
+ } { \FALSE }
+ \token_case_catcode:NnTF \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ & { \ERROR }
+ } { \ERROR } { \FALSE }
+ \token_case_charcode:Nn \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ \scan_stop: { \TRUE }
+ }
+ \token_case_charcode:NnT \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ \scan_stop: { \TRUE }
+ } { \TRUE }
+ \token_case_charcode:NnF \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ \scan_stop: { \TRUE }
+ } { \ERROR }
+ \token_case_charcode:NnTF \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ \scan_stop: { \TRUE }
+ } { \TRUE } { \ERROR }
+ \token_case_meaning:Nn \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ \scan_stop: { \ERROR }
+ }
+ \token_case_meaning:NnT \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ \scan_stop: { \ERROR }
+ } { \ERROR }
+ \token_case_meaning:NnF \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ \scan_stop: { \ERROR }
+ } { \FALSE }
+ \token_case_meaning:NnTF \c_empty_tl
+ {
+ a { \ERROR }
+ + { \ERROR }
+ \scan_stop: { \ERROR }
+ } { \ERROR } { \FALSE }
+ }
+
\END
diff --git a/l3kernel/testfiles/m3token005.tlg b/l3kernel/testfiles/m3token005.tlg
index 53416c1e8..45b96cf04 100644
--- a/l3kernel/testfiles/m3token005.tlg
+++ b/l3kernel/testfiles/m3token005.tlg
@@ -25,3 +25,17 @@ TEST 3: Char set active (make active rescan)
> C=undefined.
> D=\long macro:->Works.
============================================================
+============================================================
+TEST 4: Token case
+============================================================
+FALSE
+FALSE
+TRUE
+TRUE
+TRUE
+TRUE
+TRUE
+TRUE
+FALSE
+FALSE
+============================================================
More information about the latex3-commits
mailing list.