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.

Example:

\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}

unhbox example

I was thinking about making a macro that can expand or behave like an \unhbox

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}
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

  • Now I understand, I was trying to find a way to expand a macro that contains \futurelet. – Cristobal Montecino Nov 26 '17 at 16:06
  • 1
    @CristobalMontecino That's indeed not possible – egreg Nov 26 '17 at 16:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.