From 6167612e2eff3296cdb8990c9dc3a3b688f89a30 Mon Sep 17 00:00:00 2001 From: bruce miller Date: Thu, 26 Sep 2024 17:09:24 -0400 Subject: [PATCH] Expansions (#2421) * Adjust args to readXToken and readBalanced to support but fully and partially expanded variations * Default state->lookupExpandable same as gullet->readXToken * Make GeneralText, XGeneralText use gullet->skipFiller correctly; have Expanded be fully expanded, but introduce ExpandedPartially * pdfTeX's \expanded, \pdfstrcmp should use XGeneralText parameter types * Make Expand() expand fully; add ExpandPartially defers \protected,\the * Use partial expansion for unit type arguments * Add test case distinguishing fully vs partially expanded cases * Clarifying comments * Simplify Expand(),ExpandPartially(), probably more robust, if slightly less efficient * For gullet->readArg Add optional expanded argument (0,1,2 for not; partial; fully expanded); Use that for Expanded, ExpandedPartially ParameterTypes (slight update of POD) --- MANIFEST | 3 + lib/LaTeXML/Core/Gullet.pm | 89 +++++----- lib/LaTeXML/Core/State.pm | 1 + .../Engine/Base_ParameterTypes.pool.ltxml | 23 ++- lib/LaTeXML/Engine/pdfTeX.pool.ltxml | 4 +- lib/LaTeXML/Package.pm | 26 +-- lib/LaTeXML/Package/siunitx.sty.ltxml | 5 +- t/expansion/partial.pdf | Bin 0 -> 32341 bytes t/expansion/partial.tex | 106 ++++++++++++ t/expansion/partial.xml | 157 ++++++++++++++++++ 10 files changed, 353 insertions(+), 61 deletions(-) create mode 100644 t/expansion/partial.pdf create mode 100644 t/expansion/partial.tex create mode 100644 t/expansion/partial.xml diff --git a/MANIFEST b/MANIFEST index b1dd66ad6..75f864ffb 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1250,6 +1250,9 @@ t/expansion/numexpr.xml t/expansion/parindent.pdf t/expansion/parindent.tex t/expansion/parindent.xml +t/expansion/partial.pdf +t/expansion/partial.tex +t/expansion/partial.xml t/expansion/pdftex_expanded.pdf t/expansion/pdftex_expanded.tex t/expansion/pdftex_expanded.xml diff --git a/lib/LaTeXML/Core/Gullet.pm b/lib/LaTeXML/Core/Gullet.pm index f25a492da..dd519ca10 100644 --- a/lib/LaTeXML/Core/Gullet.pm +++ b/lib/LaTeXML/Core/Gullet.pm @@ -333,18 +333,19 @@ sub unread { # Note that most tokens pass through here, so be Fast & Clean! readToken is folded in. # `Toplevel' processing, (if $toplevel is true), used at the toplevel processing by Stomach, # will step to the next input stream (Mouth) if one is available, -# $toplevel is doing TWO distinct things. When true: +# $toplevel when true: # * If a mouth is exhausted, move on to the containing mouth to continue reading +# $fully_expand when true, OR when undef but $toplevel is true # * expand even protected defns, essentially this means expand "for execution" # Note that, unlike readBalanced, this does NOT defer expansion of \the & friends. # Also, \noexpand'd tokens effectively act ilke \relax # For arguments to \if,\ifx, etc use $for_conditional true, # which handles \noexpand and CS which have been \let to tokens specially. sub readXToken { - my ($self, $toplevel, $for_conditional) = @_; + my ($self, $toplevel, $for_conditional, $fully_expand) = @_; $toplevel = 1 unless defined $toplevel; - my $autoclose = $toplevel; # Potentially, these should have distinct controls? - my $for_evaluation = $toplevel; + my $autoclose = $toplevel; # Potentially, these should have distinct controls? + $fully_expand = $toplevel unless defined $fully_expand; my ($token, $cc, $defn, $atoken, $atype, $ahidden); while (1) { while (($token = shift(@{ $$self{pushback} })) && $CATCODE_HOLD[$cc = $$token[1]]) { @@ -376,7 +377,7 @@ sub readXToken { if ((ref $defn) eq 'LaTeXML::Core::Token') { # \let to a token? Return it! return ($for_conditional ? $defn : $token); } elsif (!$defn->isExpandable # Not expandable or is protected - || ($$defn{isProtected} && !$for_evaluation)) { + || ($$defn{isProtected} && !$fully_expand)) { return $token; } else { local $LaTeXML::CURRENT_TOKEN = $token; @@ -397,7 +398,8 @@ sub readXToken { # readBalanced approximates TeX's scan_toks (but doesn't parse \def parameter lists) # and only optionally requires the openning "{". # It may return comments in the token lists. -# it optionally ($expand) expands while reading, but deferring \the and related. +# If $expanded is true, it expands while reading, but deferring \the and related +# & \protected, unless $expanded is > 1. # The $macrodef flag affects whether # parameters are "packed" for macro bodies. # If $require_open is true, the opening T_BEGIN has not yet been read, and is required. our $DEFERRED_COMMANDS = { @@ -411,7 +413,8 @@ sub readBalanced { my ($self, $expanded, $macrodef, $require_open) = @_; $LaTeXML::ALIGN_STATE-- unless $require_open; # assume matching } [BEFORE masking ALIGN_STATE] local $LaTeXML::ALIGN_STATE = 1000000; - my $startloc = ($$self{verbosity} > 0) && getLocator($self); + my $fully_expand = (defined $expanded) && ($expanded > 1); + my $startloc = ($$self{verbosity} > 0) && getLocator($self); # Does we need to expand to get the { ??? if ($require_open) { my $token = ($expanded ? readXToken($self, 0) : readToken($self)); @@ -462,7 +465,7 @@ sub readBalanced { && defined($defn = $STATE->lookupMeaning($token)) && ((ref $defn) ne 'LaTeXML::Core::Token') # an actual definition && $defn->isExpandable - && (!$$defn{isProtected})) { # is this the right logic here? don't expand unless di + && (!$$defn{isProtected} || $fully_expand)) { # is this the right logic here? don't expand unless di local $LaTeXML::CURRENT_TOKEN = $token; my $r; no warnings 'recursion'; @@ -470,7 +473,7 @@ sub readBalanced { next unless $expansion; # If a special \the type command, push the expansion directly into the result # Well, almost directly: handle any MARKER tokens now, and possibly un-pack T_PARAM - if ($$DEFERRED_COMMANDS{ $$defn{cs}[0] }) { + if (!$fully_expand && $$DEFERRED_COMMANDS{ $$defn{cs}[0] }) { foreach my $t (@$expansion) { my $cc = $$t[1]; if ($cc == CC_MARKER) { handleMarker($self, $t); } @@ -552,16 +555,13 @@ sub skip1Space { return; } # = | \relax +# TeX Book p.276 " can be implicit", and experimentation, indicate Expansion!!! sub skipFiller { my ($self) = @_; - while (1) { - my $tok = readNonSpace($self); - return unless defined $tok; - # Should \foo work too (where \let\foo\relax) ?? - if (!$tok->equals(T_CS('\relax'))) { + while (my $tok = readXNonSpace($self)) { + if (!$tok->defined_as(T_CS('\relax'))) { unread($self, $tok); - return; } - } + return; } } return; } sub ifNext { @@ -698,14 +698,19 @@ sub readCSName { # tokens, non-expandable tokens, args, Numbers, ... #********************************************************************** sub readArg { - my ($self) = @_; + my ($self, $expanded) = @_; my $token = readNonSpace($self); if (!defined $token) { return; } elsif ($$token[1] == CC_BEGIN) { # Inline ->getCatcode! - return readBalanced($self, 0); } + return readBalanced($self, $expanded, 0, 0); } else { - return Tokens($token); } } + if ($expanded) { + return $self->readingFromMouth(LaTeXML::Core::Mouth->new(), sub { + $self->unread(T_BEGIN, $token, T_END); + return $self->readBalanced($expanded, 0, 1); }); } + else { + return Tokens($token); } } } # Note that this returns an empty array if [] is present, # otherwise $default or undef. @@ -1129,21 +1134,27 @@ Returns an object describing the current location in the input stream. =over 4 -=item C<< $tokens = $gullet->expandTokens($tokens); >> - -Return the L resulting from expanding all the tokens in C<$tokens>. -This is actually only used in a few circumstances where the arguments to -an expandable need explicit expansion; usually expansion happens at the right time. - =item C<< $token = $gullet->readToken; >> Return the next token from the input source, or undef if there is no more input. -=item C<< $token = $gullet->readXToken($toplevel,$commentsok); >> +=item C<< $token = $gullet->readXToken($toplevel,$for_conditional, $fully_expand); >> Return the next unexpandable token from the input source, or undef if there is no more input. -If the next token is expandable, it is expanded, and its expansion is reinserted into the input. -If C<$commentsok>, a comment read or pending will be returned. +If the next token is expandable, it is expanded, and its expansion is reinserted into the input, +and reading continues. +If C<$toplevel> is true, it will automatically close empty mouths as it reads, and will also fully expand macros (unless overridden by C<$fully_expand> being explicitly false). Full expansion expands protected macros as well as the results of L<\the> (and similar). +If C<$for_conditional> is true, handle L<\noexpand> appropriately for the arguments to L<\if>. + +=item C<< $tokens = $gullet->readBalanced($expanded, $macrodef, $require_open); >> + +Read a sequence of tokens from the input until the balancing '}'. +By default assumes the '{' has already been read. + +No expansion takes place if C<$expand> is 0 or undef; partial expansion (deferring protected and C<\the>) of C<$expand> is 1; full expansion if it is > 1. +The C<$macrodef> flag affects whether # parameters are "packed" for macro bodies. +If C<$require_open> is true, the opening C has not yet been read, and is required. +Returns a L. =item C<< $gullet->unread(@tokens); >> @@ -1159,6 +1170,11 @@ Push the C<@tokens> back into the input stream to be re-read. Read and return the next non-space token from the input after discarding any spaces. +=item C<< $token = $gullet->readXNonSpace; >> + +Read and return the next non-space token from the input after discarding any spaces, +partially expanding as it goes. + =item C<< $gullet->skipSpaces; >> Skip the next spaces from the input. @@ -1168,16 +1184,6 @@ Skip the next spaces from the input. Skip the next token from the input if it is a space. If C($expanded> is true, expands ( like C< > ). -=item C<< $tokens = $gullet->readBalanced($expanded, $macrodef, $require_open); >> - -Read a sequence of tokens from the input until the balancing '}'. -By default assumes the '{' has already been read. - -It optionally (C<$expand>) expands while reading, but deferring \the and related. -The C<$macrodef> flag affects whether # parameters are "packed" for macro bodies. -If C<$require_open> is true, the opening C has not yet been read, and is required. -Returns a L. - =item C<< $boole = $gullet->ifNext($token); >> Returns true if the next token in the input matches C<$token>; @@ -1206,9 +1212,12 @@ in C<@delims>. In a list context, it also returns which of the delimiters ended =over 4 -=item C<< $tokens = $gullet->readArg; >> +=item C<< $tokens = $gullet->readArg($expanded); >> -Read and return a TeX argument; the next Token or Tokens (if surrounded by braces). +Read and return a "normal" TeX argument; the next Token or Tokens (if surrounded by braces). +C<$expanded> controls expansion as if the argument were read and then expanded in isolation: +0,undef or missing gives no expansion; 1 gives partial expansion; > 1 gives full expansion. +In the case of a single unbraced expandable token, it will I read any macro arguments from the following input! =item C<< $tokens = $gullet->readOptional($default); >> diff --git a/lib/LaTeXML/Core/State.pm b/lib/LaTeXML/Core/State.pm index 6fb15c8de..38a936343 100644 --- a/lib/LaTeXML/Core/State.pm +++ b/lib/LaTeXML/Core/State.pm @@ -421,6 +421,7 @@ sub lookupExpandable { return unless $token; my $defn; my $entry; + $toplevel = 1 unless defined $toplevel; # Default, for full expansion, same as readXToken! if ($CATCODE_ACTIVE_OR_CS[$$token[1]] && ($entry = $$self{meaning}{ $$token[0] }) && ($defn = $$entry[0]) diff --git a/lib/LaTeXML/Engine/Base_ParameterTypes.pool.ltxml b/lib/LaTeXML/Engine/Base_ParameterTypes.pool.ltxml index 84fe2dd87..b31b16a5d 100644 --- a/lib/LaTeXML/Engine/Base_ParameterTypes.pool.ltxml +++ b/lib/LaTeXML/Engine/Base_ParameterTypes.pool.ltxml @@ -63,16 +63,16 @@ DefParameterType('Optional', sub { # This is a peculiar type of argument of the form # = { -# however, does get expanded while searching for the initial { -# which IS required in contrast to a general argument; ie a single token is not correct. +# [Note: expands, ignoring spaces and \relax, until opening { ] DefParameterType('GeneralText', sub { my ($gullet) = @_; - $gullet->unread($gullet->readXToken); # Force expansion to skip before required { + $gullet->skipFiller; return $gullet->readBalanced(0, 0, 1); }); +# This is like GeneralText, but it Partially expands the argument (not \protected, nor \the) DefParameterType('XGeneralText', sub { my ($gullet) = @_; - $gullet->unread($gullet->readXToken); # Force expansion to skip before required { + $gullet->skipFiller; return $gullet->readBalanced(1, 0, 1); }); DefParameterType('Until', sub { @@ -148,11 +148,20 @@ DefParameterType('XUntil', sub { push(@tokens, $token); } } Tokens(@tokens); }); -# This reads a braced tokens list, expanding as it goes, -# but expanding \the-like commands only once. +# Simulate reading a plain argument, and then fully expanding it. +# Similar to when \csname is used DefParameterType('Expanded', sub { my ($gullet) = @_; - $gullet->readBalanced(1, 0, 1); }, + return $gullet->readArg(2); }, + reversion => sub { + my ($arg) = @_; + (T_BEGIN, Revert($arg), T_END); }); + +# Like Expanded, but defers \protected, and \the expanded only once. +# Similar to when \edef is used. +DefParameterType('ExpandedPartially', sub { + my ($gullet) = @_; + return $gullet->readArg(1); }, reversion => sub { my ($arg) = @_; (T_BEGIN, Revert($arg), T_END); }); diff --git a/lib/LaTeXML/Engine/pdfTeX.pool.ltxml b/lib/LaTeXML/Engine/pdfTeX.pool.ltxml index 1be65b938..2d074996a 100644 --- a/lib/LaTeXML/Engine/pdfTeX.pool.ltxml +++ b/lib/LaTeXML/Engine/pdfTeX.pool.ltxml @@ -272,9 +272,9 @@ DefMacro('\pdfrestore', ''); # pdfspecial modifier → direct: # stack action → set | push | pop | current -DefMacro('\expanded Expanded', '#1'); +DefMacro('\expanded XGeneralText', '#1'); -DefMacro('\pdfstrcmp Expanded Expanded', sub { +DefMacro('\pdfstrcmp XGeneralText XGeneralText', sub { my $cmp = (ToString($_[1]) cmp ToString($_[2])); return ($cmp == 1 ? T_OTHER('1') : ($cmp == 0 ? T_OTHER('0') diff --git a/lib/LaTeXML/Package.pm b/lib/LaTeXML/Package.pm index 3c98930ca..fdc5eaa2e 100644 --- a/lib/LaTeXML/Package.pm +++ b/lib/LaTeXML/Package.pm @@ -80,7 +80,7 @@ our @EXPORT = (qw(&DefAutoload &DefExpandable &DefLigature &DefMathLigature), # Mid-level support for writing definitions. - qw(&Expand &Invocation &Digest &DigestText &DigestIf &DigestLiteral + qw(&Expand &ExpandPartially &Invocation &Digest &DigestText &DigestIf &DigestLiteral &RawTeX &Let &StartSemiverbatim &EndSemiverbatim &Tokenize &TokenizeInternal &IsEmpty), @@ -899,17 +899,23 @@ sub generateID_nextid { # #====================================================================== -# Return $tokens with all tokens expanded +# Return $tokens with all tokens fully expanded sub Expand { my (@tokens) = @_; return () unless @tokens; - return $STATE->getStomach->getGullet->readingFromMouth(LaTeXML::Core::Mouth->new(), sub { - my ($gullet) = @_; - $gullet->unread(@tokens); - my @expanded = (); - while (defined(my $t = $gullet->readXToken(0))) { - push(@expanded, $t); } - return Tokens(@expanded); }); } + my $gullet = $STATE->getStomach->getGullet; + return $gullet->readingFromMouth(LaTeXML::Core::Mouth->new(), sub { + $gullet->unread(T_BEGIN, @tokens, T_END); + return $gullet->readBalanced(2, 0, 1); }); } + +# Return $tokens, partially expanded (defer protected, and results of \the) +sub ExpandPartially { + my (@tokens) = @_; + return () unless @tokens; + my $gullet = $STATE->getStomach->getGullet; + return $gullet->readingFromMouth(LaTeXML::Core::Mouth->new(), sub { + $gullet->unread(T_BEGIN, @tokens, T_END); + return $gullet->readBalanced(1, 0, 1); }); } sub Invocation { my ($token, @args) = @_; @@ -4390,7 +4396,7 @@ is applied only when C returns true. Predefined Ligatures combine sequences of "." or single-quotes into appropriate Unicode characters. -=item CC<=>>I<$replacment>,I<%options>);> +=item C=>I<$replacment>,I<%options>);> X A Math Ligature typically combines a sequence of math tokens (XMTok) into a single one. diff --git a/lib/LaTeXML/Package/siunitx.sty.ltxml b/lib/LaTeXML/Package/siunitx.sty.ltxml index b0e35f24e..95c5e898d 100644 --- a/lib/LaTeXML/Package/siunitx.sty.ltxml +++ b/lib/LaTeXML/Package/siunitx.sty.ltxml @@ -1126,7 +1126,7 @@ sub six_parse_literalunits { sub six_process_units { my ($expr) = @_; - $expr = Expand($expr); + $expr = ExpandPartially($expr); # Apparently only partially here if (my $defns = six_convertUnits($expr)) { return six_format_units(six_parse_units($defns)); } else { @@ -1222,8 +1222,9 @@ DefMacro('\lx@six@unitobject@arg{}{}', sub { # Collapsing nested definitions: If the data of this unit are just more unit objects, return them, DefMacro('\lx@six@unitobject@collapsible{}{}', sub { + #DefMacro('\lx@six@unitobject@collapsible{} Expanded', sub { my ($gullet, $name, $data) = @_; - $data = Expand($data); + $data = ExpandPartially($data); # Apparently only partially here my @tokens = $data->unlist; my @result = (); while (@tokens) { diff --git a/t/expansion/partial.pdf b/t/expansion/partial.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1988d63dfd3340f3afffd4d46722add6370e71bc GIT binary patch literal 32341 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 QK*vZ2NlYv(D+2ky0725avH$=8 literal 0 HcmV?d00001 diff --git a/t/expansion/partial.tex b/t/expansion/partial.tex new file mode 100644 index 000000000..8dae40913 --- /dev/null +++ b/t/expansion/partial.tex @@ -0,0 +1,106 @@ +\documentclass{article} +\title{Partial vs.~Full Expansion} +\def\foo{Foo} +\def\foofoo{\foo} +\protected\def\pfoo{\foo} +\DeclareRobustCommand\rfoo{\foo} + +\newtoks\tfoo +\tfoo={\foo} + +\newtoks\mysave + +\let\notrelax\relax +\def\junk{ \relax \notrelax } +\def\junkjunk{ \junk \relax \junk } + + +\begin{document} + +\section{Test Filler} +Uppercase: +\uppercase{letters}, +\uppercase \relax {letters}, +\uppercase \notrelax {letters}, +\uppercase \junk {letters}, +\uppercase \junkjunk {letters}. + +strcmp: \pdfstrcmp{\foo}{\foo}, +\pdfstrcmp \relax {\foo}{\foo}, +\pdfstrcmp \junk {\foo} \junkjunk {\foo}. + +\section{cmp to \string\foo (0=same)} +w/M=Macro, I=Indirect, P=Protected, R=Robust, T=The, X=expandafter + +M \pdfstrcmp{\foo}{\foo}; +I \pdfstrcmp{\foofoo}{\foo}; +P \pdfstrcmp{\pfoo}{\foo}; +R \pdfstrcmp{\rfoo}{\foo}; +T \pdfstrcmp{\the\tfoo}{\foo}; +XP \expandafter\pdfstrcmp\expandafter{\pfoo}{\foo}; +XR \expandafter\pdfstrcmp\expandafter{\rfoo}{\foo}; +XT \expandafter\pdfstrcmp\expandafter{\the\tfoo}{\foo}. + + +% Error: \expanded\foo +%\foo \foofoo \pfoo \rfoo \the\tfoo + + +\section{Test \string\expanded\ redefinition timing} + +\begin{itemize} +\item[Normal:] {M \foo; I \foofoo; P \pfoo; R \rfoo; T \the\tfoo.} + +\item[Expanded:] \expanded{M \foo; I \foofoo; P \pfoo; R \rfoo; T \the\tfoo.} + +{ +\edef\stuff{M \foo; I \foofoo; P \pfoo; R \rfoo; T \the\tfoo.} +\def\foo{FOO} +\item[Edef:] \stuff +} + +{ +\mysave{M \foo; I \foofoo; P \pfoo; R \rfoo; T \the\tfoo.} +\def\foo{FOO} +\item[Tokens:] \the\mysave +} + +{ +\expandafter\mysave\expandafter{M \foo; I \foofoo; P \pfoo; R \rfoo; T \the\tfoo.} +\def\foo{FOO} +\item[Expandafter Tokens:] \the\mysave +} + +{ +\mysave={\expanded{M \foo; I \foofoo; P \pfoo; R \rfoo; T \the\tfoo.}} +\def\foo{FOO} +\item[Tokens Expanded:] \the\mysave +} + +{ +\expandafter\mysave\expandafter{\expanded{M \foo; I \foofoo; P \pfoo; R \rfoo; T \the\tfoo.}} +\def\foo{FOO} +\item[Expandafter Tokens Expanded:] \the\mysave +} + + +{ +% OMIT Robust!!! +\item[CSName:] \expandafter\string\csname M \foo; I \foofoo; P \pfoo; T \the\tfoo.\endcsname +} +\end{itemize} + +\section{Environments} +\newenvironment{bracketed}{[}{]\par} +\newtoks\mytestname +\mytestname={bracketed} +\def\testname{bracketed} +\protected\def\ptestname{bracketed} +\DeclareRobustCommand{\Ptestname}{bracketed} +Normal: \begin{bracketed}stuff\end{bracketed} +Macro: \begin{\testname}stuff\end{\testname} +Protected: \begin{\ptestname}stuff\end{\ptestname} +%Robust: \begin{\Ptestname}stuff\end{\Ptestname} +Robust: Error!\par +The: \begin{\the\mytestname}stuff\end{\the\mytestname} +\end{document} diff --git a/t/expansion/partial.xml b/t/expansion/partial.xml new file mode 100644 index 000000000..1a92014aa --- /dev/null +++ b/t/expansion/partial.xml @@ -0,0 +1,157 @@ + + + + + + + Partial vs. Full Expansion +
+ + 1 + 1 + §1 + + <tag close=" ">1</tag>Test Filler + +

Uppercase: +LETTERS, +LETTERS, +LETTERS, +LETTERS, +LETTERS.

+
+ +

strcmp: 0, +0, +0.

+
+
+
+ + 2 + 2 + §2 + + <tag close=" ">2</tag>cmp to “foo(0=same) + +

w/M=Macro, I=Indirect, P=Protected, R=Robust, T=The, X=expandafter

+
+ +

M 0; +I 0; +P 1; +R 1; +T 1; +XP 0; +XR 1; +XT 0.

+
+
+
+ + 3 + 3 + §3 + + <tag close=" ">3</tag>Test “expanded redefinition timing + + + + + Normal: + item Normal: + + +

M Foo; I Foo; P Foo; R Foo; T Foo.

+
+
+ + + Expanded: + item Expanded: + + +

M Foo; I Foo; P Foo; R Foo; T Foo.

+
+
+ + + Edef: + item Edef: + + +

M Foo; I Foo; P FOO; R Foo; T FOO.

+
+
+ + + Tokens: + item Tokens: + + +

M FOO; I FOO; P FOO; R FOO; T FOO.

+
+
+ + + Expandafter Tokens: + item Expandafter Tokens: + + +

M FOO; I FOO; P FOO; R FOO; T FOO.

+
+
+ + + Tokens Expanded: + item Tokens Expanded: + + +

M FOO; I FOO; P FOO; R FOO; T FOO.

+
+
+ + + Expandafter Tokens Expanded: + item Expandafter Tokens Expanded: + + +

M Foo; I Foo; P FOO; R Foo; T FOO.

+
+
+ + + CSName: + item CSName: + + +

“M Foo; I Foo; P Foo; T Foo.

+
+
+
+
+
+
+ + 4 + 4 + §4 + + <tag close=" ">4</tag>Environments + +

Normal: [stuff]

+
+ +

Macro: [stuff]

+
+ +

Protected: [stuff]

+
+ +

Robust: Error!

+
+ +

The: [stuff]

+
+
+