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

1 Answer 1

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

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .