3

The \foreach command from pgffor package has a good feature that it can distinguish arguments inside braces and single-token arguments without braces:

\foreach \i in {1,2,3} {do some thing}

\def\myvar{1,2,3}
\foreach \i in \myvar {do other thing}

Can I use xparse (without manually define auxiliary macros) to define this kind of commands:

\NewDocumentCommand \MyCommand {???} {
  If (#1 is inside braces) Then
    Do Some Thing
  Else
    Do Other Thing
  End
}

so that the command accepts both types of arguments and do different things accordingly?

\MyCommand {1,2,3} % do some thing
\MyCommand \myvar  % do other thing
9
  • Well, another alternative would be the peek_analysis function family. (although, you know, it's not possible in the general case and there's a corner case where peek_analysis fails)
    – user202729
    May 17 at 1:31
  • 3
    No unless you use the dreaded G-type argument (please don't :). For m-type arguments, xparse (ltcmd nowadays) uses simple TeX argument grabbing, as that covers nearly all use cases. As user202279 said, you can use \peek_meaning(_ignore_spaces):NTF \c_group_begin_token ... to emulate that yourself May 17 at 1:36
  • Replace the first paragraph with ”The \foreach command has a nasty feature…”
    – egreg
    May 17 at 19:40
  • @egreg Then how would you do if you are designing the syntax of \foreach command?
    – L.J.R.
    May 17 at 23:26
  • 1
    \foreach*{<var spec>}[<options>]{<list>}{<code>} where the * announces use of a command for the list.
    – egreg
    May 18 at 7:41

2 Answers 2

3

No. At the document command level, Lamport's book has always been clear: there are no arguments which are 'always N-type'. Handling the difference in semantics between {X} and X would be down to a programming-layer interface or a custom parser (e.g. TikZ doesn't use standard LaTeX syntax, so couldn't be implemented using ltcmd).

1

The tokcycle package can tell whether things are being absorbed in braced groups or not, and can do "some thing" or "other thing" based on that status.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle}
\Characterdirective{%
  ``Do other thing'' with ``#1''\tcpush{\noexpand\endtokcycraw}%
}
\Groupdirective{%
  ``Do some thing'' with ``#1''\tcpush{\noexpand\endtokcycraw}%
}
\Macrodirective{%
  ``Do other thing'' with ``\string#1''\tcpush{\noexpand\endtokcycraw}%
}
\stripgroupingtrue
\let\mycommand\tokencyclexpress
\begin{document}
\mycommand{ab cd}.

\mycommand A.

\mycommand\macroname.
\end{document}

enter image description here

p.s. Generally, unbraced spaces won't be an issue following the invocation of \mycommand, since they will not be part of the argument. However, if one was concerned about the argument being an unbraced implicit space, a \Spacedirective can be defined to handle that, too.

p.p.s. This implementation is doing "some" or "other" things while the token stream is still being absorbed. If one requires the some/other thing to only occur at the conclusion of the argument absorption, that is a trivial change...as shown below:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle}
\Characterdirective{%
  \addcytoks{``Do other thing'' with ``#1''}%
  \tcpush{\noexpand\endtokcycraw}%
}
\Groupdirective{%
  \addcytoks{``Do some thing'' with ``#1''}%
  \tcpush{\noexpand\endtokcycraw}%
}
\Macrodirective{%
  \addcytoks{``Do other thing'' with ``\string#1''}%
  \tcpush{\noexpand\endtokcycraw}%
}
\stripgroupingtrue
\let\mycommand\tokencyclexpress
\begin{document}
\mycommand{ab cd}.

\mycommand A.

\mycommand\macroname.
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.