% \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} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{xparse} %\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} % % \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} } } % % \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} % % \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} % % \end{macrocode} % % % \Finale % \endinput