2

To prevent expansion of a macro in expansion contexts we can define the macro as \protected. I'm wondering if there's a way to do the same for an arbitrary token list.

So is it possible to define a command \protecttoks which can be used like \protecttoks{<token list>} and works in the following way:

  • In normal execution mode it just inserts <token list> in the token stream, such that they can be executed normally.
  • In expansion mode it expands to itself, i.e. the unexpanded token list \protecttoks{<token list>}.

The idea is to be able to insert literal material into a token list, where the exact number of expansions done on the token list isn't know in advance.

EDIT: Perhaps the comment about \protect in LaTeX as an example led to confusion, I removed that. The point is to define something that still gives the correct output for \foo, even if that command breaks after expansion:

\def\foo{\textcolor{blue}{x}}
\edef\bar{\protecttoks{\foo}}

\edef\bar{\bar}
% more calls here ...
\edef\bar{\bar}
\bar
3

With the help of a \protected macro it is possible to come close to what you want. The basic idea is to start with a \protected macro followed by another non-\protected macro. In an \edef (or \write or \expanded or...) the \protected macro will be skipped by TeX and the other macro will expand leaving itself (preceded by \noexpand) and \unexpanded{<stuff>}. Everywhere else the \protected macro should expand, stripping the unprotected macro and a layer of braces.

The basic setup is:

\protected\def\ifsafe#1#2{#2}
\def\elseifunsafe#1{\noexpand\elseifunsafe{\unexpanded{#1}}}

then you use as \ifsafe\elseifunsafe{<stuff>}. In an \edef \ifsafe doesn't expand and \elseifunsafe does and leaves \elseifunsafe{<stuff>}, so you are left with the \ifsafe\elseifunsafe{<stuff>} you started with. In other places \ifsafe expands consuming the \elseifunsafe and the braces around <stuff>.

You can define a \protecting macro with \def\protecting{\ifsafe\elseifunsafe}, but it will disappear after the first \edef, leaving the actual protection machinery in place.

A test document:

\protected\def\ifsafe#1#2{#2}
\def\elseifunsafe#1{\noexpand\elseifunsafe{\unexpanded{#1}}}

\def\protecting{\ifsafe\elseifunsafe}

\def\tmpa{\protecting{\something undefined}}\show\tmpa
\edef\tmpa{\tmpa 1}\show\tmpa
\edef\tmpa{\tmpa 2}\show\tmpa
\edef\tmpa{\tmpa 3}\show\tmpa

\tt
\detokenize\expandafter{\tmpa}\par
\detokenize\expandafter\expandafter\expandafter{\tmpa}
\bye

prints in the terminal:

> \tmpa=macro:
->\protecting {\something undefined}.
l.8 ...protecting{\something undefined}}\show\tmpa

?
> \tmpa=macro:
->\ifsafe \elseifunsafe {\something undefined}1.
l.9 \edef\tmpa{\tmpa 1}\show\tmpa

?
> \tmpa=macro:
->\ifsafe \elseifunsafe {\something undefined}12.
l.10 \edef\tmpa{\tmpa 2}\show\tmpa

?
> \tmpa=macro:
->\ifsafe \elseifunsafe {\something undefined}123.
l.11 \edef\tmpa{\tmpa 3}\show\tmpa

?

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.