# Runaway argument error when creating a macro for code that works outside a macro

I'm certain my problem is due to my almost complete lack of understanding of LaTeX's expansion rules...

I wrote some code, which uses the SageTeX package to keep track of a list of answers to homework problems and then print them all at the end. Here is an example of part of it:

\begin{sagesilent}
class AnswerList:
def __init__(this):
this.answers = []
def _latex_(this):
result = "\\begin{answers}\n"
for answer in this.answers:
result += "    \\item " + str(answer) + "\n"
result += "\\end{answers}\n"
return result
def next(this, answer):
this.answers.append(answer)
answerlist = AnswerList()
\end{sagesilent}


This compiles in my LaTeX document just fine. I then use other SageTeX commands to add answers (in order) to this object, and then print them all at the end automatically, and it produces the desired results. However, I was hoping to move all the programming into macros in a separate file to make it more reusable and to keep my LaTeX document clean. So, one macro I created was:

\newcommand{\makeanswers}{%
\begin{sagesilent}
class AnswerList:
def __init__(this):
this.answers = []
def _latex_(this):
result = "\\begin{answers}\n"
for answer in this.answers:
result += "    \\item " + str(answer) + "\n"
result += "\\end{answers}\n"
return result
def next(this, answer):
this.answers.append(answer)
answerlist = AnswerList()
\end{sagesilent}
}


I then include the second document into my first document (with an \input command) and call \makeanswers right after I enter the document environment in my main LaTeX file. I'm getting runaway argument errors when I try to compile the document.

Is there a way to create a macro that inserts this chunk of LaTeX code? There is probably a more LaTeX-friendly, less Python-dependent, approach to my problem here, but it is what I know...

-
As David says, a MWE would be nice. I have a feeling that this could be useful for me too, if I had some compilable code to work with. –  Svend Tveskæg Jan 23 '13 at 11:12

## 2 Answers

You should be able to get this to work with sagetex, but a pure LaTeX solution is probably best, and shouldn't be too difficult. Here are some ideas on using sagetex, followed by a pure LaTeX solution.

Have you tried putting the sagesilent in an external file without wrapping it in a macro? I think that would work. You will probably have to \input the external file from within the body of the document, because sagesilent doesn't seem to work in the preamble.

I don't have Sage to test with, but here's an equivalent with my pythontex package. If you replace my pycode with sagesilent and \pyc with \sagestr (and maybe get rid of the print()), things will probably work, or at least be close. My definition of the \addanswer macro assumes that your answers won't include # or % (or possibly a few other special characters for sagetex). You should be able to put the class definition and macro definitions in an external file and then \input within the document body (again, sagesilent doesn't seem to like the preamble...incidentally, pythontex doesn't have that limitation).

\documentclass{article}

\usepackage{pythontex}

\newenvironment{answers}{\begin{enumerate}}{\end{enumerate}}

\begin{document}

\begin{pycode}
class AnswerList:
def __init__(this):
this.answers = []
def _latex_(this):
result = "\\begin{answers}\n"
for answer in this.answers:
result += "    \\item " + str(answer) + "\n"
result += "\\end{answers}\n"
return result
def next(this, answer):
this.answers.append(answer)
answerlist = AnswerList()
\end{pycode}

\newcommand{\addanswer}[1]{\pyc{answerlist.next("#1")}}
\newcommand{\printanswers}{\pyc{print(answerlist._latex_())}}

\addanswer{123}

\addanswer{345}

\printanswers

\end{document}


And here's an approach that doesn't need any external Python program. You might be able to modify something like this for your needs.

\documentclass{article}

\makeatletter
\newcommand{\storedanswers}{}
\newcommand{\addanswer}[1]{\g@addto@macro\storedanswers{\item #1}}
\newcommand{\makeanswers}{%
\begin{enumerate}
\storedanswers
\end{enumerate}
}
\makeatother

\begin{document}

\addanswer{123}

\addanswer{345}

\makeanswers

\end{document}

-
+1 for the version directly within LaTeX. –  Bruno Le Floch Jan 23 '13 at 16:58
Love the LaTeX-only implementation. Thanks! –  Jeremy West Jan 24 '13 at 7:51

It helps if you post complete documents rather than fragments, although I don't think I have that package, but if it is doing what I assume it is doing then something like this untested code will probably work.

\catcodeZ=0
\catcode\\=12

Znewcommand{Zmakeanswers}{%
Zbegin{sagesilent}
class AnswerList:
def __init__(this):
this.answers = []
def _latex_(this):
result = "\\begin{answers}\n"
for answer in this.answers:
result += "    \\item " + str(answer) + "\n"
result += "\\end{answers}\n"
return result
def next(this, answer):
this.answers.append(answer)
answerlist = AnswerList()
\end{sagesilent}
}
ZcatcodeZ\=0
`
-