3

I need to pass the result of a macro as a string to another macro (I'm using xparse). Here is a minimum working example:

\documentclass{minimal}
\usepackage{xparse}

\NewDocumentCommand{\TwoVarFunction}{mm}{#1 is a #2}
\NewDocumentCommand{\foo}{}{this;string}
\NewDocumentCommand{\foobar}{>{\SplitArgument{1}{;}}m}{\TwoVarFunction #1}

\begin{document}
\foo

\TwoVarFunction{this}{string}

\foobar{this;string}

\foobar{\foo}
\end{document}

I expected the output of the last three lines to be the same in the pdf (namely this is a string). However, \foo is not being parsed as an input to \foobar the way I expected; the actual output of \foobar{\foo} is "this;string is a -No Value-".

Please (1) explain why LaTeX is not reading my mind, and (2) help me find a way to process \foo so that the output is the same.

1
  • \foobar looks for a semicolon in its argument and finds none, because the argument isn't expanded until later.
    – egreg
    Nov 7, 2019 at 21:26

1 Answer 1

3

When an argument is absorbed, it is not processed in any way (unless a processor is applied), so with your code \foo is seen and it doesn't contain a semicolon at the upper level.

You can define your own processor. An xparse argument processor works by setting \ProcessedArgument to the desired token list; in this case you need to expand once the argument, with the help of \tl_set:No (o for “once”).

Thus the chain is first apply \ExpandArg, then \SplitArgument, so

\foo → this;string → {this}{string}

and this is what #1 means in the replacement text and seen by \TwoVarFunction.

Without \ExpandArg, no semicolon would be seen at the outer level and we'd get

\foo → {\foo}{-NoValue-}

because this is how \SplitArgument normalizes the output when less than the stated number of separators is seen.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new_protected:Nn \__user_expand_arg:n
 {
  \tl_set:No \ProcessedArgument { #1 }
 }
\cs_set_eq:NN \ExpandArg \__user_expand_arg:n

\ExplSyntaxOff

\NewDocumentCommand{\TwoVarFunction}{mm}{#1 is a #2}
\NewDocumentCommand{\foobar}{>{\SplitArgument{1}{;}}>{\ExpandArg}m}{%
  \TwoVarFunction #1%
}

\newcommand{\foo}{this;string}

\begin{document}
\foo

\TwoVarFunction{this}{string}

\foobar{this;string}

\foobar{\foo}
\end{document}

Note that you have to define \foo with \newcommand, because \NewDocumentCommand would introduce a (large) number of layers until the expansion is this;arg.

enter image description here

2
  • Thanks! I've accepted this answer. If it isn't asking too much, could you make some comments in the code as to what is going on between \ExplSyntaxOn ... \ExplSyntaxOff ? I don't follow how this is fixing the issue.
    – User12345
    Nov 7, 2019 at 21:49
  • @User12345 I added some explanation.
    – egreg
    Nov 7, 2019 at 21:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .