This is a precursor to my real question. But for whatever reason, when I tried reducing my code for something to post here, I got more errors. In particular, the following code gives me an error with the \endcsname in the \foreach loop. While the loop doesn't do anything like what I want it to, in my original code it actually compiled. Now in this snippet I get an error message about a missing \endcsname. Could someone please point out what I'm obviously overlooking?

\documentclass{article}

\usepackage{pgffor}
\usepackage{etoolbox}

\makeatletter

\def\ae@set@main#1:#2\@nil{%%
\expandafter\def\csname ae@slogan@#1/main\endcsname{#2}}
\def\slogan{\@ifstar{\set@slogan}{\get@slogan}}

\def\set@slogan#1#2{\ae@set@#1.0.0.0:#2\@nil}
\def\ae@set@#1.#2.#3.#4:#5\@nil{%%
\expandafter\def\csname ae@slogan@#1@max\endcsname{#2}%%'0
\expandafter\def\csname ae@slogan@#1.#2\endcsname{#5}}

\newif\if@iterate@through@subslogans
\def\get@slogan#1{%%
\@ae@sep#1.0.0\@nil
\ifnum\ae@second>0\relax
\expandafter\ae@get@\ae@first.0.0.0\@nil
:\hspace{0.5em}%%'
\else
\xdef\aemax{\csname ae@slogan@\ae@first @max\endcsname}%%
\typeout{====> MAX=\aemax}%%'
\ifnum\aemax>0\relax
\@iterate@through@subsloganstrue
\fi
\fi
\ae@get@#1.0.0.0\@nil
\if@iterate@through@subslogans
\expandafter\@iterate@subslogans
\fi
\@iterate@through@subslogansfalse
}
\def\ae@get@#1.#2.#3.#4\@nil{%%
\csname ae@slogan@#1.#2\endcsname}

\def\@iterate@subslogans{%%
\edef\ae@list{}
\foreach \myx in {1,2,...,\aemax}
{\typeout{==> (\myx|\ae@first) \csname ae@slogan@\ae@first.\myx \endcsname}%%' :\ae@list
}
\begin{enumerate}\item
\ae@list
\end{enumerate}
}

\def\aeitem{\item}
\def\@ae@sep#1.#2.#3\@nil{%%
\def\ae@first{#1}%%
\def\ae@second{#2}}

%% define slogans
\slogan*{1}{First of all train in the preliminaries}
\slogan*{1.1}{Arithmetic\rule{1em}{2pt}}
\slogan*{1.2}{Algebra}
\slogan*{1.3}{Geometry}

\makeatother
\pagestyle{empty}
\begin{document}

\slogan{1}

\slogan{1.2}

\end{document}


The error message

====> MAX=3
! Missing \endcsname inserted.
\def
l.65   \slogan{1}

-
\usepackage{fixltx2e} will robustify a number of fragile LaTeX commands, including \rule. It, too, will fix your code, for the reasons that David cites in his answer. –  Steven B. Segletes Feb 3 at 0:14

\rule is a fragile command so you can not use it in a \write without \protect.

\slogan*{1.1}{Arithmetic \protect\rule{1em}{2pt}}

-
Argh. I knew I was overlooking something. Stay tuned for my real question because it's this same issue, I think, popping up all over again, but I can't seem to get it to work. –  A.Ellett Feb 2 at 22:09

I'm unable to get even the slightest idea what your code is supposed to do, however, putting \tracingmacros=1 before \slogan{1} shows the following:

\ae@set@ #1.#2.#3.#4:#5\@nil ->\expandafter \def \csname ae@slogan@#1@max\endcs
name {#2}\expandafter \def \csname ae@slogan@#1.#2\endcsname {#5}
#1<-\def
#2<-0
#3<-0
#4<-0
#5<-\reserved@b
! Missing \endcsname inserted.
\def
l.65   \slogan{1}


Since #1 is \def which is not expandable, it can't be used inside \csname...\endcsname.

-
That's where I was getting stuck. There's no \def there to complain about. –  A.Ellett Feb 2 at 22:07
@A.Ellett the \def is random fallout from inappropriate expansion of the \@ifnextchar in the optional argument handling for \rule which doesn't work in a \write –  David Carlisle Feb 2 at 22:10
My code is supposed to define a series of slogans when called as \slogan*{<number>}{<content>}. The code should then present the slogan when called as \slogan{<number>}. Some slogans have subslogans affiliated with them. When calling the master slogan, I was thinking it would be nice to print a list of the subslogans too. It seems, via @DavidCarlisle 's comments and answer, that it isn't in how I'm defining the slogans but in the combination of \typeouts that expansion issues are getting confounded. –  A.Ellett Feb 2 at 22:41

I actually need an alternative to @davidcarlisle 's answer because I cannot rely upon the content passed to \typeout having fragile commands appropriately \protected. Here's a solution which also works by making a call to \detokenize:

  \foreach \myx in {1,2,...,\aemax}
{\typeout{==> (\myx|\ae@first) \csname ae@slogan@\ae@first.\myx \endcsname}%%' :\ae@list
}


  \foreach \myx in {1,2,...,\aemax}

Nevertheless, many thanks to David because I hadn't been thinking about issues with \typeout{...}.