Consider the construction \expandafter\@gobble\expandafter{\iffalse}\fi
. First \iffalse}\fi
is expanded and disappears. Then \@gobble
gobbles everything until it reaches an extra closing brace. A variant of this can maybe be used to implement some form of expandable \aftergroup
(which would only work with brace groups). I also use it in the following.
We test whether the first token of a given list of tokens is an explicit begin group character. Note that using \futurelet
would not distinguish between an implicit brace \bgroup
and an explicit brace {
. Also the solution below is expandable.
So, first a LaTeX code using no package. The trick is to hit the argument, #1
, with \string
. We know that initially, #1
is balanced. If the first token is not a begin group character, then \string#1
is still balanced after one expansion. On the other hand, if the first token is an explicit catcode 1
character, then \string
converts it to a harmless catcode, and \string#1
now has an extra end group character (catcode 2
).
\makeatletter
\long\def\@thirdoffour#1#2#3#4{#3}
\long\def\iffirst@brace#1{%
\expandafter\@gobble\expandafter{\expandafter{%
\string#1*%
}\expandafter \@thirdoffour \expandafter {\iffalse}\fi
}\@secondoftwo
}
We make use of this fact using \@gobble
, which grabs a brace group and removes it. If the first token was not of catcode 1
, then after \string
is expanded, the situation looks like
\@gobble{{%
...*%
}\expandafter\@thirdoffour\expandafter{\iffalse}\fi
}\@secondoftwo
\@gobble
only leaves \@secondoftwo
, which is what we want to grab the false
branch coming afterwards. On the other hand, if the first token is a brace group, then the situation looks like
\@gobble{{%
...}...*%
}\expandafter\@thirdoffour\expandafter{\iffalse}\fi
}\@secondoftwo
Here, \@gobble
leaves
\expandafter\@thirdoffour\expandafter{\iffalse}\fi
}\@secondoftwo
We still have an extra closing brace... But \iffalse}\fi
is expanded and disappears, and \@thirdoffour
takes the arguments {}\@secondoftwo{true branch}{false branch}
, and only leaves {true branch}
.
The star is just some random non-brace token, here so that \string
does not act on the next (closing brace) token if the argument is empty. Some tests:
% For testing purposes only:
\def\test#1{\message{\iffirst@brace{#1}{true}{false}}}
\test{{ab}cd} \test{a{bc}d} \test{ {ab}d} % "true false false"
\test{{}} \test{ } \test{} % "true false false"
Initially, I had written the code using the LaTeX3 convention (the expl3
package). It defines a \tl_if_first_brace:nTF
equivalent to the above, and also the variants \tl_if_first_brace:nT
and \tl_if_first_brace:nF
, which only have a true branch
or false branch
. It also defines a predicate \tl_if_first_brace_p:n
, which has no equivalent in "plain" LaTeX2e.
\RequirePackage{expl3}
\ExplSyntaxOn
\prg_new_conditional:Npnn \tl_if_first_brace:n #1 {p,T,F,TF} {
\exp_after:wN \use_none:n \exp_after:wN { \exp_after:wN {
\token_to_str:N #1 ?
}\prg_return_true: \exp_after:wN \use_none:nn \exp_after:wN {\if_false:}\fi:
}\prg_return_false:
}
\alignsafe@testopt
in amsmath.sty would be great. (In thedtx
they say "Testing for an optional argument can be really, really tricky in certain complicated contexts.")\expandafter
s in\Bgroup
and\bbgroup
? I don't see what changes if the\expandafter
s are omitted.\Bgroup
and\bbgroup
actually expand to an open brace when hit from the left by expansion. For instance,\expandafter\somemacro\expandafter{\iffalse}\fi
will grab the rest of the current brace group. I think that it should be possible to use it for an expandable\afterbracegroup
. See my answer below for another use.