Background
Using a handful of answers in this site, I have come up with a solution for building a list of equations (with tocloft
), such that two or more of them can be grouped inside an align
environment and high-level typesetting is relatively simple:
\documentclass{article}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{amsmath}
\usepackage{tocloft}
\usepackage{blindtext}
% Add a new list for equations
\newcommand{\loename}{List of equations}
\newlistof{equations}{equ}{\loename}
\newcommand{\aligneqs}[2]%
{\addcontentsline{equ}{equations}{\protect\numberline{\ref{#2}}#1}}
\setlength{\cftequationsnumwidth}{2.5em}
% https://tex.stackexchange.com/q/451/53787
% https://tex.stackexchange.com/q/16883/53787
\makeatletter
% Temporary lists: store equations, references, and deferred commands
\gdef\listeqs{}
\gdef\listrefs{}
\gdef\listdefers{}
\newcounter{DeferredCommands}
% Converts a number to Roman notation
% https://tex.stackexchange.com/q/9718/53787
% https://tex.stackexchange.com/q/23487/53787
\newcommand*{\rom}[1]{\expandafter\@slowromancap\romannumeral #1@}
% Add an element to a list
\def\addtolist#1#2{%
\g@addto@macro{#1}{#2,}
}
% Add an element to a list, expanding it first
% https://tex.stackexchange.com/q/67367/53787
\def\addexpandedtolist#1#2{%
\edef\ATL@temp{\noexpand\g@addto@macro\noexpand#1{\noexpand#2,}}
\ATL@temp
}
% Defers the execution of a command, storing it in a list
\DeclareDocumentCommand{\DeferCommand}{mm}{%
\stepcounter{DeferredCommands}
\expandafter\def\csname DC@\rom{\arabic{DeferredCommands}}\endcsname{#2}
\addexpandedtolist{#1}{DC@\rom{\arabic{DeferredCommands}}}
}
% Inserts an equation, its reference, and its TOC line to their
% respective lists
\DeclareDocumentCommand{\InsertEquation}{mmm}{%
\addtolist{\listeqs}{#1}
\addtolist{\listrefs}{#3}
\DeferCommand{\listdefers}{\aligneqs{#2}{#3}}
}
% Execute all the deferred commands of the given list
% https://tex.stackexchange.com/q/28787/53787
\DeclareDocumentCommand{\DeferredExecute}{m}{%
\@for \i:=#1 \do{\@nameuse{\i}}
\setcounter{DeferredCommands}{0}
\let#1\@empty
}
% http://handyfloss.net/2007.08/latex-programming-how-to-implement-conditionals/
\newcounter{GArepnum}
\newif\ifGA@first
% Put all the equations inside a macro (first traversal) along
% with placeholders for labels, substitute the placeholders with
% their respective labels (second traversal), and show everything
% inside an "align". After it, execute all the deferred commands
% (stored when inserting an equation) that add the corresponding
% lines to the list of equations.
\DeclareDocumentCommand{\GenerateAlign}{}{%
\def\GA@ans{}
\setcounter{GArepnum}{1}
\GA@firsttrue
\@for \i:=\listeqs \do{%
% https://tex.stackexchange.com/q/53068/53787
\ifx\i\empty\else
\ifGA@first
\GA@firstfalse
\else
% https://tex.stackexchange.com/q/74707/53787
\edef\GA@temp{\noexpand\g@addto@macro\noexpand\GA@ans{\noexpand\\}}
\GA@temp
\fi
\edef\GA@temp{\noexpand\g@addto@macro\noexpand\GA@ans{\i ???}}
\GA@temp
\stepcounter{GArepnum}
\fi
}
\@for \j:=\listrefs \do{%
\ifx\j\empty\else
% https://tex.stackexchange.com/q/104506/53787
\begingroup\edef\GA@perform{\endgroup
\noexpand\patchcmd
{\noexpand\GA@ans}%
{\noexpand ???}%
{\noexpand\label{\unexpanded\expandafter{\j}}}%
{}%
{}%
}%
\GA@perform
\fi
}
\begin{align}
\GA@ans
\end{align}
\DeferredExecute{\listdefers}
\let\listeqs\@empty
\let\listrefs\@empty
}
\makeatother
\begin{document}
\listofequations
\clearpage
\section*{Important formulas}
\blindtext
\InsertEquation{a^2 + b^2 &= c^2}{Pythagorean theorem}{eq:first}
Following is eq.~\ref{eq:first}, depicting Pythagora's theorem:
\GenerateAlign
\Blindtext
\InsertEquation{e &= mc^2}{Einstein Relativity theory}{eq:second}
Following is eq.~\ref{eq:second}, depicting Einstein's relativity theory:
\GenerateAlign
\blindtext
\end{document}
The problem
When isolated and compiled with latexmk -pdf
, the code above works as it should. However, when trying to integrate such code into a larger project (a maths book, complete with TOC, references and the like), I keep getting:
- either
TeX input capacity exceeded (sorry)
, or Runaway argument?
Such results are strange, given that the solution works alone.
The question
Are using lists to store commands or other data (just like in the example) prone to stack exhaustion when combined with other packages?
Depending on the answer, I will post another question, regarding the efficiency of the solution.
%
at ends of lines (that on its own can prevent tail recursion) – David Carlisle Aug 21 '17 at 6:22