% \iffalse %% File: l3quark.dtx Copyright (C) 1990-2009 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/svnroot/experimental/trunk/ %% %% 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 1365 2009-05-31 17:26:17Z mittelba $ {L3 Experimental Quark Commands} %\iffalse %<*driver> %\fi \ProvidesFile{\filename.\filenameext} [\filedate\space v\fileversion\space\filedescription] %\iffalse \documentclass[full]{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 % % \begin{documentation} % % 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:w". 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. % % % \section{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 / (EXP) | % \quark_if_no_value:n / (TF)(EXP) | % \quark_if_no_value_p:N / (EXP) | % \quark_if_no_value:N / (TF)(EXP) | % } % \begin{syntax} % "\quark_if_no_value:nTF" \Arg{token list} \Arg{true code} \Arg{false code} % "\quark_if_no_value:NTF" \Arg{true code} \Arg{false code} % \end{syntax} % This tests whether or not contains only the quark % "\q_no_value". % % If to be tested is stored in a token list variable use % "\quark_if_no_value:NTF", or "\quark_if_no_value:NF" or check the % value directly with "\if_meaning:w". 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:w" 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 / (EXP) | % \quark_if_nil:N / (TF)(EXP) | % } % \begin{syntax} % "\quark_if_nil:NTF" \Arg{true code} \Arg{false code} % \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 / (EXP) | % \quark_if_nil_p:V / (EXP) | % \quark_if_nil_p:o / (EXP) | % \quark_if_nil:n / (TF)(EXP) | % \quark_if_nil:V / (TF)(EXP) | % \quark_if_nil:o / (TF)(EXP) | % } % \begin{syntax} % "\quark_if_nil:nTF" \Arg{tokens} \Arg{true code} \Arg{false code} % \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} % % \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. % % \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 / (EXP) | % \quark_if_recursion_tail_stop:n / (EXP) | % \quark_if_recursion_tail_stop:o / (EXP) | % } % \begin{syntax} % "\quark_if_recursion_tail_stop:n" \Arg{list element} \\ % "\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} % "\tl_set:Nn \l_tmpa_tl {" "}" % \end{quote} % \end{function} % % \begin{function}{% % \quark_if_recursion_tail_stop_do:Nn / (EXP) | % \quark_if_recursion_tail_stop_do:nn / (EXP) | % \quark_if_recursion_tail_stop_do:on / (EXP) | % } % \begin{syntax} % "\quark_if_recursion_tail_stop_do:nn" % ~~~~\Arg{list element} \Arg{post action} % "\quark_if_recursion_tail_stop_do:Nn" % ~~~~ \Arg{post action} % \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} % % \section{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} % % \begin{variable}{\q_error} % Delimits the end of % the computation for purposes of error recovery. % \end{variable} % % \begin{variable}{\q_mark} % Used in parameter text when we need a scanning boundary that is % distinct from |\q_stop|. % \end{variable} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3quark} 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} %<*package> \ProvidesExplPackage {\filename}{\filedate}{\fileversion}{\filedescription} \package_check_loaded_expl: % %<*initex|package> % \end{macrocode} % % \begin{macro}{\quark_new:N} % Allocate a new quark. % \begin{macrocode} \cs_new_nopar:Npn \quark_new:N #1{\tl_new:Nn #1{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\q_stop,\q_no_value,\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} % % \begin{macro}{\q_error,\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} % % % \begin{macro}{\q_recursion_tail,\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} % % \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} \cs_new:Npn \quark_if_recursion_tail_stop:n #1 { \exp_after:wN\if_meaning:w \quark_if_recursion_tail_aux:w #1?\q_nil\q_recursion_tail\q_recursion_tail \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: } \cs_new:Npn \quark_if_recursion_tail_stop:N #1 { \if_meaning:w#1\q_recursion_tail \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: } \cs_generate_variant:Nn \quark_if_recursion_tail_stop:n {o} % \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} \cs_new:Npn \quark_if_recursion_tail_stop_do:nn #1#2 { \exp_after:wN\if_meaning:w \quark_if_recursion_tail_aux:w #1?\q_nil\q_recursion_tail\q_recursion_tail \exp_after:wN \use_i_delimit_by_q_recursion_stop:nw \else: \exp_after:wN\use_none:n \fi: {#2} } \cs_new:Npn \quark_if_recursion_tail_stop_do:Nn #1#2 { \if_meaning:w #1\q_recursion_tail \exp_after:wN \use_i_delimit_by_q_recursion_stop:nw \else: \exp_after:wN\use_none:n \fi: {#2} } \cs_generate_variant:Nn \quark_if_recursion_tail_stop_do:nn {on} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[aux]{\quark_if_recursion_tail_aux:w} % \begin{macrocode} \cs_new:Npn \quark_if_recursion_tail_aux:w #1#2 \q_nil \q_recursion_tail {#1} % \end{macrocode} % \end{macro} % % \begin{macro}{\quark_if_no_value_p:N,\quark_if_no_value_p:n} % \begin{macro}[TF]{\quark_if_no_value:N,\quark_if_no_value:n} % Here we test if we found a special quark as the first argument. % 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} \prg_new_conditional:Nnn \quark_if_no_value:N {p,TF,T,F} { \if_meaning:w \q_no_value #1 \prg_return_true: \else: \prg_return_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 variable % 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_exist:cTF {pdf_strcmp:D} { \prg_new_conditional:Nnn \quark_if_no_value:n {p,TF,T,F} { \if_num:w \pdf_strcmp:D {\exp_not:N \q_no_value} {\exp_not:n{#1}} = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } } { \prg_new_conditional:Nnn \quark_if_no_value:n {p,TF,T,F} { \exp_args:NNo \if_predicate:w \str_if_eq_var_p:nf {\token_to_str:N\q_no_value\iow_space:} {\tl_to_str:n{#1}} \prg_return_true: \else: \prg_return_false: \fi: } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\quark_if_nil_p:N} % \begin{macro}[TF]{\quark_if_nil:N} % A function to check for the presence of |\q_nil|. % \begin{macrocode} \prg_new_conditional:Nnn \quark_if_nil:N {p,TF,T,F} { \if_meaning:w \q_nil #1 \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\quark_if_nil_p:n,\quark_if_nil_p:V,\quark_if_nil_p:o} % \begin{macro}[TF]{\quark_if_nil:n,\quark_if_nil:V,\quark_if_nil:o} % A function to check for the presence of |\q_nil|. % \begin{macrocode} \cs_if_exist:cTF {pdf_strcmp:D} { \prg_new_conditional:Nnn \quark_if_nil:n {p,TF,T,F} { \if_num:w \pdf_strcmp:D {\exp_not:N \q_nil} {\exp_not:n{#1}} = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } } { \prg_new_conditional:Nnn \quark_if_nil:n {p,TF,T,F} { \exp_args:NNo \if_predicate:w \str_if_eq_var_p:nf {\token_to_str:N\q_nil\iow_space:} {\tl_to_str:n{#1}} \prg_return_true: \else: \prg_return_false: \fi: } } \cs_generate_variant:Nn \quark_if_nil_p:n {V} \cs_generate_variant:Nn \quark_if_nil:nTF {V} \cs_generate_variant:Nn \quark_if_nil:nT {V} \cs_generate_variant:Nn \quark_if_nil:nF {V} \cs_generate_variant:Nn \quark_if_nil_p:n {o} \cs_generate_variant:Nn \quark_if_nil:nTF {o} \cs_generate_variant:Nn \quark_if_nil:nT {o} \cs_generate_variant:Nn \quark_if_nil:nF {o} % \end{macrocode} % \end{macro} % \end{macro} % % % % Show token usage: % \begin{macrocode} %<*showmemory> \showMemUsage % % \end{macrocode} % % \end{implementation} % \PrintIndex % % \endinput