summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/inlinedef/inlinedef.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/inlinedef/inlinedef.dtx')
-rw-r--r--Master/texmf-dist/source/latex/inlinedef/inlinedef.dtx1220
1 files changed, 1220 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/inlinedef/inlinedef.dtx b/Master/texmf-dist/source/latex/inlinedef/inlinedef.dtx
new file mode 100644
index 00000000000..6d4966a1007
--- /dev/null
+++ b/Master/texmf-dist/source/latex/inlinedef/inlinedef.dtx
@@ -0,0 +1,1220 @@
+% \iffalse
+%
+% inlinedef.dtx
+% Copyright 2008 Stephen D. Hicks
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+% http://www.latex-project.org/lppl.txt
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is Stephen D. Hicks
+%
+% This work consists of the files
+% README
+% inlinedef.dtx (this file)
+% inlinedef.ins
+% inlinedef.pdf
+% and the derived files
+% inlinedef.sty
+% inlinetest.tex
+%
+% Run LaTeX on this file to produce documentation.
+% Run LaTeX on the .ins file to produce the package.
+%<*driver>
+\ProvidesFile{inlinedef.dtx}
+%</driver>
+%
+%<package>\NeedsTeXFormat{LaTeX2e}
+%<package>\ProvidesPackage{inlinedef}%
+%<testsuite>\documentclass{minimal}
+%<testsuite>\usepackage{inlinedef}%
+ [2008/07/10 v1.0 Inlined expansions within definitions]
+%<*driver>
+\documentclass{ltxdoc}
+\CheckSum{1876}
+%\OnlyDescription % (un)comment this line to show (hide) source code
+\RecordChanges
+\EnableCrossrefs
+\CodelineIndex % (un)comment this line to index source by page (line)
+\begin{document}
+ \newcommand*{\Lopt}[1]{\textsf {#1}}
+ \parindent0pt
+ \def\*#1{\texttt{\string#1}} %% sdh - |...| doesn't work in headings
+ \makeatletter
+ %
+ \newcount\mac@depth\mac@depth\z@
+ \newcommand\@macros{}\newcommand\@endmacros{}
+ \catcode`&3 %% we use a funny catcode to ensure never used.
+ \def\@macros#1,{\macro{#1}\global\advance\mac@depth\@ne\relax
+ \@ifnextchar&\@gobble\@macros}
+ \def\@endmacros{\let\mac@next\relax\ifnum\mac@depth>\z@
+ \endmacro\let\mac@next\@endmacros
+ \global\advance\mac@depth\m@ne\fi\mac@next}
+ \newenvironment{macros}[1]{\@macros#1,&}{\@endmacros}
+ \catcode`&4 %% put it back
+ % Stop indexing at a certain point
+ \newcommand\StopIndexing{\let\special@index\@gobble}
+ % done...
+ \makeatother %% must be balanced for character table to work properly
+ %
+ % Don't index unimportant names...
+ \DoNotIndex{\@ne,\@whilesw,\@gobble,\@eha,\@ehd,\@empty,\xa}
+ \DoNotIndex{\advance,\begin,\begingroup,\xdef}
+ \DoNotIndex{\catcode,\DeclareRobustCommand,\def,\detokenize,\edef}
+ \DoNotIndex{\end,\endgroup,\errorcontextlines,\expandafter,\foo}
+ \DoNotIndex{\futurelet,\gdef,\global,\let,\long}
+ \DoNotIndex{\m@ne,\makeatletter,\makeatother,\meaning,\message}
+ \DoNotIndex{\MessageBreak,\newcommand,\newcount,\newif,\newtoks}
+ \DoNotIndex{\noexpand,\outer,\PackageError,\protect,\protected@edef}
+ \DoNotIndex{\relax,\renewcommand,\space,\string,\the\toks,\undefined}
+ \DoNotIndex{\ifcat,\ifnum,\ifx,\else,\fi,\fi,\fi}
+ % Do the stuff
+ \DocInput{inlinedef.dtx}
+ \setcounter{IndexColumns}{2}
+ \def\bang{\texttt{!}}
+ \PrintIndex
+ %\PrintChanges
+\end{document}
+%</driver>
+% \fi
+% \changes{v1.0}{2008/07/05}
+% {(SDH) Initial version.}
+%
+% \GetFileInfo{inlinedef.dtx}
+% \title{The \textsf{inlinedef}%
+% \iffalse - don't include this for now...
+% \thanks{\textsf{darcs} repository at
+% \texttt{http://www.physics.cornell.edu/$\sim$shicks/darcs/latex/inlinedef/}.
+% Patch submissions welcome.}\fi
+% package}
+% \author{Stephen Hicks\thanks{email: \texttt{sdh33@cornell.edu}}}
+% \date{\fileversion{} -- \filedate}
+% \maketitle
+%
+% \section{Usage}
+%
+% \subsection{The problem}
+% Often package writers want to redefine certain macros to do slightly
+% more than what they did previously, adding a control sequence or two
+% to the beginning or the end of the definition. The easiest way to
+% accomplish this is to use something like
+% \begin{verbatim}
+% \let\old@macro\macro
+% \def\macro{...\old@macro...}\end{verbatim}
+% But this sort of construction can cause problems if another package
+% also wants to redefine the same macro and happens to choose the same
+% name to save it to. It's also an ugly solution in that it pollutes
+% the global namespace with extra macro names. A much cleaner solution
+% is to define the new macro with the old macro expanded inline, as in
+% |\edef\macro{...\macro...}|. This is generally problemmatic because
+% there are often undefined control sequences and macros that we don't
+% want to expand quite yet. A compromise is to use |\expandafter|, but
+% this leads to error-prone and unreadable code:
+% \begin{verbatim}
+% \expandafter\def\expandafter\macro\expandafter{\expandafter
+% ...\macro...}\end{verbatim}
+%
+% \subsection{The solution}
+% What we really want is a way to expand just a few
+% tokens in the definition and leave the rest untouched.
+% \iffalse - not ready yet...
+% The package |expansions| provides a way to do this more
+% generally, but in the case of definitions, this package is more
+% expressive and simpler.
+% \fi
+% We provide a command \DescribeMacro\Inline|\Inline|
+% that can be inserted before a |\def| or |\gdef| (optionally prefixed
+% by |\long|, |\outer|, and/or |\global|, as in
+% |\Inline\long\outer\gdef...|). Within |\Inline| definitions,
+% only tokens preceded by \DescribeMacro\Expand|\Expand| are expanded.
+% Thus, the previous example becomes
+% \begin{verbatim}
+% \Inline\def\macro{...\Expand\macro...}\end{verbatim}
+%
+% \subsection{Special commands}
+% While nearly everything can be done with |\Expand| alone, we provide
+% a few more keywords for completeness and convenience.
+% \begin{itemize}
+% \item\DescribeMacro\Expand|\Expand| - Performs a single expansion
+% on the token or group
+% immediately following and places the result directly into the
+% definition without further processing. In the case of a group,
+% only the first token is expanded (although |\expandafter|s may
+% be used to expand a different token), and
+% the outermost grouping braces are discarded.
+% \item\DescribeMacro\MultiExpand|\MultiExpand|\marg{number} -
+% Expands the following token or group the given number of times.
+% For example,
+% \begin{verbatim}
+% \MultiExpand{3}{\expandafter\expandafter\expandafter\a
+% \expandafter\b\c}\end{verbatim}
+% expands first |\c|, then |\b|, then |\a|, and inserts the whole
+% expansion into the definition with no braces. Note that the braces
+% are important. Otherwise it will just try to expand the first
+% |\expandafter| three times, which is clearly wrong.
+% \item\DescribeMacro\UnsafeExpand|\UnsafeExpand| - This version simply
+% inserts an |\expandafter|, performing the expansion as in |\Expand|
+% above, but reinserting the result back
+% into the stream to be processed. Thus, any tokens like |\Expand| or
+% |\Super| in the expansion will be acted on. Unlike the previous two
+% commands, groups are \emph{not\/} treated differently.
+% \item\DescribeMacro\NoExpand|\NoExpand| - If a token is preceeded
+% by |\NoExpand| then it is inserted in the definition exactly as-is.
+% This is required to insert any of the special tokens |\Expand|,
+% |\NoExpand|, etc, as well as the internal token |\Q@END|, into a
+% definition. If the token immediately following |\NoExpand| is
+% an open-brace then the entire text of the group will be inserted
+% without expansion, and the outer level of grouping will be lost.
+% \item\DescribeMacro\Super|\Super| - When redefining an already
+% existing macro, |\Super| will expand to the previous definition of
+% the macro. Any macro parameters are automatically substituted.
+% If the macro is undefined, or if the new parameter text doesn't match
+% with the old text, then this will cause an error.
+% \item\DescribeMacro\Recurse|\Recurse| - This is complementary to
+% |\Super| and, while not strictly necessary, is included for clarity.
+% |\Recurse| is equivalent to
+% |\NoExpand\macro| when defining |\macro|. However, since |\macro|
+% is, by default, not expanded anyway, this is a bit redundant.
+% \end{itemize}
+%
+% \goodbreak
+% \subsection{Calling options}
+% When the name of the macro we're defining is encountered, there are
+% three different ways we might proceed: leave it alone (|\NoExpand|),
+% expand it with implicit parameters (|\Super|), or expand it with
+% explicit parameters (|\UnsafeExpand|).
+% We therefore allow zero, one, or two stars to come after |\Inline| to
+% change this behavior.
+% \begin{itemize}
+% \item\DescribeMacro\Inline|\Inline| - Without any stars, we default
+% to leaving the macro name alone, as in |\NoExpand\macro|.
+% This is the most consistent behavior with the rest of the package and
+% works regardless of whether the macro is being defined or redefined.
+% \item\DescribeMacro{\Inline*}|\Inline*| - With a single star, we treat
+% the macro name as a
+% call to |\Super| and expand it with parameters inserted automatically.
+% This is preferred over |\Expand| because it doesn't lead to the possible
+% surprises in the case of recursively-defined macros.
+% \item\DescribeMacro{\Inline**}|\Inline**| - Finally, with two stars,
+% the macro name is treated as if it were preceeded by |\UnsafeExpand|.
+% Any parameters must be inserted explicitly, and the expansion is
+% itself subject to inline processing. Note that this form is the most
+% dangerous.
+% \end{itemize}
+%
+% \index{Inline\bang=\verb!*+\Inline+\bang|usage}
+% \begingroup\def\index#1{}%\iffalse - index by hand! - \fi
+% \DescribeMacro{\Inline!}\endgroup
+% One final option applies only in the case of redefining an already-existing
+% macro. In this case, if the parameter text of the new definition differs
+% from the parameter text of the old definition, we will produce an error.
+% This error can be suppressed by adding a bang to the end of |\Inline|
+% (either before or after the stars), acknowledging that any ill consequences
+% that result are your own fault.
+%
+% \iffalse - this part not yet implemented!
+% The last special
+% token is \DescribeMacro\Args|\Args|. |\Args| inserts a protected
+% version of the argument text, that can be used when recursing, as
+% in |\Recurse\Args|, to make the exact same call again. Otherwise,
+% when using |\Recurse|, you are responsible for passing the arguments
+% yourself, unlike |\Super|, which behaves like a hypothetical
+% |\ExpandAfter\ExpandAfter\ExpandAfter\Expand\ExpandAfter\Recurse\Args|
+% (though |\ExpandAfter| doesn't currently
+% exist).
+% \fi
+%
+% \subsection{Known issues}
+% \begin{itemize}
+% \item If a macro is defined with a character other than |#| catcoded to
+% 6, then |\Super| will fail unless the same character is used in the
+% redefinition.
+% \end{itemize}
+%
+% \subsection{Related packages}
+% \begin{description}
+% \item[moredefs] The \textsf{moredefs} package in the \textsf{frankenstein}
+% collection provides some similar syntactic sugar, but is not as
+% expressive.
+% \end{description}
+%
+% \StopEventually{}
+%
+% \filbreak
+% \makeatletter
+% \section{Implementation}
+% \begin{macro}{\xa}
+% Make the |@|-sign into a letter for use in macro names. As long as the
+% packages are well-behaved, we can put this here and not later. We also
+% define |\xa| to be |\expandafter| for convenience.
+% \begin{macrocode}
+%<*package>
+\makeatletter
+\let\xa\expandafter
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macros}{\ifID@aborted,\ifID@star,\ifID@starstar,\ifID@bang}
+% We define a conditional so that we can gracefully abort in case of an error.
+% \begin{macrocode}
+\newif\ifID@aborted
+\newif\ifID@star
+\newif\ifID@starstar
+\newif\ifID@bang
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@toks,\ID@count}
+% At some point we need to stop using the internal toks registers and allocate
+% our own, because somebody might want to |\Expand{\the\toks@}| and expect
+% something else. We can get by with a single one though by defining a
+% |\ID@pdef| that doubles all the |#| signs and then does a regular def, so that
+% |\ID@pdef\cs\ID@toks ... \cs| will be the same as |\the\ID@toks|.
+% \begin{macrocode}
+\newtoks\ID@toks
+\newcount\ID@count
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\Inline,\ID@scandef}
+% These are the macros that get it all started. |\Inline| opens up
+% a group (which is closed at the end of |\ID@def|) and initializes a
+% toks register (we don't bother allocating it since we're in a group
+% and don't call any \LaTeX{} or \TeX{} macros that make use of allocated
+% toks registers. Then we scan the tokens until we
+% find either an |\edef| or an |\xdef|. If it's anything else, we just
+% add it to the toks register. We also have a list of bad tokens that
+% will cause an error message, so that we don't go too far before figuring
+% out what went wrong. Should |\Inline| be |\outer|?
+% \begin{macrocode}
+\DeclareRobustCommand\Inline{%
+ \begingroup
+ % Define a few ``quarks''
+ \def\Expand{\Expand}\def\Super{\Super}%
+ \def\UnsafeExpand{\UnsafeExpand}\def\MultiExpand{\MultiExpand}%
+ \def\Recurse{\Recurse}\def\NoExpand{\NoExpand}%
+ \def\Q@END{\Q@END}%
+ % Define a toks register
+ \ID@toks{}%
+ % Signal that we need to look for a star
+ \@testtrue\ID@starfalse\ID@starstarfalse\ID@bangfalse
+ % Start scanning for \def or \gdef
+ \futurelet\@foo\ID@scandef
+}
+\newcommand\ID@scandef{%
+ \let\next\ID@saveprefix % Default behavior
+ % If this is the first few tokens after the \Inline, check for * or !
+ \if@test
+ \ifx\@foo*%
+ \ifID@star
+ \ifID@bang\let\next\ID@sd@lastcheck\else\let\next\ID@sd@checkagain\fi
+ \ID@starstartrue
+ \else
+ \let\next\ID@sd@checkagain
+ \ID@startrue
+ \fi
+ \fi
+ \ifx\@foo!%
+ \ifID@bang\else % two bangs - can this be anything but an error?
+ \ID@bangtrue
+ \xa\let\xa\next\ifID@starstar\ID@sd@lastcheck\else\ID@sd@checkagain\fi
+ \fi
+ \fi
+ \fi
+ % Now look for a \def or \gdef
+ \ifx\@foo\def
+ \def\next{\ID@start\def}%
+ \fi
+ \ifx\@foo\gdef
+ \def\next{\ID@start\gdef}%
+ \fi
+ \ifcat\noexpand\@foo\space
+ \def\next{\ID@toks\xa\xa\xa{\xa\the\xa\ID@toks\space}%
+ \xa\futurelet\xa\@foo\xa\ID@scandef\ID@unspace}% copied from ID@space
+ \fi
+ % Error checking (minimal)
+ \@testfalse
+ \ifx\@foo\edef\@testtrue\fi\ifx\@foo\xdef\@testtrue\fi
+ \ifx\@foo\newcommand\@testtrue\fi\ifx\@foo\renewcommand\@testtrue\fi
+ \ifx\@foo\DeclareRobustCommand\@testtrue\fi
+ \if@test\PackageError{inlinedef}{Only \protect\def\space and \protect\gdef\space are
+ allowed after \protect\Inline,\MessageBreak but some other type of
+ definition was found}\@eha\let\next\ID@abort\fi
+ \@testfalse
+ \ifx\@foo\bgroup\@testtrue\fi\ifx\@foo\let\@testtrue\fi
+ \if@test\PackageError{inlinedef}{No \protect\def\space or \protect\gdef\space found
+ after \protect\Inline}\@ehd\def\next{\ID@abort{}}\fi
+ \next
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@sd@checkagain,\ID@sd@lastcheck}
+% These just get the scandef loop started again and set |\@testtrue| if we're
+% still looking for stars and/or bangs.
+% \begin{macrocode}
+\def\ID@sd@checkagain#1{\@testtrue\futurelet\@foo\ID@scandef}
+\def\ID@sd@lastcheck#1{\futurelet\@foo\ID@scandef}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@saveprefix,\ID@abort,\ID@start}
+% These are the three macros called by |\ID@scandef| to either save the
+% prefix (|\long|, |\outer|, etc) to a token register, (attempt to) abort
+% the procedure in case of an error, or else get the definition started
+% once we find the |\edef| or |\xdef|.
+% \begin{macrocode}
+\newcommand*\ID@saveprefix[1]{%
+ \ID@toks\xa{\the\ID@toks#1}%
+ \futurelet\@foo\ID@scandef
+}
+% \end{macrocode}
+% In case the error was just the wrong type of |\def|, we consume up to and
+% including the first explicit group.
+% \begin{macrocode}
+\newcommand\ID@abort{}\def\ID@abort#1#{\endgroup\@gobble}
+% \end{macrocode}
+% To get the definition process started, we take |#1| as the definition
+% command to save (either |\def| or |\gdef|), |#2| as the command that
+% was provided (which we discard), |#3| is the name of the macro to define,
+% and |#4| is the parameter text, delimited by a begin-group character.
+% \begin{macrocode}
+\newcommand\ID@start{}\def\ID@start#1#2#3#4#{%
+ \xa\def\xa\ID@prefix\xa{\the\ID@toks#1}%
+ \ID@def#3{#4}%
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@fixparams,\ID@fp@start}
+% In order for |\Super| to work properly, we need to fix the parameter
+% list to put the |#1| in braces, since it actually consists of two tokens.
+% Therefore, |\ID@fixparams| takes everything between it and |\Q@END|
+% and puts it in |\toks@fixedparams|. If it finds a |#|, then it checks
+% whether the argument is delimited or not, and if not, it inserts
+% a pair of braces. We currently define these with |\newcommand*|, though
+% if there were a reason we could conceivably make them |\long|.
+% Update: we now use |\ID@toks| and then define |\ID@fixedparams| from there.
+% \begin{macrocode}
+\newcommand*\ID@fixparams{\begingroup\ID@toks{}\futurelet\@foo\ID@fp@start}
+\newcommand*\ID@fp@start{%
+ \let\next\ID@fp@normal
+ \ifx\@foo\Q@END\let\next\ID@fp@end\fi
+ \ifcat\noexpand\@foo##\let\next\ID@fp@param\fi % was \ifx\@foo - broken?
+ \ifcat\noexpand\@foo\space
+ \def\next{\ID@toks\xa\xa\xa{\xa\the\xa\ID@toks\space}%
+ \xa\futurelet\xa\@foo\xa\ID@fp@start\ID@unspace}% copied from ID@space
+ \fi
+ \next
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@fp@normal,\ID@fp@param,\ID@fp@end}
+% These are the two commands that |\ID@fixparams| calls to actually
+% consume each token, depending on whether it was a parameter.
+% \begin{macrocode}
+\newcommand*\ID@fp@normal[1]{%
+ \ID@toks\xa{\the\ID@toks#1}\futurelet\@foo\ID@fp@start
+}
+\newcommand*\ID@fp@param[2]{%
+ % We used to just use ###2 but need two more now...
+ % Need another doubling because we're now using it inside a def...
+ \def\@arg{#########2}% assume delimited unless we find # or \Q@END
+ \ifcat\noexpand\@foo##\def\@arg{{#########2}}\fi
+ \ifx\@foo\Q@END\def\@arg{{#########2}}\fi
+ \ID@toks\xa\xa\xa{\xa\the\xa\ID@toks\@arg}%
+ \futurelet\@foo\ID@fp@start
+}
+\newcommand*\ID@fp@end[1]{%
+ \xa\endgroup\xa\def\xa\ID@fixedparams\xa{\the\ID@toks}%
+}
+% \end{macrocode}
+% This should deal with everything \emph{except} a single |#|,
+% but that's a hairy situation in the first place and we really don't
+% want to allow using |\Super| in that case. We could probably make
+% an error message to say so. The only other alternative would be to
+% ``go back in time'' and change the last |{#1}| to a |#1{}| and even
+% then we end up with an extra |{}| on the input stream. I can't actually
+% figure out how to test if this has happened in |...@insertp|, anyway.
+% \end{macros}
+%
+% \begin{macros}{\ID@def}
+% Here is where the ``main loop'' is initiated. We start by
+% pretending to allocate another token register (though we actually
+% just |\toksdef| it), and then define a number of quarks which we
+% use as delimiters for various purposes. Finally, we start scanning.
+% Afterwards, we test if there was an error and if not, we expand the
+% definition command \emph{after} the |\endgroup| so that we can clean
+% up all the local variables.
+% \begin{macrocode}
+\newcommand\ID@def[3]{%
+ % Other definitions
+ \global\ID@abortedfalse
+ \let\@reservedc#1%
+ \def\@macroname{#1}% for error message
+ \ID@fixparams#2\Q@END
+ % These are used by \Super but easier to define here
+ \def\@reservedb#2{}%
+ \edef\@reservedb{\xa\ID@getprefix\meaning\@reservedb\Q@END}%
+ \ifx#1\undefined % hopefully nobody's going around defining \undefined
+ \let\@reserveda\undefined
+ \else
+ \edef\@reserveda{\xa\ID@getprefix\meaning#1\Q@END}%
+ \fi
+ % Scan it all into \ID@toks
+ \ifID@bang\else\ID@checkusage\fi
+ \ifID@aborted\else
+ \ID@toks{}\ID@scan#3\Q@END{}% we need the {} so that the the #1# works...
+ \fi
+ \ifID@aborted
+ \def\command{}% gracefully ignore
+ \else
+ \let#1\relax % don't want it expanded in the |\edef| below
+ % We don't need to worry about scope anymore
+ \toks0\ID@toks % likely redundant, but what if ID@toks=1 or 2?
+ \toks1\xa{\ID@prefix}% (easiest way to avoid expansion...)
+ \toks2{#2}%
+ \edef\command{\the\toks1#1\the\toks2{\the\toks0}}%
+ % We could also write this with 3 levels of \xa...
+ \fi
+ \global\ID@toks\xa{\ID@fixedparams}% just to test...
+ \expandafter\endgroup\command
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@scan,\ID@switch}
+% This is the main loop. We look at each token in turn and deal with it,
+% mostly by inserting it into |\ID@toks|. If it's a |\Q@END| then we're done.
+% If it's |\Super| or |\Expand| then we need to do something special.
+% If it's a space, then we need to add the space to
+% |\ID@toks|. Finally, if it's a |\bgroup| then we need to figure out whether
+% it's an explicit or an implicit group. In the former case, we descend into
+% it (writing |{...}| to |\ID@toks|) and in the latter, we just pick it up like
+% normal.
+% \begin{macrocode}
+\newcommand\ID@scan{\futurelet\@foo\ID@switch}
+\newcommand\ID@switch{%
+ \let\next\ID@normal
+ \ifx\@foo\Q@END
+ \let\next\@gobble
+ \fi
+ \ifx\@foo\@reservedc % macro name... what to do?
+ \ifID@star
+ \ifID@starstar
+ \let\next\ID@expandmacro
+ \else
+ \let\next\ID@expandsuper
+ \fi
+ \fi
+ \fi
+ \ifx\@foo\Super
+ \let\next\ID@expandsuper
+ \fi
+ \ifx\@foo\Expand
+ \let\next\ID@expandnext
+ \fi
+ \ifx\@foo\UnsafeExpand
+ \let\next\ID@expandunsafe
+ \fi
+ \ifx\@foo\MultiExpand
+ \let\next\ID@expandmulti
+ \fi
+ \ifx\@foo\NoExpand
+ \let\next\ID@noexpandnext
+ \fi
+ \ifx\@foo\Recurse
+ \def\next{\xa\xa\xa\ID@scan\xa\xa\xa\NoExpand\xa\@macroname\@gobble}%
+ \fi
+ \ifcat\noexpand\@foo\space
+ \let\next\ID@space
+ \fi
+ \ifcat\noexpand\@foo\bgroup
+ \let\next\ID@trygroup
+ \fi
+ \next
+}
+% \end{macrocode}
+% \end{macros}
+% \begin{macros}{\ID@space,\ID@unspace}
+% It's a bit tricky to deal with spaces properly. In particular,
+% picking up just a space from the token list takes some doing. We
+% need a fully-expandable macro so that the whole thing disappears.
+% |\ID@space| then adds a space to |\ID@toks| and then expands
+% |\ID@unspace| after |\ID@scan| so that the |\futurelet| sees the
+% next token after the space and can deal with it properly.
+% We need the |\expandafter| in defining |\ID@unspace| to actually get the
+% space token into the parameter text; otherwise, it gets
+% gobbled up by the lexer after reading the control sequence name.
+% \begin{macrocode}
+\newcommand\ID@space{%
+ \ID@toks\xa\xa\xa{\xa\the\xa\ID@toks\space}%
+ \xa\ID@scan\ID@unspace
+}
+\newcommand\ID@unspace{}
+\xa\def\xa\ID@unspace\space{}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@trygroup,\ID@recurse}
+% The next two macros are used to check if the |\bgroup| token was an
+% explicit or an implicit grouping character. If it's explicit then
+% the next macro that takes an argument will scoop the whole thing up
+% at once, and so we need to be aware of this to deal with it.
+% |\ID@trygroup| uses the special |#| delimiter and compares the argument
+% with |\@empty| to see if anything comes before the next |{}|. If it
+% doesn't find anything then it was an explicit group and we recurse.
+% One consequence of this is that we always need to put a |{}| after
+% |\Q@END| so that we don't get an error here.
+% \begin{macrocode}
+\newcommand\ID@trygroup{}
+\long\def\ID@trygroup#1#{% check for explicit/implicit grouping!
+ \def\@reservedd{#1}%
+ \xa\let\xa\next
+ \ifx\@reservedd\@empty\ID@recurse\else\ID@normal\fi
+ \next#1%
+}
+% \end{macrocode}
+% Here we need to do some gymnastics to get the |{| and |}| tokens into
+% the toks register. It would be easiest if we could just add them one
+% at a time, but we can only add \emph{balanced text}, so we need to
+% expand the whole thing \emph{first} and then add it back to the register
+% we expanded it into. Thus, we enter a new level of grouping to save
+% the contents of |\ID@toks|, expand the inner group, and use |\expandafter|
+% across an |\endgroup| to get the correct tokens in the right place in
+% |\ID@toks|.
+% \begin{macrocode}
+\newcommand\ID@recurse[1]{%
+ \begingroup\ID@toks{}% start a new level of grouping and empty \ID@toks
+ \ID@scan#1\Q@END{}% % parse...
+ \xa\endgroup\xa % this fiasco should get the job done...!
+ \ID@toks\xa\xa\xa{\xa\the\xa\ID@toks\xa{\the\ID@toks}}%
+ \ID@scan
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@normal,ID@noexpandnext}
+% This is what we do when it's not anything special.
+% \begin{macrocode}
+\newcommand\ID@normal[1]{\ID@toks\xa{\the\ID@toks#1}\ID@scan}
+\newcommand\ID@noexpandnext[2]{\ID@toks\xa{\the\ID@toks#2}\ID@scan}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@checkusage,\ID@checkredef}
+% Here we define tests that will issue errors if the parameter
+% texts aren't the same, or the original function isn't defined.
+% \begin{macrocode}
+\newcommand*\ID@checkusage{%
+ % Make sure parameter lists are the same, does nothing if undefined
+ \ifx\@reserveda\@reservedb
+ \else
+ % Error messages
+ \ifx\@reserveda\undefined % undefined - okay
+ \else
+ \global\ID@abortedtrue
+ \ifx\@foo\Super
+ \PackageError{inlinedef}{Cannot use \protect\Super\space in \expandafter
+ \protect\@macroname\space because\MessageBreak
+ parameter lists don't match:\MessageBreak
+ `\@reservedb' (new) != `\@reserveda' (old)}\@eha
+ \else
+ \ifID@bang % auto-expansion forbidden
+ \PackageError{inlinedef}{Cannot use \protect\Inline* auto-expansion in
+ \expandafter\protect\@macroname\MessageBreak
+ because parameter lists don't match:\MessageBreak
+ `\@reservedb' (new) != `\@reserveda' (old)}\@eha
+ \else
+ \PackageError{inlinedef}{Parameter lists for
+ \expandafter\protect\@macroname\space don't match:\MessageBreak
+ `\@reservedb' (new) != `\@reserveda' (old)\MessageBreak
+ Use !-form of \protect\Inline\space to ignore this}\@eha
+ \fi
+ \fi
+ \fi
+ \fi
+}
+\newcommand*\ID@checkredef{%
+ \ifx\@reserveda\undefined % undefined - okay
+ \PackageError{inlinedef}{Cannot use \ifx\@foo\Super\protect\Super\space
+ \else\protect\Inline** \fi in \expandafter\protect\@macroname\space
+ because \MessageBreak it hasn't been defined yet}%
+ \@eha
+ \global\ID@abortedtrue
+ \fi
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@expandsuper,\ID@expandnext,\ID@expandmulti,%
+% \ID@expandunsafe,\ID@expandmacro}
+% These correspond to the two special tokens, |\Super| and |\Expand|.
+% The first one tests that the parameter list is alright and that the
+% original command wasn't undefined. If all is well, it expands everything
+% in the right order. The second one is simpler, just inserting an
+% |\expandafter| before the continuation (|\ID@scan|) to expand whatever
+% comes next once. There is (yet) no way to fully-expand, although several
+% |\Expand|s and |\expandafter|s can be stacked cleverly to expand several
+% things in a specific order.
+% \begin{macrocode}
+\newcommand*\ID@expandsuper[1]{%
+ \ID@checkusage\ID@checkredef
+ \ifID@aborted\else
+ \ID@toks\xa\xa\xa\xa\xa\xa\xa
+ {\xa\xa\xa\the\xa\xa\xa\ID@toks\xa\@reservedc\ID@fixedparams}%
+ \fi
+ \ID@scan
+}
+\newcommand\ID@expandnext[2]{%
+ \ID@toks\xa\xa\xa{\xa\the\xa\ID@toks#2}\ID@scan
+}
+\newcommand\ID@expandmulti[3]{%
+ \begingroup % #1 is the \MultiExpand...
+ \ID@count#2\relax % this will need to be allocated too!
+ \ID@toks{#3}%
+ \@testtrue\ifnum\ID@count<\@ne\@testfalse\fi
+ \@whilesw\if@test\fi{%
+ \ID@toks\xa\xa\xa{\the\ID@toks}% one expansion...
+ \advance\ID@count\m@ne\ifnum\ID@count<\@ne\@testfalse\fi
+ }%
+ \xa\endgroup\xa\ID@toks\xa\xa\xa{\xa\the\xa\ID@toks\the\ID@toks}\ID@scan
+}
+
+\newcommand*\ID@expandunsafe[1]{\expandafter\ID@scan}
+\newcommand*\ID@expandmacro[1]{\expandafter\ID@scan\@reservedc}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\ID@getprefix}
+% This is used to compare argument lists.
+% \begin{macrocode}
+\newcommand\ID@getprefix{}\long\def\ID@getprefix#1:#2->#3\Q@END{\detokenize{#2}}
+% \end{macrocode}
+% \end{macros}
+%
+% Finally we clean up by restoring |@|'s catcode.
+% \begin{macrocode}
+\makeatother
+%</package>
+% \end{macrocode}
+%
+% \StopIndexing
+% \filbreak
+% \section{Test suite}
+% We include a somewhat-comprehensive test suite to make sure that everything
+% is working. If it works properly, it should output nothing.
+%
+% First we define a few helper-functions to test for errors, etc.
+% \begin{macrocode}
+%<*testsuite>
+\makeatletter
+\errorcontextlines=10
+\def\WantError#1#2#3{%
+ \let\WE@packageerror\PackageError
+ \def\PackageError##1##2##3{%
+ \protected@edef\@goterror{##2}\protected@edef\@wanterror{#2}%
+ \edef\@goterror{\xa\detokenize\xa{\@goterror}}%
+ \edef\@wanterror{\xa\detokenize\xa{\@wanterror}}%
+ \protected@edef\@gotpackage{##1}\protected@edef\@wantpackage{#1}%
+ \edef\@gotpackage{\xa\detokenize\xa{\@gotpackage}}%
+ \edef\@wantpackage{\xa\detokenize\xa{\@wantpackage}}%
+ \global\let\PackageError\WE@packageerror
+ \@tempswafalse
+ \ifx\@gotpackage\@wantpackage\else\message{^^J(arg 1 differs)^^J}\@tempswatrue\fi
+ \ifx\@goterror\@wanterror\else\message{^^J(arg 2 differs)^^J}\@tempswatrue\fi
+ \ifx#3##3\else\message{^^J(arg 3 differs)^^J}\@tempswatrue\fi
+ \if@tempswa\PackageError{inlinedef (test)}{wrong error}\@eha\PackageError{##1}{##2}##3\fi
+ }%
+}
+
+\def\CheckError{%
+ \ifx\PackageError\WE@packageerror\else
+ \PackageError{inlinedef (test)}{expected error not thrown}\@eha\fi
+ \global\let\PackageError\WE@packageerror
+}
+\newcommand\CheckDefinition[1][]{\@CheckDefinition{#1}}
+\def\@CheckDefinition#1#2#3#{\@checkdefn{#1}#2{#3}}
+\def\@checkdefn#1#2#3#4{#1\def\@reserveda#3{#4}\ifx#2\@reserveda\else
+ \message{^^J^^J\meaning#2^^J(got)vs(wanted)^^J\meaning\@reserveda^^J^^J}
+ \PackageError{inlinedef (test)}{definition of \detokenize{#2}didn't match}\@eha\fi
+}
+\let\eha\@eha\let\ehd\@ehd
+\makeatother
+% \end{macrocode}
+%
+% Here we predefine copies of the errors so that we can look for them easily
+% \begin{macrocode}
+\catcode`\#=12
+\def\pound{#}
+\catcode`\#=6
+
+\def\WantSuperNoMatch#1#2#3{%
+ \WantError{inlinedef}{Cannot use \protect\Super\space in
+ \protect#1\space because\MessageBreak
+ parameter lists don't match:\MessageBreak
+ `#3' (new) != `#2' (old)}\eha
+}
+\def\WantStarNoMatch#1#2#3{%
+ \WantError{inlinedef}{Cannot use \protect\Inline* auto-expansion in
+ \protect#1\MessageBreak because
+ parameter lists don't match:\MessageBreak
+ `#3' (new) != `#2' (old)}\eha
+}
+\def\WantNoMatchBang#1#2#3{%
+\WantError{inlinedef}{Parameter lists for
+ \protect#1\space don't match:\MessageBreak
+ `#3' (new) != `#2' (old)\MessageBreak
+ Use !-form of \protect\Inline\space to ignore this}\eha
+}
+\def\WantOnlyDefGdef{%
+ \WantError{inlinedef}{Only \protect\def\space and \protect\gdef\space are
+ allowed after \protect\Inline,\MessageBreak but some other type of
+ definition was found}\eha
+}
+\def\WantNoDefGdef{%
+ \WantError{inlinedef}{No \protect\def\space or \protect\gdef\space found
+ after \protect\Inline}\ehd
+}
+\def\WantSuperNoRedef#1{%
+ \WantError{inlinedef}{Cannot use \protect\Super\space in \protect#1\space
+ because \MessageBreak it hasn't been defined yet}\eha
+}
+% \end{macrocode}
+%
+% Now we start the actual tests.
+% \begin{macrocode}
+ % I. Basic stuff
+ % A. Simple definition
+\let\a\undefined
+\Inline\def\a{b}
+\CheckDefinition\a{b}
+
+ % B. Simple redefinition
+\def\a{b}
+\Inline\def\a{d}
+\CheckDefinition\a{d}
+
+ % C. Erroneous redefinition (needs !)
+\def\a{b}
+\WantNoMatchBang\a{}{\pound1}
+\Inline\def\a#1{c}
+\CheckError
+\CheckDefinition\a{b} % shouldn't have changed
+
+\def\a{b}
+\Inline!\def\a#1{c}
+\CheckDefinition\a#1{c}
+
+ % D. Local/global definition
+\def\a{b}
+\begingroup
+\Inline\def\a{c}
+\endgroup
+\CheckDefinition\a{b}
+
+\begingroup
+\Inline\gdef\a{c}
+\endgroup
+\CheckDefinition\a{c}
+
+{\Inline\global\def\a{d}}
+\CheckDefinition\a{d}
+
+ % E. Collecting arguments
+\Inline\long\def\a{e}
+\CheckDefinition[\long]\a{e}
+
+\Inline\outer\def\a{f}
+\edef\a{\meaning\a}
+\edef\b{\detokenize{\outer macro:->f}}
+\xa\CheckDefinition\xa\a\xa{\b}
+
+\Inline\long\outer\def\a{g}
+\edef\a{\meaning\a}
+\edef\b{\string\long\string\outer\space\detokenize{macro:->g}}
+\xa\CheckDefinition\xa\a\xa{\b}
+
+\def\a{g}
+\Inline!\long\def\a#1{h}
+\CheckDefinition[\long]\a#1{h}
+
+ % II. Special tokens
+ % A. Recursion
+\def\a{b}
+\Inline\def\a{a\a c}
+\CheckDefinition\a{a\a c}
+
+ % B. Expansion
+\def\a{b}
+\Inline\def\a{a\Expand\a c}
+\CheckDefinition\a{abc}
+
+\def\a{b}
+\Inline\def\a{\Expand a\Expand\a\Expand c}
+\CheckDefinition\a{abc}
+
+\def\a{\b}
+\def\b{c}
+\Inline\def\a{a\Expand\a c}
+\CheckDefinition\a{a\b c}
+
+\toks0{b}\toks1{d}
+\Inline\def\a{a\the\toks0c\the\toks1e}
+\CheckDefinition\a{a\the\toks0c\the\toks1e}
+
+\Inline\def\a{a\Expand{\the\toks0}c\Expand{\the\toks1}e}
+\CheckDefinition\a{abcde}
+
+\Inline\def\a{\Expand{a\the\toks0}c\Expand{\the\toks1}e}
+\CheckDefinition\a{a\the\toks0cde}
+
+\Inline\def\a{\Expand{\expandafter a\the\toks0}c\Expand{\the\toks1e}}
+\CheckDefinition\a{abcde}
+
+ % C. MultiExpand
+\def\x{\y}
+\def\y{\z}
+\def\z{0}
+\Inline\def\a{a\MultiExpand0\x b}
+\CheckDefinition\a{a\x b}
+
+\Inline\def\a{a\MultiExpand1\x b}
+\CheckDefinition\a{a\y b}
+
+\Inline\def\a{a\MultiExpand2\x b}
+\CheckDefinition\a{a\z b}
+
+\Inline\def\a{a\MultiExpand3\x b}
+\CheckDefinition\a{a0b}
+
+\Inline\def\a{a\MultiExpand{10}\x b}
+\CheckDefinition\a{a0b}
+
+ % i. use with \expandafter
+\Inline\def\a{a\MultiExpand2{\expandafter\expandafter\x\x}b}
+\CheckDefinition\a{a\y\y b}
+
+\Inline\def\a{a\MultiExpand1{\expandafter\expandafter\x\x}b}
+\CheckDefinition\a{a\expandafter\y\x b}
+
+\Inline\def\a{a\MultiExpand2{\expandafter\expandafter\expandafter\x\x}b}
+\CheckDefinition\a{a\x\z b}
+
+\Inline\def\a{a\MultiExpand3{\expandafter\expandafter\expandafter\x\x}b}
+\CheckDefinition\a{a\y\z b}
+
+\Inline\def\a{a\MultiExpand4{\expandafter\expandafter\expandafter\x\x}b}
+\CheckDefinition\a{a\z\z b}
+
+\Inline\def\a{a\MultiExpand5{\expandafter\expandafter\expandafter\x\x}b}
+\CheckDefinition\a{a0\z b}
+
+ % D. UnsafeExpand
+\def\x{b\Super c}
+\Inline\def\a{a\Expand\x d}
+\CheckDefinition\a{ab\Super cd}
+
+\def\a{0}
+\Inline\def\a{a\UnsafeExpand\x d}
+\CheckDefinition\a{ab0cd}
+
+\def\a{b\Super d}
+\Inline\def\a{a\UnsafeExpand\a e}
+\CheckDefinition\a{abb\Super dde}
+
+\def\a{b\Super d}
+\Inline**\def\a{a\a e}
+\CheckDefinition\a{abb\Super dde}
+
+ % Would be nice if we could catch TeX capacity exceeded errors...
+ % Then try \def\a{b\a d}\Inline**\def\a{a\a e}
+
+\def\x#1{b#1d}
+\Inline\def\a{a\x ce}
+\CheckDefinition\a{a\x ce}
+
+\Inline\def\a{a\UnsafeExpand\x ce}
+\CheckDefinition\a{abcde}
+
+ % E. NoExpand
+\Inline\def\a{a\NoExpand\Expand\x b}
+\CheckDefinition\a{a\Expand\x b}
+
+\Inline*\def\a{a\NoExpand\a b}
+\CheckDefinition\a{a\a b}
+
+\Inline**\def\a{a\NoExpand\a b}
+\CheckDefinition\a{a\a b}
+
+\Inline\def\a{a\NoExpand{\Expand\x\Expand\y}b}
+\CheckDefinition\a{a\Expand\x\Expand\y b}
+
+ % F. Super
+\def\a{bcd}
+\Inline\def\a{a\Super e}
+\CheckDefinition\a{abcde}
+
+\def\a#1{b#1d}
+\Inline\def\a#1{a\Super e}
+\CheckDefinition\a#1{ab#1de}
+
+\def\a#1{b#1d}
+\Inline*\def\a#1{a\Super e}
+\CheckDefinition\a#1{ab#1de}
+
+\def\a#1{b#1d}
+\Inline**\def\a#1{a\Super e}
+\CheckDefinition\a#1{ab#1de}
+
+ % G. Recurse
+\def\a{q}
+\Inline\def\a{a\Recurse b}
+\CheckDefinition\a{a\a b}
+
+\Inline*\def\a{a\Recurse b}
+\CheckDefinition\a{a\a b}
+
+\Inline**\def\a{a\Recurse b}
+\CheckDefinition\a{a\a b}
+
+ % III. Tricky parsing
+ % A. Spaces
+\def\a{b c d}
+\Inline\def\a{a \Super e}
+\CheckDefinition\a{a b c de}
+
+\def\a{b c d}
+\Inline\def\a{a \Expand\a e}
+\CheckDefinition\a{a b c de}
+
+\def\a{b c d}
+\Inline\def\a{a \Expand{\a} e}
+\CheckDefinition\a{a b c d e}
+
+\Inline\def\a{a\NoExpand{\Expand\x\Expand\y} b}
+\xa\CheckDefinition\xa\a\xa{\xa a\xa\Expand\xa\x\xa\Expand\xa\y\space b}
+
+ % B. Grouping
+\def\a{b{c d}e}
+\Inline\def\a{{a\Super}f\Super}
+\CheckDefinition\a{{ab{c d}e}fb{c d}e}
+
+\Inline\def\a{{ }{}}
+\Inline\def\a{{\Expand\a\a}{} {{\Super}{}}}
+\CheckDefinition\a{{{ }{}\a}{} {{{ }{}}{}}}
+
+ % C. Parameters
+\def\a#1bcd#2{[#1...#2]}
+\Inline\def\a#1bcd#2{a\Super b}
+\CheckDefinition\a#1bcd#2{a[#1...#2]b}
+
+\def\a#1\##2{y}
+\Inline\def\a#1\##2{x\UnsafeExpand\a{#1}\#{#2}z}
+\CheckDefinition\a#1\##2{xyz}
+
+\def\a#1\##2{#1y#2}
+\Inline\def\a#1\##2{x\UnsafeExpand\a{#1}\#{#2}z}
+\CheckDefinition\a#1\##2{x#1y#2z}
+
+ % i. spaces!
+\def\a #1 {y}
+\Inline\def\a#1 {x\Super z}
+\CheckDefinition\a#1 {xyz}
+
+\xa\def\xa\a\space{y}
+\xa\Inline\xa\def\xa\a\space{x\Super z}
+\xa\CheckDefinition\xa\a\space{xyz}
+
+ % ii. funky catcodes
+ %%%% This test fails.
+ %\begingroup
+ % \catcode`&=6
+ % \def\a&1{b#1d}
+ % \Inline\def\a#1{a\Super e}
+ % \CheckDefinition\a#1{b&1d}
+ %\endgroup
+
+ % D. Active characters
+\begingroup
+ \catcode`A=13
+ \defA#1{b#1d}
+ \Inline\defA#1{aAe}
+ \CheckDefinitionA#1{aAe}
+
+ \defA#1{b#1d}
+ \Inline*\defA#1{aAe}
+ \CheckDefinitionA#1{ab#1de}
+\endgroup
+
+ % IV. Auto-expansion
+
+\def\a#1{y}
+\Inline\def\a#1{x\a z}
+\CheckDefinition\a#1{x\a z}
+
+\def\a#1{y}
+\Inline*\def\a#1{x\a z}
+\CheckDefinition\a#1{xyz}
+
+\def\a#1{y}
+\Inline**\def\a#1{x\a{#1}z}
+\CheckDefinition\a#1{xyz}
+
+ % A. With delimited arguments
+\def\a[#1]#2{#1y#2}
+\Inline*\def\a[#1]#2{x\a z}
+\CheckDefinition\a[#1]#2{x#1y#2z}
+
+\def\a[#1]#2{#1y#2}
+\Inline**\def\a[#1]#2{x\a[#1]{#2}z}
+\CheckDefinition\a[#1]#2{x#1y#2z}
+
+ % V. Errors
+
+\def\bar#1{d #1 f}
+\def\x{b}
+
+\WantSuperNoMatch\a{\pound1}{.\pound1}
+\def\a#1{x}
+\Inline!\def\a.#1{y\Super}
+\CheckError
+\CheckDefinition\a#1{x}
+
+\WantStarNoMatch\a{\pound1}{.\pound1}
+\def\a#1{x}
+\Inline*!\def\a.#1{y\a}
+\CheckError
+\CheckDefinition\a#1{x}
+
+\def\a#1{x}
+\Inline!\def\a.#1{y} % ok
+\CheckDefinition\a.#1{y}
+
+\WantOnlyDefGdef
+\def\foo{a}
+\Inline\edef\foo{b}
+\CheckError
+\CheckDefinition\foo{a}
+\let\foo\undefined
+
+\WantOnlyDefGdef
+\Inline\global\outer\xdef{}
+\CheckError
+
+\WantOnlyDefGdef
+\Inline\global\outer\abc\space vbcda s \newcommand{}
+\CheckError
+
+\WantNoDefGdef
+\Inline\let\relax\relax
+\CheckError
+
+\WantNoDefGdef
+\Inline{}
+\CheckError
+
+\WantSuperNoRedef\foo
+\Inline\def\foo#1{a \Expand\x\space cd #1 fg \x\space i\Super}
+\CheckError
+
+\WantNoMatchBang\a{}{\pound1}
+\def\a{b}
+\Inline\def\a#1{a\a c}
+\CheckError
+
+ % Miscellaneous (read: "old") tests
+
+\def\test#1{d #1 f}
+\Inline\def\test#1{a \Expand\x\space c\Super g \x\space i}
+\CheckDefinition\test#1{a b\space cd #1 fg \x\space i}
+
+\Inline*\def\bar#1{a \Expand\x\space c\bar g \x\space i}
+\CheckDefinition\bar#1{a b\space cd #1 fg \x\space i}
+
+\def\bar#1{d #1 f}
+\Inline**\def\bar#1{a \Expand\x\space c\bar{#1}g \x\space i}
+\CheckDefinition\bar#1{a b\space cd #1 fg \x\space i}
+
+\Inline\def\foo#1{a \Expand\x\space cd #1 fg \x\space i}
+\CheckDefinition\foo#1{a b\space cd #1 fg \x\space i}
+
+\def\a{b}
+\Inline!\def\a#1{a\Expand\a c}
+\CheckDefinition\a#1{abc}
+
+\def\a{b}
+\Inline!**\def\a#1{a\a c}
+\CheckDefinition\a#1{abc}
+
+\Inline\def\a#1{a\a c}
+\CheckDefinition\a#1{a\a c}
+
+\Inline\def\a#1{a\Recurse c}
+\CheckDefinition\a#1{a\a c}
+
+\Inline!\def\a{a\NoExpand{b\Super c}d}
+\CheckDefinition\a{ab\Super cd}
+
+\Inline*\def\a{gh\a jk}
+\CheckDefinition\a{ghab\Super cdjk}
+
+ % SURPRISE! unsafe expansion...
+\def\a{ab\Super cd}
+\Inline**\def\a{gh\a jk}
+\CheckDefinition\a{ghabab\Super cdcdjk}
+
+\def\a{ab\Super cd}
+\Inline\def\a{gh\UnsafeExpand\a jk}
+\CheckDefinition\a{ghabab\Super cdcdjk}
+
+\def\x{\x a} % This is a fun one...!
+\Inline\def\a{\MultiExpand{5}\x}
+\CheckDefinition\a{\x aaaaa}
+
+\message{^^JAll tests completed.^^J}
+
+\begin{document}
+\end{document}
+%</testsuite>
+% \end{macrocode}
+%
+% \makeatother
+% \eject
+% \Finale
+%
+%
+% \iffalse
+%
+% The next line of code prevents DocStrip from adding the
+% character table to the generated files(s).
+
+% Removed stuff
+
+\endinput
+%
+% \fi
+%
+%% \CharacterTable
+%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+%% Digits \0\1\2\3\4\5\6\7\8\9
+%% Exclamation \! Double quote \" Hash (number) \#
+%% Dollar \$ Percent \% Ampersand \&
+%% Acute accent \' Left paren \( Right paren \)
+%% Asterisk \* Plus \+ Comma \,
+%% Minus \- Point \. Solidus \/
+%% Colon \: Semicolon \; Less than \<
+%% Equals \= Greater than \> Question mark \?
+%% Commercial at \@ Left bracket \[ Backslash \\
+%% Right bracket \] Circumflex \^ Underscore \_
+%% Grave accent \` Left brace \{ Vertical bar \|
+%% Right brace \} Tilde \~}
+%%