diff options
author | Karl Berry <karl@freefriends.org> | 2007-05-22 17:49:29 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2007-05-22 17:49:29 +0000 |
commit | b7e7419f2fbc20f964ebd505f4c9d35c4b37d6e7 (patch) | |
tree | 81f166fc88d80a1bc49c16f7de6aff4d4250cdec /Master/texmf-dist/source/latex/xbase/xparse.dtx | |
parent | 51266997b22750d1cef71d44b0785cc31337f0d5 (diff) |
new package xbase, subsuming some others?
git-svn-id: svn://tug.org/texlive/trunk@4337 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/xbase/xparse.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/xbase/xparse.dtx | 2167 |
1 files changed, 2167 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/xbase/xparse.dtx b/Master/texmf-dist/source/latex/xbase/xparse.dtx new file mode 100644 index 00000000000..90346556975 --- /dev/null +++ b/Master/texmf-dist/source/latex/xbase/xparse.dtx @@ -0,0 +1,2167 @@ +% \iffalse +%% File: xparse.dtx (C) Copyright 1999 Frank Mittelbach, Chris Rowley, David Carlisle +%% (C) Copyright 2004-2006 Frank Mittelbach, 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 ``xbase 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/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: xparse.dtx 574 2006-08-21 23:30:10Z morten $ + {generic document command parser} +% \iffalse +%<*driver> + \documentclass{ltxdoc} + \usepackage[T1]{fontenc} + \usepackage{textcomp} + \makeatletter + \providecommand*\eTeX{% + \if b\expandafter\@car\f@series\@nil\boldmath\fi + $\m@th\varepsilon$-\TeX} + \makeatother +% \usepackage{ldcdoc} + \begin{document} + \catcode`\_=11 + \catcode`\:=11 + \DocInput{xparse.dtx} + \end{document} +%</driver> +% \fi +% +% \CheckSum{621} +% +% +% \title{The \textsf{xparse} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}} +% \author{FMi, CAR, DPC, MH} +% \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). +% Thus the argument spec for headings as implemented by +% |\@startsection| in standard \LaTeX{} would be represented by the +% three letters |som|. Other argument types are available and can be +% added at will. For a complete list of built-in argument types see +% the next section. +% +% There is one important argument specifier worth taking note of. The +% |P| does not behave as a normal argument specifier but allows the +% next argument to take an argument containing the |\par| token which +% is not allowed by default. +% +% +% \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\{default\}] will return the parsed argument surrounded by a +% brace pair if present. Otherwise it will return the |{default}| +% as specified above. +% \item[S\{\meta{symbol}\}] will return either the token |\c_true| or +% |\c_false| depending on whether or not the next token is +% \meta{symbol}. +% \item[s] will return either the token |\c_true| or |\c_false| +% depending on whether or not a star was parsed. This is just a +% shorthand for |S{*}|. +% \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\{\{x-default\}\{y-default\}\}] behaves like |c|, i.e., +% parses a coordinate pair if present. If the coordinate pair is +% missing it returns the default values instead. +% \item[l] Reads everything up to the first left brace as the +% argument. +% \end{description} +% For example, given the spec |soomO{default}| the input +% |*[Foo]{Bar}| would be parsed as +% |\c_true{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. +% +% There are a few exceptions to this rule as the r\^ole of following +% letters is to affect how the next argument is read. +% \begin{description} +% \item[>] takes a mandatory argument like |{P}| or |{PW}| and +% inserts these extra argument specifiers so that they act on the +% next regular argument type. See below. +% \item[P] will cause the next argument to allow |\par| in it's +% argument. Thus the specification |m>{P}mm| will cause the command to +% read three mandatory arguments but only the second can contain the +% |\par| token. +% \item[W] will cause the next argument to \emph{not} ignore a space +% when trying to scan ahead for a special symbol such as a |*| or an +% optional argument. This is mostly useful when the last argument(s) +% of a document command are optional (see example later on). +% \end{description} +% +% +% \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 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} +% \DescribeMacro\ReDeclareDocumentCommand +% \DescribeMacro\ProvideDocumentCommand +% The commands |\ReDeclareDocumentCommand| and +% |\ProvideDocumentCommand| work just like |\DeclareDocumentCommand| +% with the exception that |\Re..| can only redefine an existing +% command and |\Provide...| will only define the command if it is +% already free. +% +% +% \DescribeMacro\DeclareDocumentEnvironment +% \DescribeMacro\ReDeclareDocumentEnvironment +% \DescribeMacro\ProvideDocumentEnvironment 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 aqnd end of the environment. The parsed arguments are +% available to both the start and the finish as |#1|, |#2|, etc. +% +% All commands and environments defined with the above commands are +% automatically robust. +% +% +% +% \subsection{A different interface (for class design?)} +% +% Combining signature and top-level definition of a command |\foo| as +% in +% \begin{verbatim} +% \DeclareDocumentCommand \foo { m c m } +% { \typeout{1:#1} +% \typeout{2:#2} +% \typeout{3:#3} +% } +% \end{verbatim} +% is fine in certain cases, e.g., if the user wants to declare a few +% commands this way in the preamble of a document. However in a class +% file it probably better to completely separate signature (i.e., +% argument \#1 and \#2) from top-level implementation (i.e., argument +% \#3). +% +% +% \begin{verbatim} +% \DeclareDocumentCommandInterface \foo {bar} { m c m } +% \end{verbatim} +% The above now declare only the signature of the command |\foo| and +% states that the implementation is to be found under the label |bar|. +% +% A bunch of such statements would then for the first time clearly +% define a document class (i.e., what a document class instance needs +% to define to be compliant). +% +% An instance would then consist of a lot of declarations of the type +% \begin{verbatim} +% \DeclareDocumentCommandImplementation {bar} {3} +% { \typeout{1:#1} +% \typeout{2:#2} +% \typeout{3:#3} +% } +% \end{verbatim} +% i.e., defining how to format things being referenced as part of the +% signature. +% +% The functions |\DeclareDocumentCommandInterface| and +% |\DeclareDocumentCommandImplementation| are implemented for now but +% it is not sure if they will stay. If a document command is defined +% with |\DeclareDocumentCommandInterface| but there is no matching +% interface it prints the label in quotes as |``bar''|. +% +% +% +% +% \subsection{Checking for a value or boolean} +% +% It would make perfect sense to make |\NoValue| a \LaTeX3 quark but +% as there is a real danger of it getting executed by accident it is +% best not to as it would result in an infinite loop. +% +% \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} +% \tlp_set:Nn \l_seen_tlp {#1} +% \tlp_set:Nn \l_hidden_novalue_tlp {\NoValue} +% \tlp_if_eq:NNTF \l_seen_tlp \l_hidden_novalue_tlp +% \end{verbatim} +% will be true if |#1| was |\NoValue| but false if |#1| itself +% contains a macro which contains |\NoValue|; a case that happens +% unfortunately very often in practice. Using an unguarded |x| type +% expansion to define |\l_seen_tlp| is out of the question as |#1| is +% typically either |\NoValue| or arbitrary user input for which we +% can't properly guard it unless we are sure people only use robust +% commands. When running a pure \LaTeX3 format where all document +% commands are robust this is perhaps something to be looked at again +% but when running on top of \LaTeXe{} we have to be careful. +% +% Therefore we use a somewhat different procedure here, which goes +% like this: +% \begin{enumerate} +% \item Store |#1| in a temporary variable and check if it equals a +% variable containing |\NoValue|. If true, execute the \meta{true} +% code, otherwise go to~2. +% \item Peek at the first token in |#1|. If this is a macro taking no +% arguments expand |#1| once and go to~1. Otherwise execute the +% \meta{false} code. +% \end{enumerate} +% The reason for the careful peeking ahead is that |#1| may very well +% be a macro taking arguments and it is not certain that these +% arguments are present! Hence this could lead to the well-known +% \begin{verbatim} +% Argument of \XXX has an extra } +% \end{verbatim} +% and we wouldn't want that\dots{} Goes without saying that this +% procedure is quite tedious but usually it will exit after the first +% time |#1| has been inspected. One additional test could be added, +% namely that |#1| should also contain exactly one token but I don't +% think that is going to matter much. +% +% \DescribeMacro\IfNoValueTF +% \DescribeMacro\IfNoValueT +% \DescribeMacro\IfNoValueF +% \DescribeMacro\IfValueTF +% \DescribeMacro\IfValueT +% \DescribeMacro\IfValueF +% These macros are used for checking if an optional argument was +% present as in the example below. +% \begin{verbatim} +% \DeclareDocumentCommand\testcmd{om}{ +% \IfNoValueTF{#1}{``#2''}{#1,#2} +% } +% \end{verbatim} +% +% +% +% \DescribeMacro\IfBooleanTF +% \DescribeMacro\IfBooleanT +% \DescribeMacro\IfBooleanF +% As mentioned earlier, the parsing result for a symbol argument like +% |s| or |S{+}| is represented as the one of the tokens |\c_true| or +% |\c_false| respectively. To test for these values the macro +% |\IfBooleanTF| can be used. It expects as its first argument either +% |\c_true| or |\c_false| 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 a slower +% internal test instead of a fast two-way switch. +% +% +% \subsection{New argument types and shorthands} +% +% New argument types can be added at in a fairly straight forward +% manner with the command +% |\DeclareArgumentType|\DescribeMacro\DeclareArgumentType. This +% command takes seven arguments: |#1| is a symbol denoting the +% argument type, |#2| is the token the scanner should look for, |#3| +% is one of the words |meaning|, |charcode| or |catcode| which is +% handed down to the underlying |\peek_meaning:NTF| or +% |\peek_charcode:NTF| etc. functions. For instance you can use the +% |charcode| version if you want to pick up a literal |*| and not +% just something that has the same \emph{meaning} as a regular +% |*|. |#4| is for executing a special action (like an error message) +% if no argument is found, |#5| is the default value in case of a +% missing argument, |#6| is what the scanner will encounter, and +% finally |#7| is what the scanner grabs from the argument type. This +% is perhaps clearer with an example\dots{} This is how the |o| type +% is implemented: +% \begin{verbatim} +% \DeclareArgumentType o [ {meaning} {} {\NoValue} {#1[#2]} {#2} +% \end{verbatim} +% In a similar fashion a |b| type expecting its argument inside |<| +% and |>| would be defined as +% \begin{verbatim} +% \DeclareArgumentType b < {meaning} {} {\NoValue} {#1<#2>} {#2} +% \end{verbatim} +% +% \DescribeMacro\DeclareArgumentTypeWithDefault +% |\DeclareArgumentTypeWithDefault| is even simpler as this type +% expects the default value to be input at the time of argument +% specification. Thus arguments |#3| and |#4| from above are +% unnecessary and are simply absent. Thus the |O| type is +% implemented\footnote{I would say it is at best wishful thinking +% that the interface could be something like +% \texttt{\cs{DeclareArgumentTypeWithDefault} +% C\{2\}\{meaning\}\{(\#1,\#2)\}\{\{\#1\}\{\#2\}\}} as it would +% be quite troublesome implementation-wise and the current syntax +% isn't that difficult to use.} as +% \begin{verbatim} +% \DeclareArgumentTypeWithDefault O [ {meaning}{#1[#2]} {#2} +% \end{verbatim} +% and again a similar |B| type could be implemented as +% \begin{verbatim} +% \DeclareArgumentTypeWithDefault B < {meaning}{#1<#2>} {#2} +% \end{verbatim} +% +% +% There is also a possibility to define a shorthand for a specific +% sequence of arguments with the command +% \DescribeMacro\DeclareArgumentTypeShorthand +% |\DeclareArgumentTypeShorthand|. As an example the |s| argument +% type is just a different way of saying |S{*}| so it's simply +% implemented as +% \begin{verbatim} +% \DeclareArgumentTypeShorthand s {S{*}} +% \end{verbatim} +% Similarly one could add a shorthand |M| for inserting five +% mandatory arguments where the latter is allowed to take |\par| in +% its argument: +% \begin{verbatim} +% \DeclareArgumentTypeShorthand M {mmmm>{P}m} +% \end{verbatim} +% +% Finally there is also the command +% \DescribeMacro\DeclareSymbolArgument|\DeclareSymbolArgument| which +% defines the low level interface to looking ahead for specific +% symbols and removing them. For instance the |S| type argument is +% declared as +% \begin{verbatim} +% \DeclareSymbolArgument S{meaning} +% \end{verbatim} +% So symbols picked up by this type will compare the meaning of the +% tokens. One could do a +% \begin{verbatim} +% \DeclareSymbolArgument A{charcode} +% \end{verbatim} +% and then the |A| type would compare character codes instead. For +% instance a command which expects a |+| symbol would return +% \meta{true} if a |+| of any catcode is detected, not just catcode +% 12 as is usual. +% +% \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 careful +% expansion we do internally) 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).\footnote{These comments were made +% before the extensive changes in expl3 and xparse in 2005.} +% +%\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} +% +% +% \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} +% +% +% +% Here's another example which shows how one can use the |W| specifier. +% The \textsf{amsmath} environments use their own definition of |\\| +% which goes under the name |\math@cr|. As there is a good chance the +% next line of math begins with either an asterisk or something in +% square brackets this often leads to errors. The following example +% definition works (I \emph{did} try it). +% \begin{verbatim} +% \CodeStart +% \cs_gundefine:N \math@cr +% \DeclareDocumentCommand\math@cr{>{W}s >{W}O{\z@}}{ +% \IfBooleanTF{#1} +% { \global\@eqpen\@M }{ +% \global\@eqpen +% \ifnum\dspbrk@lvl <\z@ +% \interdisplaylinepenalty +% \else +% -\@getpen\dspbrk@lvl +% \fi +% } +% \math@cr@@@ +% \noalign{\vskip#2\relax} +% } +% \CodeStop +% \end{verbatim} +% Note that this definition automatically avoids problems within the +% alignments even if it is called as |\\&|. +% +% +% +% +% \subsection{Open issues} +% +% In this section unresolved issues or ideas to think about and +% perhaps implement are collected. There is no particular order to +% them. +% +% \begin{itemize} +% \item +% Support for parsing verbatim type of arguments was considered (and +% actually implemented at one stage. E.g., +% |g{|\meta{prepare-parsing}|}| where |g| first run +% \meta{prepare-parsing} (which might involve |catcode| +% changes)\footnote{urg horror!}, then look at the next token: if +% that would be a |{| it would scan a brace delimited argument +% (reverting catcodes of |{| and |}| if needed) otherwise would scan +% for an argument delimited by that token so that something like +% |\verb+%\+| would scan |%\| as its argument assuming that the +% \meta{prepare-parsing} turned |%| and |\| into non-letters. +% +% All kind of nasty problems lurking especially no proper error +% checks possible and of course as we all know such commands would +% then not work inside arguments of other commands. At least they +% would have some restrictions. +% +% Also no way to make the parsing smart by not accepting newlines as +% part of the code (|\verb| does this right now and this is really +% helpful as it catches runaways nicely). +% +% +% \item +% \textsf{xparse} should probably go into the \LaTeX3 kernel in which +% case it should also provide the definitions of |\begin| and |\end| +% and this raises a few questions: Will environments be defined as +% control sequences |\foo| and |\endfoo|? If they are do we then want +% to include support for a separate command |\foo| and if so what +% about using the environment forms in special scanner mechanisms +% where we \emph{can't} use |\begin{foo}|? In those cases one could +% use a special command like what the \textsf{fancyvrb} package +% provides with the command |\VerbatimEnvironment| and all packages +% that define such special arguments should then also make sure that +% the |\foo| command issued on its own should cause an error. +% Another solution would be to simply define environments as +% |\beginfoo| and |\endfoo| and then let |\begin| check if it was +% used to call an environment or a command. If the latter is the +% case then insert grouping as that could be handled by |\beginfoo| +% itself. When |\end| is reached check if |\endfoo| exists. If it +% does then use that, otherwise we were probably using a normal +% command which should just close the group. +% \end{itemize} +% +% +% \subsection{Rejected ideas---and why} +% +% Let's say the document command |\testmo| has signature |mo|. If we +% call it as |\testmo{arg} [opt]| a following space will be obeyed. +% However calling it with the mandatory argument only as in +% |\testmo{arg}| will gobble a following space because the peek ahead +% in the |o| type ignores spaces. We can record that a space has been +% gobbled when peeking ahead and we can also put it back in if needed +% but I have only ever seen one request for this and in that case the +% better solution was to use a signature |mWo| so that no spaces are +% allowed between the mandatory and the optional argument. One could +% even argue that this is the most appropriate thing to do if the user +% is really that sensitive to spaces! In any case it is not +% implemented here as it creates an unnecessary overhead for something +% that is never used and a simple solution exists. +% +% \subsection{Experimental features} +% +% Experimental features in an experimental packages\dots{} Needless to +% say that you can't rely on them staying! +% +% +% One new feature is what I decided to call ``pseudo +% arguments''. Strictly speaking these aren't real arguments but +% instead read by removing a begin group token and then using +% |\tex_aftergroup:D| to regain control. The definition of |\footnote| +% in plain \TeX\ uses this so that people can use +% |\verb| and the like inside the footnotes. The command +% |\DeclarePseudoArgument|\DescribeMacro{\DeclarePseudoArgument} takes +% four arguments: |#1| is a name for the pseudo argument, |#2| is the +% number of arguments it takes, |#3| is the action to be taken right +% before the left brace is removed and |#4| is what to be done when +% the right brace has been read and we regain control. Note that both +% |#3| and |#4| may use arguments! Here is a silly example: +% \begin{verbatim} +% \DeclarePseudoArgument{boxtest}{1} +% {Before:~`#1',\hbox_set_inline_begin:N \l_tmpa_box } +% {\hbox_set_inline_end: \text_put_sp: the~ box:~ +% \hbox_unpack_and_clear:N\l_tmpa_box ,~ +% After:~`#1'} +% \end{verbatim} +% Now when you want to use it, you simply call it with the macro +% |\UsePseudoArgument|\DescribeMacro{\UsePseudoArgument}, which as its +% first argument takes a name and the remaining depend on how many +% arguments the pseudo argument was defined to have. Hence we could +% use our |boxtest| definition like this: +% \begin{verbatim} +% \DeclareDocumentCommand\sillyboxtest{m}{ +% Testing~#1:~\UsePseudoArgument{boxtest}{#1} +% } +% \end{verbatim} +% Then calling |\sillyboxtest{AB}{a\verb*+% $%&\+b}| produces +% \begin{quote} +% Testing AB: Before: `AB', the box: +% a\verb*+% $%&\+b, After: `AB' +% \end{quote} +% |\UsePseudoArgument| should always come last in the document +% command definition. +% +% \StopEventually{} +% +% \section{Implementation} +% +% Versions prior to and including 1.19 contained several different +% implementations. These are gone now but can be looked at by +% getting an older version of the package from the CVS repository. +% +% First the required packages. +% \begin{macrocode} +%<*package> +\RequirePackage{l3tlp,l3num,l3toks,l3prg,l3int,l3seq,l3token} +% \end{macrocode} +% +% +% +% \subsection{Error and warning messages} +% +% Here we define the error message we're going to use in this package. +% +% \begin{macro}{\xparse_already_defined_error_msg:N} +% \begin{macro}{\xparse_not_yet_defined_error_msg:N} +% \begin{macro}{\xparse_begins_with_end_error_msg:N} +% \begin{macro}{\xparse_unknown_arg_type_error_msg:N} +% \begin{macro}{\xparse_number_of_arguments_error_msg:Nn} +% \begin{macro}{\xparse_no_command_implementation_warning:n} +% The names should give the function's purpose away. +% \begin{macrocode} +\def_new:NNn \xparse_already_defined_error_msg:N 1 { + \xparse_error:x { + Command~name~`\token_to_string:N #1'~ already~defined! + } +} +\def_new:NNn \xparse_not_yet_defined_error_msg:N 1 { + \xparse_error:x { + Command~`\token_to_string:N #1'~ not~ yet~defined! + } +} +\def_new:NNn \xparse_begins_with_end_error_msg:N 1 { + \xparse_error:x { + Command~`\token_to_string:N #1'~begins~with~ + `\token_to_string:N \end'! + } +} +% \end{macrocode} +% This one is for when we've encountered an unknown argument type in +% the argument specification. We can try to recover by putting in an +% |m| type instead and hope for the best. +% \begin{macrocode} +\def_new:NNn \xparse_unknown_arg_type_error_msg:N 1{ + \xparse_error:x { + Unknown~ argument~ type~ `#1'~ + I'll~ substitute~ it~ with~ `m'~ for~ now.~ Fingers~ crossed... + } +} +% \end{macrocode} +% A message for people using the wrong number of arguments. +% \begin{macrocode} +\def_new:NNn \xparse_no_command_implementation_warning:n 1 { + \xparse_warning:x {No~ implementation~ for~ `#1'~ defined} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\xparse_error:x} +% \begin{macro}{\xparse_warning:x} +% Here's how we produce the error messages and warnings currently. +% This awaits a proper error message module! +% \begin{macrocode} +\def_new:NNn \xparse_error:x 1{\tex_errmessage:D {xparse~error:~#1}} +\def_new:NNn \xparse_warning:x 1{\io_put_term:x{xparse~warning:~#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% \subsection{Checking for valid command names} +% +% +% \begin{macro}{\xparse_if_definable:NT} +% \begin{macro}{\xparse_if_definable:cT} +% A definable command is either |\c_undefined| or |\scan_stop:| and +% furthermore we won't allow it to start with |\end|. +% If the command is definable we do what was asked for otherwise +% we give an appropriate error message. +% \begin{macrocode} +\def_new:NNn \xparse_if_definable:NTF 1 { +% \end{macrocode} +% First check if the control sequence is free. +% \begin{macrocode} + \cs_free:NTF #1 +% \end{macrocode} +% If free check if it begins with |\end|. +% \begin{macrocode} + { + \xparse_begins_with_end:NTF #1 + { \xparse_begins_with_end_error_msg:N #1 \use_arg_ii:nn } + \use_arg_i:nn + } +% \end{macrocode} +% If not free give an error message. +% \begin{macrocode} + { \xparse_already_defined_error_msg:N #1 \use_arg_ii:nn } +} +\def_new:NNn \xparse_if_definable:cTF 0 { + \exp_args:Nc \xparse_if_definable:NTF +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\xparse_if_redefinable:NTF} +% \begin{macro}{\xparse_if_redefinable:cTF} +% A re-definable command is almost the same as above but here we +% demand that it already exists. +% \begin{macrocode} +\def_new:NNn \xparse_if_redefinable:NTF 1 { + \cs_free:NTF #1 + { \xparse_not_yet_defined_error_msg:N #1 \use_arg_ii:nn } + { + \xparse_begins_with_end:NTF #1 + { \xparse_begins_with_end_error_msg:N #1 \use_arg_ii:nn } + \use_arg_i:nn + } +} +\def_new:NNn \xparse_if_redefinable:cTF 0 { + \exp_args:Nc \xparse_if_redefinable:NTF +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\xparse_begins_with_end:NTF} +% \begin{macro}{\xparse_begins_with_end_aux:N} +% Finally we need the magic function for checking if the control +% sequence begins with |\end|. +% We wish to determine if the control sequence in question begins with +% |\end| which is forbidden. The end goal is to get a control sequence +% consisting of the first three letters to test against |\end| with +% |\cs_if_eq_name_p:NN|. The function |\cs_to_str:N| will remove the |\| +% from a command name and return the rest of the characters with +% category code 12. Thus using an |f| type expansion to get the first +% three characters is perfectly safe as it'll stop right there. Then +% we turn these three letters into a control sequence with a simple +% expansion which is then tested with |\xparse_begins_with_end_aux:N|. +% \begin{macrocode} +\def_new:NNn \xparse_begins_with_end:NTF 1 { +% \end{macrocode} +% We do it all in a group as there is no need to fill up the hash +% table with weird three letter control sequences. +% \begin{macrocode} + \group_begin: + \exp_args:Nc \xparse_begins_with_end_aux:N { + \tlist_head_iii:f { \cs_to_str:N #1 ??} + } +} +% \end{macrocode} +% After the above expansion tricks we now have a real control sequence +% to test against |\end|. We end the group again. +% \begin{macrocode} +\def_new:NNn \xparse_begins_with_end_aux:N 1 { + \if:w \cs_if_eq_name_p:NN #1 \end + \group_end: + \exp_after:NN \use_arg_i:nn + \else: + \group_end: + \exp_after:NN \use_arg_ii:nn + \fi: +} +% \end{macrocode} +% Note that these definitions make no use of temporary variables. +% \end{macro} +% \end{macro} +% +% +% +% \subsection{The high level commands} +% +% +% Here we set up the functions for defining and redefining document +% commands and environments. It's all rather straight forward here so +% I've saved on the comments. +% +% \begin{macro}{\DeclareDocumentCommand} +% \begin{macro}{\ReDeclareDocumentCommand} +% In case we can't do what the user wanted we gobble the next +% arguments from the input stream. For commands there are two +% arguments waiting. +% \begin{macrocode} +\def_new:NNn \DeclareDocumentCommand 1 { + \xparse_if_definable:NTF #1 + { \xparse_declare_document_command:Nnn #1 } + \use_none:nn +} +\def_new:NNn \ReDeclareDocumentCommand 1 { + \xparse_if_redefinable:NTF #1 + { \xparse_declare_document_command:Nnn #1 } + \use_none:nn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\DeclareDocumentEnvironment} +% \begin{macro}{\ReDeclareDocumentEnvironment} +% Three arguments for environments. +% \begin{macrocode} +\def_new:NNn \DeclareDocumentEnvironment 1 { + \xparse_if_definable:cTF {#1} + { \xparse_declare_document_environment:nnnn {#1} } + \use_none:nnn +} +\def_new:NNn \ReDeclareDocumentEnvironment 1 { + \xparse_if_redefinable:cTF {#1} + { \xparse_declare_document_environment:nnnn {#1} } + \use_none:nnn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ProvideDocumentCommand} +% \begin{macro}{\ProvideDocumentEnvironment} +% When providing a command we just check if the control sequence is +% free. If it is let |\DeclareDocument...| do the rest, otherwise +% gobble the next arguments. +% \begin{macrocode} +\def_new:NNn \ProvideDocumentCommand 1{ + \cs_free:NTF #1 + { \DeclareDocumentCommand #1} + \use_none:nn +} +\def_new:NNn \ProvideDocumentEnvironment 1{ + \cs_free:cTF {#1} + { \DeclareDocumentEnvironment {#1} } + \use_none:nnn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% \subsection{The low level definitions} +% +% +% First some helper functions +% \begin{macro}{\l_xparse_grabbed_args_toks} +% \begin{macro}{\l_xparse_end_environment_args_toks} +% \begin{macro}{\l_xparse_mandatory_args_int} +% \begin{macro}{\l_xparse_total_args_int} +% We need some \meta{token} registers to keep track of things. We also +% allocate an \meta{int} register to keep track of the number of +% arguments. +% \begin{macrocode} +\toks_new:N \l_xparse_grabbed_args_toks +\toks_new:N \l_xparse_end_environment_args_toks +\int_new:N \l_xparse_mandatory_args_int +\int_new:N \l_xparse_total_args_int +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\xparse_declare_document_command:Nnn} +% \begin{macro}{\xparse_declare_document_command:cnn} +% |\xparse_declare_document_command:Nnn| is a two step procedure. The +% user level command |\|\meta{cmd} contains the argument grabbers +% while the internal command |\\|\meta{cmd} holds the actual +% definition of what to do with the arguments. Naturally this calls +% for every such user level command to be robust which is done using +% the \eTeX{} protection feature. +% \begin{macrocode} +\def_long:NNn \xparse_declare_document_command:Nnn 3{ +% \end{macrocode} +% First we prepare the signature. +% \begin{macrocode} + \xparse_prepare_signature:n {#2} +% \end{macrocode} +% Now for the document command. Make it robust and make sure it starts +% with |\toks_set:Nn \l_xparse_grabbed_args_toks {\\|\meta{cmd}|}|. +% \begin{macrocode} + \def_protected:Npx #1 { + \exp_not:n { \toks_set:Nn \l_xparse_grabbed_args_toks } + {\exp_not:c {\token_to_string:N #1}} +% \end{macrocode} +% Then add the argument grabbers which contain code gathered when +% preparing the signature. +% \begin{macrocode} + \toks_use:N \l_xparse_grabbed_args_toks +% \end{macrocode} +% Finally execute |\toks_use:N \l_xparse_grabbed_args_toks| which now +% holds the grabbed arguments enclosed in braces and starts with the +% internal command |\\|\meta{cmd}. +% \begin{macrocode} + \exp_not:n{ \toks_use:N \l_xparse_grabbed_args_toks} + } +% \end{macrocode} +% Define the internal command by making it a |\long| macro with number +% of arguments equal to |\l_xparse_total_args_int| and definition as +% given by |#3|. Even though this internal macro allows |\par| in its +% argument the decision is left to the individual argument grabbers. +% \begin{macrocode} + \def_long:cNn {\token_to_string:N #1}\l_xparse_total_args_int{#3} +} +\def_new:Npn \xparse_declare_document_command:cnn { + \exp_args:Nc \xparse_declare_document_command:Nnn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\xparse_declare_document_environment:nnnn} +% |\xparse_declare_document_environment:nnnn| is almost the same. In +% order to use the grabbed arguments we take them from +% |\l_xparse_grabbed_args_toks| just before they are executed. We +% also insert a |\group_begin:| as it will otherwise fail miserably +% in case a user tries to use it without |\begin ... \end|. +% \begin{macrocode} +\def_long_new:NNn \xparse_declare_document_environment:nnnn 4 { + \xparse_declare_document_command:cnn {#1}{#2} + { \group_begin: + \toks_set_eq:NN \l_xparse_end_environment_args_toks + \l_xparse_grabbed_args_toks + #3 + } +% \end{macrocode} +% We let |\end|\meta{envir} equal to a standard version which will do +% all the work. +% \begin{macrocode} + \let:cN {end #1} \xparse_parsed_end_environment: +% \end{macrocode} +% Now define |\end\\|\meta{envir}. +% \begin{macrocode} + \def_long:cNn {end \token_to_string:N \\ #1} + \l_xparse_total_args_int{#4} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_parsed_end_environment:} +% \begin{macro}{\xparse_parsed_end_environment_aux:N} +% |\end|\meta{envir} is set equal to |\xparse_parsed_end_environment:| +% which then executes |\end\\|\meta{envir}. The |\\|\meta{envir} comes +% from the argument grabbing. The remainder of the token list is the +% grabbed arguments. We better make this robust as well. +% \begin{macrocode} +\def_protected_new:NNn \xparse_parsed_end_environment: 0{ + \exp_after:NN \xparse_parsed_end_environment_aux:N + \toks_use:N \l_xparse_end_environment_args_toks + \group_end: +} +\def_new:NNn \xparse_parsed_end_environment_aux:N 1{ + \cs_use:c {end \token_to_string:N #1 } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \subsubsection{A class designer interface} +% +% Below is the implementation of |\DeclareDocumentCommandInterface| +% and the close cousin |\DeclareDocumentCommandImplementation|. +% It is an open issue whether this concept should be supported. +% +% \begin{macro}{\DeclareDocumentCommandInterface} +% With this macro we define the document command |#1| to have +% signature |#3| which does the argument grabbing. The arguments are +% passed on to the internal command |\impl-#2|. +% \begin{macrocode} +\def_long_new:NNn \DeclareDocumentCommandInterface 3{ + \xparse_prepare_signature:n {#3} + \def_protected:Npx #1 { + \exp_not:n { \toks_set:Nn \l_xparse_grabbed_args_toks } + {\exp_not:c {impl-#2}} + \toks_use:N\l_xparse_grabbed_args_toks + \exp_not:n{ \toks_use:N \l_xparse_grabbed_args_toks} + } +% \end{macrocode} +% Define the internal command by making it a |\long| macro as we did +% for |\DeclareDocumentCommand| but give it just a default definition +% instead (usually an error message). +% \begin{macrocode} + \def_long:cNn {impl-#2} \l_xparse_total_args_int + {\xparse_undefined_command_implementation:n{#2}} +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\xparse_undefined_command_implementation:n} +% What to do if no implementation is made and the command is +% called. Let's just typeset the name in quotes indicating that +% something is wrong. +% \begin{macrocode} +\def_new:NNn \xparse_undefined_command_implementation:n 1{ + ``#1'' +% \ensuremath{\langle\textit{#1}\rangle} + \xparse_no_command_implementation_warning:n {#1} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DeclareDocumentCommandImplementation} +% Defines the internal command |\impl-#1| with |#2| arguments +% and definition |#3|. +% \begin{macrocode} +\def_long_new:NNn \DeclareDocumentCommandImplementation 3{ + \def_long:cNn {impl-#1}#2{#3} +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Creating the signature} +% +% +% \begin{macro}{\xparse_prepare_signature:n} +% The actual preparation of the signature is always the same but we +% have different ways of handling it afterwards, so we make it a +% separate function. +% \begin{macrocode} +\def_new:NNn \xparse_prepare_signature:n 1 { +% \end{macrocode} +% Initialize the counter taking care of the number of arguments. In +% case we reach more than nine we will give an error message later on. +% \begin{macrocode} + \int_zero:N \l_xparse_total_args_int +% \end{macrocode} +% Clear the token register we use when building the signature and the +% number of ``normal'' mandatory arguments. Also clear out the special +% markers and initialize the two booleans to \meta{false}. +% \begin{macrocode} + \toks_clear:N \l_xparse_grabbed_args_toks + \int_zero:N \l_xparse_mandatory_args_int + \bool_gset_false:N \g_xparse_insert_marker_bool + \bool_gset_false:N \g_xparse_allow_par_bool + \tlp_gset_eq:NN \g_xparse_ignore_marker_tlp + \g_xparse_ignore_spaces_marker_tlp +% \end{macrocode} +% Then call |\xparse_parse_signature:n|. +% \begin{macrocode} + \xparse_parse_signature:n #1 \q_nil +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{The argument types} +% +% +% +% All argument types must be denoted by single letters.\footnote{You +% can use a multi-letter sequence to denote a shorthand but it +% requires you to put two brace groups around it in the signature and +% it's not officially supported.} We have three categories of letters: +% Special markers, basic argument types, and shorthands. +% +% For certain argument types where we peek ahead in the token stream +% we have a multitude of choices for how the macro should work: +% Should it ignore spaces or other tokens? Which test should it use +% for comparing tokens: meaning, catcode or charcode? Because of +% these difficulties every argument that require peeking ahead must +% be declared as one of the three test types. +% +% \subsubsection{Special markers} +% +% Since there are different markers that may be used at the same +% time, we use the a special ``insert'' marker |>| to do this. +% +% \begin{macro}{\g_xparse_ignore_marker_tlp} +% The current ignore marker is contained in this string. +% \begin{macrocode} +\tlp_new:Nn \g_xparse_ignore_marker_tlp {} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_xparse_ignore_marker_seq} +% We start out by declaring a new sequence to contain all the +% different types of ignore functions. Each element should be the +% missing part of a |\peek_meaning|\meta{text}|:NTF| function. +% \begin{macrocode} +\seq_new:N \g_xparse_ignore_marker_seq +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_xparse_insert_marker_bool} +% A boolean to check if we just saw an insert marker. +% \begin{macrocode} +\bool_new:N \g_xparse_insert_marker_bool +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_add_arg_type_>:} +% The insert marker is called when this is seen. Is has a funny +% definition but it works. |#1| is some test in the loop function +% and |#2| is the list of markers. +% \begin{macrocode} +\def_new:cpn {xparse_add_arg_type_>:} #1 + \xparse_read_arg_type_or_grab_default:n #2{ +% \end{macrocode} +% Insert pending |m| args first. +% \begin{macrocode} + \xparse_add_remaining_m_args: +% \end{macrocode} +% Then we set the boolean true and subtract one from the argument +% count. +% \begin{macrocode} + \bool_gset_true:N \g_xparse_insert_marker_bool + \int_decr:N \l_xparse_total_args_int +% \end{macrocode} +% Then go through the list and call each subtype if it exists. +% \begin{macrocode} + \tlist_map_inline:nn{#2}{ + \xparse_check_and_add_argument_type:N ##1 + } +% \end{macrocode} +% Finally call the loop again. +% \begin{macrocode} + \xparse_parse_signature:n +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_add_ignore_marker:Nnn} +% A small function for adding a new ignore type marker. +% \begin{macrocode} +\def_new:NNn \xparse_add_ignore_marker:Nnn 3{ + \tlp_new:cn {g_xparse #2 _marker_tlp}{#3} + \seq_gpush:NC \g_xparse_ignore_marker_seq {g_xparse #2 _marker_tlp} + \def_new:cpn {xparse_add_arg_type_#1:}{ + \tlp_gset_eq:Nc \g_xparse_ignore_marker_tlp {g_xparse #2 _marker_tlp} + } +} +% \end{macrocode} +% \end{macro} +% Here we add some ignore markers. +% \begin{macrocode} +\xparse_add_ignore_marker:Nnn W{_ignore_nothing}{} +\xparse_add_ignore_marker:Nnn i{_ignore_spaces}{_ignore_spaces} +\xparse_add_ignore_marker:Nnn I{_ignore_pars}{_ignore_pars} +% \end{macrocode} +% +% \begin{macro}{\xparse_add_arg_type_P:} +% This is simple, just set a boolean. +% \begin{macrocode} +\def_new:NNn \xparse_add_arg_type_P: 0{ + \bool_gset_true:N \g_xparse_allow_par_bool +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_xparse_allow_par_bool} +% The boolean for allowing the |\par| token. +% \begin{macrocode} +\bool_new:N \g_xparse_allow_par_bool +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\xparse_parse_signature:n} +% |\xparse_parse_signature:n| reads the signature one token/brace +% group at a time and builds a list of argument grabbers which is +% stored in |\l_xparse_grabbed_args_toks|. The function is recursive +% which is why we use a quark to delimit it. +% \begin{macrocode} +\def_new:NNn \xparse_parse_signature:n 1{ +% \end{macrocode} +% Check if we reached the end of the signature. +% \begin{macrocode} + \quark_if_nil:NTF #1 +% \end{macrocode} +% If we did we may have pending |m| type arguments so we clear them +% out here. Also check if the insert marker is true because if it is, +% something is wrong. Otherwise we just continue. +% \begin{macrocode} + { + \xparse_add_remaining_m_args: + } +% \end{macrocode} +% Then proceed with adding arguments. +% \begin{macrocode} + { + \int_incr:N \l_xparse_total_args_int + \xparse_check_and_add_argument_type:N #1 +% \end{macrocode} +% If the insert marker is true at this point we reset it again and +% also disallow |\par| in arguments and make all |\peek| functions use +% the |_ignore_spaces| versions. +% \begin{macrocode} + \bool_if:NT \g_xparse_insert_marker_bool + { + \bool_gset_false:N \g_xparse_insert_marker_bool + \bool_gset_false:N \g_xparse_allow_par_bool + \tlp_gset_eq:NN \g_xparse_ignore_marker_tlp + \g_xparse_ignore_spaces_marker_tlp + } +% \end{macrocode} +% After adding arguments we better set the boolean false in case we +% don't have an insert marker. +% \begin{macrocode} +% \end{macrocode} +% First we add the remaining |m| arguments. +% \begin{macrocode} +% \end{macrocode} +% Then we run the loop again. +% \begin{macrocode} + \xparse_read_arg_type_or_grab_default:n + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\xparse_check_and_add_argument_type:N} +% This function checks if the argument type actually exists and gives +% an error if it doesn't. +% \begin{macrocode} +\def_new:NNn \xparse_check_and_add_argument_type:N 1 { + \cs_free:cTF {xparse_add_arg_type_#1:} + { \xparse_unknown_arg_type_error_msg:N #1 + \int_incr:N \l_xparse_mandatory_args_int + } +% \end{macrocode} +% Otherwise we just add it with its dedicated function. +% \begin{macrocode} + { \cs_use:c {xparse_add_arg_type_#1:} } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\xparse_read_arg_type_or_grab_default:n} +% \begin{macro}{\xparse_grab_default_arg:n} +% \begin{macro}{\xparse_grab_default_arg_allow_par:n} +% The function for grabbing a default value. The default setting is +% just to tun the loop again. However, some argument types need to +% add a default argument so we add these as well. +% \begin{macrocode} +\let_new:NN \xparse_read_arg_type_or_grab_default:n + \xparse_parse_signature:n +\def_new:NNn \xparse_grab_default_arg:n 1{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks {{#1}} + \let:NN \xparse_read_arg_type_or_grab_default:n + \xparse_parse_signature:n + \xparse_parse_signature:n +} +\def_long_new:NNn \xparse_grab_default_arg_allow_par:n 1{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks {{#1}} + \let:NN \xparse_read_arg_type_or_grab_default:n + \xparse_parse_signature:n + \xparse_parse_signature:n +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% +% +% +% \subsubsection{The default argument types} +% +% +% +% When scanning the signature we need to add the argument type which +% is done by a function |\xparse_add_arg_type_|\meta{X}|:|, where +% \meta{X} is the letter denoting the argument type. If not found an +% error message is issued ny |\xparse_unknown_arg_type_error_msg:N|. +% +% By default the package implements the argument types |m|, |S|, |c|, +% |C|, |o|, and |O| argument types as low level ones. The |s| type is +% a shorthand as we shall see later. +% +% As we don't make every single |m| argument a separate grabber all +% other types must clear out any pending |m|s. +% +% \paragraph{Mandatory arguments} +% +% Below follows the implementation of mandatory arguments. +% +% \begin{macro}{\xparse_add_arg_type_m:} +% Check if the user asked for an |m| argument allowing |\par| +% tokens and insert it. Otherwise increment the number of +% non-|\long| argument grabbers. +% \begin{macrocode} +\def_new:Npn \xparse_add_arg_type_m: { + \bool_if:NTF \g_xparse_allow_par_bool + { + \toks_put_right:Nn \l_xparse_grabbed_args_toks {\xparse_allow_par_m:w} + } + { \int_incr:N \l_xparse_mandatory_args_int } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_add_remaining_m_args:} +% And here is the function for clearing out normal pending |m| +% arguments. There is little point in adding any arguments if none +% are required. +% \begin{macrocode} +\def_new:Npn \xparse_add_remaining_m_args: { + \int_compare:nNnF \l_xparse_mandatory_args_int = \c_zero + { + \toks_put_right:Nx \l_xparse_grabbed_args_toks { + \exp_not:c{xparse_m + \int_use:N \l_xparse_mandatory_args_int + :w } + } + \int_zero:N \l_xparse_mandatory_args_int + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\xparse_m1:w} +% \begin{macro}{\xparse_m2:w} +% \begin{macro}{\xparse_m3:w} +% \begin{macro}{\xparse_m4:w} +% \begin{macro}{\xparse_m5:w} +% \begin{macro}{\xparse_m6:w} +% \begin{macro}{\xparse_m7:w} +% \begin{macro}{\xparse_m8:w} +% \begin{macro}{\xparse_m9:w} +% Grabbing 1--9 mandatory arguments. The one grabbing nine arguments +% will automatically end with +% |\toks_use:N \l_xparse_grabbed_args_toks| anyway so we avoid +% problems with that one. +% \begin{macrocode} +\def_new:cpn {xparse_m1:w} #1 \l_xparse_grabbed_args_toks#2{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m2:w} #1 \l_xparse_grabbed_args_toks #2#3{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}{#3}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m3:w} #1 \l_xparse_grabbed_args_toks #2#3#4{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}{#3}{#4}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m4:w} #1 \l_xparse_grabbed_args_toks #2#3#4#5{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}{#3}{#4}{#5}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m5:w} #1 \l_xparse_grabbed_args_toks #2#3#4#5#6{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}{#3}{#4}{#5}{#6}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m6:w} #1 \l_xparse_grabbed_args_toks #2#3#4#5#6#7{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks + {{#2}{#3}{#4}{#5}{#6}{#7}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m7:w} #1 \l_xparse_grabbed_args_toks#2#3#4#5#6#7#8{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks + {{#2}{#3}{#4}{#5}{#6}{#7}{#8}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m8:w} #1\l_xparse_grabbed_args_toks + #2#3#4#5#6#7#8#9{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks + {{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m9:w} \toks_use:N \l_xparse_grabbed_args_toks + #1#2#3#4#5#6#7#8#9{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks + {{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}} + \toks_use:N \l_xparse_grabbed_args_toks +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\xparse_allow_par_m:w} +% The |m| type allowing |\par| tokens. We only define one of them as +% two in a row would be quite rare. +% \begin{macrocode} +\def_long_new:Npn \xparse_allow_par_m:w #1 \l_xparse_grabbed_args_toks#2{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}} + #1 \l_xparse_grabbed_args_toks +} +% \end{macrocode} +% \end{macro} +% +% \paragraph{Arguments delimited by a left brace} +% +% \begin{macro}{\xparse_add_arg_type_l:} +% \begin{macro}{\xparse_l:w} +% \begin{macro}{\xparse_allow_par_l:w} +% This is almost exactly the same as the |m| type except we read +% everything up to the first left brace. +% \begin{macrocode} +\def_new:Npn \xparse_add_arg_type_l: { + \xparse_add_remaining_m_args: + \bool_if:NTF \g_xparse_allow_par_bool + { + \toks_put_right:Nn \l_xparse_grabbed_args_toks {\xparse_allow_par_l:w} + } + { \toks_put_right:Nn \l_xparse_grabbed_args_toks {\xparse_l:w} } +} +\def_new:Npn \xparse_l:w #1 \l_xparse_grabbed_args_toks#2#{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}} + #1 \l_xparse_grabbed_args_toks +} +\def_long_new:Npn \xparse_allow_par_l:w #1 \l_xparse_grabbed_args_toks#2#{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}} + #1 \l_xparse_grabbed_args_toks +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \paragraph{Adding a symbol argument type} +% +% +% \begin{macro}{\DeclareSymbolArgument} +% The actual grabber functions just issue a |\peek_meaning_remove:NTF| +% or similar on the symbol chosen. If found, we put a |\c_true| on the +% argument stack and |\c_false| otherwise. +% \begin{macrocode} +\def_new:NNn \DeclareSymbolArgument 2{ + \seq_map_variable:NNn \g_xparse_ignore_marker_seq \l_tmpa_tlp { + \def:cpx {xparse \l_tmpa_tlp _#1:w}##1##2\l_xparse_grabbed_args_toks{ + \exp_not:c{peek_ #2 _remove \l_tmpa_tlp :NTF} ##1 + { + \exp_not:N \toks_put_right:Nn \exp_not:N + \l_xparse_grabbed_args_toks \exp_not:N \c_true + ##2 \exp_not:N\l_xparse_grabbed_args_toks + } + { + \exp_not:N \toks_put_right:Nn \exp_not:N + \l_xparse_grabbed_args_toks \exp_not:N \c_false + ##2 \exp_not:N\l_xparse_grabbed_args_toks + } + } + } +% \end{macrocode} +% Implementing a symbol type is fairly straight forward. It needs to +% grab a default argument. First we must clear out any pending |m| +% arguments. +% \begin{macrocode} + \def:cpn {xparse_add_arg_type_#1:} { + \xparse_add_remaining_m_args: + \toks_put_right:Nx \l_xparse_grabbed_args_toks + { \exp_not:c {xparse \g_xparse_ignore_marker_tlp _#1:w } } +% \end{macrocode} +% Nothing special when building the signature: We always grab a single +% default argument. +% \begin{macrocode} + \let:NN \xparse_read_arg_type_or_grab_default:n \xparse_grab_default_arg:n + } +} +% \end{macrocode} +% It is this easy now: +% \begin{macrocode} +\DeclareSymbolArgument S{meaning} +% \end{macrocode} +% \end{macro} +% +% +% \paragraph{Adding delimited arguments} +% +% +% \begin{macro}{\DeclareArgumentType} +% Argument types that read their argument delimited as the |o| type +% can be defined with this function. |#1| is the letter associated +% with the type, |#3| is the test type we should use, i.e., +% meaning, charcode or catcode. |#2| is the left delimiter \LaTeX{} +% will look for, |#4| can be used for an error message or such in +% case of a missing value, and |#5| the value inserted in case the +% optional argument is missing. The last two arguments control how +% the arguments are picked up and parsed on to the inner parsing. +% \begin{macrocode} +\def_new:NNn \DeclareArgumentType 7{ +% \end{macrocode} +% For instance, we want |\DeclareArgumentType a{charcode}[...| to +% define the function |\xparse_ignore_spaces_a:w| with meaning +% |\peek_charcode_ignore_spaces:NTF [{...}{...}|. We want to define a +% series of functions for each of these delimited argument types. One +% for each of the |ignore| types plus an identical version of each of +% these allowing the |\par| token in the argument. All the different +% ignore types are stored in the sequence +% |\g_xparse_ignore_marker_seq| so we go through that when doing the +% definitions. +% \begin{macrocode} + \seq_map_variable:NNn \g_xparse_ignore_marker_seq \l_tmpa_tlp { + \def:cpx {xparse \l_tmpa_tlp _#1:w}##1\l_xparse_grabbed_args_toks{ + \exp_not:c{peek_#3 \l_tmpa_tlp :NTF} \exp_not:N #2 + { \exp_not:c{xparse_#1_#3_help:nw}{##1} } + { + \exp_not:n { + #4 \toks_put_right:Nn \l_xparse_grabbed_args_toks {#5} + } + ##1 \exp_not:N\l_xparse_grabbed_args_toks + } + } +% \end{macrocode} +% And now an almost identical version which allows the |\par| token. +% \begin{macrocode} + \def_long:cpx {xparse_allow_par \l_tmpa_tlp _#1:w}##1 + \l_xparse_grabbed_args_toks{ + \exp_not:c{peek_#3 \l_tmpa_tlp :NTF} \exp_not:N #2 + { \exp_not:c{xparse_allow_par_#1_#3_help:nw}{##1} } + { + \exp_not:n { + #4 \toks_put_right:Nn \l_xparse_grabbed_args_toks {#5} + } + ##1 \exp_not:N\l_xparse_grabbed_args_toks + } + } + } +% \end{macrocode} +% Here is the function for building the argument grabbing. We clear +% out the remaining |m| arguments first. +% \begin{macrocode} + \def:cpn {xparse_add_arg_type_#1:} { + \xparse_add_remaining_m_args: + \toks_put_right:Nx \l_xparse_grabbed_args_toks { + \exp_not:c {xparse +% \end{macrocode} +% Insert |_allow_par| in the csname if needed. This also applies to +% the argument grabber (although this should probably just be the +% default). +% \begin{macrocode} + \bool_if:NT \g_xparse_allow_par_bool {_allow_par} + \g_xparse_ignore_marker_tlp + _#1:w + } + } + \let:NN \xparse_read_arg_type_or_grab_default:n \xparse_parse_signature:n + } +% \end{macrocode} +% Now all we need to do is to define the helper functions. +% \begin{macrocode} + \xparse_define_helper:Nnnn #1{#3}{#6}{#7} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DeclareArgumentTypeDefaultValue} +% The same as above but expects a default value in the signature. +% Therefore it doesn't have the arguments of the default value and +% what to do if it is missing like the above. +% \begin{macrocode} +\def_new:NNn \DeclareArgumentTypeDefaultValue 5{ + \seq_map_variable:NNn \g_xparse_ignore_marker_seq \l_tmpa_tlp { + \def:cpx {xparse \l_tmpa_tlp _#1:w}##1##2\l_xparse_grabbed_args_toks{ + \exp_not:c{peek_#3 \l_tmpa_tlp :NTF} \exp_not:N #2 + { \exp_not:c{xparse_#1_#3_help:nw}{##2} } + { + \exp_not:N \toks_put_right:Nn + \exp_not:N \l_xparse_grabbed_args_toks {{##1}} + ##2 \exp_not:N \l_xparse_grabbed_args_toks + } + } +% \end{macrocode} +% And now an almost identical version which allows the |\par| token. +% \begin{macrocode} + \def_long:cpx {xparse_allow_par \l_tmpa_tlp _#1:w}##1##2 + \l_xparse_grabbed_args_toks{ + \exp_not:c{peek_#3 \l_tmpa_tlp :NTF} \exp_not:N #2 + { \exp_not:c{xparse_allow_par_#1_#3_help:nw}{##2} } + { + \exp_not:N \toks_put_right:Nn + \exp_not:N \l_xparse_grabbed_args_toks {{##1}} + ##2 \exp_not:N \l_xparse_grabbed_args_toks + } + } + } +% \end{macrocode} +% Here is the function for building the argument grabbing. We clear +% out the remaining |m| arguments first. +% \begin{macrocode} + \def:cpn {xparse_add_arg_type_#1:} { + \xparse_add_remaining_m_args: + \toks_put_right:Nx \l_xparse_grabbed_args_toks { + \exp_not:c {xparse +% \end{macrocode} +% Insert |_allow_par| in the csname if needed. This also applies to +% the argument grabber (although this should probably just be the +% default). +% \begin{macrocode} + \bool_if:NT \g_xparse_allow_par_bool {_allow_par} + \g_xparse_ignore_marker_tlp + _#1:w + } + } + \let:Nc \xparse_read_arg_type_or_grab_default:n + {xparse_grab_default_arg + \bool_if:NT \g_xparse_allow_par_bool {_allow_par} + :n + } + } +% \end{macrocode} +% Now all we need to do is to define the helper functions. +% \begin{macrocode} + \xparse_define_helper:Nnnn #1{#3}{#4}{#5} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_define_helper:Nnnn} +% All we need now is the helper functions. We define a generic +% interface that should be fairly easy to use. +% \begin{macrocode} +\def_new:NNn \xparse_define_helper:Nnnn 4{ + \toks_set:Nn \l_tmpa_toks + { + #3 + { +% \end{macrocode} +% Remember to add an extra set of braces here. +% \begin{macrocode} + \toks_put_right:Nn \l_xparse_grabbed_args_toks {{#4}} + ##1 \l_xparse_grabbed_args_toks + } + } +% \end{macrocode} +% The next bit looks a little ugly but that's life. +% \begin{macrocode} + \toks_set:Nx \l_tmpa_toks { + \exp_not:n {\def:cpn{xparse_#1_#2_help:nw}} + \toks_use:N \l_tmpa_toks + \exp_not:n {\def:cpn{xparse_allow_par_#1_#2_help:nw}} + \toks_use:N\l_tmpa_toks + } + \toks_use:N \l_tmpa_toks +} +% \end{macrocode} +% \end{macro} +% +% All the above may seem like an awful lot of trouble but it is +% general and it allows the following simple definitions: +% \begin{macrocode} +\DeclareArgumentType o[{meaning}{}{\NoValue}{#1[#2]}{#2} +% \end{macrocode} +% For the |c| type we add give an error message. +% \begin{macrocode} +\DeclareArgumentType c({meaning}{ + \xparse_error:x{ + Missing~ coordinate~ argument.~ A~ value~ of~ (0,0)~ is~ assumed} + } + {{00}} + {#1(#2,#3)}{{#2}{#3}} +\DeclareArgumentTypeDefaultValue O[{meaning}{#1[#2]}{#2} +\DeclareArgumentTypeDefaultValue C({meaning}{#1(#2,#3)}{{#2}{#3}} +% \end{macrocode} +% One could also do +% \begin{verbatim} +% \DeclareArgumentTypeDefaultValue O[{charcode}{#1#2#3]}{#3} +% \end{verbatim} +% where argument |#2| is the bracket but not requiring it to have +% catcode~12. However we can't use the same trick for reading the end +% of the argument. +% +% Another interesting one could be +% \begin{verbatim} +% \DeclareArgumentType a\c_group_begin_token{catcode}{}{\NoValue}{#1#2}{#2} +% \end{verbatim} +% which would basically be an optional argument in braces. +% +% +% +% \subsubsection{Argument shorthands} +% +% +% \begin{macro}{\DeclareArgumentTypeShorthand} +% Letting a letter or symbol be a shorthand for a more complicated +% structure is rather easy actually. All we need to do is to gobble +% the remainder of the main loop in the signature creation until +% |\xparse_parse_signature:n|, decrement the argument counter, put +% in the replacement argument specifiers and start the loop +% again. The disadvantage of this scheme is that we have to cheat +% and give it the wrong name as it should have a |w| argument +% specification but I hope you can forgive this little white lie. +% \begin{macrocode} +\def_new:NNn \DeclareArgumentTypeShorthand 2{ + \def_new:cpn {xparse_add_arg_type_#1:} + ##1 \xparse_read_arg_type_or_grab_default:n { + \int_decr:N \l_xparse_total_args_int + \xparse_read_arg_type_or_grab_default:n #2 + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\xparse_add_arg_type_s:} +% Defining the |s| type is easy now since it really means |S{*}|. +% \begin{macrocode} +\DeclareArgumentTypeShorthand s {S{*}} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Checking for optional values} +% +% +% \begin{macro}{\IfBooleanTF} +% \begin{macro}{\IfBooleanT} +% \begin{macro}{\IfBooleanF} +% The logical \meta{true} and \meta{false} statements are just our +% normal |\c_true| and |\c_false| so testing for them is done with +% our usual |\prg_if_predicate:nTF| functions from \textsf{l3prg}. +% \begin{macrocode} +\let_new:NN \IfBooleanTF \prg_if_predicate:nTF +\let_new:NN \IfBooleanT \prg_if_predicate:nT +\let_new:NN \IfBooleanF \prg_if_predicate:nF +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\NoValue} +% \begin{macro}{\c_xparse_hidden_no_value_tlp} +% |\NoValue| is just a text string and we define it as a token list +% pointer. However we will actually test for token list pointers +% with \emph{meaning} |\NoValue|. Hence if an argument is really +% |-NoValue-| it will not be detected but that shouldn't happen. +% \begin{macrocode} +\tlp_new:Nn \NoValue {-NoValue-} +\tlp_new:Nn \c_xparse_hidden_no_value_tlp {\NoValue} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\xparse_if_no_value:nTF} +% The test start by making a token list pointer out of the first +% argument and then check if it is equal to +% |\c_xparse_hidden_no_value_tlp| which contains |\NoValue|. +% \begin{macrocode} +\def_long_new:Npn \xparse_if_no_value:nTF #1{ + \tlp_set:Nx \l_tmpa_tlp{\exp_not:n{#1}} + \tlp_if_eq:NNTF \l_tmpa_tlp \c_xparse_hidden_no_value_tlp +% \end{macrocode} +% If they are equal we just exit and execute the \meta{true} code. +% \begin{macrocode} + { \use_arg_i:nn } +% \end{macrocode} +% If not, take a closer look at |#1|. Peek ahead at the first token in +% |#1| and then call the function |\xparse_if_no_value_aux:| but only +% if |#1| is not empty or a blank space: in that case we can execute +% the \meta{false} code immediately. We must use this test at some +% point otherwise the macros for checking tokens will break since the +% argument may be empty. +% \begin{macrocode} + { \tlist_if_blank:nTF {#1} + { \use_arg_ii:nn } + {\peek_after:NN \xparse_if_no_value_aux: #1 \q_nil {#1} } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_if_no_value_aux:} +% Now we simply check the argument specification of the token. If +% it is not a macro the function |\token_get_arg_spec:N| returns +% |\scan_stop:|. +% \begin{macrocode} +\def_long_new:Npn \xparse_if_no_value_aux: { + \tlp_set:Nx \l_tmpa_tlp{\token_get_arg_spec:N \l_peek_token } +% \end{macrocode} +% Then check if |\l_tmpa_tlp| is empty, because this means we have a +% macro taking zero arguments and we can expand it once +% safely. Otherwise we just exit and execute the false code. Remember +% that we have the sequence |{#1}| waiting after the |\q_nil| in +% |\xparse_if_no_value:nTF| above. +% \begin{macrocode} + \tlp_if_empty:NTF \l_tmpa_tlp + {\use_arg_i_delimit_by_q_nil:nw {\exp_args:No\xparse_if_no_value:nTF}} + {\use_arg_i_delimit_by_q_nil:nw {\use_arg_iii:nnn}} +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\IfNoValueTF} +% \begin{macro}{\IfNoValueT} +% \begin{macro}{\IfNoValueF} +% \begin{macro}{\IfValueTF} +% \begin{macro}{\IfValueT} +% \begin{macro}{\IfValueF} +% |\IfNoValueTF| and its varieties are implemented as subcases of +% |\xparse_if_no_value:nTF|. +% \begin{macrocode} +\let_new:NN \IfNoValueTF \xparse_if_no_value:nTF +\def_long_new:NNn \IfNoValueT 2 {\xparse_if_no_value:nTF{#1}{#2}{}} +\def_long_new:NNn \IfNoValueF 1 {\xparse_if_no_value:nTF {#1}{}} +% \end{macrocode} +% For |\IfValueTF| we just reverse the arguments. +% \begin{macrocode} +\def_long_new:NNn \IfValueTF 3{\xparse_if_no_value:nTF {#1}{#3}{#2}} +\let_new:NN \IfValueT \IfNoValueF +\let_new:NN \IfValueF \IfNoValueT +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \subsection{Pseudo arguments} +% +% \begin{macro}{\l_xparse_pseudo_post_arg_tlp} +% A temporary token list pointer to store the post-arguments. +% \begin{macrocode} +\tlp_new:Nn \l_xparse_pseudo_post_arg_tlp {} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\DeclarePseudoArgument} +% Must be called at the end of the replacement text. Can use the +% parameters picked up so far. |#1| is a name for it, |#2| is the +% number of arguments, |#3| is the pre-argument definition, |#4| is +% the post-argument definition. The idea here is to define two +% functions: One to execute before the special pseudo argument is +% found and one to to it afterwards. Hence we define such two +% functions with |#2| arguments and definitions |#3| and |#4| +% respectively. +% \begin{macrocode} +\def_long_new:NNn \DeclarePseudoArgument 4{ + \def_long:cNn {xparse_pseudo_pre_arg_#1:\prg_replicate:nn{#2}{n}}#2{#3} + \def_long:cNn {xparse_pseudo_post_arg_#1:\prg_replicate:nn{#2}{n}}#2{#4} +% \end{macrocode} +% In case the user doesn't put the argument in braces, it must be a +% single token which we just grab and then execute the +% post-argument. Surely it won't be a |\par| token! +% \begin{macrocode} + \def:cNn {xparse_pseudo_nobrace_arg_#1:N} 1 { + ##1 \l_xparse_pseudo_post_arg_tlp + } +% \end{macrocode} +% The regular version of the command is then this: +% \begin{enumerate} +% \item Execute the pre-code at level $n$. +% \item Store the post-code in a token list pointer at level $n$. +% \item Look for a begin-group token. +% \item[4a] If found, remove it, start a group (level $n+1$) and make +% sure the token list pointer from 2) is executed after the group +% has ended (at level $n$). +% \item[4b] If not found, call the |nobrace_arg| version which also +% executes the token list pointer from 2) at level $n$. +% \end{enumerate} +% This scheme enables these commands to be nested since they all +% appear at different grouping levels. +% +% Next we define the function. Also make sure that it gets all the +% arguments carried over to the post-argument. +% \begin{macrocode} + \def_long:cNx {xparse_pseudo_arg_#1:w} #2 + { + \exp_not:c { + xparse_pseudo_pre_arg_#1: \prg_replicate:nn{#2}{n} + } + \cs_use:c{def_aux_use_\int_use:N \int_eval:n{#2}_parameter:} + \exp_not:n {\tlp_set:Nn \l_xparse_pseudo_post_arg_tlp} + { + \exp_not:c {xparse_pseudo_post_arg_#1:\prg_replicate:nn{#2}{n}} + \cs_use:c{def_aux_use_\int_use:N \int_eval:n{#2}_parameter:} + } + \exp_not:n{ \peek_catcode_remove_ignore_spaces:NTF \c_group_begin_token } + { +% \end{macrocode} +% Here we insert the left brace token which was removed removed. +% In case you're wondering then yes, I know that |\c_group_begin_token| +% and |\group_execute_after:N| are unexpandable but I prefer this method +% because I don't want to remember which commands are expandable and +% which are not. +% \begin{macrocode} + \exp_not:n { + \c_group_begin_token + \group_execute_after:N \l_xparse_pseudo_post_arg_tlp + } + } + { + \exp_not:c{xparse_pseudo_nobrace_arg_#1:N} + } + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\UsePseudoArgument} +% Just a nice wrapper for calling such an argument. +% \begin{macrocode} +\def_new:NNn \UsePseudoArgument 1{\cs_use:c{xparse_pseudo_arg_#1:w}} +% \end{macrocode} +% \end{macro} +% +% +% +% +% \Finale +% +\endinput +% +% $Log$ +% Revision 1.25 2006/07/17 22:25:53 morten +% Minor change to reflect change in l3basics.dtx +% +% Revision 1.24 2006/07/08 22:44:29 morten +% Fixed two lurking problems in \xparse_if_no_value:nTF. +% +% Revision 1.23 2006/07/06 14:56:04 morten +% Change to use new \def:NNn syntax +% +% Revision 1.22 2006/01/17 23:04:08 morten +% Added `l' type argument for reading up to a left brace. +% +% Revision 1.21 2006/01/04 02:42:35 morten +% Changed RCS information retrieval. Rewrote \DeclareArgumentType and +% its relatives in order for them to work properly with the new \peek_ +% functions. Changed how special markers are inserted into the +% signature. Added `pseudo arguments'. Updated documentation to reflect +% all these changes. And more which I can't remember right now :-) +% +% Revision 1.20 2005/04/06 21:24:47 morten +% Total rewrite - there is only one implementation in the package +% now. Documentation updated to match the changes. +% +% +% |