diff options
Diffstat (limited to 'Master/texmf-dist/source/latex3/xparse/xparse.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex3/xparse/xparse.dtx | 1339 |
1 files changed, 1339 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex3/xparse/xparse.dtx b/Master/texmf-dist/source/latex3/xparse/xparse.dtx new file mode 100644 index 00000000000..1bee47bb059 --- /dev/null +++ b/Master/texmf-dist/source/latex3/xparse/xparse.dtx @@ -0,0 +1,1339 @@ +% \iffalse +%% +%% (C) Copyright 1999 Frank Mittelbach, Chris Rowley, David Carlisle +%% All rights reserved. +%% +%% Not for general distribution. In its present form it is not allowed +%% to put this package onto CD or an archive without consulting the +%% the authors. +%% +%<*dtx> + \ProvidesFile{xparse.dtx} +%</dtx> +%<package>\NeedsTeXFormat{LaTeX2e} +%<package>\ProvidesPackage{xparse} +%<driver>\ProvidesFile{xparse.drv} +% \fi +% \ProvidesFile{xparse.dtx} + [1999/09/10 v0.17 generic document command parser] +% +% \iffalse +%<*driver> + \documentclass{ltxdoc} + \usepackage{textcomp} +% \usepackage{ldcdoc} + \begin{document} + \DocInput{xparse.dtx} + \end{document} +%</driver> +% \fi +% +% \CheckSum{667} +% +% \GetFileInfo{xparse.dtx} +% +% \title{The \textsf{xparse} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}} +% \author{FMi, CAR, DPC} +% \date{\copyright~\filedate} +% \maketitle +% +% \begin{abstract} +% The interfaces described in this document are not meant to be final +% but only as a basis for discussion. Building productive applications +% using the current code is discouraged. +% \end{abstract} +% +% \section{Interface} +% +% This package implements high-level interface commands for class file +% writers which allows the separation of formatting commands +% (typically instances of so-called `templates') and their arguments +% from the signature of document-level commands. +% +% This works by declaration commands that provide a general +% specification method for the typical \LaTeX{} syntax, e.g., +% star-form, optional arguments, and mandatory arguments. A command +% (or environment) declared in this way parses the input according to +% its spec and presents its findings in a normalized way for further +% processing. +% +% \subsection{Argument spec} +% +% An argument specification is a list of letters each representing a +% type of argument, i.e., |m| is a mandatory argument (surrounded by +% braces), |o| an optional argument (surrounded by brackets if +% present), and |s| represents a star (which might be present or +% not).\footnote{Other argument types such as \texttt{c} for picture +% coordinates could be integrated in principle --- the last prototype +% now contains support for\texttt{c}.} Thus the argument +% spec for headings as implemented by |\@startsection| in standard +% \LaTeX{} would be represented by the three letters |som|. +% +% With the new proof of concept implementation there is also +% |O{default}| which acts like |o| which also scans for an optional +% argument but allows to specify a default value if the optional +% argument is not present. I.e., it can be used to turn mandatory +% arguments of a template (that is those that do not check for +% |\NoValue|) into optional ones by supplying a default on the +% document command level. +% +% We also have |C{{x-default}{y-default}}| to allow for optional +% coordinate pairs which is, for example, needed to provide something +% like the picture environment in current \LaTeX. +% +% \subsection{Parsing results} +% +% To normalise the result of parsing the input according to an +% argument specification it is important to uniquely identify all +% arguments found. For this reason each parsing operation initiated by +% one of the argument spec letters will result in an identifiable +% output as follows: +% \begin{description} +% \item[m] will return the parsed argument surrounded by a brace pair, +% i.e., will normally be the identity; +% \item[o] will return the parsed argument surrounded by a brace pair +% if present. Otherwise it will return the token |\NoValue|; +% \item[O\textbraceleft default\textbraceright] will return the parsed +% argument surrounded by a brace pair +% if present. Otherwise it will return the |{default}| as specified above. +% \item[s] will return either the token |\BooleanTrue| or +% |\BooleanFalse| depending on whether or not a star was parsed. +% \item[c] will parse the syntax |(|\meta{x}|,|\meta{y}|)|, i.e., a +% coordinate pair and will return |{{|\meta{x}|}{|\meta{y}|}}| as +% the result. If no open parentheses is scanned an error is signalled. +% \item[C\textbraceleft\textbraceleft x-default\textbraceright\textbraceleft +% y-default\textbraceright\textbraceright] behaves like |c|, i.e., parses a +% coordinate pair if present. If the coordinate pair is missing it +% returns the default values instead. +% \end{description} +% For example, given the spec |soomO{default}| the input |*[Foo]{Bar}| would be +% parsed as |\BooleanTrue{Foo}\NoValue{Bar}{default}|. In other words +% there will be always exactly the same number of brace groups or +% tokens as the number of letters in the argument spec. +% +% \subsection{Applying the parsing results} +% +% Since the result of the parsing is a well defined number of tokens or +% brace groups it is easy to pass them on in any order to any +% processing function. To this end the tokens or brace groups are +% associated with the standard argument specifiers in \TeX{} macros, +% i.e., |#1|, |#2|, and so forth. This limits the argument +% specification to a maximum number of 9 letters, but for practical +% applications this should be sufficient. +% +% \subsection{The class designer interface} +% +% This package provides two commands for declaring commands +% and environments to be used within the document body. +% +% \DescribeMacro\DeclareDocumentCommand +% The |\DeclareDocumentCommand| declaration takes three arguments. The +% first argument is the name of the command to be declared, the second +% is the argument specification in the syntax described above, and the +% third is the action to be carried out once the arguments are +% parsed. Within the third argument |#1|, |#2|, etc.\ denote the +% result of the parsing, e.g., +%\begin{verbatim} +% \DeclareDocumentCommand{\chapter}{som} +% { \IfBooleanTF {#1} +% { \typesetnormalchapter {#2}{#3} } +% { \typesetstarchapter {#3} } +% } +%\end{verbatim} +% would be a way to define a |\chapter| command which would +% essentially behave like the current \LaTeX{} command (except that it +% would accept an optional argument even when a |*| was parsed). The +% |\typesetnormalchapter| could test its first argument for being +% |\NoValue| to see if an optional argument was present. +% +% Of course something like the |\IfNoValueTF| test could also be +% placed inside a function that would process all three arguments, thus +% using the templates and their instances as provided by the +% \texttt{template} package such a declaration would probably look +% more like the following example: +%\begin{verbatim} +% \DeclareDocumentCommand{\chapter}{som} +% { \UseInstance {head} {A-head-main} {#1} {#2} {#3} } +%\end{verbatim} +% +% Using the |\DeclareDocumentCommand| interface it is easy to modify +% the document-level syntax while still applying the same +% layout-generating functions, e.g., a class that would not support +% optional arguments or star forms for the heading commands could +% define |\chapter| like this: +%\begin{verbatim} +% \DeclareDocumentCommand{\chapter}{m} +% { \UseInstance {head} {A-head-main} \BooleanFalse \NoValue {#1} } +%\end{verbatim} +% while a class that would allow for an additional optional argument +% (for whatever reason) could define it like that: +%\begin{verbatim} +% \DeclareDocumentCommand{\chapter}{somo} +% { \doSomethingWithTheExtraOptionalArg {#4} +% \UseInstance {head} {A-head-main} {#1} {#2} {#3} } +%\end{verbatim} +% +% Commands declared in this way are automatically robust (in David's +% implementation). +% +% \DescribeMacro\DeclareDocumentEnvironment +% The |\DeclareDocumentEnvironment| declaration is similar to +% |\DeclareDocumentCommand| except that it takes four arguments: the +% first being the environment name (without a backslash), the second +% again the argument-spec, and the third and forth are the actions +% taken at start end end of the environment. The parsed arguments are +% available to both the start and the finish as |#1|, |#2|, +% etc.\footnote{It is wishful thinking that the args can be made available +% to the end of the environment. In the current implementation this +% was buggy and has been taken out again below.} +% +% +% \subsubsection{Comparing tokens in a quarky way} +% +% Something like |\NoValue| would perhaps be best implemented as a +% ltx3 quark, i.e. a token which expands to itself as this is +% can be easily tested even if hidden inside a macro. The unfortunate +% side effect however is that it will result in a tight loop if it ever +% gets executed by mistake. +% +% \DescribeMacro\NoValue +% For this reason |\NoValue| is defined to expand to the string +% |-NoValue-| which would get typeset if ever executed thus clearly +% indicating the type of error the writer made. +% +% However this makes testing for this token slightly complicated as in +% that case the test +%\begin{verbatim} +% \def\seen{#1} +% \def\containsNoValue{\NoValue} +% \ifx\seen\containsNoValue +%\end{verbatim} +% will be true if |#1| was |\NoValue| but false if if |#1| itself +% contains a macro which contains |\NoValue|; a case that happens +% unfortunately very often in practice. Using unguarded |\edef| to +% define |\seen| is out of question as |#1| typically is either +% |\NoValue| or arbitrary user input (which is likely to die horribly +% even in a |\protected@edef|. +% +% \DescribeMacro\IfSomethingTF +% \DescribeMacro\IfSomethingT +% \DescribeMacro\IfSomethingF +% Therefore the |\IfSomethingTF| test uses a slower recursive +% procedure: it tests if |#1| and |#2| are equal. If they are testing +% stops and the true-case (argument |#3|) will be executed. If not, it +% expands the first token of |#2| and checks if the resulting +% token-list is identical to |#2| (this would happen if this first +% token is unexpandable or |#2| is empty). In the latter case testing +% terminates and the false-case (argument |#4|) will be +% executed. However if the token-list created this way differs from +% |#2| the macro recurses using this token-list in place of |#2|. +% +% \DescribeMacro\IfNoValueTF +% \DescribeMacro\IfNoValueT +% \DescribeMacro\IfNoValueF +% \DescribeMacro\IfValueTF +% \DescribeMacro\IfValueT +% \DescribeMacro\IfValueF +% The test |\IfNoValueTF| is implemented as an application of +% |\IfSomethingTF|, i.e., +%\begin{verbatim} +% \def\IfNoValueTF{\IfSomethingTF\NoValue} +%\end{verbatim} +% where the three arguments (test token, true and false case) are +% picked up by |\IfSomethingTF|. Similar tests for other quark-like +% tokens could be defined similarly. |\IfValueTF| is the same test +% with the true/false case exchanged. +% +% +% \subsection{Some comments on the need for the \texttt{O} specifier} +% +% With |\newcommand| there is the possibility of specifying a default +% for an optional argument which is stored away in a more or less +% efficient manner. For example below is the old definition of +% |\linebreak| as can be found in the \LaTeX2e kernel: +%\begin{verbatim} +%\def\linebreak{\@testopt{\@no@lnbk-}4} +%\def\@no@lnbk #1[#2]{% +% \ifvmode +% \@nolnerr +% \else +% \@tempskipa\lastskip +% \unskip +% \penalty #1\@getpen{#2}% +% \ifdim\@tempskipa>\z@ +% \hskip\@tempskipa +% \ignorespaces +% \fi +% \fi} +%\end{verbatim} +% Ignoring for the moment that the above is slightly optimised an +% expansion of this code under |\tracingall| will result in about 90 +% lines of tracing output. +% If we reimplement this using |\DeclarDocumentCommand\linebreak{o}| +% we have to use |\IfNoValueTF| to find out if an argument was present +% which (because of the somewhat slow expansion of |\IfSomethingTF|) +% results in about twice as much of tracing lines. In contrast using +% |O{4}| as below we end up with 110 lines, which seems roughly the +% price we have to pay for the extra generality available (though this +% could perhaps even be reduced by a better implementation of the +% parsing machine as originally done by David, before i talked him +% into adding support for arguments in the end code of an environment). +% +%\begin{verbatim} +%\DeclareDocumentCommand\linebreak { O{4} } +% { +% \ifvmode +% \@nolnerr +% \else +% \@tempskipa\lastskip +% \unskip +% % \IfNoValueTF{#1} +% % {\break} +% % {\penalty -\@getpen{#1}} +% \penalty -\@getpen{#1} +% \ifdim\@tempskipa>\z@ +% \hskip\@tempskipa +% \ignorespaces +% \fi +% \fi +% } +%\end{verbatim} +% +% \subsubsection{A boolean data type} +% +% \DescribeMacro\BooleanTrue +% \DescribeMacro\BooleanFalse +% The parsing result for a star etc is presented as the token +% |\BooleanTrue| or |\BooleanFalse| respectively! +% +% \DescribeMacro\IfBooleanTF +% \DescribeMacro\IfBooleanT +% \DescribeMacro\IfBooleanF +% To test for these values the macro |\IfBooleanTF| can be used. It +% expects as its first argument either |\BooleanTrue| or +% |\BooleanFalse| and executes its second or third argument depending +% on this value. |\IfBooleanT| and |\IfBooleanF| are obvious +% shortcuts. +% +% At one point in time i thought that one can represent everything +% using |\NoValue|, e.g., for the star case either return |*| or +% |\NoValue|. However, this slows down processing of commands like +% |\\*| considerably since they would then have to use the slow +% |\IfSomethingTF| internally instead of a fast two-way switch. So now +% this data type is back in. +% +% \subsection{A somewhat complicated example} +% +% This example reimplements the |\makebox| and |\framebox| interface +% of \LaTeX{} both of which are unfortunately quite overloaded +% syntactically. For this reason the example isn't meant to show good +% coding practice but to show the power of the interface even though +% applied in a somewhat bad way. +% +% |\makebox| and |\framebox| support the following different document +% syntax forms: +% \begin{itemize} +% \item +% |\makebox{A}|: only a single mandatory argument. +% +% \item +% |\makebox[20pt]{B}|: one optional argument specify the box width. +% +% +% \item +% |\makebox[30pt][r]{C}|: two optional arguments the second specifying +% the text position within the box being made (l,c,r being allowed +% with c being the default). +% +% \item +% |\makebox(20,30){D}|: within picture mode the width is specified not +% as an optional argument in brackets but as a coordinate pair. +% +% \item +% |\makebox(0,0)[lt]{E}|: in that case an optional argument following +% coordinate pair denotes the placement within the box which can have +% different values compared to case C above. +% \end{itemize} +% +% To cater for this overloaded structure we can define |\makebox| to +% be something like the following: +%\begin{verbatim} +%\DeclareDocumentCommand \makebox { C{\NoValue} o O{c} m} +% { \IfNoValueTF{#1} +% { \ltx@maketextbox{#2}{#3}{#4} } +% { \ltx@makepicbox #1 {#2}{#4} } } +%\end{verbatim} +% In other words: if we do not see a coordinate pair first (i.e., +% first argument is |\NoValue| then we expect up to two optional +% arguments (the width of the box or |\NoValue| if not given and the +% placement specifier with a default of |c| if not given) and one +% mandatory one which is the text. In that case we pass argument 2 to +% 4 to an internal function |\ltx@maketextbox| which builds the text +% box. +% +% Otherwise, if the first argument is a coordinate pair we parse an +% optional argument denoting the placement specifier. Since +% \texttt{xparse} doesn't support variant syntax we actually parse for +% another optional argument (which has no meaning in that case and is +% in fact ignored if present) followed by a mandatory one containing +% the box text. In that case we pass the coordinate pair (|#1|), the +% specifier (|#2|), and the text (|#4|) to the function +% |\ltx@makepicbox| which builds the picture box. Note the special +% handling of the coordinatesD: which are passed without surrounding +% braces to |\ltx@makepicbox|: since the coordinate argument looks +% like |{x-val}{y-val}| the receiving function |\ltx@makepicbox| gets +% the |x-val| as argument one and the |y-val| as argument two. +% +% A definition for |\framebox| would look more or less identical +% except that we would need to pass the arguments to slightly +% different internal functions. The alternative is to give the +% internal functions an extra argument that controls whether or not a +% frame is bying built. +% +% \begin{macro}{\ltx@makepicbox} +% So here is a possible implementation of |\ltx@makepicbox| that +% builds a picture box with or without frame. It takes the following +% mandatory arguments: +% \begin{enumerate} +% \item x-part of coordinate +% \item y-part of coordinate +% \item placement specifier, e.g., |lt| or |\NoValue| +% \item text of box +% \item the token |\frame| (if a frame should surround the box) or the +% token |\@firstofone| --- not pretty i agree +% \end{enumerate} +%\begin{verbatim} +%\def\ltx@makepicbox#1#2#3#4#5 +% { +% #5{ +% \vbox to#2\unitlength +% {\let\mb@b\vss \let\mb@l\hss\let\mb@r\hss +% \let\mb@t\vss +% \IfNoValueF{#3} +% { +% \@tfor\reserved@a :=#3\do{ +% \if s\reserved@a +% \let\mb@l\relax\let\mb@r\relax +% \else +% \expandafter\let\csname mb@\reserved@a\endcsname\relax +% \fi}% +% } +% \mb@t +% \hb@xt@ #1\unitlength{\mb@l #4\mb@r} +% \mb@b +% \kern\z@} +% } +% } +%\end{verbatim} +% \end{macro} +% +% +% +% \begin{macro}{\ltx@maketextbox} +% For the text case the internal function could take the following +% mandatory arguments: +% \begin{enumerate} +% \item width of the box or |\NoValue| (denoting to build the box at +% natural width) +% \item placement specifier, e.g., |l|. (No test for |\NoValue| being undertaken) +% \item text of box +% \item the token |\fbox| (if a frame should surround the box) or the +% token |\mbox| +% \end{enumerate} +% The actual code is taken straight from the current \LaTeX{} kernel +% and looks kind of scary. +%\begin{verbatim} +%\def\ltx@maketextbox#1#2#3#4 +% { +% \IfNoValueTF{#1} +% {#4{#3}} +% { +% \leavevmode +% \@begin@tempboxa\hbox{#3} +% \setlength\@tempdima{#1} +% \ifx#4\fbox +% \setbox\@tempboxa\hb@xt@\@tempdima +% {\kern\fboxsep\csname bm@#2\endcsname\kern\fboxsep} +% \@frameb@x{\kern-\fboxrule} +% \else +% \hb@xt@\@tempdima{\csname bm@#2\endcsname} +% \fi +% \@end@tempboxa +% } +% } +%\end{verbatim} +% \end{macro} +% +% \begin{macro}{\makebox} +% \begin{macro}{\framebox} +% Given the above internal functions the declarations of |\makebox| +% and |\framebox| would then look like this: +%\begin{verbatim} +%\DeclareDocumentCommand \makebox { C{\NoValue} o O{c} m} +% { \IfNoValueTF{#1} +% { \ltx@maketextbox{#2}{#3}{#4}\mbox } +% { \ltx@makepicbox #1 {#2}{#4}\@firstofone } } +% +%\DeclareDocumentCommand \framebox { C{\NoValue} o O{c} m} +% { \IfNoValueTF{#1} +% { \ltx@maketextbox{#2}{#3}{#4}\fbox } +% { \ltx@makepicbox #1 {#2}{#4}\frame } } +%\end{verbatim} +% \end{macro} +% \end{macro} +% +% +% \StopEventually{} +% +% \section{Implementation} +% +% The implementation section currently contains several trial +% implementations and updates. This final version will probably look +% quite differently again. +% +% Set up certain defaults including to ignore white space +% within the body of this package. +% \begin{macrocode} +%<*package> +\RequirePackage{ldcsetup} +\IgnoreWhiteSpace +% \end{macrocode} +% +% + +% \subsection{The Mittelbach/Rowley prove-of-concept +% implementation for the parsing} +% +% \begin{macro}{\DeclareDocumentCommand} +% \begin{macrocode} +%<*obsolete> +\def\DeclareDocumentCommand #1 #2 { +% \parse@countargs {#2} % sets \@tempc % Not implemented yet + \def\parse@csname{#1} + \def\parse@spec{#2} + \afterassignment \declare@dt@ + \toks@ +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\declare@dt@} +% \begin{macrocode} +\def \declare@dt@ { + \expandafter \edef \parse@csname + { \noexpand \parse@something + { \parse@spec } + { \the\toks@ } + % { \@tempc } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DeclareDocumentEnvironment} +% \begin{macrocode} +\long\def\DeclareDocumentEnvironment #1 #2 { +% \parse@countargs {#2} % sets \@tempc % Not implemented yet + \def\parse@csname{#1} + \def\parse@spec{#2} + \afterassignment \declare@de@ + \toks@ +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\declare@de@} +% \begin{macrocode} +\def \declare@de@ { + \expandafter \edef \csname \parse@csname \endcsname + { \begingroup + \noexpand \parse@something + { \parse@spec } + { \the\toks@ } + % { \@tempc } + } + \afterassignment \declare@dee@ + \toks@ +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\declare@dee@} +% \begin{macrocode} +\def \declare@dee@ { + \expandafter \edef \csname end\parse@csname \endcsname + { \noexpand \parse@apply + { \the\toks@ } + \noexpand \parse@results + \endgroup + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\parse@apply} +% \begin{macrocode} +\def\parse@apply #1 { + \renewcommand \parse@tempa [\the\parse@cnt] {#1} + \expandafter \parse@tempa % #2 implicit +} +\let\parse@tempa\@empty % or \renew... might bulk the first time +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\parse@something} +% \begin{macrocode} +%% CCC here and elsewhere there are some suggestions for +% not counting args at run-time +\def \parse@something #1 #2 { % #3 + \parse@body {#2} + % \parse@cnt #3 + \parse@cnt \m@ne % REMOVE + \parse@args #1x \parse@args {} +} +% \end{macrocode} +% +% \begin{macrocode} +\newcount\parse@cnt +\newtoks\parse@body +% \end{macrocode} +% +% \begin{macrocode} +\def\parse@args #1 #2\parse@args #3 { + \advance \parse@cnt \@ne % REMOVE + \csname parse@#1 \endcsname {#2}{#3} +} +% \end{macrocode} +% +% \begin{macrocode} +\def \parse@s #1 #2 { + \@ifstar + { \parse@args #1 \parse@args { #2 \BooleanTrue } } + { \parse@args #1 \parse@args { #2 \BooleanFalse } } +} +% \end{macrocode} +% +% \begin{macrocode} +\def \parse@m #1 #2 #3 { + \parse@args #1 \parse@args { #2 {#3} } +} +% \end{macrocode} +% +% \begin{macrocode} +\def \parse@x #1 #2 { + \def \parse@results {#2} % for environment +% \def \parse@tempa { +% \renewcommand \parse@tempb [\the\parse@cnt] +% } +% \expandafter \parse@tempa \expandafter { \the \parse@body } +% \parse@tempb #2 + \expandafter \parse@apply \expandafter { \the \parse@body } + \parse@results % \parse@apply expands this! +} +% \end{macrocode} +% +% \begin{macrocode} +\def \parse@o #1 #2 { + \@ifnextchar [ + { \parse@o@ {#1}{#2} } + { \parse@args #1 \parse@args { #2 \NoValue } } +} +% \end{macrocode} +% +% \begin{macrocode} +\def \parse@o@ #1 #2 [#3] { + \parse@args #1 \parse@args { #2 {#3} } +} +%</obsolete> +% \end{macrocode} +% \end{macro} +% +% +% \subsection{The Carlisle implementation for the parsing} +% +% Not implemented in this version is |\DeclareDocumentEnvironment| +% (exercise for the reader).\footnote{Exercise now completed by DPC :-) +% (required re-implementing argument grabbers to grab to a toks +% register rather that into a brace group in the input stream.) } +% +% Seemed to need two toks registers. +% \begin{macrocode} +\newtoks\@temptokenb +% \end{macrocode} +% +% \begin{macrocode} +\newtoks\xparsed@args +% \end{macrocode} +% +% +% \begin{macro}{\DeclareDocumentCommand} +% Args: |#1| csname, +% |#2| soom argument spec, +% |#3| code +% +% In |#2| currently supported types are: +% s star, +% o \oarg{optional}, +% m \marg{mandatory}.\footnote{More added in reimplementation below.} +% +% |#3| is just grabbed so as to not get a space in the argument spec +% for definition. +% +% \begin{macrocode} +\long\def\DeclareDocumentCommand #1 #2 #3{ +% \end{macrocode} +% +% Needed to count no of arguments +% \begin{macrocode} + \@tempcnta\z@ +% \end{macrocode} +% +% Builds up list of argument parsers |\@ddc@s\@ddc@m| etc +% \begin{macrocode} + \toks@{} +% \end{macrocode} +% +% Builds up |#1#2#3#4| argument spec +% \begin{macrocode} + \@temptokena\toks@ +% \end{macrocode} +% +% Builds up list of m-argument parsers |\@ddc@m\@ddc@m| +% occurred since start or since argument of another type. +% \begin{macrocode} + \@temptokenb\toks@ +% \end{macrocode} +% +% Start parsing argument spec +% \begin{macrocode} + \@ddc#2X +% \end{macrocode} +% +% Define top level command, this just has the wrapper command +% |\@ddc@| then the argument grabbers from |\toks@| then the original +% command name (in case we need to |\protect|) then the internal +% command with the code. +% The |\long| below could be |\relax| if wanted to have a star-non-long +% form of this, cf |\newcommand*|. The argument preamble for +% |\def| comes from |\@temptokena|. +% \begin{macrocode} + \edef#1{ + \noexpand\@ddc@ + {\the\toks@} + \expandafter\noexpand\csname\string#1\endcsname + \noexpand#1 + } + \long\expandafter\def\csname\string#1\expandafter\endcsname + \the\@temptokena{#3}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DeclareDocumentEnvironment} +% The implementation here could save a csname or two per environment +% if |\begin| and especially |\end| were modified but that not done here +% so each end code responsible for getting its own arguments. +% +% Arguments: |#1| env name, +% |#2| soom spec, +% |#3| begin code, +% |#4| end code. +% +% \begin{macrocode} +\long\def\DeclareDocumentEnvironment#1#2#3#4{ + \expandafter\DeclareDocumentCommand\csname #1\endcsname{#2}{ + \xparsed@args\toks@ + #3} + \expandafter\let\csname end #1\endcsname\@parsed@endenv + \long\expandafter\def\csname end \string\\#1\expandafter\endcsname + \the\@temptokena {#4}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@parsed@endenv} +% All end codes are let to this. (Could be merged into |\end|.) +% \begin{macrocode} +\def\@parsed@endenv{ + \expandafter\@parsed@endenv@\the\xparsed@args} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@parsed@endenv@} +% Helper that just replaces the internal name of the begin code +% with that of the end code. +% \begin{macrocode} +\def\@parsed@endenv@#1{ + \csname end\string#1\endcsname} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@ddc@} +% +% Arguments: |#1| set of argument grabbers, +% |#2| internal command, +% |#3| top level command for |\protect|ing. +% +% \begin{macrocode} +\def\@ddc@#1#2#3{ + \ifx\protect\@typeset@protect + \expandafter\@firstofone + \else + \protect#3\expandafter\@gobble + \fi +% \end{macrocode} +% +% The command+arguments so far are kept in a token register until +% the last moment for ease of processing. So need to initialise +% that and use it at the end. +% \begin{macrocode} + {\toks@{#2} #1\the\toks@}} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@ddc} +% Argument: |#1| one of s o m (or X denoting end of parsing). +% \begin{macrocode} +\def\@ddc#1{ + \ifx #1X +% \end{macrocode} +% fini +% \begin{macrocode} + \else + \ifx #1m +% \end{macrocode} +% If doing an m, just stick another |\@ddc@m| in a temporary list. +% \begin{macrocode} +% \@temptokenb\expandafter{% +% \the\@temptokenb +% \@ddc@m} + \addto@hook\@temptokenb m + \else +% \end{macrocode} +% +% Otherwise for o and s +% in |\toks@| first add any `m' argument parsers saved up +% then add |\@ddc@o| or |\@ddc@s|. +% \begin{macrocode} + \toks@\expandafter{% + \the\expandafter\toks@ + \csname @ddc@\the\@temptokenb\expandafter\endcsname + \csname @ddc@#1\endcsname} +% \end{macrocode} +% +% Clear list of m's: +% \begin{macrocode} + \@temptokenb{} + \fi +% \end{macrocode} +% +% Add one to argument count. +% \begin{macrocode} + \advance\@tempcnta\@ne +% \end{macrocode} +% +% Internally all arguments are non delimited args, so add +% |#|\meta{n} to the list in |\@temptokena| +% \begin{macrocode} + \@temptokena\expandafter{ + \the\expandafter\@temptokena\expandafter##\the\@tempcnta} +% \end{macrocode} +% +% Loop: +% \begin{macrocode} + \expandafter + \@ddc +% \end{macrocode} +% +% \begin{macrocode} + \fi} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@ddc@s} +% Argument: |#1| any remaining argument grabbers (+ |\the|) +% \begin{macrocode} +\long\def\@ddc@s#1\toks@{ +% \end{macrocode} +% +% put back the rest of the argument grabbers, but add new +% (boolean) argument to list of arguments inside the register. +% \begin{macrocode} + \@ifstar + {\addto@hook\toks@\BooleanTrue #1\toks@} + {\addto@hook\toks@\BooleanFalse #1\toks@}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@ddc@m} +% Arguments: |#1| any remaining argument grabbers (+ |\the|), +% |#2| argument to be grabbed. +% \begin{macrocode} +\long\def\@ddc@m#1\toks@#2{ +% \end{macrocode} +% put back the rest of the argument grabbers, but copy +% argument to list of arguments inside the toks register. +% Any `m' at the end will be discarded and the internal +% command will pick up its own arguments. +% \begin{macrocode} + \addto@hook\toks@{{#2}} #1\toks@} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@ddc@o} +% Argument: |#1| any remaining argument grabbers (+ |\the|). +% \begin{macrocode} +\long\def\@ddc@o#1\toks@{ +% \end{macrocode} +% +% Put back the rest of the argument grabbers, but copy +% argument (now with |{}| or |\NoValue| to list of arguments +% inside toks register. +% \begin{macrocode} + \@ifnextchar[ + {\@ddc@o@{#1}} + {\addto@hook\toks@\NoValue #1\toks@}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@ddc@o@} +% Helper to remove []. +% \begin{macrocode} +\long\def\@ddc@o@#1[#2]{ + \addto@hook\toks@{{#2}} #1\toks@} +% \end{macrocode} +% \end{macro} +% +% +% +% \subsection{A Mittelbach update to the Carlisle implementation +% supporting O with default for optional arg and c for coordinates +% --- prove of concept only} +% +% Only changed and new commands are listed. +% +% +% \begin{macro}{\@ddc} +% The big switch that builds up the parser for the document command. +% +% The complexity of the |\@ddc| rewrite suggests that there might +% be better ways to do it, but for a proto-type solution this is +% fine enough. +% +% \begin{macrocode} +\def\@ddc#1{ + \ifx #1X +% \end{macrocode} +% Normally we do nothing at this point and don't pick up the +% trailing mandatory args into |\toks@| but if we want to reuse the +% argument list in an end environment we have to so |\perhaps@grab@ms| +% is normally |\relax| but might be |\grab@ms| instead. +% \begin{macrocode} + \perhaps@grab@ms + \else + \ifx #1m +% \end{macrocode} +% Just record how many m's seen so far +% \begin{macrocode} + \addto@hook\@temptokenb m + \else +% \end{macrocode} +% If anything other than an m is scanned we add to |\toks@| and +% argument grabber that gets all m's in one go rather than argument +% grabbers that pick up each m at a time. Right now this +% unnecessarily adds |\@ddc@x| if no m's have been +% seen.\footnote{fix, see also below} +% \begin{macrocode} + \toks@\expandafter{% + \the\expandafter\toks@ + \csname @ddc@x\the\@temptokenb\expandafter\endcsname + \csname @ddc@#1\endcsname} + \@temptokenb{} +% \end{macrocode} +% In case of |O| and |C| we have to grab the default next. +% \begin{macrocode} + \ifx #1O + \let\next@ddc\grab@default + \else + \ifx #1C + \let\next@ddc\grab@default + \fi + \fi + \fi + \advance\@tempcnta\@ne + \@temptokena\expandafter{ + \the\expandafter\@temptokena\expandafter##\the\@tempcnta} + \expandafter + \next@ddc + \fi +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\next@ddc} +% By default the loop in the |\@ddc| code above calls itself +% recursively until the whole spec is processed. +% \begin{macrocode} +\let\next@ddc\@ddc +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grab@default} +% However if we've seen an |O| we need to grab the default value first. +% \begin{macrocode} +\def\grab@default #1{ + \toks@\expandafter{% + \the\toks@ + {#1}} + \let\next@ddc\@ddc + \@ddc +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@ddc@O} +% This command expects the default value (to use if no |[| is +% parsed) after it. +% \begin{macrocode} +\long\def\@ddc@O#1#2\toks@{ + \@ifnextchar[ + {\@ddc@o@{#2}} + {\addto@hook\toks@{{#1}} #2\toks@}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@ddc@} +% We look for the `(' and signal an error +% if not found. By using |\@ifnextchar| this also takes care of any +% space tokens in front ot the the parentheses. +% \begin{macrocode} +\long\def\@ddc@c#1\toks@{ + \@ifnextchar ( + {\@ddc@c@ #1} + {\PackageError{xparse}{Missing~ coordinate~ argument} + {A~ value~ of~ (0,0)~ is~ assumed} + \addto@hook\toks@{{00}} #1\toks@} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@ddc@c@} +% Helper for |\@ddc@c| and |\@ddc@C| below to parse a |(x,y)| if we +% know it is there. +% \begin{macrocode} +\long\def\@ddc@c@#1(#2,#3){ + \addto@hook\toks@{{{#2}{#3}}} #1\toks@} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@ddc@C} +% This way we can also directly implement the optional argument case in +% a natural way. +% \begin{macrocode} +\long\def\@ddc@C#1#2\toks@{ + \@ifnextchar ( + {\@ddc@c@ #2} + {\addto@hook\toks@{{#1}} #2\toks@}} +% \end{macrocode} +% \end{macro} +% +% +% +% Normally we don't pick up trailing m-args but if we do we grab them +% all at once. +% \begin{macrocode} +\let\perhaps@grab@ms\relax +\def\grab@ms { + \toks@\expandafter{ + \the\expandafter\toks@ + \csname @ddc@x\the\@temptokenb\endcsname +}} +% \end{macrocode} +% +% \begin{macro}{\@ddc@xm} +% Instead of |\@ddc@m| we use |\@ddc@xm| as with the implementation +% below we might have a need for |\@ddc@x| (that is no m's pending) +% and this would result in a name clash. A potentially better +% implementation (cause faster) would be not to use |\@temptokenb| +% above to record the number of m's seen but a counter register and +% generate grabber function names containing the number in their +% name. This way one could better single out the empty case which +% currently will always result and a |\@ddc@x| grabber doing +% nothing. +% \begin{macrocode} +\let\@ddc@m\undefined +\long\def\@ddc@xm#1\toks@#2{ + \addto@hook\toks@{{#2}} #1\toks@} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@ddc@xmm} +% \begin{macro}{\@ddc@xmmm} +% \begin{macro}{\@ddc@xmmm...} +% Arguments: |#1| any remaining argument grabbers (+ |\the|), +% |#2#3| argument to be grabbed; and so on. There can be at most 8 +% such mandatory arguments in the variations defined below. +% \begin{macrocode} +\long\def\@ddc@xmm#1\toks@#2#3{ +% \end{macrocode} +% Put back the rest of the argument grabbers, but copy +% argument to list of arguments inside the toks register. +% Any `m' at the end will be discarded and the internal +% command will pick up its own arguments. +% \begin{macrocode} + \addto@hook\toks@{{#2}{#3}} #1\toks@} +% \end{macrocode} +% +% And here are the cases for 3 to eight upcoming mandatory args: +% \begin{macrocode} +\long\def\@ddc@xmmm#1\toks@#2#3#4{ + \addto@hook\toks@{{#2}{#3}{#4}} #1\toks@} +\long\def\@ddc@xmmmm#1\toks@#2#3#4#5{ + \addto@hook\toks@{{#2}{#3}{#4}{#5}} #1\toks@} +\long\def\@ddc@xmmmmm#1\toks@#2#3#4#5#6{ + \addto@hook\toks@{{#2}{#3}{#4}{#5}{#6}} #1\toks@} +\long\def\@ddc@xmmmmmm#1\toks@#2#3#4#5#6#7{ + \addto@hook\toks@{{#2}{#3}{#4}{#5}{#6}{#7}} #1\toks@} +\long\def\@ddc@xmmmmmmm#1\toks@#2#3#4#5#6#7#8{ + \addto@hook\toks@{{#2}{#3}{#4}{#5}{#6}{#7}{#8}} #1\toks@} +\long\def\@ddc@xmmmmmmmm#1\toks@#2#3#4#5#6#7#8#9{ + \addto@hook\toks@{{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}} #1\toks@} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\@ddc@xmmmmmmmmm} +% If we grab arguments even if they are all mandatory we might have +% even 9 such arguments, thus we also need: +% \begin{macrocode} +\long\def\@ddc@xmmmmmmmmm\the\toks@#1#2#3#4#5#6#7#8#9{ + \addto@hook\toks@{{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}\the\toks@} +% \end{macrocode} +% And in that case we also need to provide |\@ddc@x| as that name will +% be executed if there are no trailing mandatory arguments. +% \begin{macrocode} +\let\@ddc@x\relax +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DeclareDocumentEnvironment} +% Fixing |\DeclareDocumentEnvironment| to not choke on the spec +% |m|. Interestingly enough |mm| does work with the old +% implementation: it simply grabs |\@checkend{name}| whereas the +% first only grabs |\@checkend| leaving |{name}| around for +% typesetting :-) +% +% If we don't make the arguments available in the end code we +% should most likely revert to David's original code which worked +% without assigning everything to toks registers (or at least check +% what is faster!) +% \begin{macrocode} +\long\def\DeclareDocumentEnvironment#1#2#3#4{ + \expandafter\DeclareDocumentCommand\csname #1\endcsname{#2}{ +% \end{macrocode} +% After |\DeclareDocumentCommand| has parsed the arguments the +% parsing result is available in |\@toks| except that trailing +% |m|'s are picked up directly and their values are therefore not +% part of this token register. So either we have to slow down +% everything by individually parsing those as well or this bright +% idea is not working. For the moment i disabled it again! +% \begin{macrocode} +% \xparsed@args\toks@ + #3} +% \end{macrocode} +% In that case the following can be simplified as well: +% \begin{macrocode} + \@namedef{end #1}{#4} +% \expandafter\let\csname end #1\endcsname\@parsed@endenv +% \long\expandafter\def\csname end \string\\#1\expandafter\endcsname +% \the\@temptokena{#4} +} +% \end{macrocode} +% And those are no longer necessary: +% \begin{macrocode} +\let\@parsed@endenv\undefined +\let\@parsed@endenv@\undefined +% \end{macrocode} +% +% The above does the fixing by not providing the arguments to the +% end command. The alternative is to do full parsing and could +% perhaps look more or less like this: +% \begin{macrocode} +%<*perhaps> +\long\def\DeclareDocumentEnvironment#1#2#3#4{ + \let\perhaps@grab@ms\grab@ms + \expandafter\DeclareDocumentCommand\csname #1\endcsname{#2}{ +% \end{macrocode} +% I think we need as a safety measure add a group here or else the +% code will fail over if people use it without |\begin|\ldots +% |\end|. +% Or not? I don't really like it but then i don't want to maintain +% a private stack here. +% \begin{macrocode} + \begingroup + \xparsed@args\toks@ + #3} + \let\perhaps@grab@ms\relax + \expandafter\let\csname end #1\endcsname\@parsed@endenv + \long\expandafter\def\csname end \string\\#1\expandafter\endcsname + \the\@temptokena {#4} +} +% \end{macrocode} +% Same as in David's again except that we have the added group now. +% \begin{macrocode} +\def\@parsed@endenv{ + \expandafter\@parsed@endenv@\the\xparsed@args\endgroup} +\def\@parsed@endenv@#1{ + \csname end\string#1\endcsname} +%</perhaps> +% \end{macrocode} +% However the above will fail with |\begin{macro}| code of the +% \texttt{doc} package as this code cancels the outer group so it is +% dangerous and for the moment i have not activated it. +% +% \end{macro} +% +% \subsection{A Quark-like datatype} +% +% If it turns out that the only quark thingie is going to be +% |\NoValue| then this can be streamlined for speed (and it looks +% like this is the case)! +% +% \begin{macro}{\IfSomethingTF} +% \begin{macro}{\IfSomethingT} +% \begin{macro}{\IfSomethingF} +% Setting up the stage \ldots +% \begin{macrocode} +\def\IfSomethingTF#1{\def\something@in{#1} \If@SomethingTF} +\def\IfSomethingT#1#2#3{\def\something@in{#1} + \If@SomethingTF{#2}{#3}\@empty} +\def\IfSomethingF#1#2#3{\def\something@in{#1} + \If@SomethingTF{#2}\@empty{#3}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\If@SomethingTF} +% \ldots and then for the recursive part: +% \begin{macrocode} +\def\If@SomethingTF#1{ + \def\something@tmp{#1} + \ifx\something@tmp\something@in +%fini true + \expandafter\@secondofthree + \else + \expandafter\def\expandafter\something@tmpb\expandafter{#1} + \ifx\something@tmp\something@tmpb +%fini false + \expandafter\expandafter\expandafter\@thirdofthree + \else +%try again expanded + \expandafter\expandafter\expandafter\@firstofone + \fi + \fi + {\expandafter\If@SomethingTF\expandafter{#1}} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@secondofthree} +% \begin{macro}{\@thirdofthree} +% Some helpers missing in \LaTeX{}; the others are |\long| so we make +% those long as well: +% \begin{macrocode} +\long\def\@secondofthree#1#2#3{#2} +\long\def\@thirdofthree #1#2#3{#3} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \subsection{Testing for \texttt{\textbackslash NoValue}} +% +% +% \begin{macro}{\NoValue} +% \begin{macrocode} +\def\NoValue{-NoValue-} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\NoValueInIt} +% might be handy sometimes\ldots +% \begin{macrocode} +\def\NoValueInIt{\NoValue} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\IfNoValueTF} +% \begin{macro}{\IfNoValueT} +% \begin{macro}{\IfNoValueF} +% \begin{macrocode} +\def\IfNoValueTF{\IfSomethingTF\NoValue} +\def\IfNoValueT {\IfSomethingT \NoValue} +\def\IfNoValueF {\IfSomethingF \NoValue} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\IfValueTF} +% \begin{macro}{\IfValueT} +% \begin{macro}{\IfValueF} +% \begin{macrocode} +\def\IfValueTF #1 #2 #3 { \IfNoValueTF {#1} {#3} {#2} } +\let \IfValueT \IfNoValueF +\let \IfValueF \IfNoValueT +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{A Boolean datatype} +% +% \begin{macro}{\BooleanFalse} +% \begin{macro}{\BooleanTrue} +% \begin{macrocode} +\def\BooleanFalse{TF} +\def\BooleanTrue{TT} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\IfBooleanTF} +% \begin{macro}{\IfBooleanT} +% \begin{macro}{\IfBooleanF} +% \begin{macrocode} +\def\IfBooleanTF #1 { + \if#1 + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +\def\IfBooleanT #1 #2 { + \IfBooleanTF {#1} {#2} \@empty +} +\def\IfBooleanF #1 { + \IfBooleanTF {#1} \@empty +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% +% \Finale +% +\endinput |