Introspection and reflection with LaTeX/TeX macros

EDIT: a few weeks ago, I wrote this "answer", wishing for something more powerful than Yiannis did, namely, the ability of executing step by step the LaTeX file. I have a prototype. See the bottom of this post for the full code.

EDIT 2,3,4: improved the code.

I am not sure that this should be an answer, but it is definitely too long for a comment.

I would find it neat if I could type \unravel{\section*{title}} and see the macro unravel: first, expand it once, then expand the first of these macros once and show me the resulting token list, and continue expanding in the order that TeX would do it, until there is a need to read something after the token list given as an argument to \unravel.

For instance, \unravel{\section*} should give

\@startsection {section}{1}{\z@ }{-3.5ex \@plus -1ex \@minus 
-.2ex}{2.3ex \@plus .2ex}{\normalfont \Large \bfseries }*

notice the star at the end. Then it should give

\if@noskipsec \leavevmode \fi \par \@tempskipa -3.5ex \@plus -1ex 
\@minus -.2ex\relax \@afterindenttrue \ifdim \@tempskipa <\z@ 
\@tempskipa -\@tempskipa \@afterindentfalse \fi \if@nobreak 
\everypar {}\else \addpenalty \@secpenalty \addvspace \@tempskipa 
\fi \@ifstar {
  \@ssect {\z@ }{-3.5ex \@plus -1ex \@minus -.2ex}{2.3ex \@plus 
  .2ex}{\normalfont \Large \bfseries }
}{
  \@dblarg {\@sect {section}{1}{\z@ }{-3.5ex \@plus -1ex \@minus 
  -.2ex}{2.3ex \@plus .2ex}{\normalfont \Large \bfseries }}
}*

etc. It would also be neat to be able to skip the expansion of some commands: if I already know very well what \@sect does, I should be able to happily do several steps of the expansion at that point.

EDIT (cont.): Sorry, the code is quite big (and has bugs). I tried to include some comments. In the end, you just write \debug@unravel{\textrm{Hello}} to see TeX at work.

\documentclass{article}
\usepackage{trace}
\makeatletter

% Storing a few primitives that we use, to avoid crashes if they are
% redefined by the user. [...]

% =========== Setup.
% "todo": tokens that are going to be read, expanded, etc.
% "modifiers": a place to save modifiers (so far, only "\global")
% "done": the output, which in the best possible world would contain
%   tokens that produce the same output as the original ones.
\newtoks\debug@toks@todo
\long\xdef\debug@modifiers@tl{}
\newtoks\debug@toks@done
\long\gdef\debug@afterassignment@token{}


\long\gdef\debug@toks@done@append#1{%
  \global\debug@toks@done\expandafter{\the\debug@toks@done#1}%
}


% Various scratch objects.
\newcount\debug@tmp@count
\newskip\debug@tmp@skip
\newbox\debug@tmp@box

% A few parameters to control display:
\newcounter{debug@output@stream} \setcounter{debug@output@stream}{16}
\newcounter{debug@prompt@stream} \setcounter{debug@prompt@stream}{-1}
\newcounter{debug@noise}         \setcounter{debug@noise}{1}
\newcounter{debug@steps}         \setcounter{debug@steps}{0}
\newcounter{debug@nonstop}       \setcounter{debug@nonstop}{1}

% Spaces make \debug@unravel{...} choke!
%
% Explicit braces which start a group (rather than the argument
% of a macro) are not yet implemented.
% 
% \noexpand, \afterassignments, \aftergroup,
% \unhbox, \unvbox, \unhcopy, \unvcopy,
% \write, 
% ...
% need to be implemented



% The main command, \debug@unravel, simply sets the toks \debug@toks@todo,
% and repeatedly does one step of the expansion until we reach the
% end of the list.
\long\gdef\debug@unravel#1{%
  \debug@print@welcome%
  % 
  \global\debug@toks@todo{#1}%
  \global\debug@toks@done{}%
  \global\let\debug@head\relax%
  % 
  \loop%
  \debug@set@to@head\debug@head\debug@toks@todo%
  \unless\ifx\debug@head\debug@qstop%
  \debug@step%
  \repeat%
  % 
  \debug@print@outcome%
}



\long\gdef\debug@insurance#1{%
  \begingroup\escapechar=`\\\relax%`
  #1%
  \endgroup%
}


\long\gdef\debug@step{%
  % 
  % Then, in a safe environment (\escapechar=92),
  % - analyse the token,
  % - print the token list
  % - print/show the first token
  % - figure out whether we should be using \debug@type or @iv 
  % - prepare the message on what we will be doing
  \debug@insurance{%
    \debug@type@from@meaning\debug@head%
    \debug@print@done%
    \debug@print@todo%
    \debug@print@first%
    \debug@prompt%
    \debug@type@find@correct%
    \debug@setup@print@wedid%
  }%
  %
  % Finally, do what we should do.
  \csname debug@do@\debug@type@correct\endcsname%
  \debug@print@wedid% auto-insured
}

\long\gdef\debug@type@find@correct{%
  \@ifundefined{debug@do@\debug@type}{%
    \@ifundefined{debug@do@\debug@type@iv}{%
      \debug@read@unsafe{1}%
      \debug@typeout{Warning: Unknown token \debug@solid@name.}%
      \debug@typeout{\@spaces Input code to insert here. Or press return to proceed:}%
      \debug@typeout{\@spaces this dumps \debug@solid@name into the output,}%
      \debug@typeout{\@spaces by inserting \noexpand\debug@primitive{\debug@type}{unsupp}}%
      \debug@prompt@{\debug@type@find@correct@ifempty}%
      \debug@type@find@correct%
    }{%
      \global\let\debug@type@correct\debug@type@iv%
    }%
  }{%
    \global\let\debug@type@correct\debug@type%
  }%
}

\long\gdef\debug@type@find@correct@ifempty#1{%
  \ifx\debug@empty@short#1%
  \debug@primitive{\debug@type}{unsupp}%
  \fi
  #1}

% short, not long!
\gdef\debug@empty@short{}
\long\gdef\debug@empty@long{}

% ========== Macros to read the beginning of \debug@toks@todo.
\long\gdef\debug@qstop{\debug@qstop}
\global\let\debug@varqstop\debug@qstop
\long\gdef\debug@to@stop#1\debug@qstop{}
\long\gdef\debug@to@stop@keep#1\debug@qstop{#1}
\long\gdef\debug@set@to@head#1#2{%
  \expandafter\futurelet\expandafter#1%
  \expandafter\debug@to@stop\the#2\debug@qstop}


% ==== below, "unsafe" means we do not check for explicit braces or #.
% \debug@read@unsafe{3} reads the 3 first (at least 1) tokens of 
% \debug@toks@todo and stores them in \debug@read@x.
\newcount\debug@read@count%
%
\long\gdef\debug@read@unsafe#1{%
  \debug@read@count #1\relax%
  \long\gdef\debug@read@x{}%
  \expandafter\debug@read@unsafe@aux\the\debug@toks@todo%
  \debug@varqstop\debug@qstop%
}
\long\gdef\debug@read@unsafe@aux#1{%
  \expandafter\long\expandafter\gdef%
  \expandafter\debug@read@x\expandafter{\debug@read@x#1}%
  \advance \debug@read@count by \m@ne%
  \ifnum\debug@read@count>0\relax%
  \expandafter\debug@read@unsafe@aux%
  \else%
  \expandafter\debug@to@stop%
  \fi%
}




% ========== Macros to understand the meaning of the head.
\long\gdef\debug@type@from@meaning#1{%
  \expandafter\debug@meaning@aux\meaning#1 \debug@qstop%
  \expandafter\debug@tfm@macro\meaning#1->\debug@qstop%
  \long\xdef\debug@type@iv{%
    \expandafter\debug@type@nondigits\debug@type\debug@qstop}%
}

\long\gdef\debug@tfm@macro#1->#2\debug@qstop{%
  \ifx\debug@qstop#2\debug@qstop%
  \else%
  \long\gdef\debug@type{macro}%
  \fi}

\begingroup
\lccode`\*`\\
\lowercase{%
  \endgroup%
  \let\debug@char@bs*}

% \long\gdef\debug@iv#1#2#3#4#5\debug@qstop{#1#2#3#4}


\long\gdef\debug@type@nondigits#1{%
  \ifx\debug@qstop#1%
  \expandafter\debug@use@TF%
  \else%
  \expandafter\debug@use@FT%
  \fi%
  {}{%
    \ifnum9<1#1 % Critical space
    \expandafter\debug@use@TF%
    \else%
    \expandafter\debug@use@FT%
    \fi%
    {\debug@to@stop}%
    {#1\debug@type@nondigits}%
  }%
}

\long\gdef\debug@use@TF#1#2{#1}
\long\gdef\debug@use@FT#1#2{#2}
\long\gdef\debug@use@FF#1#2{}
\long\gdef\debug@use@F#1{}
\long\gdef\debug@gobble#1{}


\long\gdef\debug@meaning@aux#1#2 #3\debug@qstop{%
  \ifx\debug@char@bs#1%
  \long\gdef\debug@type{#2}%
  \else%
  \long\gdef\debug@type{character}%
  \fi%
}




% ============= Let us now act! =======================

% For "macros", we expand once, whether it is protected or not.
\long\gdef\debug@do@expand{%
  \debug@toks@expandfirst\debug@toks@todo}

\long\gdef\debug@toks@expandfirst#1{%
  \expandafter\expandafter\expandafter\expandafter%
  \expandafter\expandafter\expandafter\global%
  \expandafter\expandafter\expandafter\expandafter%
  \expandafter\expandafter\expandafter#1%
  \expandafter\expandafter\expandafter\expandafter%
  \expandafter\expandafter\expandafter{%
    \expandafter\expandafter\expandafter\empty%
    \the#1%
  }%
}

% Special type of expansion: conditionals, for which we wish to also
% output the outcome of the test.
\long\gdef\debug@do@expand@if#1{%
  \debug@insurance{%
    \debug@read@unsafe{#1}%
    \long\xdef\debug@print@wedid@tl{\space%
      Test: \detokenize\expandafter{\debug@read@x}= %
      \debug@read@x true \else false \fi%
    }%
  }%
  \debug@do@expand%
}


% For a few other cases, we remove the head of \debug@toks@todo
% and append it to \debug@toks@done
\long\gdef\debug@do@keep{%
  \debug@save@first\debug@use@first\debug@remove@first}
\long\gdef\debug@do@character{%
  \debug@save@first\debug@use@first\debug@remove@first}
\long\gdef\debug@do@unsupp{%
  \debug@save@first\debug@remove@first}
\long\gdef\debug@do@throw{\debug@remove@first}
\long\gdef\debug@do@justdo{%
  \expandafter\expandafter\expandafter\global%
  \expandafter\expandafter\expandafter\debug@toks@todo%
  \expandafter\expandafter\expandafter{%
    \expandafter\debug@use@F\the\debug@toks@todo}% 
  \debug@head%
}
\long\gdef\debug@do@relax{%
  \expandafter\expandafter\expandafter\global%
  \expandafter\expandafter\expandafter\debug@toks@todo%
  \expandafter\expandafter\expandafter{%
    \expandafter\debug@use@F\the\debug@toks@todo}% 
}

% For assignments, we use \afterassignment\debug@do@assign@aux
% to regain control after letting TeX do the assignment.
\long\gdef\debug@do@assign@after{%
  \long\xdef\debug@modifiers@tl{}%
  \let\debug@tmpa\debug@afterassignment@token%
  \let\debug@afterassignment@token\debug@empty@long%
  \global\debug@toks@todo\expandafter\expandafter\expandafter{%
    \expandafter\debug@tmpa\iffalse}\fi%
}
\long\gdef\debug@do@assign{%
  \afterassignment\debug@do@assign@after%
  \iffalse{\fi%
    \expandafter\debug@modifiers@tl%
    \the\debug@toks@todo}%
}

% Todo: reset modifiers after any step
\long\gdef\debug@do@modifier{%
  \debug@read@unsafe{1}%
  \long\xdef\debug@modifiers@tl{%
    \debug@modifiers@tl\debug@read@x}%
  \debug@remove@first%
}

% Experimental \afterassignment.
\long\gdef\debug@do@afterassignment{%
  \debug@remove@first%
  \debug@read@unsafe{1}%
  \debug@remove@first%
  \let\debug@afterassignment@token\debug@read@x%
}


% When we want to keep things like skips, penalties, etc., and
% particularly cleanup after them, we assign their "argument" to 
% an internal skip or count, and regain control \afterassignment.
% We use \debug@do@keep@skip and \debug@do@keep@count.
\long\gdef\debug@remember#1{\long\gdef\debug@remembered{#1}}

\long\gdef\debug@do@keep@after{%
  \long\xdef\debug@modifiers@tl{}%
  \global\debug@toks@todo\expandafter{\iffalse}\fi%
}

\long\gdef\debug@do@keep@#1{%
  \long\gdef\debug@tmpa{\afterassignment\debug@do@keep@after%
    \csname debug@tmp@#1\endcsname}%
  \afterassignment\debug@tmpa%
  \iffalse{\fi\expandafter\debug@remember\the\debug@toks@todo}%
  % 
  \expandafter\debug@remembered\the\csname debug@tmp@#1\endcsname%
  %
  \expandafter\expandafter\expandafter\debug@toks@done@append%
  \expandafter\expandafter\expandafter{%
    \expandafter\debug@remembered%
    \the\csname debug@tmp@#1\endcsname%
    \relax}%
}

\long\gdef\debug@do@keep@count{\debug@do@keep@{count}}
\long\gdef\debug@do@keep@skip{\debug@do@keep@{skip}}


\long\gdef\debug@do@keep@count@edef{%
  \long\gdef\debug@tmpa{% captures the rest of the toks
    \global\debug@toks@todo\expandafter{\iffalse}\fi%
  }%
  \long\gdef\debug@tmpb{% captures the text to write, then proceed
    \afterassignment\debug@tmpa%
    \edef\debug@tmpw% will get the text to write
  }%
  \long\gdef\debug@tmpc{% captures the stream number, then proceed
    \afterassignment\debug@tmpb%
    \global\debug@tmp@count% will get the stream.
  }%
  \afterassignment\debug@tmpc%
  \iffalse{\fi\expandafter\debug@remember\the\debug@toks@todo}%
  % 
  \long\xdef\debug@tmpa{%
    \debug@modifiers@tl%
    \expandafter\noexpand\debug@remembered%
    \the\debug@tmp@count%
    {\unexpanded\expandafter{\debug@tmpw}}%
  }%
  \debug@tmpa%
  \expandafter\debug@toks@done@append\expandafter{\debug@tmpa}%
  \long\xdef\debug@modifiers@tl{}%
}



% For \setbox, the situation is more complicated: \afterassignment only
% brings us inside the box. So we \afterassignment a macro which expands
% to \aftergroup \<regain_control>.

\long\gdef\debug@do@assign@after@afgr{\aftergroup\debug@do@assign@after}
\long\gdef\debug@do@assign@box{%
  \afterassignment\debug@do@assign@after@afgr%
  \iffalse{\fi%
    \the\debug@toks@todo}%
}


% For \hbox, \vbox, \vtop, we cheat by storing them inside the dummy 
% box \debug@tmp@box (using \savebox that we have just obtained).
\long\gdef\debug@do@any@box{%
  \global\debug@toks@todo\expandafter{%
    \expandafter\setbox\expandafter\debug@tmp@box\expandafter=%
    \the\debug@toks@todo}%
}



% ===== Moving the first from \debug@toks@todo to \debug@toks@done.

\long\gdef\debug@remove@first{%
  \expandafter\expandafter\expandafter\global%
  \expandafter\expandafter\expandafter\debug@toks@todo%
  \expandafter\expandafter\expandafter{%
    \expandafter\debug@use@F\the\debug@toks@todo}% 
}

\long\gdef\debug@save@first{%
  \expandafter\debug@save@first@\the\debug@toks@todo\debug@qstop}
\long\gdef\debug@save@first@#1{%
  \debug@toks@done@append{#1}%
  \debug@to@stop}

\long\gdef\debug@use@first{%
  \expandafter\debug@use@first@\the\debug@toks@todo\debug@qstop}
\long\gdef\debug@use@first@#1{%
  \expandafter#1\debug@to@stop}




% ============ Setup one macro per primitive

\long\gdef\debug@primitive#1{%
  \long\xdef\debug@tmpa@tl{#1}%
  \debug@primitive@aux%
}
\long\gdef\debug@primitive@iv#1{%
  \long\xdef\debug@tmpa@tl{\debug@type@nondigits #1\debug@qstop}%
  \debug@primitive@aux%
}
\long\gdef\debug@primitive@aux#1{%
  \long\xdef\debug@tmpb@tl{%
    \unexpanded\expandafter\expandafter\expandafter{%
      \csname debug@text@do@#1\endcsname}}%
  \expandafter\global\expandafter\let%
  \csname debug@do@\debug@tmpa@tl\expandafter\endcsname%
  \csname debug@do@#1\endcsname%
  \expandafter\long\expandafter\gdef\csname debug@text@do@\debug@tmpa@tl%
    \expandafter\endcsname\expandafter{\debug@tmpb@tl}%
}


\long\gdef\debug@solid@name{\detokenize\expandafter{\debug@read@x}}
\long\gdef\debug@text@do@character{Output the character \debug@solid@name. }
\long\gdef\debug@text@do@expand{Expanded \debug@solid@name once. }
\long\gdef\debug@text@do@keep{Sent \debug@solid@name to the output. }
\long\gdef\debug@text@do@justdo{Just did \debug@solid@name! }
\long\gdef\debug@text@do@throw{Ignored \debug@solid@name! }
\long\gdef\debug@text@do@relax{Relaxed a bit with \debug@solid@name. }
\long\gdef\debug@text@do@keep@skip{Output \debug@solid@name and its skip. }
\long\gdef\debug@text@do@keep@count{Output \debug@solid@name and its count. }
\long\gdef\debug@text@do@keep@count@edef{Maybe it was a write? \debug@solid@name. }
\long\gdef\debug@text@do@unsupp{Unsupported \debug@solid@name dumped into the output. }
\long\gdef\debug@text@do@assign{Assigned using %
  \detokenize\expandafter{\debug@modifiers@tl}\debug@solid@name... }
\long\gdef\debug@text@do@assign@box{Assigned a box using \debug@solid@name... }
\long\gdef\debug@text@do@any@box{Preparing to store the \debug@solid@name in our box. }
\long\gdef\debug@text@do@modifier{Remembering the modifier \debug@solid@name. }
\long\gdef\debug@text@do@afterassignment{Attempting to take care of afterassignment.}

% In the current implementation, macros are mis-recognized as
% their modifiers, so we need to cheat and pretend that those
% modifiers should just be expanded. This will fail if there
% is a genuine \long or \protected or \outer out there.

\debug@primitive{immediate}{modifier}
\debug@primitive{global}{modifier}
%\debug@primitive{outer}{modifier}%disabled because it will break me.
\debug@primitive{long}{modifier}
\debug@primitive{protected}{modifier}

\debug@primitive{macro}{expand}
\debug@primitive{expandafter}{expand}
\debug@primitive{noexpand}{expand}
\debug@primitive{detokenize}{expand}
\debug@primitive{string}{expand}
\debug@primitive{csname}{expand}
\debug@primitive{lowercase}{expand}
\debug@primitive{uppercase}{expand}

\debug@primitive{relax}{relax}
\debug@primitive{par}{keep}
\debug@primitive{indent}{keep}
\debug@primitive{unskip}{keep}
\debug@primitive{unhbox}{keep@count}
\debug@primitive{unhcopy}{keep@count}
\debug@primitive{penalty}{keep@count}
\debug@primitive{vskip}{keep@skip}
\debug@primitive{hskip}{keep@skip}
\let\debug@do@muskipAA\debug@do@keep@muskip% not yet supported!


\debug@primitive{begingroup}{keep}
\debug@primitive{endgroup}{keep}
\debug@primitive{write}{keep@count@edef}

\debug@primitive{ignorespaces}{unsupp}
\debug@primitive{unpenalty}{unsupp}
\debug@primitive{/}{unsupp}
\debug@primitive{hbox}{unsupp}
\debug@primitive{vbox}{unsupp}
\debug@primitive{afterassignment}{afterassignment}
\debug@primitive{aftergroup}{throw}


\debug@primitive{futurelet}{assign}
\debug@primitive{let}{assign}
\debug@primitive{def}{assign}
\debug@primitive{edef}{assign}
\debug@primitive{gdef}{assign}
\debug@primitive{xdef}{assign}
\debug@primitive{advance}{assign}
\debug@primitive@iv{toks}{assign}
\debug@primitive@iv{skip}{assign}
\debug@primitive@iv{font}{assign}
\debug@primitive@iv{muskip}{assign}
\debug@primitive@iv{dimen}{assign}
\debug@primitive@iv{count}{assign}
\debug@primitive{everypar}{assign}
\debug@primitive{baselineskip}{assign}
\debug@primitive{parfillskip}{assign}
\debug@primitive{parskip}{assign}
\debug@primitive{leftskip}{assign}
\debug@primitive{rightskip}{assign}
\debug@primitive{parindent}{assign}
\debug@primitive{parshape}{assign}
\debug@primitive{escapechar}{assign}
\debug@primitive{hyphenchar}{assign}
\debug@primitive{catcode}{assign}
\debug@primitive{lccode}{assign}
\debug@primitive{uccode}{assign}
\debug@primitive{accent}{assign}%??
\debug@primitive{tracingassigns}{assign}
\debug@primitive{tracingcommands}{assign}
\debug@primitive{tracinggroups}{assign}
\debug@primitive{tracinglostchars}{assign}
\debug@primitive{tracingmacros}{assign}
\debug@primitive{tracingonline}{assign}
\debug@primitive{tracingoutput}{assign}
\debug@primitive{tracingpages}{assign}
\debug@primitive{tracingparagraphs}{assign}
\debug@primitive{tracingrestores}{assign}
\debug@primitive{tracingstats}{assign}
\debug@primitive{showboxbreadth}{assign}
\debug@primitive{showboxdepth}{assign}

\debug@primitive{setbox}{assign@box}
\debug@primitive{hbox}{any@box}
\debug@primitive{vbox}{any@box}
\debug@primitive{vtop}{any@box}

\debug@primitive{if}{expand}
\debug@primitive{ifdim}{expand}
\debug@primitive{ifnum}{expand}
\debug@primitive{else}{expand}
\debug@primitive{fi}{expand}
\long\gdef\debug@do@ifx{\debug@do@expand@if{3}}
\long\gdef\debug@do@ifvmode{\debug@do@expand@if{1}}
\long\gdef\debug@do@ifhmode{\debug@do@expand@if{1}}
\long\gdef\debug@do@ifmmode{\debug@do@expand@if{1}}
\long\gdef\debug@do@iffalse{\debug@do@expand@if{1}}
\long\gdef\debug@do@iftrue{\debug@do@expand@if{1}}




% ========== Messages.
\usepackage{hardwrap}

\long\gdef\debug@typeout#1{\immediate\write\c@debug@output@stream{#1}}

\long\gdef\debug@print@welcome{%
  \debug@typeout{}%
  \debug@typeout{======== Welcome to the debug package ========}%
  \debug@typeout{\@spaces "|>" denotes tokens that we will act on.}%
  \debug@typeout{\@spaces "<|" denotes the output to TeX's stomach.}%
  \debug@typeout{\@spaces Type "\string\step{2}" to do two steps [...]}%
  \debug@typeout{}%
}

\long\gdef\debug@print@outcome{%
  \debug@typeout{Step \the\c@debug@steps\space===== The end!}%
  \debug@print@done%
}

\long\gdef\debug@message@aux#1#2#3{%
  \begingroup%
  \lccode`\*=\newlinechar\relax%
  \lowercase{\def\debug@newline{*}}%
  \def\MessageBreak{%
    \debug@newline #1\space\space}%
  \set@display@protect%
  \debug@typeout{#2\MessageBreak #3}%
  \debug@typeout{}%
  \endgroup}%

\long\gdef\debug@message#1#2#3{%
  \HardWrap{\debug@message@aux{#1}{#2}}{72}{\HardWrapSetup}%
  {\MessageBreak}{#3}}

\long\gdef\debug@print@todo{%
  \ifnum\the\c@debug@noise>-1\relax%
  \debug@message{|>}{\expandafter\debug@use@F}{%
    \detokenize\expandafter{\the\debug@toks@todo}}%
  \fi}

\long\gdef\debug@print@done{%
  \debug@insurance{%
    \debug@message{<|}{\expandafter\debug@use@F}{%
      \detokenize\expandafter{\the\debug@toks@done}}}}

\long\gdef\debug@setup@print@wedid{%
  \debug@read@unsafe{1}%
  \long\xdef\debug@print@wedid@tl{\space%
    \csname debug@text@do@\debug@type@correct\endcsname}}

\long\gdef\debug@print@wedid{%
  \debug@insurance{%
    \global\advance \c@debug@steps by 1\relax%
    \lccode`\*=\newlinechar%
    \lowercase{\long\gdef\MessageBreak{*\@spaces\@spaces\@spaces}}%
    \debug@typeout{Step \the\c@debug@steps\space%
      =====\debug@print@wedid@tl}%
    \ifnum\c@debug@noise>-1\relax%
    \debug@typeout{}%
    \fi%
  }%
}



% ============= To show the first token.

\long\gdef\debug@print@first{%
  \ifnum\the\c@debug@noise>0\relax
  \debug@read@unsafe{1}%
  \long\xdef\debug@first@meaning{\expandafter\meaning\debug@read@x}%
  \long\xdef\debug@first@string{\expandafter\string\debug@read@x}%
  \debug@message{\debug@use@FF}{\debug@use@F}{%
    \debug@first@string=\debug@first@meaning}%
  \fi%
}






% ============= The prompt
\long\def\debug@hop@else#1\else#2\fi{\fi#1}
\long\def\debug@hop@fi#1\fi{\fi#1}


\long\gdef\debug@prompt{%
  \ifnum\the\c@debug@nonstop=1\relax%
  \debug@hop@else\debug@prompt@{\debug@prompt@treat}%
  \else%
  \global\advance\c@debug@nonstop by -1\relax%
  \fi%
}

\long\gdef\debug@prompt@treat#1{%
  \expandafter\debug@prompt@treat@aux#1\debug@qstop}
\long\gdef\debug@prompt@treat@aux#1{%
  \ifcat A\noexpand#1\relax%
  \expandafter\debug@use@TF%
  \else%
  \expandafter\debug@use@FT%
  \fi%
  {\csname debug@prompt@treat@#1\endcsname%
    \debug@prompt@treat@aux}%
  {\debug@to@stop@keep#1}%
}
\long\gdef\debug@prompt@treat@q{\noise{-1}\step{0}}
\long\gdef\debug@prompt@treat@x{\endgroup\endgroup\fi\iffalse}
\long\gdef\debug@prompt@treat@s#1#2{\silentstep{#2}#1}
\long\gdef\debug@prompt@treat@o#1#2{%
  \ifnum#2<0\relax%
  \else\ifnum#2=0\relax%
  \global\c@debug@output@stream-1\relax%
  \else%
  \global\c@debug@output@stream16\relax%
  \fi\fi%
  #1}


\long\xdef\debug@prompt@tl#1{%
  \noexpand\read\noexpand\c@debug@prompt@stream to%
  \expandafter\noexpand\csname Your input \endcsname%
  #1\expandafter\noexpand\csname Your input \endcsname}
\long\gdef\debug@prompt@before@tl{}
\long\gdef\debug@prompt@#1{%
  \begingroup\escapechar=-1\relax%
  \def\step##1{\global\c@debug@nonstop##1\relax}%
  \def\noise##1{\global\c@debug@noise##1\relax}%
  \def\silentstep##1{%
    \noise{-1}%
    \step{##1}%
    \long\gdef\debug@prompt@before@tl{\noise{1}}%
  }%
  \endlinechar=-1%
  \debug@prompt@before@tl%
  \long\gdef\debug@prompt@before@tl{}%
  \debug@prompt@tl{#1}%
  \endgroup}


\usepackage{amsmath}
\begin{document}


\section{Normal-section}

Title above for comparison purposes.

\debug@unravel{\section{Unravelled-section}}%

The section title above was typeset as we unravelled.

\the\debug@toks@done%

That third section is made using what is stored at 
the end of the unravelling.

Only trivial maths works: $\debug@unravel{xy = z}$, 
and it is stored in our ouput token list, $\the\debug@toks@done$.

Some more complex maths symbols fail, complain, cheat: 
\[
\debug@unravel{\int\mathrm{d}x\sin(\pi)=0}
\]
\[
\the\debug@toks@done.
\]

And sub- and super-scripts are totally unsupported so far.

\end{document}

Charles has asked me to post a summary of the comments above; here's a quick synopsis.

Will:

I might not be in the target audience, but I don't see this being very useful to me. (It's certainly fun to experiment with, however.) I usually find that when I need to inspect macro definitions, the lack of indentation and line breaks in the output of \show and \meaning limit their utility in many cases.

Barbara:

cute. two comments:

  1. i think of "reflect" as what happens in a mirror, and have used that name to mirror horizontally symbols or strings using the graphics package (which already has a \reflectbox command). i'd call this something different, maybe \unwrap or \unravel.
  2. maybe i assumed too much, but i tried to run this directly, without wrapping it with a document class and \begin/\end{document}, ... and failed. guess i'm spoiled, but i like examples that run right out of the box.

Manuel:

For quick debugging, I prefer to run TeX interactively and use \show to see the output directly on the terminal.