diff options
author | Karl Berry <karl@freefriends.org> | 2011-07-31 18:27:06 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2011-07-31 18:27:06 +0000 |
commit | dac945b204407dae96f70ec228206516093156d7 (patch) | |
tree | 02ca182689947e45dec95e17ba08b503c959bd17 /Master/texmf-dist/source/latex/l3kernel/l3quark.dtx | |
parent | c1840548792cfbc7c9f746da1d53d89b94406e72 (diff) |
l3kernel (5jun11)
git-svn-id: svn://tug.org/texlive/trunk@23282 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3quark.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3quark.dtx | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx new file mode 100644 index 00000000000..2326fd4519d --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx @@ -0,0 +1,486 @@ +% \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 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental quarks} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \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: +%</package> +% \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{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex +% +% \endinput |