6

Related

I made some simple macros for lists, but I do not know how to save a value with an \edef.

I'm not interested in another way to create lists, because it's just an experiment.

I want to know how to save the value of a fully extended macro.

For example: Perform the expansion of \unhbox in a \edef

Edit: I know it does not work, just an example to explain the idea that it expands inside a \hbox but not within an \edef.

<blockquote>
  <p><b>Example:</b></p>

\newlist\mylist
\mylist{append}{hello world}
\begin{document}
    \setbox0=\hbox{\mylist[0]}
    \mylist[0]={bye}
    \edef\value{\unhbox0}
    Saved value: \value\par
    Meaning: {\tt\meaning\value}\par
    Current value: \mylist[0]
\end{document}
  <p><a href="https://i.stack.imgur.com/rpTJ0.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/rpTJ0.png" alt="unhbox example"></a></p>

  <p>I was thinking about making a macro that can expand or behave like an <code>\unhbox</code></p>
</blockquote>

The code for lists

\makeatletter
\def\@parcialexpand#1#2{%
    \def\reserved@a{#1}%
    \edef\reserved@b{#2}%
    \expandafter\reserved@a\reserved@b%
}

\def\@argument#1#2{%
    \begingroup%
        \def\reserved@a{\global#1=}%
        \begingroup%
            \aftergroup\reserved@a\aftergroup{%
                \aftergroup##%
                \aftergroup#2%
            \aftergroup}%
        \endgroup%
    \endgroup%
}

\def\@list@command#1#2{\csname @list@name@#1@command@#2\endcsname}

\def\@list@value#1#2{\csname @list@name@#1@value@#2\endcsname}

\long\def\@list@setvalue#1#2#3{%
    \begingroup%
        \@temptokena=\expandafter{\@list@value{#1}{#2}}%
        \def\reserved@a##1{\@temptokena=\expandafter{##1}}%
        \expandafter\reserved@a\expandafter{\the\@temptokena}%
%
        \edef\reserved@a{\the\@temptokena}%
        \expandafter\gdef\reserved@a{#3}%
    \endgroup%
}

\def\@list@ifexists#1{%
    \edef\reserved@a{\csname @list@name@#1@exists\endcsname}%
    \@temptokena=\expandafter{\csname @list@name@#1@exists\endcsname}%
    \edef\reserved@b{\the\@temptokena}%
    \ifx\reserved@b\reserved@a\relax%
}

\long\def\@list@append#1#2{%
    \begingroup%
        \@tempcnta=\@list@command{#1}{len}%
        %
        \def\reserved@a##1{%
            \@list@setvalue{#1}{##1}{#2}%
        }%
        \expandafter\reserved@a\the\@tempcnta%
%
        \@temptokena=\expandafter{\@list@command{#1}{len}}%
        \def\reserved@a##1{\@temptokena=\expandafter{##1}}%
        \expandafter\reserved@a\expandafter{\the\@temptokena}%
        \edef\reserved@a{\the\@temptokena}%
        %
        \advance\@tempcnta by 1%
        \expandafter\xdef\reserved@a{\the\@tempcnta}%
    \endgroup%
}

\def\@list@pop#1{%
    \begingroup%
        \@tempcnta=\@list@command{#1}{len}%
        %
        \@temptokena=\expandafter{\@list@command{#1}{len}}%
        \def\reserved@a##1{\@temptokena=\expandafter{##1}}%
        \expandafter\reserved@a\expandafter{\the\@temptokena}%
        \edef\reserved@a{\the\@temptokena}%
        %
        \advance\@tempcnta by -1%
        \expandafter\xdef\reserved@a{\the\@tempcnta}%
%
        \def\reserved@a##1{%
            \@list@value{#1}{##1}%
        }%
        \expandafter\reserved@a\the\@tempcnta%
    \endgroup%
}

\def\@list@push#1#2{%
    \begingroup%
        \def\reserved@a##1{\@list{#1}{append}{##1}}%
        \expandafter\reserved@a\expandafter{#2}%
    \endgroup%
}

\def\@list@checkexists#1{%
    \@list@ifexists{#1}%
        \@latex@error{\string\@list: Undefined list: #1}{}%
    \fi%
}
\def\@list@checknoexists#1{%
    \@list@ifexists{#1}%
        \relax%
    \else%
        \@latex@error{\string\@list: Already exists: #1}{}%
    \fi%    
}

\def\@list#1{%
    \@list@checkexists{#1}%
    \@ifnextchar[{%
        \@argument\@temptokena{1}%
        \@parcialexpand{\def\reserved@a}{[\the\@temptokena]}{%
            \@ifnextchar={%
                \@argument\@temptokena{1}%
                \@parcialexpand{\def\reserved@a=}{\the\@temptokena}{%
                    \@list@setvalue{#1}{####1}{################1}%
                }%
                \reserved@a%
            }{%s
                \@list@value{#1}{####1}%
            }%
        }%
        \reserved@a%
    }{%
        \@argument\@temptokena{1}%
        \@parcialexpand{\def\reserved@a}{\the\@temptokena}{%
            \@list@command{#1}{####1}%
        }%
        \reserved@a%
    }%
}

\def\@list@newlist#1#2{%
    \@list@checknoexists{#1}%
    \expandafter\def\csname @list@name@#1@exists\endcsname{}%
    \expandafter\def\csname @list@name@#1@command@len\endcsname{0}%
    \expandafter\def\csname @list@name@#1@command@append\endcsname{\@list@append{#1}}%
    \expandafter\def\csname @list@name@#1@command@pop\endcsname{\@list@pop{#1}}%
    \expandafter\def\csname @list@name@#1@command@push\endcsname{\@list@push{#1}}%
    \def#2{\@list{#1}}%
}
\def\newlist#1{\expandafter\@list@newlist\expandafter{\string#1}#1}
\makeatother

note: push expands the value and performs an append

An example

\newlist\list
\list{append}{hello world}

\begin{document}
        Len is \list{len}\par
        [0]: \list[0]
\end{document}

out

When I tried to use an \edef

\begin{document}
        Len is \list{len}\par
        [0]: \list[0]

        \edef\zerovalue{\list[0]}
\end{document}

! TeX capacity exceeded, sorry [input stack size=5000].
\@argument #1#2->\begingroup \def \reserved@a 
                                              {\global #1=}\begingroup \afte...
l.149   \edef\zerovalue{\list
                            [0]}
!  ==> Fatal error occurred, no output PDF file produced!

A simple trace

\def\expand#1{%
    \toks0=\expandafter{#1}%
    \showthe\toks0%
}
\def\makeexpand#1{\expandafter\expand\expandafter{#1}}
\makeexpand{\list[0]}
\makeexpand{\the\toks0}
\makeexpand{\the\toks0}
\message{LOOP^^J}
\makeexpand{\the\toks0}

> \@list@checkexists {\list}\@ifnextchar [{\@argument \@temptokena {1}\@parcial
expand {\def \reserved@a }{[\the \@temptokena ]}{\@ifnextchar ={\@argument \@te
mptokena {1}\@parcialexpand {\def \reserved@a =}{\the \@temptokena }{\@list@set
value {\list}{####1}{################1}}\reserved@a }{\@list@value {\list}{####
1}}}\reserved@a }{\@argument \@temptokena {1}\@parcialexpand {\def \reserved@a 
}{\the \@temptokena }{\@list@command {\list}{####1}}\reserved@a }[0].
l.151 \makeexpand{\list[0]}

> \@list@ifexists {\list}\@latex@error {\string \@list : Undefined list: \list}
{}\fi \@ifnextchar [{\@argument \@temptokena {1}\@parcialexpand {\def \reserved
@a }{[\the \@temptokena ]}{\@ifnextchar ={\@argument \@temptokena {1}\@parciale
xpand {\def \reserved@a =}{\the \@temptokena }{\@list@setvalue {\list}{####1}{#
###############1}}\reserved@a }{\@list@value {\list}{####1}}}\reserved@a }{\@ar
gument \@temptokena {1}\@parcialexpand {\def \reserved@a }{\the \@temptokena }{
\@list@command {\list}{####1}}\reserved@a }[0].
l.152 \makeexpand{\the\toks0}

> \edef \reserved@a {\csname @list@name@\list@exists\endcsname }\@temptokena =\
expandafter {\csname @list@name@\list@exists\endcsname }\edef \reserved@b {\the
 \@temptokena }\ifx \reserved@b \reserved@a \relax \@latex@error {\string \@lis
t : Undefined list: \list}{}\fi \@ifnextchar [{\@argument \@temptokena {1}\@par
cialexpand {\def \reserved@a }{[\the \@temptokena ]}{\@ifnextchar ={\@argument 
\@temptokena {1}\@parcialexpand {\def \reserved@a =}{\the \@temptokena }{\@list
@setvalue {\list}{####1}{################1}}\reserved@a }{\@list@value {\list}{
####1}}}\reserved@a }{\@argument \@temptokena {1}\@parcialexpand {\def \reserve
d@a }{\the \@temptokena }{\@list@command {\list}{####1}}\reserved@a }[0].
l.153 \makeexpand{\the\toks0}

LOOP
> \edef \reserved@a {\csname @list@name@\list@exists\endcsname }\@temptokena =\
expandafter {\csname @list@name@\list@exists\endcsname }\edef \reserved@b {\the
 \@temptokena }\ifx \reserved@b \reserved@a \relax \@latex@error {\string \@lis
t : Undefined list: \list}{}\fi \@ifnextchar [{\@argument \@temptokena {1}\@par
cialexpand {\def \reserved@a }{[\the \@temptokena ]}{\@ifnextchar ={\@argument 
\@temptokena {1}\@parcialexpand {\def \reserved@a =}{\the \@temptokena }{\@list
@setvalue {\list}{####1}{################1}}\reserved@a }{\@list@value {\list}{
####1}}}\reserved@a }{\@argument \@temptokena {1}\@parcialexpand {\def \reserve
d@a }{\the \@temptokena }{\@list@command {\list}{####1}}\reserved@a }[0].
l.155 \makeexpand{\the\toks0}
  • 2
    You cannot save the expansion of an \unhbox because \unhbox is unexpandable. If your goal is to recover the tokens that were in the box, you cannot do it. See also https://tex.stackexchange.com/questions/31430/expansion-of-macros-and-box-contents – Steven B. Segletes Nov 26 '17 at 02:07

1 Answers1

1

Your \list[0] is not fully expandable. What you mean by “expanding \unhbox” is unclear, though.

Here's a different implementation:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\newlist}{m}
 {
  % allocate the new list
  \montecino_lists_newlist:Nf #1 { \cs_to_str:N #1 }
 }

\cs_new_protected:Nn \montecino_lists_newlist:Nn
 {
  \seq_new:c { l_montecino_lists_#2_seq }
  \NewExpandableDocumentCommand{#1}{m}
   {
    \str_case:nnF { ##1 }
     {
      {len}{ \montecino_lists_len:n { #2 } }
      {append}{ \montecino_lists_append:nn { #2 } }
      {push}{ \montecino_lists_append:nn { #2 } }
      {pop}{ \montecino_lists_pop:n { #2 } }
     }
     { \montecino_lists_get:nn { #2 } { ##1 + 1 } }
   }
 }
\cs_generate_variant:Nn \montecino_lists_newlist:Nn { Nf }

\cs_new:Nn \montecino_lists_len:n
 {
  \seq_count:c { l_montecino_lists_#1_seq }
 }
\cs_new_protected:Nn \montecino_lists_append:nn
 {
  \seq_put_right:cn { l_montecino_lists_#1_seq } { #2 }
 }
\cs_new_protected:Nn \montecino_lists_pop:n
 {
  \seq_pop_right:cN { l_montecino_lists_#1_seq } \l_tmpa_tl
  \tl_use:N \l_tmpa_tl
 }
\cs_new:Nn \montecino_lists_get:nn
 {
  \seq_item:cn { l_montecino_lists_#1_seq } { #2 }
 }

\ExplSyntaxOff

\newlist\mylist

\mylist{append}{hello world}

\begin{document}

Len is \mylist{len}

[0]: \mylist{0}

\mylist{append}{ABC} \mylist{len}

\mylist{push}{DEF} \mylist{len}

\mylist{0} \mylist{1} \mylist{2}

\mylist{pop} \mylist{len}

\edef\test{\mylist{len}}\texttt{\meaning\test}

\edef\test{\mylist{0}}\texttt{\meaning\test}

\end{document}

I can't see a difference between your append and push, so I implemented them with the same function.

I also changed the name, because \list is taken in LaTeX.

enter image description here

egreg
  • 1,121,712