[Tex/LaTex] Dealing with lists: error “Argument of \reserved@a has an extra }”

errors

I'm trying to set up a program in order to iterate over a list of elements formatted like [number1][content1][number2][content2]. The following code is a minimal not working example: (in real code the variable \@list would be defined inputting a whole file).

\documentclass[a4paper,11pt]{article}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[italian]{babel}

\makeatletter
\newif\ifendlist%
\endlistfalse%
\errorcontextlines 10000
\tracingmacros5

\def\@list{[1][A string][1][Another string][2][Yet another one]}

\def\@grabnextelement[#1][#2]{%
  \gdef\@elementnumber{#1}%
  \gdef\@elementcontent{#2}%
}

\def\@nextelement{%
  \@ifnextchar[\@grabnextelement\endlisttrue%
}

\def\@advancelist{%
  \expandafter\protected@xdef\expandafter\@list{\expandafter\@nextelement\@list}%
}

\def\printlist{%
  \loop\unless\ifendlist%
  \@advancelist%
  \@elementnumber \hskip 1.5em \@elementcontent

  \repeat%
}
\makeatother

\begin{document}
\printlist%
\end{document}

I don't understand why, if I try to execute the above code, I get an error:

! Argument of \reserved@a has an extra }.
<inserted text> 
                \par 
<to be read again> 
                   }
\iterate ->\unless \ifendlist \@advancelist 
                                            \@elementnumber \hskip 1.5em \@e...

\loop ...elax \expandafter \iterate \fi }\iterate 
                                                  \let \iterate \relax 

l.38 \printlist
               %

I'm not a TeX wizard, but I tried to protect all edef and xdef.
Can someone point out what is happening here?

More informations about the expansions:

\printlist ->\loop \unless \ifendlist \@advancelist \@elementnumber \hskip 1.5em \@elementcontent \par \repeat 

\loop #1\repeat ->\def \iterate {#1\relax \expandafter \iterate \fi }\iterate \let \iterate \relax 
#1<-\unless \ifendlist \@advancelist \@elementnumber \hskip 1.5em \@elementcontent \par 

\iterate ->\unless \ifendlist \@advancelist \@elementnumber \hskip 1.5em \@elementcontent \par \relax \expandafter \iterate \fi 

\@advancelist ->\expandafter \protected@xdef \expandafter \@list {\expandafter \@nextelement \@list }

\protected@xdef ->\let \@@protect \protect \let \protect \@unexpandable@protect \afterassignment \restore@protect \xdef 

\@list ->[1][A string][1][Another string][2][Yet another one]

\@nextelement ->\@ifnextchar [\@grabnextelement \endlisttrue 

\@ifnextchar #1#2#3->\let \reserved@d =#1\def \reserved@a {#2}\def \reserved@b {#3}\futurelet \@let@token \@ifnch 
#1<-[
#2<-\@grabnextelement 
#3<-\endlisttrue 

\reserved@a #10#2{->\expandafter \def \expandafter \it@ccap  \reserved@b #10{

I do see there is some odd thing going on with \reserved@a, but I don't realize how it could be solved and why it is happening.

Best Answer

You can't use \@ifnextchar in a \protected@xdef as it doesn't work via expansion however do you need the loop and definitions at all, as opposed to simply evaluating the list?

enter image description here

\documentclass{article}

\begin{document}

\makeatletter

\def\@list{[1][A string][1][Another string][2][Yet another one]}

\def\printlist{\expandafter\printitem\@list[\relax][]}

\def\printitem[#1][#2]{%
  \ifx\relax#1%
  \else
  #1\hskip 1.5em #2\par
  \expandafter\printitem
  \fi}

\printlist

\end{document}
Related Question