Is it possible to define an `\escape` command in LaTeX?

I think you just want \@namueuse.

  • \@nameuse{foo} becomes \foo

  • {\@nameuse{newcommand}}{\hi}{hi} really means {\newcommand}{\hi}{hi}, which is an error. But I think it is just an error in the question, and you intended \escape{newcommand}{\hi}{hi} (without some braces).

Use

\makeatletter
\let\escape=\@nameuse
\makeatother

Or skip right into the simple definition of \@nameuse

\newcommand*\escape[1]{\csname #1\endcsname}

I can offer a macro \CsNameToCsToken:

\CsNameToCsToken{foo}\foo  .

(If this suits your needs you can replace \CsNameToCsToken by \escape. But I think the name "CsNameToCsToken" does better describe what the macro in question does.)

Syntax:

\CsNameToCsToken⟨stuff not in braces⟩{⟨NameOfCs⟩}

⟨stuff not in braces⟩\NameOfCs

(⟨stuff not in braces⟩ may be empty.)

Definition (in LaTeX 2ε):

\begingroup
\makeatletter
\@firstofone{%
  \endgroup
  \@ifdefinable\CsNameToCsToken{%
    \long\def\CsNameToCsToken#1#{\romannumeral\InnerCsNameToCsToken{#1}}%
  }%
  \newcommand\InnerCsNameToCsToken[2]{%
    \expandafter\exchange\expandafter{\csname#2\endcsname}{\z@#1}%
  }%
  \newcommand\exchange[2]{#2#1}%
}%

In plain-TeX

  • either also define \z@, e.g., to be a macro which expands to 0⟨explicit space token⟩, or to be a \dimendef-token denoting a register holding length-value 0pt,

  • or do:

    \long\def\CsNameToCsToken#1#{\romannumeral0\InnerCsNameToCsToken{#1}}%
    \long\def\InnerCsNameToCsToken#1#2{%
      \expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}% <- the space before #1 must be!
    }%
    \long\def\exchange#1#2{#2#1}%
    

(Due to \romannumeral-expansion the result is obtained by triggering two expansion-steps, e.g., by having two "hits" with \expandafter.)

With such a macro you are not bound to specific definition commands:

\CsNameToCsToken{foo}\foo  .

\CsNameToCsToken\newcommand{foo}\newcommand\foo  .

\CsNameToCsToken\DeclareRobustCommand{foo}\DeclareRobustCommand\foo  .

\CsNameToCsToken\global\long\outer\def{foo}\global\long\outer\def\foo  .

\CsNameToCsToken\expandafter{foo}\bar\expandafter\foo\bar  .

\CsNameToCsToken\let{foo}=\bar\let\foo=\bar  .

\CsNameToCsToken\string{foo}\string\foo  .

\CsNameToCsToken\meaning{foo}\meaning\foo  .


And here is the requested \NewDocumentCommand-example:

With \NewDocumentCommand you don't really need braces surrounding the control sequence token to define.

E.g.,
\NewDocumentCommand\foo{m}{foo's argument is: #1}
is the same as
\NewDocumentCommand{\foo}{m}{foo's argument is: #1}

Therefore you can do:

\CsNameToCsToken\NewDocumentCommand{foo}...\NewDocumentCommand\foo...  .


You can as well use such a macro for defining/calling macros whose names contain spaces:

\CsNameToCsToken{foo }\foo␣  .

\CsNameToCsToken\newcommand{foo }\newcommand\foo␣  .

\CsNameToCsToken\DeclareRobustCommand{foo }\DeclareRobustCommand\foo␣  .

\CsNameToCsToken\global\long\outer\def{foo }\global\long\outer\def\foo␣  .

\CsNameToCsToken\expandafter{foo }\bar\expandafter\foo␣\bar  .

\CsNameToCsToken\let{foo }=\bar\let\foo␣=\bar  .

\CsNameToCsToken\string{foo }\string\foo␣  .

\CsNameToCsToken\meaning{foo }\meaning\foo␣  .

You can also nest the calls of \CsNameToCsToken:

Example 1:

   \CsNameToCsToken\CsNameToCsToken\expandafter{f o o }{b a r }

Processing the first \CsNameToCsToken yields:
   \CsNameToCsToken\expandafter\f␣o␣o␣{b a r }  .

Processing the second \CsNameToCsToken yields:
   \expandafter\f␣o␣o␣\b␣a␣r␣  .

(Analogously: \CsNameToCsToken\CsNameToCsToken\let{f o o }={b a r }\let\f␣o␣o␣=\b␣a␣r␣.)

Example 2:

   \CsNameToCsToken\CsNameToCsToken\CsNameToCsToken\expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

Processing the first \CsNameToCsToken yields:
   \CsNameToCsToken\CsNameToCsToken\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  .

Processing the second \CsNameToCsToken yields:
   \CsNameToCsToken\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  .

Processing the third \CsNameToCsToken yields:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Example 3:

In expansion contexts you can use \romannumeral-expansion in order to keep things going.

   \romannumeral\CsNameToCsToken\CsNameToCsToken\CsNameToCsToken\z@\expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

\romannumeral triggers expansion until TeX has found a sequence of tokens that forms a ⟨number⟩-quantity. In the end TeX will find the ⟨number⟩-quantity \z@ whose value is 0 while with non-positive numbers \romannumeral silently swallows the tokens forming the ⟨number⟩-quantity while not delivering any token at all:
   %\romannumneral-expansion in progress
   \CsNameToCsToken\CsNameToCsToken\CsNameToCsToken\z@\expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

Processing the first \CsNameToCsToken yields:
   %\romannumneral-expansion in progress
   \CsNameToCsToken\CsNameToCsToken\z@\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  .

Processing the second \CsNameToCsToken yields:
   %\romannumneral-expansion in progress
   \CsNameToCsToken\z@\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  .

Processing the third \CsNameToCsToken yields:
   %\romannumneral-expansion in progress
   \z@\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Now \romannumeral finds \z@, i.e., the number 0 (in a way where no further digits and no to be discarded space-token terminating the ⟨number⟩ will be searched). Therefore \romannumeral-expansion gets aborted and \romannumeral won't deliver any token:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Be aware that \CsNameToCsToken internally applies \csname while applying \csname as a side effect yields assigning the control sequence in question the meaning of the \relax-primitive in case the control sequence in question was undefined before applying \csname. That assignment will be restricted to the current scope even if the \globaldefs-parameter had a positive value at the time of applying \csname.

Tags:

Macros