diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/l3kernel/l3quark.dtx |
Initial commit
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3quark.dtx')
-rw-r--r-- | macros/latex/contrib/l3kernel/l3quark.dtx | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/macros/latex/contrib/l3kernel/l3quark.dtx b/macros/latex/contrib/l3kernel/l3quark.dtx new file mode 100644 index 0000000000..9ef207f346 --- /dev/null +++ b/macros/latex/contrib/l3kernel/l3quark.dtx @@ -0,0 +1,636 @@ +% \iffalse meta-comment +% +%% File: l3quark.dtx +% +% Copyright (C) 1990-2019 The LaTeX3 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 +% +% https://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,kernel]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3quark} package\\ Quarks^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2019-08-25} +% +% \maketitle +% +% \begin{documentation} +% +% Two special types of constants in \LaTeX3 are \enquote{quarks} and +% \enquote{scan marks}. By convention all constants of type quark +% start out with |\q_|, and scan marks start with |\s_|. +% +% \section{Quarks} +% +% Quarks are control sequences that expand to themselves and should +% therefore \emph{never} be executed directly in the code. +% This would result in an endless loop! +% +% They are meant to be used as delimiter in weird functions, the most +% common use case being the `stop token' (\emph{i.e.}~\cs{q_stop}). +% For example, when writing a macro to parse a user-defined date +% \begin{verbatim} +% \date_parse:n {19/June/1981} +% \end{verbatim} +% one might write a command such as +% \begin{verbatim} +% \cs_new:Npn \date_parse:n #1 { \date_parse_aux:w #1 \q_stop } +% \cs_new:Npn \date_parse_aux:w #1 / #2 / #3 \q_stop +% { <do something with the date> } +% \end{verbatim} +% +% Quarks are sometimes also used as error return values for functions +% that receive erroneous input. +% For example, in the function \cs{prop_get:NnN} to retrieve a value stored +% in some key of a property list, if the key does not exist then the return value +% is the quark \cs{q_no_value}. +% As mentioned above, such quarks are extremely fragile and it is imperative +% when using such functions that code is carefully written to check for +% pathological cases to avoid leakage of a quark into an uncontrolled +% environment. +% +% Quarks also permit the +% following ingenious trick when parsing tokens: +% when you pick up a token in a temporary variable +% and you want to know whether you have picked up a particular quark, +% all you have to do is compare the temporary variable to the quark using +% \cs{tl_if_eq:NNTF}. A set of special quark testing functions is set up +% below. All the quark testing functions are expandable although the +% ones testing only single tokens are much faster. +% An example of the quark testing functions and their use in recursion +% can be seen in the implementation of \cs{clist_map_function:NN}. +% +% \section{Defining quarks} +% +% \begin{function}{\quark_new:N} +% \begin{syntax} +% \cs{quark_new:N} \meta{quark} +% \end{syntax} +% Creates a new \meta{quark} which expands only to \meta{quark}. +% The \meta{quark} is defined globally, and an error message +% is raised if the name was already taken. +% \end{function} +% +% \begin{variable}{\q_stop} +% Used as a marker for delimited arguments, such as +% \begin{verbatim} +% \cs_set:Npn \tmp:w #1#2 \q_stop {#1} +% \end{verbatim} +% \end{variable} +% +% \begin{variable}{\q_mark} +% Used as a marker for delimited arguments when \cs{q_stop} is +% already in use. +% \end{variable} +% +% \begin{variable}{\q_nil} +% Quark to mark a null value in structured variables or functions. Used +% as an end delimiter when this may itself need to be tested +% (in contrast to \cs{q_stop}, which is only ever used as a delimiter). +% \end{variable} +% +% \begin{variable}{\q_no_value} +% A canonical value for a missing value, when one is requested from +% a data structure. This is therefore used as a \enquote{return} value +% by functions such as \cs{prop_get:NnN} if there is no data to +% return. +% \end{variable} +% +% \section{Quark tests} +% +% The method used to define quarks means that the single token (\texttt{N}) +% tests are faster than the multi-token (\texttt{n}) tests. The latter +% should therefore only be used when the argument can definitely take +% more than a single token. +% +% \begin{function}[EXP,pTF]{\quark_if_nil:N} +% \begin{syntax} +% \cs{quark_if_nil_p:N} \meta{token} +% \cs{quark_if_nil:NTF} \meta{token} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is equal to \cs{q_nil}. +% \end{function} +% +% \begin{function}[EXP,pTF]{\quark_if_nil:n, \quark_if_nil:o, \quark_if_nil:V} +% \begin{syntax} +% \cs{quark_if_nil_p:n} \Arg{token list} \\ +% \cs{quark_if_nil:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token list} contains only \cs{q_nil} (distinct +% from \meta{token list} being empty or containing \cs{q_nil} plus one +% or more other tokens). +% \end{function} +% +% \begin{function}[EXP,pTF]{\quark_if_no_value:N, \quark_if_no_value:c} +% \begin{syntax} +% \cs{quark_if_no_value_p:N} \meta{token} \\ +% \cs{quark_if_no_value:NTF} \meta{token} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is equal to \cs{q_no_value}. +% \end{function} +% +% \begin{function}[EXP,pTF]{\quark_if_no_value:n} +% \begin{syntax} +% \cs{quark_if_no_value_p:n} \Arg{token list} \\ +% \cs{quark_if_no_value:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token list} contains only \cs{q_no_value} +% (distinct from \meta{token list} being empty or containing +% \cs{q_no_value} plus one or more other tokens). +% \end{function} +% +% \section{Recursion} +% +% This module provides a uniform interface to intercepting and +% terminating loops as when one is doing tail recursion. The building +% blocks follow below and an example is shown in +% Section~\ref{sec:l3quark:quark-example}. +% +% \begin{variable}{\q_recursion_tail} +% This quark is appended to the data structure in question and +% appears as a real element there. This means it gets any list +% separators around it. +% \end{variable} +% +% \begin{variable}{\q_recursion_stop} +% This quark is added \emph{after} the data structure. Its purpose +% is to make it possible to terminate the recursion at any point +% easily. +% \end{variable} +% +% \begin{function}{\quark_if_recursion_tail_stop:N} +% \begin{syntax} +% \cs{quark_if_recursion_tail_stop:N} \meta{token} +% \end{syntax} +% Tests if \meta{token} contains only the marker +% \cs{q_recursion_tail}, and if so uses +% \cs{use_none_delimit_by_q_recursion_stop:w} to terminate the +% recursion that this belongs to. The +% recursion input must include the marker tokens \cs{q_recursion_tail} +% and \cs{q_recursion_stop} as the last two items. +% \end{function} +% +% \begin{function}[updated = 2011-09-06] +% {\quark_if_recursion_tail_stop:n, \quark_if_recursion_tail_stop:o} +% \begin{syntax} +% \cs{quark_if_recursion_tail_stop:n} \Arg{token list} +% \end{syntax} +% Tests if the \meta{token list} contains only +% \cs{q_recursion_tail}, and if so uses +% \cs{use_none_delimit_by_q_recursion_stop:w} to terminate the +% recursion that this belongs to. The +% recursion input must include the marker tokens \cs{q_recursion_tail} +% and \cs{q_recursion_stop} as the last two items. +% \end{function} +% +% \begin{function}{\quark_if_recursion_tail_stop_do:Nn} +% \begin{syntax} +% \cs{quark_if_recursion_tail_stop_do:Nn} \meta{token} \Arg{insertion} +% \end{syntax} +% Tests if \meta{token} contains only the marker +% \cs{q_recursion_tail}, and if so uses +% \cs{use_i_delimit_by_q_recursion_stop:w} to terminate the +% recursion that this belongs to. The +% recursion input must include the marker tokens \cs{q_recursion_tail} +% and \cs{q_recursion_stop} as the last two items. The \meta{insertion} +% code is then added to the input stream after the recursion has +% ended. +% \end{function} +% +% \begin{function}[updated = 2011-09-06] +% {\quark_if_recursion_tail_stop_do:nn, \quark_if_recursion_tail_stop_do:on} +% \begin{syntax} +% \cs{quark_if_recursion_tail_stop_do:nn} \Arg{token list} \Arg{insertion} +% \end{syntax} +% Tests if the \meta{token list} contains only +% \cs{q_recursion_tail}, and if so uses +% \cs{use_i_delimit_by_q_recursion_stop:w} to terminate the +% recursion that this belongs to. The +% recursion input must include the marker tokens \cs{q_recursion_tail} +% and \cs{q_recursion_stop} as the last two items. The \meta{insertion} +% code is then added to the input stream after the recursion has +% ended. +% \end{function} +% +% +% \begin{function}[added = 2018-04-10] +% { +% \quark_if_recursion_tail_break:NN, +% \quark_if_recursion_tail_break:nN +% } +% \begin{syntax} +% \cs{quark_if_recursion_tail_break:nN} \Arg{token list} \cs[no-index]{\meta{type}_map_break:} +% \end{syntax} +% Tests if \meta{token list} contains only \cs{q_recursion_tail}, and +% if so terminates the recursion using \cs[no-index]{\meta{type}_map_break:}. +% The recursion end should be marked by \cs{prg_break_point:Nn} +% \cs[no-index]{\meta{type}_map_break:}. +% \end{function} +% +% \section{An example of recursion with quarks} +% \label{sec:l3quark:quark-example} +% +% Quarks are mainly used internally in the \pkg{expl3} code to define +% recursion functions such as \cs{tl_map_inline:nn} and so on. +% Here is a small example to demonstrate how to use quarks in this fashion. +% We shall define a command called |\my_map_dbl:nn| which takes a token list +% and applies an operation to every \emph{pair} of tokens. +% For example, |\my_map_dbl:nn {abcd} {[--#1--#2--]~}| would produce +% \enquote{\ttfamily [--a--b--]~[--c--d--]~}. +% Using quarks to define such functions simplifies their logic and ensures +% robustness in many cases. +% +% +% Here's the definition of |\my_map_dbl:nn|. +% First of all, define the function that does the processing based on the +% inline function argument |#2|. +% Then initiate the recursion using an internal function. +% The token list |#1| is terminated using \cs{q_recursion_tail}, with +% delimiters according to the type of recursion (here a pair of +% \cs{q_recursion_tail}), concluding with \cs{q_recursion_stop}. +% These quarks are used to mark the end of the token list being operated upon. +%\begin{verbatim} +% \cs_new:Npn \my_map_dbl:nn #1#2 +% { +% \cs_set:Npn \__my_map_dbl_fn:nn ##1 ##2 {#2} +% \__my_map_dbl:nn #1 \q_recursion_tail \q_recursion_tail +% \q_recursion_stop +% } +%\end{verbatim} +% +% The definition of the internal recursion function follows. +% First check if either of the input tokens are the termination quarks. +% Then, if not, apply the inline function to the two arguments. +%\begin{verbatim} +% \cs_new:Nn \__my_map_dbl:nn +% { +% \quark_if_recursion_tail_stop:n {#1} +% \quark_if_recursion_tail_stop:n {#2} +% \__my_map_dbl_fn:nn {#1} {#2} +%\end{verbatim} +% Finally, recurse: +%\begin{verbatim} +% \__my_map_dbl:nn +% } +%\end{verbatim} +% Note that contrarily to \LaTeX3 built-in mapping functions, this +% mapping function cannot be nested, since the second map would overwrite +% the definition of |\__my_map_dbl_fn:nn|. +% +% \section{Scan marks} +% +% Scan marks are control sequences set equal to \cs{scan_stop:}, +% hence never expand in an expansion context and are (largely) +% invisible if they are encountered in a typesetting context. +% +% Like quarks, they can be used as delimiters in weird functions +% and are often safer to use for this purpose. +% Since they are harmless when executed by \TeX{} in non-expandable +% contexts, they can be used to mark the end of a set of instructions. +% This allows to skip to that point if the end of the instructions +% should not be performed (see \pkg{l3regex}). +% +% \begin{function}[added = 2018-04-01]{\scan_new:N} +% \begin{syntax} +% \cs{scan_new:N} \meta{scan mark} +% \end{syntax} +% Creates a new \meta{scan mark} which is set equal to \cs{scan_stop:}. +% The \meta{scan mark} is defined globally, and an error message +% is raised if the name was already taken by another scan mark. +% \end{function} +% +% \begin{variable}[added = 2018-04-01]{\s_stop} +% Used at the end of a set of instructions, as a marker +% that can be jumped to using \cs{use_none_delimit_by_s_stop:w}. +% \end{variable} +% +% \begin{function}[added = 2018-04-01]{\use_none_delimit_by_s_stop:w} +% \begin{syntax} +% \cs{use_none_delimit_by_s_stop:w} \meta{tokens} \cs{s_stop} +% \end{syntax} +% Removes the \meta{tokens} and \cs{s_stop} from the input stream. +% This leads to a low-level \TeX{} error if \cs{s_stop} is absent. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3quark} implementation} +% +% \TestFiles{m3quark001.lvt} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \subsection{Quarks} +% +% \begin{macrocode} +%<@@=quark> +% \end{macrocode} +% +% \begin{macro}{\quark_new:N} +% \UnitTested +% Allocate a new quark. +% \begin{macrocode} +\__kernel_patch:nnNNpn { \__kernel_chk_var_scope:NN q #1 } { } +\cs_new_protected:Npn \quark_new:N #1 + { + \__kernel_chk_if_free_cs:N #1 + \cs_gset_nopar:Npn #1 {#1} + } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\q_nil, \q_mark, \q_no_value, \q_stop} +% Some \enquote{public} quarks. \cs{q_stop} is an \enquote{end of +% argument} marker, \cs{q_nil} is a empty value and \cs{q_no_value} +% marks an empty argument. +% \begin{macrocode} +\quark_new:N \q_nil +\quark_new:N \q_mark +\quark_new:N \q_no_value +\quark_new:N \q_stop +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\q_recursion_tail, \q_recursion_stop} +% Quarks for ending recursions. Only ever used there! +% \cs{q_recursion_tail} is appended to whatever list structure we are +% doing recursion on, meaning it is added as a proper list item with +% whatever list separator is in use. \cs{q_recursion_stop} is placed +% directly after the list. +% \begin{macrocode} +\quark_new:N \q_recursion_tail +\quark_new:N \q_recursion_stop +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\quark_if_recursion_tail_stop:N} +% \UnitTested +% \begin{macro}{\quark_if_recursion_tail_stop_do:Nn} +% \UnitTested +% When doing recursions, it is easy to spend a lot of time testing if the +% end marker has been found. To avoid this, a dedicated end marker is used +% each time a recursion is set up. Thus if the marker is found everything +% can be wrapper up and finished off. The simple case is when the test +% can guarantee that only a single token is being tested. In this case, +% there is just a dedicated copy of the standard quark test. Both a gobbling +% version and one inserting end code are provided. +% \begin{macrocode} +\cs_new:Npn \quark_if_recursion_tail_stop:N #1 + { + \if_meaning:w \q_recursion_tail #1 + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + } +\cs_new:Npn \quark_if_recursion_tail_stop_do:Nn #1 + { + \if_meaning:w \q_recursion_tail #1 + \exp_after:wN \use_i_delimit_by_q_recursion_stop:nw + \else: + \exp_after:wN \use_none:n + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\quark_if_recursion_tail_stop:n, \quark_if_recursion_tail_stop:o} +% \UnitTested +% \begin{macro} +% {\quark_if_recursion_tail_stop_do:nn, \quark_if_recursion_tail_stop_do:on} +% \UnitTested +% \begin{macro}{\@@_if_recursion_tail:w} +% See \cs{quark_if_nil:nTF} for the details. Expanding +% \cs{@@_if_recursion_tail:w} once in front of the tokens chosen here +% gives an empty result if and only if |#1|~is exactly +% \cs{q_recursion_tail}. +% \begin{macrocode} +\cs_new:Npn \quark_if_recursion_tail_stop:n #1 + { + \tl_if_empty:oTF + { \@@_if_recursion_tail:w {} #1 {} ?! \q_recursion_tail ??! } + { \use_none_delimit_by_q_recursion_stop:w } + { } + } +\cs_new:Npn \quark_if_recursion_tail_stop_do:nn #1 + { + \tl_if_empty:oTF + { \@@_if_recursion_tail:w {} #1 {} ?! \q_recursion_tail ??! } + { \use_i_delimit_by_q_recursion_stop:nw } + { \use_none:n } + } +\cs_new:Npn \@@_if_recursion_tail:w + #1 \q_recursion_tail #2 ? #3 ?! { #1 #2 } +\cs_generate_variant:Nn \quark_if_recursion_tail_stop:n { o } +\cs_generate_variant:Nn \quark_if_recursion_tail_stop_do:nn { o } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\quark_if_recursion_tail_break:NN} +% \begin{macro}{\quark_if_recursion_tail_break:nN} +% Analogues of the \cs[index=quark_if_recursion_tail_stop:n] +% {quark_if_recursion_tail_stop\ldots{}} functions. +% Break the mapping using |#2|. +% \begin{macrocode} +\cs_new:Npn \quark_if_recursion_tail_break:NN #1#2 + { + \if_meaning:w \q_recursion_tail #1 + \exp_after:wN #2 + \fi: + } +\cs_new:Npn \quark_if_recursion_tail_break:nN #1#2 + { + \tl_if_empty:oT + { \@@_if_recursion_tail:w {} #1 {} ?! \q_recursion_tail ??! } + {#2} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\quark_if_nil:N} +% \UnitTested +% \begin{macro}[pTF]{\quark_if_no_value:N, \quark_if_no_value:c} +% \UnitTested +% Here we test if we found a special quark as the first argument. +% We better start with \cs{q_no_value} as the first argument since +% the whole thing may otherwise loop if |#1| is wrongly given +% a string like |aabc| instead of a single token.\footnote{It may +% still loop in special circumstances however!} +% \begin{macrocode} +\prg_new_conditional:Npnn \quark_if_nil:N #1 { p, T , F , TF } + { + \if_meaning:w \q_nil #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Npnn \quark_if_no_value:N #1 { p, T , F , TF } + { + \if_meaning:w \q_no_value #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_generate_conditional_variant:Nnn \quark_if_no_value:N + { c } { p , T , F , TF } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\quark_if_nil:n, \quark_if_nil:V, \quark_if_nil:o} +% \UnitTested +% \begin{macro}[pTF]{\quark_if_no_value:n} +% \UnitTested +% \begin{macro}{\@@_if_nil:w, \@@_if_no_value:w} +% \begin{macro}[EXP]{\@@_if_empty_if:o} +% Let us explain |\quark_if_nil:n(TF)|. Expanding \cs{@@_if_nil:w} +% once is safe thanks to the trailing \cs{q_nil} |??!|. The result of +% expanding once is empty if and only if both delimited arguments |#1| +% and~|#2| are empty and |#3|~is delimited by the last tokens~|?!|. +% Thanks to the leading~|{}|, the argument~|#1| is empty if and only +% if the argument of \cs{quark_if_nil:n} starts with \cs{q_nil}. The +% argument~|#2| is empty if and only if this \cs{q_nil} is followed +% immediately by~|?| or by~|{}?|, coming either from the trailing +% tokens in the definition of \cs{quark_if_nil:n}, or from its +% argument. In the first case, \cs{@@_if_nil:w} is followed by +% |{}\q_nil| |{}?| |!\q_nil|~|??!|, hence |#3|~is delimited by the +% final~|?!|, and the test returns \texttt{true} as wanted. In the +% second case, the result is not empty since the first~|?!| in the +% definition of \cs{quark_if_nil:n} stop~|#3|. The auxiliary here +% is the same as \cs{__tl_if_empty_if:o}, with the same comments +% applying. +% \begin{macrocode} +\prg_new_conditional:Npnn \quark_if_nil:n #1 { p, T , F , TF } + { + \@@_if_empty_if:o + { \@@_if_nil:w {} #1 {} ? ! \q_nil ? ? ! } + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new:Npn \@@_if_nil:w #1 \q_nil #2 ? #3 ? ! { #1 #2 } +\prg_new_conditional:Npnn \quark_if_no_value:n #1 { p, T , F , TF } + { + \@@_if_empty_if:o + { \@@_if_no_value:w {} #1 {} ? ! \q_no_value ? ? ! } + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new:Npn \@@_if_no_value:w #1 \q_no_value #2 ? #3 ? ! { #1 #2 } +\prg_generate_conditional_variant:Nnn \quark_if_nil:n + { V , o } { p , TF , T , F } +\cs_new:Npn \@@_if_empty_if:o #1 + { + \exp_after:wN \if_meaning:w \exp_after:wN \q_nil + \__kernel_tl_to_str:w \exp_after:wN {#1} \q_nil + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Scan marks} +% +% \begin{macrocode} +%<@@=scan> +% \end{macrocode} +% +% \begin{variable}{\g_@@_marks_tl} +% \UnitTested +% The list of all scan marks currently declared. +% \begin{macrocode} +\tl_new:N \g_@@_marks_tl +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\scan_new:N} +% \UnitTested +% Check whether the variable is already a scan mark, +% then declare it to be equal to \cs{scan_stop:} globally. +% \begin{macrocode} +\__kernel_patch:nnNNpn { \__kernel_chk_var_scope:NN s #1 } { } +\cs_new_protected:Npn \scan_new:N #1 + { + \tl_if_in:NnTF \g_@@_marks_tl { #1 } + { + \__kernel_msg_error:nnx { kernel } { scanmark-already-defined } + { \token_to_str:N #1 } + } + { + \tl_gput_right:Nn \g_@@_marks_tl {#1} + \cs_new_eq:NN #1 \scan_stop: + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\s_stop} +% \UnitTested +% We only declare one scan mark here, more can be defined +% by specific modules. +% \begin{macrocode} +\scan_new:N \s_stop +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\use_none_delimit_by_s_stop:w} +% \UnitTested +% Similar to \cs{use_none_delimit_by_q_stop:w}. +% \begin{macrocode} +\cs_new:Npn \use_none_delimit_by_s_stop:w #1 \s_stop { } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex |