How to capitalize letter (using \uppercase) that has been assigned to \let (or to \def)?

\uppercase and \lowercase

  • do only apply to explicit character tokens.
  • do not trigger expansion after finding
    • either the left brace { of the ⟨balanced text⟩ that is to be uppercased/lowercased.
    • or the single not-brace-nested unexpandable non-⟨filler⟩-token that is to be uppercased/lowercased. (⟨filler⟩ denotes a sequence of \relax and/or explicit/implicit spaces.)

When using \csname..\endcsname instead of using the control-word-token directly, you can probably do somehing like this:

\let\zTest=t
\let\ZTEST=T
\let\ztest=t
\def\Ztest{t}

% \zTest and \ZTEST and \ztest are implicit character tokens.
% Let`s use uppercased/lowercased \csname..\endcsname for selecting 
% which implicit character token to use:

\csname zTest\endcsname

\uppercase{\csname zTest\endcsname}%

\lowercase{\csname zTest\endcsname}%

% \Ztest is a macro, expanding to explicit character token "t".
% You can use \expandafter for triggering "toplevel-expansion"
% while \uppercase/\lowercase still searches the "{" that
% marks the begin of the balanced text:

\Ztest

\uppercase\expandafter{\Ztest}%

\lowercase\expandafter{\Ztest}%

% With more recent TeX-engines, where \expanded is available,
% you can do:
%   \lowercase\expandafter{\expanded{\Ztest}}%
% "toplevel-expansion" of \expanded<general text> will deliver
% "total expansion" of the content of the <general text>'s 
% <balanced text> 

\bye

The following is a macro that is able to uppercase a let token if it was let to a letter (e.g., with \let\foo=t assuming standard category codes). It does so by first checking whether the magic tokens the letter are the start of the meaning of the passed in token, and then grabs the letter following it and uppercases that, if the meaning doesn't seem to be a letter then the input is output. The test is only applied to the first token of the input, but it is not checked whether the input is only a single token (so \uppercaselettoken{t more stuff} would see that t is a letter but passes more stuff to \uppercase, too. So this is only a proof-of-concept not a stable implementation.

\documentclass[]{article}

\let\foo=t

\makeatletter
\def\uppercaselettoken@ifletter#1%
  {%
    \def\uppercaselettoken@ifletter##1#1##2\end
      {%
        \if\relax\detokenize{##2}\relax
          \expandafter\@secondoftwo
        \else
          \if\relax\detokenize{##1}\relax
            \expandafter\@firstoftwo
          \else
            \expandafter\@secondoftwo
          \fi
          {\expandafter\@firstoftwo}
          {\expandafter\@secondoftwo}%
        \fi
      }%
    \def\uppercaselettoken@letter#1##1\end{\uppercase{##1}}%
  }
\expandafter\uppercaselettoken@ifletter\expandafter{\detokenize{the letter }}
\long\edef\uppercaselettoken@#1#2%
  {%
    \noexpand\uppercaselettoken@ifletter#1\detokenize{the letter }\noexpand\end
      {%
        \noexpand\uppercaselettoken@letter#1\noexpand\end
      }%
      {#2}% not a letter, no uppercasing
  }

\newcommand\uppercaselettoken[1]
  {%
    \expandafter\uppercaselettoken@\expandafter{\meaning#1}{#1}%
  }
\makeatother

\usepackage{unravel}

\begin{document}
\uppercaselettoken{\foo}
\uppercaselettoken{t}% works too
\end{document}

enter image description here

While it is possible to implement something that interrogates the meaning of unexpandable tokens, recognises implicit characters defined by \let and look up their upper case form, there are very few reasons to get into that situation, using \def (or \renewcommand) is the documented LaTeX interface and is essentially trivial to make work as you just have to expand the macros before uppercasing, and it works out of the box using LaTeX:

\documentclass{article}

\begin{document}

\let\zza=a
\let\zzb=b
\let\zzc=c

1 \MakeUppercase{\zza\zzb\zzc}


\renewcommand\zza{a}
\renewcommand\zzb{b}
\renewcommand\zzc{c}

2 \MakeUppercase{\zza\zzb\zzc}


\end{document}