LaTeX: collecting "values" and spitting them out several times?
Well, long story.
The most common way to collect some tokens and then process them, is by storing them inside either a so-called tokens register, or by adding the new tokens to an existing command. The first trick is adding them to an existing tokens register or command rather than overwriting the existing value. You can do this by using the low-level TeX primitive \expandafter
. For commands, this would look like
\expandafter\def\expandafter\cmd\expandafter{\cmd <new contents here>}
The \expandafter
tells TeX to temporarily ignore the next command (or token) and work on the one after it. (One level expansion to be precise.) For example,
\def\cmd{A}
\expandafter\def\expandafter\cmd\expandafter{\cmd <new contents here>}
is effectively
\def\cmd{A<new contents here>}
Tokens registers work a little differently, but the idea is the same:
\newtoks{\argumenttoks} % you must allocate a toks once, ever, before using it
...
\argumenttoks={A}% like \(re)newcommand\cmd{A}
\argumenttoks=\expandafter{\the\argumenttoks <new contents here>}
The difference is between both methods is 1) speed (toks are faster) and 2) toks allow TeX chars like #, and \def
or \(re)newcommand
don't like that, and 3) toks are considered pretty low-level, and there is finite number of them, which you must claim (through \newtoks
).
We're half way there now. The next thing is: how can I read the list? The most common way to read a list, is to execute it, strangely enough. But to process each item with a command, you need to be able to add that command before each list element. The trick commonly used is to actually add that command when you're building the list:
\newcommand{\argument}[3]{%
\argumenttoks=\expandafter{\the\argumenttoks \showarg{#1}{#2}{#3}}%
}
This way,
\argument{bar}{int}{The answer to the ultimate question.}
\argument{baz}{int}{Number of years you are willing to wait for the question.}
is stored as a list
\showarg{bar}{int}{The answer to the ultimate question.}
\showarg{baz}{int}{Number of years you are willing to wait for the question.}
So to use the list, you must execute it at the right location, and make sure \showarg
does the right thing at that point.
\newtoks{\argumenttoks}
\newenvironment{function}[1]{%
\argumenttoks={}% make sure it's empty
% other stuff here
}{% \end{function}
\textit{\storedreturntype} \storedfunctionname
% now the arglist
\let\showarg=\showargcommaseparated
\let\argcomma=\empty % no comma at the start
(\the\argumenttoks)
...
% now the table
\let\showarg=\showargtabular
\let\argrowsep=\empty
\begin{tabular}{lll}\the\argumenttoks\end{tabular}
...
}
\newcommand{\showargcommaseparated}[3]{%
\argcomma % first time empty, second time a comma
\def\argcomma{, }% next time
\textit{#2} #1%
}
\newcommand{\showargtabular}[3]{%
\argrowsep % first time empty, second time a \\
#1 & #2 & #3
\def\argrowsep{\\}% next time
}
If you're not familiar with low-level TeX: \def
is like \newcommand
that never complains (it works whether the command exists or not so it's ideal for overwriting a command you own), and \let
copies the definition of one command to another, so you can switch the meaning of a command quickly, like I did with the \showarg
command.
Note that a low-level LaTeX programmer would optimize this much further, but using self-modifying commands and such can be a bit mind boggling, and I think this has become difficult enough!