# Strange error message due to xparse and \newenvironment

I get the following strange error when I compile my document:

! Incomplete \ifcase; all text was ignored after line 256.
<inserted text>
\fi
l.256       \foo[
0]{|>I>-:a:c.-:a:c:c b|}\\
?

This is far from a minimal working example, but here is a relevant piece of it:

\documentclass{article}

\usepackage{xparse}

\usepackage{tikz}
\tikzset{external/system call={pdflatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"}}
\tikzexternalize[prefix=figures/cache/] %,up to date check=md5]

% Colors
\definecolor{tape}{rgb}{.9,.9,.9}
\definecolor{transition}{rgb}{.1,.4,.9}
\definecolor{quantum}{rgb}{1,.8,.1}
\newcommand{\ta}{.8}
\newcommand{\dx}{.175}

\pgfdeclarelayer{blurb}
\pgfdeclarelayer{pipe}
\pgfdeclarelayer{tape}
\pgfdeclarelayer{quantum}
\pgfsetlayers{background,blurb,pipe,tape,quantum,main}

% Graph environments
% need to use environ package to work with externalizing tikz for caching
\usepackage{environ}
\NewEnviron{tape}[1][1]{%
%\newenvironment{tape}[1][1]{%
%expand body command exactly once, then take md5 sum from it
\tikzsetnextfilename{\pdfmdfivesum{\expandafter\detokenize\expandafter\expandafter\expandafter{\csname BODY\endcsname}}}%
\begin{tikzpicture}[
tape/.style = {fill = tape, draw = tape, line width=\dx\ts, align = center, rounded corners=.1\ts},
debug/.style = {fill = none, draw = none},
quantum/.style = {fill = quantum, draw = quantum, line width=\dx\ts, align = center, rounded corners=.1\ts},
transition/.style = {fill = transition, draw=none, line width=\dx\ts},
draw=black,
line width=.08\ts,
baseline = #1,
x=\ta\ts,y=\ts
]
%}{
\BODY
\begin{pgfonlayer}{tape}
\draw[tape] (0,0) rectangle (\thetx+\thetx*\dx-\dx,1);
\end{pgfonlayer}
\draw[debug] (current bounding box.north east) rectangle (current bounding  box.south west);
\end{tikzpicture}%
}

% Tape symbol macro
\makeatletter
\newcommand\tapesymbols[1]{%
\@tapesymbols#1\@nnil
}
\def\@tapesymbols#1{%
\ifx\@nnil#1\relax\else%
\@nameuse{tapesymbols@char@#1\expandafter}%
\fi
}
\DeclareDocumentCommand \defcharcode { m O{} O{} m }{
\@namedef{tapesymbols@char@#1}#2#3{
\begin{scope}[shift={(\thetx + \thetx*\dx,0)}]
\draw[debug] (0,0) rectangle (\ta\ts,\ts);
\begin{pgfinterruptboundingbox}
#4
\end{pgfinterruptboundingbox}
\end{scope}
\stepcounter{tx}
\@tapesymbols
}%
}
\makeatother
\DeclareDocumentCommand \inputinkscape{ m O{.01} }{
\begin{scope}[x=#2\ts,y=#2\ts,yscale=-1,shift={(0,-\ts)}]%have to give explicit units here
\InputIfFileExists{./figures/#1}{}{\input{#1}}
\end{scope}
}

% transition and penalty markers
\defcharcode{>}{
}
\defcharcode{<}{
}
\defcharcode{-}{
\begin{pgfonlayer}{quantum}
\draw[quantum] (0,0) rectangle (\ta\ts,\ts);
\end{pgfonlayer}
}
\defcharcode{,}{
\begin{pgfonlayer}{quantum}
\draw[quantum] (0,0) rectangle (2*\ta\ts+6*\dx,\ts);
\end{pgfonlayer}
}
% rhombus
\newcommand{\rhombus}[1]{
\draw[#1] (.1,.5) -- (.5,.8) -- (.9,.5) -- (.5,.2) -- cycle;
}

% symbols
\defcharcode{|}{
\draw[double=tape] (.5,0) -- (.5,1);
}
\defcharcode{!}{
\draw[decorate, decoration={coil, aspect=0, amplitude=.04cm, segment length=0.07cm}] (.5,0) -- (.5,1);
}
\defcharcode{?}{
\draw[line width=1.5*\dx\ts,black] (.5,0) -- (.5,1);
}
\defcharcode{o}{
\draw[rounded corners=.2] (.1,.1) rectangle (.9,.9);
}
\defcharcode{O}[#1]{
\draw[rounded corners=.2,fill=black] (.05,.05) rectangle (.95,.95);
\ifx#1T
\node[text centered,text height=5,scale=.7,white] at (.5,.4) {\textbf{\textup{T}}};
\else\ifx#1U
\node[text centered,text height=5,scale=.7,white] at (.5,.4) {\textbf{\textup{U}}};
\else\ifx#1A
\node[text centered,text height=5,scale=.7,white] at (.5,.4) {\textbf{\textup{A}}};
\else\ifx#1H
\node[text centered,text height=5,scale=.7,white] at (.5,.4) {\textbf{\textup{H}}};
\else\ifx#1S
\node[text centered,text height=5,scale=.7,white] at (.5,.4) {\textbf{\textup{S}}};
\else
\node[text centered,text depth=1,white] at (.5,.4) {$#1$};
\fi\fi\fi\fi\fi
}
\defcharcode{.}{
\stepcounter{tx}
}
\defcharcode{G}{
\inputinkscape{ghost}
}
\defcharcode{B}{
\inputinkscape{ghostb}
}
\defcharcode{g}{
\inputinkscape{ighost}
}
\defcharcode{b}{
\inputinkscape{ighostb}
}
\defcharcode{I}{
\inputinkscape{initializer}
}
\defcharcode{+}{
\draw[fill,rounded corners=.2] (.1,0) -- (.1,1) -- (1,.5) -- cycle;
\begin{scope}[line width=1,white,line cap=round]
\draw (0.2,.5) -- (0.7,.5);
\draw (0.45,.25) -- (.45,.75);
\end{scope}
}
\defcharcode{D}{
\draw[fill,rounded corners=.2] (.1,0) -- (.1,1) -- (1,.5) -- cycle;
}
\defcharcode{X}{
\draw[rounded corners=.2] (.1,0) -- (.1,1) -- (1,.5) -- cycle;
}
\defcharcode{Y}{
\draw[rounded corners=.2] (.1,0) -- (.1,1) -- (1,.5) -- cycle;
\draw[rounded corners=.2] (.3,.3) -- (.3,.7) -- (.65,.5) -- cycle;
}
\defcharcode{Z}{
\draw[rounded corners=.2] (.9,0) -- (0,.5) -- (.9,1) -- cycle;
}
\defcharcode{C}{
\draw[fill, rounded corners=.2] (.9,0) -- (0,.5) -- (.9,1) -- cycle;
}
\defcharcode{:}[#1]{
\ifx#1T
\node[text centered,text height=5,scale=.7] at (.5,.35) {\textbf{\textup{T}}};
\else\ifx#1U
\node[text centered,text height=5,scale=.7] at (.5,.35) {\textbf{\textup{U}}};
\else\ifx#1A
\node[text centered,text height=5,scale=.7] at (.5,.35) {\textbf{\textup{A}}};
\else\ifx#1H
\node[text centered,text height=5,scale=.7] at (.5,.35) {\textbf{\textup{H}}};
\else\ifx#1S
\node[text centered,text height=5,scale=.7] at (.5,.35) {\textbf{\textup{S}}};
\else
\node[text centered,text height=5] at (.5,.4) {$#1$};
\fi\fi\fi\fi\fi
}
\defcharcode{;}[#1]{
\node[text centered,text height=5,text depth=-0.2] at (.6,.4) {$\dot{#1}$};
}
\defcharcode{"}[#1]{
\node[text centered,text height=5,text depth=-0.2] at (.6,.4) {$\ddot{#1}$};
}
\defcharcode{*}[#1]{
\node[text centered,text height=5,text depth=-0.2] at (.6,.4) {$\vec{#1}$};
}
\defcharcode{@}[#1]{
\draw[fill = black] (0,0) -- (0,1) -- (.6,1) -- (1,.5) -- (.6,0) -- cycle;
\ifx#1r
\rhombus{fill=white,draw=none}
\else\ifx#1T
\node[text centered,text height=5,scale=.7,white] at (.4,.4) {\textbf{\textup{T}}};
\else\ifx#1U
\node[text centered,text height=5,scale=.7,white] at (.4,.4) {\textbf{\textup{U}}};
\else\ifx#1A
\node[text centered,text height=5,scale=.7,white] at (.4,.4) {\textbf{\textup{A}}};
\else\ifx#1H
\node[text centered,text height=5,scale=.7,white] at (.4,.4) {\textbf{\textup{H}}};
\else\ifx#1S
\node[text centered,text height=5,scale=.7,white] at (.4,.4) {\textbf{\textup{S}}};
\else
\node[text centered,text height=5,white] at (.4,.4) {$#1$};
\fi\fi\fi\fi\fi\fi
}
\defcharcode{r}{
\rhombus{}
}
\defcharcode{R}{
\rhombus{fill=black}
}
\defcharcode{w}{
\draw (.1,.6) -- (.5,.9) -- (.9,.6);
\draw (.1,.4) -- (.5,.1) -- (.9,.4);
}

% tape macro
\newlength{\ts}
\newcounter{tx}
\DeclareDocumentCommand \foo { O{0} m } {%
\settoheight{\ts}{Z}%
\setlength{\ts}{1.2\ts}%
\setcounter{tx}{0}%
\begin{tape}
\draw[debug] (-#1-#1*\dx-\dx,0) -- (0,1);
\tapesymbols{#2}
\end{tape}%
}

\newenvironment{rules}{%
\renewcommand{\arraystretch}{0.8}%
\begin{tabular}[t]{@{}l@{}}
}{
\end{tabular}%
}

\newcommand{\rvdots}{\multicolumn{1}{c}{\vdots}}

\begin{document}
\begin{rules}
\foo[0]{|>I>-:a:c.-:a:c:c b|}\\
\foo[1]{<-:a<>I>:c}\\
\foo[2]{<:c<I}\\
\rvdots\\
\foo[6]{:c>I>:cb|}\\
\foo[7]{<:c<>I>b|}\\
\foo[0]{|-:a:c.-:a:c:c<o<B|}
\end{rules}
\end{document}

I think the problem is caused by the combination of \DeclareDocumentCommand (which takes an optional argument) and the rules environment.

Any suggestions on how to fix this while keeping the same functionality?

Note: My document used to compile just fine but the error message seems to have started to appear after I updated the xparse package very recently.

• It would be easier to provide a better solution if we would know what's intended with \foo inside of the tabular environment. – user31729 Mar 29 '16 at 18:19
• It calls something that generates a TikZ figure (which is later externalized). – Māris Ozols Mar 29 '16 at 18:33
• See my explanations to this question (and my answer there), perhaps this is related: tex.stackexchange.com/questions/283970/…, concerning the tikzexternalize feature – user31729 Mar 29 '16 at 21:16
• I don't think the externalization is causing the issue. Everything was working fine until I updated all packages to their latest version with tlmgr update --all. After that something broke and I started getting this error. I haven't been able to compile my document since. – Māris Ozols Mar 29 '16 at 21:54
• This is a 'passing issue' due to a problem in expl3: I'd expect it to go away in the next tlmgr update set. – Joseph Wright Mar 29 '16 at 22:18

\foo is not expandable (due to [...] argument), so try \DeclareExpandableDocumentCommand, but I suppose, there might be better approaches than using \foo this way.

\documentclass{article}
\usepackage{xparse}

\newenvironment{rules}{%
\tabular{l}
}{
\endtabular%
}

\DeclareExpandableDocumentCommand\foo{ O{0} m } {%
}

\begin{document}
\begin{rules}
\foo[0]{}
\end{rules}
\end{document}
• \DeclareExpandableDocumentCommand indeed fixed the problem in the code snippet I posted, but it doesn't work in the original larger file which is much more complicated (among other things this code externalizes TikZ figures). – Māris Ozols Mar 29 '16 at 18:29
• @MārisOzols: Well, I can't fix 'code' which is invisible to me – user31729 Mar 29 '16 at 18:30
• I will try to distill the relevant part... – Māris Ozols Mar 29 '16 at 18:37
• I just read up about the distinction between expandable and non-expandable (I wasn't familiar with this before). My \foo command is definitely not expandable since it involves variables and a counter. – Māris Ozols Mar 29 '16 at 20:08
• When I use \DeclareExpandableDocumentCommand in my code, I get a completely non-informative error message: ! Undefined control sequence. \hyper@makecurrent ...activestrue \edef \Hy@param {#1}\ifx \Hy@param \Hy@cha... l.232 } ? – Māris Ozols Mar 29 '16 at 20:28