% \iffalse meta-comment % %% File: l3quark.dtx Copyright (C) 1990-2011 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 %% %% 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 LaTeX3 Project. %% %% ----------------------------------------------------------------------- % %<*driver|package> \RequirePackage{l3names} \GetIdInfo$Id: l3quark.dtx 2549 2011-08-11 21:06:39Z bruno $ {L3 Experimental quarks} % %<*driver> \documentclass[full]{l3doc} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3quark} package\\ Quarks^^A % \thanks{This file describes v\ExplFileVersion, % last revised \ExplFileDate.}^^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 \ExplFileDate} % % \maketitle % % \begin{documentation} % % A special type of constants in \LaTeX3 are \enquote{quarks}. These 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 is weird functions (for % example as the stop token (\emph{i.e.}~\cs{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 % \cs{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_|. % % \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} will be defined globally, and an error message % will be 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 may 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 later % 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}. The branching % versions then leave either \meta{true code} or \meta{false code} in % the input stream, as appropriate to the truth of the test and the % variant of the function chosen. The logical truth of the test is % left in the input stream by the predicate version. % \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). The branching versions then leave either % \meta{true code} or \meta{false code} in the input stream, as % appropriate to the truth of the test and the variant of the % function chosen. The logical truth of the test is left in the input % stream by the predicate version. % \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}. The branching % versions then leave either \meta{true code} or \meta{false code} in % the input stream, as appropriate to the truth of the test and the % variant of the function chosen. The logical truth of the test is % left in the input stream by the predicate version. % \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). The branching % versions then leave either \meta{true code} or \meta{false code} in % the input stream, as appropriate to the truth of the test and the % variant of the function chosen. The logical truth of the test is % left in the input stream by the predicate version. % \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} % \begin{syntax} % \cs{quark_if_recursion_tail_stop:N} \Arg{token} % \end{syntax} % Tests if \meta{token} contains only the marker % \cs{q_recursion_tail}, and if so terminates the recursion this is % part of using \cs{use_none_delimit_by_q_recursion_stop:w}. 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:n, \quark_if_recursion_tail_stop:o} % \begin{syntax} % \cs{quark_if_recursion_tail_stop:n} \Arg{tokens} % \end{syntax} % Tests if \meta{tokens} consists of the single token % \cs{q_recursion_tail}, and if so terminates the recursion this is % part of using \cs{use_none_delimit_by_q_recursion_stop:w}. 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} \Arg{token} \Arg{insertion} % \end{syntax} % Tests if \meta{token} contains only the marker % \cs{q_recursion_tail}, and if so terminates the recursion this is % part of using \cs{use_none_delimit_by_q_recursion_stop:w}. 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} % {\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{tokens} \Arg{insertion} % \end{syntax} % Tests if \meta{tokens} consists of the single token % \cs{q_recursion_tail}, and if so terminates the recursion this is % part of using \cs{use_none_delimit_by_q_recursion_stop:w}. 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} % % \section{Internal quark functions} % % \begin{function}{\use_none_delimit_by_q_recursion_stop:w} % \begin{syntax} % \cs{use_none_delimit_by_q_recursion_stop:w} % ~~\meta{tokens} \cs{q_recursion_stop} % \end{syntax} % Used to prematurely terminate a recursion using \cs{q_recursion_stop} % as the end marker, removing any remaining \meta{tokens} from the % input stream. % \end{function} % % \begin{function}{\use_i_delimit_by_q_recursion_stop:nw} % \begin{syntax} % \cs{use_i_delimit_by_q_recursion_stop:nw} \Arg{insertion} % ~~\meta{tokens} \cs{q_recursion_stop} % \end{syntax} % Used to prematurely terminate a recursion using \cs{q_recursion_stop} % as the end marker, removing any remaining \meta{tokens} from the % input stream. The \meta{insertion} is then made into the input % stream after the end of the recursion. % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3quark} implementation} % % \TestFiles{m3quark001.lvt} % % \begin{macrocode} %<*initex|package> % \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \package_check_loaded_expl: % % \end{macrocode} % % \begin{macro}{\quark_new:N} % \UnitTested % Allocate a new quark. % \begin{macrocode} \cs_new_protected_nopar:Npn \quark_new:N #1 { \tl_const:Nn #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 #1 \q_recursion_tail \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: } \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} } % \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}[aux]{\quark_if_recursion_tail_aux:w} % The same idea applies when testing multiple tokens, but here a little more % care is needed. It is possible that |#1| might be something like % |{{{a}}}| or |{ab\iffalse}\fi|, which will therefore need to be tested % in a detokenized manner. The way that this is done is using % \cs{if_catcode:w}, with the idea being that this test will be \texttt{true} % provided the auxiliary function returns nothing at all. If the auxiliary % returns anything, it will be detokenized and so the test will be both % \texttt{false} and safe. % \begin{macrocode} \cs_new:Npn \quark_if_recursion_tail_stop:n #1 { \if_catcode:w A \etex_detokenize:D \exp_after:wN { \quark_if_recursion_tail_aux:w #1 \q_recursion_stop \q_recursion_tail \q_recursion_stop \q_stop } A \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: } \cs_new:Npn \quark_if_recursion_tail_stop_do:nn #1#2 { \if_catcode:w A \etex_detokenize:D \exp_after:wN { \quark_if_recursion_tail_aux:w #1 \q_recursion_stop \q_recursion_tail \q_recursion_stop \q_stop } A \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_aux:w #1 \q_recursion_tail #2 \q_recursion_stop #3 \q_stop { #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}[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:Nnn \quark_if_nil:N { p, T , F , TF } { \if_meaning:w \q_nil #1 \prg_return_true: \else: \prg_return_false: \fi: } \prg_new_conditional:Nnn \quark_if_no_value:N { p, T , F , TF } { \if_meaning:w \q_no_value #1 \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \quark_if_no_value_p:N { c } \cs_generate_variant:Nn \quark_if_no_value:NT { c } \cs_generate_variant:Nn \quark_if_no_value:NF { c } \cs_generate_variant:Nn \quark_if_no_value:NTF { c } % \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 % These are essentially \cs{str_if_eq:nn} tests but done directly. % \begin{macrocode} \prg_new_conditional:Nnn \quark_if_nil:n { p, T , F , TF } { \if_int_compare:w \pdftex_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_no_value:n { p, T , F , TF } { \if_int_compare:w \pdftex_strcmp:D { \exp_not:N \q_no_value } { \exp_not:n {#1} } = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \quark_if_nil_p:n { V , o } \cs_generate_variant:Nn \quark_if_nil:nTF { V , o } \cs_generate_variant:Nn \quark_if_nil:nT { V , o } \cs_generate_variant:Nn \quark_if_nil:nF { V , o } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{variable}{\q_tl_act_mark,\q_tl_act_stop} % These private quarks are needed by \pkg{l3tl}, but that is loaded % before the quark module, hence their definition is deferred. % \begin{macrocode} \quark_new:N \q_tl_act_mark \quark_new:N \q_tl_act_stop % \end{macrocode} % \end{variable} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex % % \endinput