% \iffalse %% File: l3quark.dtx Copyright (C) 1990-2006 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 %% %% http://www.latex-project.org/lppl.txt %% %% This file is part of the ``expl3 bundle'' (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% The released version of this bundle is available from CTAN. %% %% ----------------------------------------------------------------------- %% %% The development version of the bundle can be found at %% %% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ %% %% for those people who are interested. %% %%%%%%%%%%% %% NOTE: %% %%%%%%%%%%% %% %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without %% prior consultation with the LaTeX Project Team. %% %% ----------------------------------------------------------------------- % %<*driver|package> \RequirePackage{l3names} % %\fi \GetIdInfo$Id: l3quark.dtx 761 2008-08-04 21:35:13Z morten $ {L3 Experimental Quark Commands} %\iffalse %<*driver> %\fi \ProvidesFile{\filename.\filenameext} [\filedate\space v\fileversion\space\filedescription] %\iffalse \documentclass{l3doc} \begin{document} \DocInput{\filename.\filenameext} \end{document} % % \fi % % % \title{The \textsf{l3quark} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ % ``Quarks''} % \author{\Team} % \date{\filedate} % \maketitle % % % \section{Quarks} %^^A \label{sec:quarks} % % % A special type of constants in \LaTeX3 are `quarks'. These are control % sequences that expand to themselves and should therefore NEVER be % executed directly in the code. This would result in an endless loop! % % They are meant to be used as delimiter is weird functions (for % example as the stop token (i.e., "\q_stop"). They also permit the % following ingenious trick: when you pick up a token in a temporary, % and you want to know whether you have picked up a particular quark, % all you have to do is compare the temporary to the quark using % "\if_meaning:NN". 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. % % By convention all constants of type quark start out with "\q_". % % The documentation needs some updating. % % % \subsection{Functions} % % \begin{function}{% % \quark_new:N | % } % \begin{syntax} % "\quark_new:N" % \end{syntax} % Defines to be a new constant of type "quark". % \end{function} % % \begin{function}{% % \quark_if_no_value_p:n | % \quark_if_no_value:nTF | % \quark_if_no_value:nF | % \quark_if_no_value:nT | % \quark_if_no_value_p:N | % \quark_if_no_value:NTF | % \quark_if_no_value:NT | % \quark_if_no_value:NF | % } % \begin{syntax} % "\quark_if_no_value:nTF" "{""}" % " {""}{""}" % "\quark_if_no_value:NTF" % " {""}{""}" % \end{syntax} % This tests whether or not contains only the quark % "\q_no_value". % % If to be tested is stored in a token list pointer use % "\quark_if_no_value:NTF", or "\quark_if_no_value:NF" or check the % value directly with "\if_meaning:NN". All those cases are faster then % "\quark_if_no_value:nTF" so should be preferred.\footnote{Clarify % semantic of the ``n'' case \ldots{} i think it is not implement % according to what we originally intended /FMi} % % \begin{texnote} % But be aware of the fact that "\if_meaning:NN" can result in an % overflow of \TeX{}'s parameter stack since it leaves the corresponding % "\fi:" on the input until the whole replacement text is processed. It % is therefore better in recursions to use "\quark_if_no_value:NTF" as % it will remove the conditional prior to processing the "T" or "F" case % and so allows tail-recursion. % \end{texnote} % \end{function} % % \begin{function}{% % \quark_if_nil_p:N | % \quark_if_nil:NTF | % \quark_if_nil:NT | % \quark_if_nil:NF | % } % \begin{syntax} % "\quark_if_nil:NTF" % " {""}{""}" % \end{syntax} % This tests whether or not is equal to the quark % "\q_nil". % % This is a useful test for recursive loops which typically has % "\q_nil" as an end marker. % \end{function} % % % \begin{function}{% % \quark_if_nil_p:n | % \quark_if_nil:nTF | % \quark_if_nil:nT | % \quark_if_nil:nF | % \quark_if_nil_p:o | % \quark_if_nil:oTF | % \quark_if_nil:oT | % \quark_if_nil:oF | % } % \begin{syntax} % "\quark_if_nil:nTF" "{""}" % "{""}{""}" % \end{syntax} % This tests whether or not is equal to the quark % "\q_nil". % % This is a useful test for recursive loops which typically has % "\q_nil" as an end marker. % \end{function} % % \subsection{Recursion} % % This module provides a uniform interface to intercepting and % terminating loops as when one is doing tail recursion. The building % blocks follow below. % % \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 | % \quark_if_recursion_tail_stop:n | % \quark_if_recursion_tail_stop:o | % } % \begin{syntax} % "\quark_if_recursion_tail_stop:n" "{""}" \\ % "\quark_if_recursion_tail_stop:N" % \end{syntax} % This tests whether or not is equal to % "\q_recursion_tail" and then exits, i.e., it gobbles the remainder of % the list up to and including "\q_recursion_stop" which \emph{must} % be present. % % If is not under your complete control it is advisable % to use the "n". If you wish to use the "N" form you \emph{must} % ensure it is really a single token such as if you have % \begin{quote} % "\tlp_set:Nn \l_tmpa_tlp {" "}" % \end{quote} % \end{function} % % \begin{function}{% % \quark_if_recursion_tail_stop_do:Nn | % \quark_if_recursion_tail_stop_do:nn | % \quark_if_recursion_tail_stop_do:on | % } % \begin{syntax} % "\quark_if_recursion_tail_stop_do:nn"\\ % "{""}" "{" "}" % "\quark_if_recursion_tail_stop_do:Nn" % "{" "}" % \end{syntax} % Same as "\quark_if_recursion_tail_stop:N" except here the second % argument is executed after the recursion has been terminated. % \end{function} % % \subsection{Constants} % % \begin{variable}{\q_no_value} The canonical `missing value quark' % that is returned by certain functions to denote that a requested value % is not found in the data structure. % \end{variable} % % \begin{variable}{\q_stop} % This constant is used as a a marker in parameter text. This allows a % scanning function to find the end of some input string. % \end{variable} % % \begin{variable}{\q_nil} % This constant represent the nil pointer in pointer structures. % \end{variable} % % \StopEventually{} % % \subsection{The Implementation} % % We start by ensuring that the required packages are loaded. % We check for \texttt{l3expan} since this a basic package that is % essential for use of any higher-level package. % \begin{macrocode} %\ProvidesExplPackage % {\filename}{\filedate}{\fileversion}{\filedescription} %\RequirePackage{l3expan}\par %<*initex|package> % \end{macrocode} % % \begin{macro}{\quark_new:N} % Allocate a new quark. % \begin{macrocode} \def_new:Npn \quark_new:N #1{\tlp_new:Nn #1{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\q_stop} % \begin{macro}{\q_no_value} % \begin{macro}{\q_nil} % |\q_stop| is often used as a marker in parameter text, % |\q_no_value| is the canonical missing value, and |\q_nil| % represents a nil pointer in some data structures. % \begin{macrocode} \quark_new:N \q_stop \quark_new:N \q_no_value \quark_new:N \q_nil % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\q_error} % \begin{macro}{\q_mark} % We need two additional quarks. |\q_error| delimits the end of % the computation for purposes of error recovery. |\q_mark| is % used in parameter text when we need a scanning boundary that is % distinct from |\q_stop|. % \begin{macrocode} \quark_new:N\q_error \quark_new:N\q_mark % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\q_recursion_tail} % \begin{macro}{\q_recursion_stop} % Quarks for ending recursions. Only ever used there! % |\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. |\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{macro} % \end{macro} % % \begin{macro}{\quark_if_recursion_tail_stop:n} % \begin{macro}{\quark_if_recursion_tail_stop:N} % \begin{macro}{\quark_if_recursion_tail_stop:o} % When doing recursions it is easy to spend a lot of time testing if % we found the end marker. To avoid this, we use a recursion end % marker every time we do this kind of task. Also, if the recursion % end marker is found, we wrap things up and finish. % \begin{macrocode} \def_long_new:Npn \quark_if_recursion_tail_stop:n #1 { \exp_after:NN\if_meaning:NN \quark_if_recursion_tail_aux:w #1?\q_nil\q_recursion_tail\q_recursion_tail \exp_after:NN \use_none_delimit_by_q_recursion_stop:w \fi: } \def_long_new:Npn \quark_if_recursion_tail_stop:N #1 { \if_meaning:NN#1\q_recursion_tail \exp_after:NN \use_none_delimit_by_q_recursion_stop:w \fi: } \def_new:Npn \quark_if_recursion_tail_stop:o{ \exp_args:No\quark_if_recursion_tail_stop:n } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\quark_if_recursion_tail_stop_do:nn} % \begin{macro}{\quark_if_recursion_tail_stop_do:Nn} % \begin{macro}{\quark_if_recursion_tail_stop_do:on} % \begin{macrocode} \def_long_new:Npn \quark_if_recursion_tail_stop_do:nn #1#2 { \exp_after:NN\if_meaning:NN \quark_if_recursion_tail_aux:w #1?\q_nil\q_recursion_tail\q_recursion_tail \exp_after:NN \use_arg_i_delimit_by_q_recursion_stop:nw \else: \exp_after:NN\use_none:n \fi: {#2} } \def_long_new:Npn \quark_if_recursion_tail_stop_do:Nn #1#2 { \if_meaning:NN #1\q_recursion_tail \exp_after:NN \use_arg_i_delimit_by_q_recursion_stop:nw \else: \exp_after:NN\use_none:n \fi: {#2} } \def_new:Npn \quark_if_recursion_tail_stop_do:on{ \exp_args:No\quark_if_recursion_tail_stop_do:nn } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\quark_if_recursion_tail_aux:w} % \begin{macro}{\use_none_delimit_by_q_recursion_stop:w} % \begin{macro}{\use_arg_i_delimit_by_q_recursion_stop:nw} % Helper macros for picking up the first token of a list to see if % it is "\q_recursion_tail" and to stop the recursion. % \begin{macrocode} \def_long_new:Npn \quark_if_recursion_tail_aux:w #1#2\q_nil\q_recursion_tail{#1} \def_long_new:Npn\use_none_delimit_by_q_recursion_stop:w #1\q_recursion_stop {} \def_long_new:Npn\use_arg_i_delimit_by_q_recursion_stop:nw #1#2\q_recursion_stop {#1} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\quark_if_no_value_p:N} % \begin{macro}{\quark_if_no_value:NTF} % \begin{macro}{\quark_if_no_value:NT} % \begin{macro}{\quark_if_no_value:NF} % \begin{macro}{\quark_if_no_value_p:n} % \begin{macro}{\quark_if_no_value:nTF} % \begin{macro}{\quark_if_no_value:nT} % \begin{macro}{\quark_if_no_value:nF} % \begin{macro}{\quark_if_no_value:nFT} % Here we test if we found a special quark as the first argument. % \begin{macrocode} \def_long_test_function_new:npn {quark_if_no_value:N} #1 { % \end{macrocode} % We better start with |\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} \if_meaning:NN\q_no_value#1} \def_long_new:Npn \quark_if_no_value_p:N #1{ \if_meaning:NN \q_no_value #1 \c_true \else: \c_false \fi: } % \end{macrocode} % We also provide an |n| type. If run under a sufficiently new % pdf\eTeX, it uses a built-in primitive for string comparisons, % otherwise it uses the slower |\str_if_eq_var_p:nf| function. In the % latter case it would be faster to use a temporary token list pointer % but it would render the function non-expandable. Using the pdf\eTeX\ % primitive is the preferred approach. Note that we have to add a % manual space token in the first part of the comparison, otherwise it % is gobbled by |\str_if_eq_var_p:nf|. The reason for using this % function instead of |\str_if_eq_p:nn| is that a sequence like % \verb*+ \q_no_value+ will test equal to |\q_no_value| using the % latter test function and unfortunately this example turned up in one % application. % \begin{macrocode} \cs_if_really_free:cTF{pdf_strcmp:D}{ \def_long_new:Npn \quark_if_no_value_p:n #1{ \if:w \exp_args:No \str_if_eq_var_p:nf % {\token_to_string:N\q_no_value\space} % {\token_to_string:N\q_no_value\text_put_sp:} {\tlist_to_str:n{#1}} \c_true \else: \c_false \fi: } } { \def_long_new:Npn \quark_if_no_value_p:n #1{ \if_num:w \pdf_strcmp:D {\exp_not:N \q_no_value}{\exp_not:n{#1}}=\c_zero \c_true \else: \c_false \fi: } } \def_long_test_function_new:npn {quark_if_no_value:n} #1 { \if:w \quark_if_no_value_p:n{#1}} % \end{macrocode} % We also define a version where the true and false code is ordered % differently. % \begin{macrocode} \def_long:Npn \quark_if_no_value:nFT #1{ \if:w \quark_if_no_value_p:n{#1} \exp_after:NN\use_arg_ii:nn \else: \exp_after:NN\use_arg_i:nn \fi: } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\quark_if_nil_p:N} % \begin{macro}{\quark_if_nil:NTF} % \begin{macro}{\quark_if_nil:NT} % \begin{macro}{\quark_if_nil:NF} % A function to check for the presence of |\q_nil|. % \begin{macrocode} \def_long_new:Npn \quark_if_nil_p:N #1{ \if_meaning:NN \q_nil #1 \c_true \else: \c_false \fi: } \def_long_test_function_new:npn {quark_if_nil:N}#1{ \if_meaning:NN\q_nil#1} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\quark_if_nil_p:n} % \begin{macro}{\quark_if_nil:nTF} % \begin{macro}{\quark_if_nil:nT} % \begin{macro}{\quark_if_nil:nF} % \begin{macro}{\quark_if_nil_p:o} % \begin{macro}{\quark_if_nil:oTF} % \begin{macro}{\quark_if_nil:oT} % \begin{macro}{\quark_if_nil:oF} % A function to check for the presence of |\q_nil|. % \begin{macrocode} \cs_if_really_free:cTF{pdf_strcmp:D}{ \def_long_new:Npn \quark_if_nil_p:n #1{ \if:w \exp_args:No \str_if_eq_var_p:nf % {\token_to_string:N\q_nil\space} % {\token_to_string:N\q_nil\text_put_sp:} {\tlist_to_str:n{#1}} \c_true \else: \c_false \fi: } } { \def_long_new:Npn \quark_if_nil_p:n #1{ \if_num:w \pdf_strcmp:D {\exp_not:N \q_nil}{\exp_not:n{#1}}=\c_zero \c_true \else: \c_false \fi: } } \def_long_test_function_new:npn {quark_if_nil:n} #1 { \if:w \quark_if_nil_p:n{#1}} \def_new:Npn \quark_if_nil_p:o{\exp_args:No\quark_if_nil_p:n} \def_new:Npn \quark_if_nil:oTF{\exp_args:No\quark_if_nil:nTF} \def_new:Npn \quark_if_nil:oT {\exp_args:No\quark_if_nil:nT} \def_new:Npn \quark_if_nil:oF {\exp_args:No\quark_if_nil:nF} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % Show token usage: % \begin{macrocode} % %<*showmemory> \showMemUsage % % \end{macrocode} % % \endinput % % $Log$ % Revision 1.22 2006/07/30 14:39:02 morten % Changed all quark functions to be expandable regardless of whether % \pdfstrcmp is available. % % Revision 1.21 2006/07/25 15:34:21 morten % Added the non-expandable \quark_if_nil:nTF plus variants. % % Revision 1.20 2006/07/23 13:43:47 morten % Fixed minor bug in \quark_if_no_value_p:n % % Revision 1.19 2006/03/20 18:26:38 braams % Updated the copyright notice (2006) and demoted all implementation % sections to subsections and so on to clean up the toc for source3.tex % % Revision 1.18 2006/01/04 01:18:31 morten % Changed \quark_if_no_value:nTF to be expandable. Added a few predicate % functions and updated documentation. % % Revision 1.17 2005/12/27 10:04:41 morten % Minor changes plus changed RCS information retrieval % % Revision 1.16 2005/10/27 14:12:28 morten % Added gobble-until-quark functions. % % Revision 1.15 2005/07/14 18:50:31 morten % Added \quark_if_nil:NF % % Revision 1.14 2005/04/06 13:55:57 morten % Fixed \quark_if_nil:NTF % % Revision 1.13 2005/03/16 22:35:57 braams % Added the tweaks necessary to be able to load with initex % % Revision 1.12 2005/03/11 21:41:27 braams % Fixed the use of RCS information; added \StopEventually %