%%
%% Package: spectralsequences v1.3.3 2023-01-28
%% Author: Hood Chatham
%% Email: [email protected]
%% Date: 2023-01-28
%% License: Latex Project Public License
%%
%% File: sseqparsers.code.tex
%%
%%    Defines the parsers and input sanitizers. Also handles tikz primitive parsing and \isalive.
%%    ExplSyntaxOn for this whole file!

\ExplSyntaxOn
\let\sseq@NoValue\c__xparse_no_value_tl
% They changed \c__xparse_no_value_tl to \c_novalue_tl at some point. If the first definition doesn't work, try again.
\@ifundefined{sseq@NoValue}{\let\sseq@NoValue\c_novalue_tl}{}

\protected\def\sseqparseint#1#2{
   \sseq@ifintexpr{#2+0}{ % +0 here to prevent \lastx from freaking out if it's at the end of #2.
       \edef#1{\the\numexpr#2\relax}
   }{
       \sseq@error{invalid-int-expr}
   }
}

% WARNING: doesn't work =(
\def\sseq@ifint#1{
   \ifcat$\romannumeral0#1$
       \prg_return_true:
   \else
       \ifcat$\romannumeral-0#1$
           \prg_return_true:
       \else
           \prg_return_false:
       \fi
   \fi
}

% Prevent \protect from causing trouble for \pgfmathparse
\let\sseq@pgfmathparse@orig\pgfmathparse
\protected\def\sseq@pgfmathparse#1{%
   \bgroup
   \let\@@protect\protect
   \def\protect{}%
   \let\pgfmath@protected@edef\edef
   \sseq@pgfmathparse@orig{#1}%
   \restore@protect
   \sseq@smuggle@macro\pgfmathresult
   \egroup
}


%%% ifpgfmathexpr
% #1 -- expression to test
% #2 -- true case
% #3 -- false case
% This tests true if \pgfmathparse{#1} throws an error or not. Luckily, \pgfmathparse pipes its errors through \pgfmath@error so this is easy.
\def\sseq@ifpgfmathexpr#1{
   \begingroup
   \let\protect\pgfutil@empty
   \global\sseq@gtempiftrue
   \def\pgfmath@error##1##2{\global\sseq@gtempiffalse\sseq@closegroups\sseq@break}
   \def\sseq@groupflag{}
   \pgfmathparse{#1}
   \global\let\ifpgfmathunitsdeclared\ifpgfmathunitsdeclared
   \ifpgfmathunitsdeclared
       \xdef\sseq@mathresult{\pgfmathresult pt}
   \else
       \xdef\sseq@mathresult{\pgfmathresult}
   \fi
   \endgroup
   \sseq@breakpoint
   \ifsseq@gtempif
       \@xp\@firstoftwo
   \else
       \@xp\@secondoftwo
   \fi
}

\def\sseq@closegroups{\ifx\sseq@groupflag\empty\endgroup\@xp\sseq@closegroups\fi}


% Test if single token input is a digit
\def\sseq@ifdigit#1{
   \ifodd0
       \ifx#1 0 1 \else
       \ifx#1 1 1 \else
       \ifx#1 2 1 \else
       \ifx#1 3 1 \else
       \ifx#1 4 1 \else
       \ifx#1 5 1 \else
       \ifx#1 6 1 \else
       \ifx#1 7 1 \else
       \ifx#1 8 1 \else
       \ifx#1 9 1 \else
       \fi \fi \fi \fi \fi
       \fi \fi \fi \fi \fi
   \relax
       \@xp\@firstoftwo
   \else
       \@xp\@secondoftwo
   \fi
}

%%% ifintexpr
% #1 -- expresion to test
% #2 -- true case
% #3 -- false case
% This tests true if \numexpr #1\relax throws no error and consumes all of #1 and false otherwise.

% Spaces matter to us, because \sseq@ifintexpr{1 1} is false but \sseqsifintexpr{11} is true
% so we make spaces into catcode other and use \scantokens
\def\sseq@fexpsafenil{\@nx\sseq@fexpsafenil}

\def\sseq@ifintexpr#1{%
   \bgroup
   \sseq@tempcount\z@
   \sseq@ifintexpr@{needsint}#1\sseq@fexpsafenil%
   \@xp\egroup\next
}

% We need to use \futurelet so that we can detect open braces even when they only surround one token like {1}
% also we use it to detect spaces. Store the state in \sseq@ifintexpr@state first.
\def\sseq@ifintexpr@#1{\def\sseq@ifintexpr@state{#1}\futurelet\testtok\sseq@ifintexpr@@}
\def\sseq@ifintexpr@@{%
   \ifx\testtok\bgroup%
       \let\next\sseq@ifintexpr@false
   \else
       \ifx\testtok\sseq@fexpsafenil
           \@xp\let\@xp\next\csname sseq@ifintexpr@@\sseq@ifintexpr@state @done\endcsname
       \else
           % We need to check here for a space because \string<space> produces NO OUTPUT regardless of the catcode of the space.
           % This messes up \sseq@ifintexpr@@@ because it doesn't expect \string#1 to produce no characters.
           \@xp\ifx\space\testtok
               \def\next{\sseq@ifintexpr@next{\space}\@xp\next\romannumeral-`0}
           \else
               \let\next\sseq@ifintexpr@@@
           \fi
       \fi
   \fi
   \next
}

\def\sseq@ifintexpr@@@#1{
   \ifcat$\@xp\@gobble\string#1$%
       \@xp\sseq@ifintexpr@@@@\@xp#1
   \else
       % This is a macro, so fexpand it
       % Then use f expansion.
       \@xp\sseq@ifintexpr@@@fexpcs\@xp#1
   \fi
}

\def\sseq@ifintexpr@@@fexpcs{\exp_last_unbraced:Nf\sseq@ifintexpr@@@fexpcs@}
\def\sseq@ifintexpr@@@fexpcs@{\futurelet\testtok\sseq@ifintexpr@@@fexpcs@@}
\def\sseq@ifintexpr@@@fexpcs@@{
   \ifx\testtok\bgroup
       \@xp\sseq@ifintexpr@false % We already tested for groups above, so we need to check if this expanded to a group
   \else
       \@xp\sseq@ifintexpr@@@@ % If it's still a control sequence, then this will fail in the \pgfutil@ifundefined step
   \fi
}



% We can't just use \futurelet because "\let\testtok(" makes \testtok unexpandable
% (I guess that makes sense, but why is it that I need \@xp\ifx\otherspace above if I've also \let\otherspace to a character? Mysterious...),
% so then "\csname hello\testtok\endcsname" is an error. This indexes into our state machine,
% cases: a digits, + or -, * or /, (, ), or something else (anything else always leads to false
\def\sseq@ifintexpr@@@@#1{%
   \ifx#1\sseq@fexpsafenil
       \def\next{\csname sseq@ifintexpr@@\sseq@ifintexpr@state @done\endcsname\sseq@fexpsafenil}%
   \else
       \sseq@ifdigit{#1}%
           {\sseq@ifintexpr@next{digit}}%
           {%
               \ifx#1+%
                   \sseq@ifintexpr@next{+-}
               \else
                   \ifx#1-%
                       \sseq@ifintexpr@next{+-}
                   \else
                       \ifx#1*%
                           \sseq@ifintexpr@next{*/}
                       \else
                           \ifx#1/%
                               \sseq@ifintexpr@next{*/}
                           \else
                               % This extra \string here is so that if a control sequence fexpanded and still gave a control sequence,
                               % we don't get a missing \endcsname error here, it just returns false
                               \pgfutil@ifundefined{sseq@ifintexpr@@\sseq@ifintexpr@state @\string#1}%
                                   {\let\next\sseq@ifintexpr@false}%
                                   {\sseq@ifintexpr@next{#1}}%
                           \fi
                       \fi
                   \fi
               \fi
           }%
   \fi
   \next
}

\def\sseq@ifintexpr@true#1\sseq@fexpsafenil{\ifnum\sseq@tempcount=\z@ \let\next\@firstoftwo\else\let\next\@secondoftwo\fi}
\def\sseq@ifintexpr@false#1\sseq@fexpsafenil{\let\next\@secondoftwo}

\def\sseq@makeifint#1#2#3{\@xp\def\csname sseq@ifintexpr@@#1@#2\endcsname{#3}}
\def\sseq@ifintexpr@next#1{\@xp\let\@xp\next\csname sseq@ifintexpr@@\sseq@ifintexpr@state @#1\endcsname}

\sseq@makeifint{needsint}{done}{\sseq@ifintexpr@false}
\sseq@makeifint{needsint}{digit}{\sseq@ifintexpr@{int}}
\sseq@makeifint{needsint}{*/}{\sseq@ifintexpr@false}
\sseq@makeifint{needsint}{+-}{\sseq@ifintexpr@{needsint}}
\sseq@makeifint{needsint}{(}{\advance\sseq@tempcount\@ne\sseq@ifintexpr@{needsint}}
\sseq@makeifint{needsint}{)}{\sseq@ifintexpr@false}
\sseq@makeifint{needsint}{\space}{\sseq@ifintexpr@{needsint}}

\sseq@makeifint{int}{done}{\sseq@ifintexpr@true}
\sseq@makeifint{int}{digit}{\sseq@ifintexpr@{int}}
\sseq@makeifint{int}{*/}{\sseq@ifintexpr@{needsint}}
\sseq@makeifint{int}{+-}{\sseq@ifintexpr@{needsint}}
\sseq@makeifint{int}{(}{\sseq@ifintexpr@false}
\sseq@makeifint{int}{)}{
   \advance\sseq@tempcount\m@ne
   \ifnum\sseq@tempcount<\z@\relax
       \@xp\@xp\@xp\sseq@ifintexpr@false\@xp\@gobble
   \else
       \@xp\sseq@ifintexpr@
   \fi{nointallowed}
}
\sseq@makeifint{int}{\space}{\sseq@ifintexpr@{nointallowed}}

\sseq@makeifint{nointallowed}{done}{\sseq@ifintexpr@true}
\sseq@makeifint{nointallowed}{digit}{\sseq@ifintexpr@false}
\sseq@makeifint{nointallowed}{*/}{\sseq@ifintexpr@{needsint}}
\sseq@makeifint{nointallowed}{+-}{\sseq@ifintexpr@{needsint}}
\sseq@makeifint{nointallowed}{(}{\sseq@ifintexpr@false}
\sseq@makeifint{nointallowed}{)}{
   \advance\sseq@tempcount\m@ne
   \ifnum\sseq@tempcount<\z@
       \@xp\@xp\@xp\sseq@ifintexpr@false\@xp\@gobble
   \else
       \@xp\sseq@ifintexpr@
   \fi{nointallowed}
}
\sseq@makeifint{nointallowed}{\space}{\sseq@ifintexpr@{nointallowed}}

%%
%% This parser defines the syntax for the page argument of \d.
%%
%% #1 -- callback. Will pass control to this function when done.
%% stores output in \sseq@dpage
%% It also sets the flag  \sseq@tempif to be
%%      true if there is an open parenthesis after the page
%%      false if there is no open parentheis -- so no optional argument for \d.
\def\sseq@d@grabpage#1{
   \let\sseq@grabdpage@return#1
   \futurelet\testtok\sseq@grabdpage@
}
\def\sseq@grabdpage@{
   \sseq@tempiftrue
   \ifx\testtok\bgroup
       \let\next\sseq@grabdpage@group
   \else
       \def\sseq@dpage{}
       \let\next\sseq@grabdpage@norm
   \fi
   \next
}

\def\sseq@grabdpage@group#1{\def\sseq@dpage{#1}\sseq@grabdpage@return}

% I guess this is "norm" because it's the most basic case.
% Why did I make this so complicated?
\def\sseq@grabdpage@norm{
   \futurelet\testtok\sseq@grabdpage@norm@
}

% If the next token is a open group or a new paragraph, we're done collecting and there's no parenthetical argument.
% If the next token is an open paren, we're done collecting and there is a parenthetical argument.
% Spaces get added to the token list (I guess that's important because it changes arithmetic sometimes? there must have been an issue at some point)
% Every other token gets handled by \sseq@grabdpage@token
\def\sseq@grabdpage@norm@{
   \let\next\sseq@grabdpage@token
   \ifx\testtok\bgroup % Open group ==> done collecting page, no optional argument
       \sseq@tempiffalse
       \let\next\sseq@grabdpage@return
   \else
       \ifx\testtok\par % new paragraph ==> done collecting page, no optional argument
           \sseq@tempiffalse
           \let\next\sseq@grabdpage@return
       \else
           \ifx\testtok( % paren ==> done collecting page, optional argument
               \let\next\sseq@grabdpage@return
           \else
               \@xp\ifx\space\testtok
                   \let\next\sseq@grabdpage@space
               \fi
           \fi
       \fi
   \fi
   \next
}

\def\sseq@grabdpage@space{\sseq@d@addto@macro\sseq@dpage{~}\@xp\sseq@grabdpage@norm\romannumeral-`0}

% All other tokens
\def\sseq@grabdpage@token#1{
   \ifcat$\@xp\@gobble\string#1$% % If #1 is a non-macro token, just add it to \sseq@dpage
       \sseq@d@addto@macro\sseq@dpage{#1}
       \@xp\sseq@grabdpage@norm
   \else % Now it's a macor
       \ifx#1\end % \end ==> done
           \sseq@tempiffalse
           \@xp\sseq@grabdpage@return\@xp#1\romannumeral-`0
       \else
           \ifx#1\begin % \begin ==> done
               \sseq@tempiffalse
               \@xp\sseq@grabdpage@return\@xp#1\romannumeral-`0
           \else % Otherwise, let's try to expand it.
               \@xp\sseq@grabdpage@token@fexpcs\@xp#1\romannumeral-`0
           \fi
       \fi
   \fi
}

\def\sseq@grabdpage@token@fexpcs{\exp_last_unbraced:Nf\sseq@grabdpage@token@fexpcs@}
\def\sseq@grabdpage@token@fexpcs@{\futurelet\testtok\sseq@grabdpage@token@fexpcs@@}
\def\sseq@grabdpage@token@fexpcs@@{
   \ifx\testtok\bgroup
       \sseq@tempiffalse
       \@xp\sseq@grabdpage@return
   \else
       \@xp\sseq@grabdpage@token@fexpcs@@@
   \fi
}
\def\sseq@grabdpage@token@fexpcs@@@#1{
   \ifcat$\@xp\@gobble\string#1$% Did it fexpand into a non control sequence token?
       \sseq@d@addto@macro\sseq@dpage{#1} % If so add it
       \@xp\sseq@grabdpage@norm
   \else
       \sseq@tempiffalse
       \@xp\sseq@grabdpage@return\@xp#1% Else remember to put the token back if we're not going to use it!!
   \fi
}


%%
%%
%%          New Class Pattern
%%
%%

\newcount\sseq@cp@row
\newcount\sseq@cp@n

\def\SseqNewClassPattern#1#2{
   \ifcsname sseq@#1xoffset1/1\endcsname\sseq@error@n{classpattern-already-defined}{#1}\fi % could be a warning
   \begingroup
   \def\sseq@name{#1}
   \def\sseq@temp{}
   \def\sseq@state{nocoord}
   \sseq@cp@row=\@ne
   \sseq@cp@n=\z@
   \let\next\sseq@newclasspattern@
   \sseq@newclasspattern@#2\sseq@nil
}
\let\sseqnewclasspattern\SseqNewClassPattern

\def\sseq@newclasspattern@{
   \@ifnextchar\bgroup{\sseq@error@n{classpattern-unexpected-token}{\{}}{\sseq@newclasspattern@processstate}
}

\def\sseq@newclasspattern@processstate{
   \csname sseq@newclasspattern@processstate@\sseq@state\endcsname
}

\def\sseq@newclasspattern@processstate@xcoord#1{
   \ifx#1,
       \sseq@ifpgfmathexpr{\sseq@temp}{
           \let\sseq@tempx\sseq@mathresult
           \def\sseq@temp{}
           \def\sseq@state{ycoord}
       }{
           \sseq@error@x{classpattern-invalid-math-expression}{\sseq@temp}
           \let\next\sseq@newclasspattern@abort
       }
   \else
       \ifx#1\sseq@nil
           \sseq@error{classpattern-missing-tokens}
           \let\next\endgroup
       \else
           \sseq@d@addto@macro\sseq@temp{#1}
       \fi
   \fi
   \next
}

\def\sseq@newclasspattern@processstate@ycoord#1{
   \ifx#1)
       \sseq@ifpgfmathexpr{\sseq@temp}{% Need iffloatexpr =(
           \let\sseq@tempy\sseq@mathresult
           \def\sseq@temp{}
           \def\sseq@state{nocoord}
           \advance\sseq@cp@n1\relax
           \ifnum\sseq@cp@n>\sseq@cp@row\relax
               \sseq@error@xx{classpattern-extra-coord-ignored}{(\sseq@tempx,\sseq@tempy)}{\the\sseq@cp@row}
           \else
               \sseq@e@addto@macro\sseq@newclasspattern@dodefs{
                   \def\@xp\@nx\csname sseq@\sseq@name xoffset\the\sseq@cp@n/\the\sseq@cp@row\endcsname{\sseq@tempx}
                   \def\@xp\@nx\csname sseq@\sseq@name yoffset\the\sseq@cp@n/\the\sseq@cp@row\endcsname{\sseq@tempy}
               }
           \fi
       }{
           \sseq@error@x{classpattern-invalid-math-expression}{\sseq@temp}
           \let\next\sseq@newclasspattern@abort
       }
   \else
       \ifx#1\sseq@nil
           \sseq@error{classpattern-missing-tokens}
           \let\next\endgroup
       \else
           \sseq@d@addto@macro\sseq@temp{#1}
       \fi
   \fi
   \next
}

\def\sseq@newclasspattern@processstate@nocoord#1{
   \ifx#1(
       \def\sseq@state{xcoord}
   \else
       \ifx#1;
           \ifnum\sseq@cp@n<\sseq@cp@row\relax
               \sseq@error@x{classpattern-too-few-coords}{\the\sseq@cp@row}
               \let\next\sseq@newclasspattern@abort
           \else
               \advance\sseq@cp@row\@ne
               \sseq@cp@n=\z@
           \fi
       \else
           \ifx#1\sseq@nil
               \let\next\sseq@newclasspattern@finish
           \else
               \sseq@error@n{classpattern-unexpected-token}{#1}
               \let\next\sseq@newclasspattern@abort
           \fi
       \fi
   \fi
   \next
}

\def\sseq@newclasspattern@finish{
   \ifnum\sseq@cp@n=\z@\relax
       \advance\sseq@cp@row\m@ne
   \else
       \ifnum\sseq@cp@n=\sseq@cp@row\relax\else
           \sseq@error@x{classpattern-too-few-coords}{\the\sseq@cp@row}
           \let\sseq@newclasspattern@dodefs\empty
       \fi
   \fi
   % This will make a definition even if the class pattern was rejected because of the too-few-coords error
   % It doesn't matter though, because we don't use this to check for existence
   \sseq@e@addto@macro\sseq@newclasspattern@dodefs{%
       \chardef\@xp\@nx\csname sseq@\sseq@name @maxclasses\endcsname=\the\sseq@cp@row\relax
   }%
   \@xp\endgroup
   \sseq@newclasspattern@dodefs


}
\def\sseq@newclasspattern@dodefs{}
\def\sseq@newclasspattern@abort#1\sseq@nil{\endgroup}




%%%%%%                                            %%%%%%
%%                                                    %%
%%               Coordinate Parsers                   %%
%%                                                    %%
%%%%%%                                            %%%%%%


\def\sseq@ifdead#1{\ifnum\sseq@obj{class.#1[\sseq@obj{class.#1.num}].page}<\sseq@infinitycount\@xp\@firstoftwo\else\@xp\@secondoftwo\fi}


% These do all of the work of taking a coordinate of the form (x,y), (x,y,n), or (x,y,tag) and turning them
% into the internal representation needed for the rest of the package.
% This comes in two parts:
%   \sseq@parsecoord@maincoord -- separates a coordinate into {x,y}{n or tag}, numerically evaluates x and y, and adds in the values of \sseq@x and \sseq@y
%   \sseq@parsecoord@index -- decides which class {n or tag} represents
%
% There are several interface commands:
%    \sseq@parsecoord   -- for most things
%    \sseq@cparsecoord  -- for \class (but not for \replaceclass or \classoptions). Doesn't use \sseq@parsecoord@index at all.
%    \sseq@dparsecoord  -- for \d and \doptions
%    \sseq@parsecoordex -- for \isalive: the body of a page constraint needs to be \edef'd so we need a completely expandable version.
%      The expandable version doesn't have any error checking -- to get the error checking, we pass the coordinates once through the unexpandable version
%      inside of an hbox.
%    \sseq@parsecoord@allownonexisting -- doesn't raise an error if the class doesn't exist.

\def\sseq@errortype{}
\def\sseq@printerrortype#1{\@xp\sseq@ifempty\@xp{\sseq@errortype}{}{#1 \sseq@errortype}}
\def\sseq@printforerrortype{\sseq@printerrortype{~for~}}

%% Pulls off x,y and evaluates them, puts n or empty into a separate variable.
% #1 -- a coordinate of the form {x,y} or {x,y,stuff}
\let\sseq@relax\relax
% The \sseq@relax is just to make \lastclass work. It has to pull an argument off the token stream to expandably check whether
% it is an integer. However, without this \sseq@relax, \lastclass could appear as the last token of the edef, which is no good.
\def\sseq@parsecoord@maincoord#1{\exp_last_unbraced:Nx\sseq@parsecoord@maincoord@{#1\sseq@relax}}
\def\sseq@parsecoord@maincoord@#1\sseq@relax{%
   \pgfutil@in@ \sseq@protecterror { #1 }
   \ifpgfutil@in@
       \bgroup
       \sseq@restorefont % This prevents "Missing character" stuff from being written to the log.
       \let\sseq@protecterror\relax
       \setbox0=\hbox{#1} % Trigger the error message
       \egroup
       \@xp\sseq@break
   \else
       \pgfutil@in@,{#1}
       \ifpgfutil@in@
           \sseq@parsecoord@maincoord@@#1,\sseq@nil
       \else
           \pgfutil@in@{lastclass}{#1}
           \ifpgfutil@in@
               \def\handledname{#1}
           \else
               \sseq@protectedeval{\@nx\sseq@classname@handler{\sseq@classnameprefix#1\sseq@classnamepostfix}}
               \let\handledname\result
           \fi
           \sseq@obj@ifdef{class.namedclass.\detokenize\@xp{\handledname}}{
               \let\sourcename\handledname
               \@xpthree\sseq@parsecoord@maincoord@named\sseq@obj{class.namedclass.\detokenize\@xp{\sourcename}}\sseq@nil
           }{
                \sseq@error{invalid-coordinate}\sseq@breakfifi
           }
       \fi
   \fi
}

\def\sseq@parsecoord@maincoord@@#1,#2,#3\sseq@nil{%
   \sseq@ifintexpr{#1}{%
       \sseq@ifintexpr{#2}{}{\sseq@error@n{invalid-coordinate}{y~}\sseq@breakfifi} % breakfifi to get out of ifs from maincoord@
       \edef\sseq@xcoord{\the\numexpr\sseq@x+(#1)\relax}%
       \edef\sseq@ycoord{\the\numexpr\sseq@y+(#2)\relax}%
       \edef\sseq@xycoord{\sseq@xcoord,\sseq@ycoord}%
       \sseq@ifempty{#3}{\let\sseq@restcoord\pgfutil@empty}{%
           \edef\sseq@restcoord{\sseq@removecomma#3\sseq@nil}%
       }%
   }{%
       \pgfutil@in@{lastclass}{#1}%
       \ifpgfutil@in@
           \def\handledname{#1}%
       \else
           \sseq@protectedeval{\@nx\sseq@classname@handler{\sseq@classnameprefix#1\sseq@classnamepostfix}}%
           \let\handledname\result
       \fi
       \sseq@obj@ifdef{class.namedclass.\detokenize\@xp{\handledname}}{%
           \def\sourcename{#1}
           \@xpthree\sseq@parsecoord@maincoord@named\sseq@obj{class.namedclass.\detokenize{#1}}\sseq@nil
           \edef\sseq@restcoord{\sseq@removecomma#2,#3\sseq@nil}%
       }{%
           \sseq@error@n{invalid-coordinate}{x~}\sseq@breakfifi % breakfifi to get out of ifs from maincoord@
       }%
   }%
}%

\def\sseq@parsecoord@maincoord@named#1,#2,#3\sseq@nil{
   \def\sseq@xcoord{#1}%
   \def\sseq@ycoord{#2}%
   \edef\sseq@xycoord{\sseq@xcoord,\sseq@ycoord}
   \def\sseq@restcoord{}
   \pgfkeys@spdef\sseq@rawindex{#3}
   \def\sseq@index{#3}
   \let\rawindex\sseq@rawindex
   \let\index\sseq@index
}

\def\sseq@removecomma#1,\sseq@nil{#1}


% "Input" to this command is stored in the following commands:
% \sseq@xycoord -- x,y
% \sseq@rawindex -- n
% \sseq@errortype -- description for error messages
\def\sseq@errortype@tikzprim{tikz ~ primitive}% This is sort of a silly hack, but this first error check shouldn't happen in a tikz primitive.
\def\sseq@parsecoord@index{%
   \sseq@obj@ifundef{partcoord.(\sseq@xycoord).numnodes}{
       \ifsseq@parsecoord@allownonexisting
           \ifx\sseq@rawindex\pgfutil@empty
               \def\sseq@index{} %  Communicates to \sseq@tikzprimitives@coords@maybeclass that this is not a class
           \else
               \sseq@error@x{no-classes}{(\sseq@xycoord)} \sseq@fbreak
           \fi
       \else
           \sseq@error@x{no-classes}{(\sseq@xycoord)} \sseq@fbreak
       \fi
   }{
       \ifx\sseq@rawindex\pgfutil@empty
           \def\sseq@index{1}
       \else
           \sseq@obj@ifdef{partcoord.(\sseq@xycoord).tag.\sseq@class@tagprefix\sseq@rawindex}{% If the raw index is a tag
               \edef\sseq@index{\sseq@obj{partcoord.(\sseq@xycoord).tag.\sseq@class@tagprefix\sseq@rawindex}}
           }{%
               \sseq@ifintexpr{\sseq@rawindex}{%
                   \edef\sseq@rawindexeval{\the\numexpr\sseq@rawindex}
                   \ifnum\sseq@rawindexeval<\z@%
                       \edef\sseq@index{\the\numexpr\sseq@obj{partcoord.(\sseq@xycoord).numnodes} + \sseq@rawindex + \@ne\relax}%
                       \ifnum\sseq@index<\@ne
                           \sseq@error@xxx{index-too-large}{\sseq@rawindex}{\sseq@obj{partcoord.(\sseq@xycoord).numnodes}}{(\sseq@xycoord)}%
                           \edef\sseq@index{1}
                           \sseq@fbreak
                       \fi
                   \else
                       \edef\sseq@index{\the\numexpr\sseq@rawindex}
                       \ifnum\sseq@rawindexeval>\sseq@obj{partcoord.(\sseq@xycoord).numnodes}\relax
                           \sseq@error@xxx{index-too-large}{\sseq@rawindex}{\sseq@obj{partcoord.(\sseq@xycoord).numnodes}}{(\sseq@xycoord)}%
                           \edef\sseq@rawindex{\sseq@obj{partcoord.(\sseq@xycoord).numnodes}}
                           \sseq@fbreak
                       \fi
                   \fi
               }{
                   \sseq@error@xx{undefined-tag}{\sseq@rawindex}{(\sseq@xycoord)}%
                   \def\sseq@index{1}%
               }
           }
       \fi
   }
}

% #1 -- name to define
% #2 -- coordinate
% #3 -- the error message
\def\sseq@eatparens(#1){#1}
\def\sseq@parsecoord#1#2#3{%
   \def\sseq@index{}%
   \def\sseq@errortype{#3}%
   \sseq@parsecoord@maincoord{#2}%
   \exp_args:NNf\def\sseq@rawindex{\exp_args:No\sseq@trimspaces{\sseq@restcoord}}
   \ifx\sseq@index\pgfutil@empty
       \@xp\sseq@parsecoord@index
   \fi
   \sseq@parsecoord@setupvariables{#1}{#2}
}

\newif\ifsseq@parsecoord@allownonexisting
\def\sseq@parsecoord@allownonexisting#1#2#3{%
   \sseq@parsecoord@allownonexistingtrue
   \sseq@parsecoord{#1}{#2}{#3}
   \sseq@parsecoord@allownonexistingfalse
}


\def\sseq@parsecoord@setupvariables#1#2{
   % TODO: clean this up a bit? it's pretty ad-hoc.
   % Whenever you update this, make sure to update sseq@paredcoords@swap below too.
   \@xp\let\csname x\sseq@macroname#1\endcsname\sseq@xcoord
   \@xp\let\csname y\sseq@macroname#1\endcsname\sseq@ycoord
   \@xp\let\csname n\sseq@macroname#1\endcsname\sseq@index
   \@xp\let\csname \sseq@macroname#1@partial\endcsname\sseq@xycoord
   \edef#1{(\sseq@xycoord,\sseq@index)}%
   \@xp\edef\csname\sseq@macroname#1nopar\endcsname{\sseq@xycoord,\sseq@index}
   \@xp\edef\csname\sseq@macroname#1name\endcsname{(#2)}%
   \@xp\edef\csname\sseq@macroname#1nameunbraced\endcsname{\@xptwo\sseq@eatparens\csname\sseq@macroname#1name\endcsname}% edef?
   \@xp\edef\csname\sseq@macroname#1@internalname\endcsname{sseq{\sseq@xycoord,\sseq@index}}%
}


% This quiets parsecoord for the rest of the current scope.
% The reason we did it this way is because parsecoord makes too many local definitions...
\def\sseq@quiet@parsecoord{
   \msg_redirect_name:nnn {spectralsequences}{invalid-coordinate}{none}
   \msg_redirect_name:nnn {spectralsequences}{no-classes}{none}
   \msg_redirect_name:nnn {spectralsequences}{index-too-large}{none}
   \msg_redirect_name:nnn {spectralsequences}{undefined-tag}{none}
}


% These are used for \replacesource and \replacetarget, though they might be useful for other things too.
\def\sseq@parsedcoord@save#1#2{
   \cs_gset_eq:cc { sseq@parsedcoord@save@x#1 } { x\sseq@macroname#2 }
   \cs_gset_eq:cc { sseq@parsedcoord@save@y#1 } { y\sseq@macroname#2 }
   \cs_gset_eq:cc { sseq@parsedcoord@save@n#1 } { n\sseq@macroname#2 }
   \cs_gset_eq:cc { \sseq@macroname#1@partial } { \sseq@macroname#2@partial }
   \cs_gset_eq:cN { sseq@parsedcoord@save@#1 } #2
   \cs_gset_eq:cc { sseq@parsedcoord@save@#1nopar } { \sseq@macroname#2nopar }
   \cs_gset_eq:cc { sseq@parsedcoord@save@#1name } { \sseq@macroname#2name }
   \cs_gset_eq:cc { sseq@parsedcoord@save@#1nameunbraced } { \sseq@macroname#2nameunbraced }
   \cs_gset_eq:cc { sseq@parsedcoord@save@#1@internalname } { \sseq@macroname#2@internalname }
}

\def\sseq@parsedcoord@restore#1#2{
   \cs_set_eq:cc { x\sseq@macroname#1 } { sseq@parsedcoord@save@x#2 }
   \cs_set_eq:cc { y\sseq@macroname#1 } { sseq@parsedcoord@save@y#2 }
   \cs_set_eq:cc { n\sseq@macroname#1 } { sseq@parsedcoord@save@n#2 }
   \cs_set_eq:cc { \sseq@macroname#1@partial } { #2@partial }
   \cs_set_eq:Nc #1 { sseq@parsedcoord@save@#2 }
   \cs_set_eq:cc { \sseq@macroname#1nopar } { sseq@parsedcoord@save@#2nopar }
   \cs_set_eq:cc { \sseq@macroname#1name } { sseq@parsedcoord@save@#2name }
   \cs_set_eq:cc { \sseq@macroname#1nameunbraced } { sseq@parsedcoord@save@#2nameunbraced }
   \cs_set_eq:cc { \sseq@macroname#1@internalname } { sseq@parsedcoord@save@#2@internalname }
}

% #1 & #2 -- the two base commands that were handed to \sseq@parsecoord to swap.
% This is only used in \structline to normalize the name of structure lines, so that sseqpages knows what you are talking about
% if you say \structline(coorda)(coordb) and then later \structline(coordb)(coorda)
\def\sseq@parsedcoords@swap#1#2{
   \sseq@parsedcoord@save{swaptempa}{#1}
   \sseq@parsedcoord@save{swaptempb}{#2}
   \sseq@parsedcoord@restore{#1}{swaptempb}
   \sseq@parsedcoord@restore{#2}{swaptempa}
}

% EXPOSE: a wrapper around \sseq@parsecoord. Use full name of coordinate to avoid name class with sseq@parsecoord.
\sseq@DeclareDocumentCommand \parsecoordinate { m r() }{%
   \sseq@parsecoord{#1}{#2}{call of \string\parsecoord}%
}

% #1 -- coordinate
\def\sseq@cparsecoord#1{%
   \def\sseq@index{}
   \sseq@parsecoord@maincoord{#1}%
   \ifx\sseq@index\pgfutil@empty\else\sseq@error{named-coordinate-class}\fi% probably not possible to get this error
   \ifx\sseq@restcoord\pgfutil@empty\else\sseq@error{class-extra-coords}\fi%
   \let\partialcoord\sseq@xycoord
   \let\xcoord\sseq@xcoord
   \let\ycoord\sseq@ycoord
   \edef\nodenum{\sseq@obj@ifundef{partcoord.(\partialcoord).numnodes}{1}{\the\numexpr\sseq@obj{partcoord.(\partialcoord).numnodes}+1}}%
   \edef\coordnopar{\xcoord,\ycoord,\nodenum}
   \edef\coord{(\coordnopar)}%
}


% #1 -- page
% #2 -- coordinate
% #3 -- target coordinate or "No Value"
\def\sseq@dparsecoord#1#2#3{%
   \def\sseq@index{}%
   \def\sseq@errortype{differential}%
   \sseq@parsecoord@maincoord{#2}%
   \ifx\sseq@index\pgfutil@empty
       \edef\sseq@rawsindex{\@xp\sseq@dparsecoord@getxindex\@xp{\sseq@restcoord}}%
       \@xp\pgfkeys@spdef\@xp\sseq@rawsindex\@xp{\sseq@rawsindex}
       \edef\sseq@rawtindex{\@xp\sseq@dparsecoord@getyindex\@xp{\sseq@restcoord}}%
       \@xp\pgfkeys@spdef\@xp\sseq@rawtindex\@xp{\sseq@rawtindex}
%
       \let\sseq@rawindex\sseq@rawsindex
       \def\sseq@errortype{source ~ of ~ differential}
       \@xp\sseq@parsecoord@index % the \@xp is needed so that \sseq@break inside of parsecoordindex works properly.
   \else
       \edef\sseq@rawtindex{\@xp\sseq@dparsecoord@getxindex\@xp{\sseq@restcoord}}%
       \@xp\pgfkeys@spdef\@xp\sseq@rawtindex\@xp{\sseq@rawtindex}
       \edef\sseq@shouldbeempty{\@xp\sseq@dparsecoord@getyindex\@xp{\sseq@restcoord}}
       \ifx\sseq@shouldbeempty\pgfutil@empty\else
           \sseq@error{d-named-coord-two-indexes}
       \fi
   \fi
   \sseq@parsecoord@setupvariables{\source}{(\sseq@xycoord\ifx\sseq@rawindex\pgfutil@empty\else,\sseq@rawindex\fi)}
   \let\sourcecoord\source@partial
   \IfNoValueTF{#3}{
       \ifsseq@hasdegree\else\sseq@error{d-no-degree}\@xp\sseq@break\fi
       \sseq@eval{\edef\@nx\sseq@xycoord{\@nx\sseq@differential@gettarget{#1}{\sseq@xycoord}}}
       \let\sseq@rawindex\sseq@rawtindex
       \def\sseq@errortype{target ~ of ~ differential}
       \sseq@parsecoord@index
       \let\targetcoord\sseq@xycoord
       \sseq@parsecoord@setupvariables{\target}{(\sseq@xycoord\ifx\sseq@rawindex\pgfutil@empty\else,\sseq@rawindex\fi)}
   }{
       \ifx\sseq@rawtindex\pgfutil@empty\else
           \sseq@error{d-target-index-target-coord}
       \fi
       \sseq@parsecoord\target{#3}{differential}
       \let\targetcoord\target@partial
       \ifsseq@hasdegree
           \ifsseq@strictdegree
               \sseq@eval{\edef\@nx\sseq@checktarget{\@nx\sseq@differential@gettarget{#1}{\sourcecoord}}}
               \ifx\sseq@checktarget\targetcoord\else
                   \sseq@error@xxx{d-wrong-degree}{(\sseq@checktarget)}{\targetname}{(\targetcoord)}
               \fi
           \fi
       \fi
   }
   \sseq@parsedcoord@save{lastsource}{\source}
   \sseq@parsedcoord@save{lasttarget}{\target}
}

\def\sseq@differential@gettarget#1#2{\sseq@differential@gettarget@{#1}#2\sseq@nil}
\def\sseq@differential@gettarget@#1#2,#3\sseq@nil{\the\numexpr#2+\sseq@targetx{#1}\relax,\the\numexpr#3+\sseq@targety{#1}\relax}

\def\sseq@getfirsttwoelts#1,#2,#3\sseq@nil{#1,#2}
\protected\def\sseq@getdtarget#1#2#3{\sseq@eval{\edef\@nx#1{\@nx\sseq@differential@gettarget{#2}{\sseq@getfirsttwoelts#3,,\sseq@nil}}}}

% Takes a comma separated list that can be empty, have one element, or two elements, returns first element (or empty if list is empty).
\def\sseq@dparsecoord@getxindex#1{\sseq@dparsecoord@getxindex@#1,\sseq@nil}
\def\sseq@dparsecoord@getxindex@#1,#2\sseq@nil{#1}
% Takes a comma separated list that can be empty, have one element, or two elements, returns second element (or empty if less than two elements).
\def\sseq@dparsecoord@getyindex#1{\sseq@dparsecoord@getyindex@#1,\sseq@nil}
\def\sseq@dparsecoord@getyindex@#1,#2\sseq@nil{%
   \sseq@ifempty{#2}{}{%
       \sseq@removecomma#2\sseq@nil%
   }%
}

% EXPOSE: a wrapper around \sseq@parsecoord.
\sseq@DeclareDocumentCommand\parsecoordinate { m r() }{%
   \sseq@parsecoord{#1}{#2}{call of \string\parsecoord}%
}


% EXPOSE: a wrapper around \sseq@dparsecoord.
\protected\def\sseq@parsedifferential{%
   \sseq@d@grabpage\sseq@parsedifferential@
}

\DeclareDocumentCommand \sseq@parsedifferential@ { d() d() } {%
   \sseq@eval{\@nx\sseq@dparsecoord{\sseq@dpage}{\IfNoValueTF{#1}{\lastclass0}{\unexpanded{#1}}}{\unexpanded{#2}}}%
}

% Expandable coordinate parsing for \isalive.
% Doesn't do any error checking -- the error checking is done by passing it through \sseq@parsecoord in a non-\edef context.
% #1 -- a callback. Must be a single command b/c it's an N in \exp_args
% #2 -- the coordinate
\cs_set:Npn \exp_last_unbraced:NNNf #1#2#3#4
 {
   \exp_after:wN #1
   \exp_after:wN #2
   \exp_after:wN #3
   \exp:w \exp_end_continue_f:w #4
 }

\def\sseq@parsecoordex{\exp_last_unbraced:NNNf\sseq@parsecoordex@}
\def\sseq@parsecoordex@#1(#2){\sseq@parsecoordex@@#1#2,\@nil}

% Older versions of etex don't provide \expanded so need more expensive version of \exp_args:NNof.
\ifx\expanded\undefined
   \cs_set:Npn\exp_args:NNof { \::N \::o \::f \::: }
\else
   \cs_set:Npn\exp_args:NNof #1#2#3#4 {
       \expanded {
           \exp_not:N #1
           \exp_not:N #2
           { \unexpanded \expandafter { #3 } }
           { \unexpanded  \expandafter { \exp:w \exp_end_continue_f:w #4} }
       }
   }
\fi

\def\sseq@parsecoordex@@#1#2,#3,#4\@nil{
   \ifx&#4&
       \exp_args:NNo\sseq@parsecoord@indexex#1{\the\numexpr#2\@xp,\the\numexpr#3}{1}
   \else
       \exp_args:NNof\sseq@parsecoord@indexex#1{\the\numexpr#2\@xp,\the\numexpr#3\@xp\relax}{\exp_args:Nf\sseq@trimspaces{\sseq@removecomma#4\sseq@nil}}
   \fi
}


% This is \sseq@parsecoord@index pared down as much as possible -- all error checking is removed because that will happen in a
% \setbox0=\hbox{stuff} sequestered calculation that uses \sseq@parsecoord@index instead.
% #1 -- callback which takes one argument --  the final coordinate in parentheses.
% #2 -- x,y
% #3 -- n
\def\sseq@parsecoord@indexex#1#2#3{%
   \sseq@obj@ifdef{partcoord.(#2).tag.\sseq@class@tagprefix#3}{% If the raw index is a tag
       \exp_args:NNo\sseq@parsecoord@indexex@#1{\the\numexpr\sseq@obj{partcoord.(#2).tag.\sseq@class@tagprefix#3}}{#2}%
   }{%
       \ifnum\numexpr#3<0\space
           \exp_args:NNo\sseq@parsecoord@indexex@#1{\the\numexpr\sseq@obj{partcoord.(#2).numnodes} + #3 + 1}{#2}%
       \else
           \exp_args:NNo\sseq@parsecoord@indexex@#1{\the\numexpr#3}{#2}%
       \fi
   }%
}
\def\sseq@parsecoord@indexex@#1#2#3{
   #1(#3,#2)
}




%%%
%%% The Stack
%%%

% This maybe should be moved into sseqmain.code.tex...
\sseq@addtostorelist\sseq@stacktop{}
\def\sseq@stackitem#1#2{\csname sseq.\[email protected].#1.#2\endcsname} % gobble #2 which we added in for the error message
\def\sseq@getstackentry#1#2{
   \ifnum#1<\sseq@stackdepth
       \exp_args:No\sseq@getstackentry@{\sseq@stacktop}{#1}{#2}
   \else
       \sseq@protecterror{\sseq@error@xx{index-out-of-bounds}{#1}{\the\sseq@stackdepth}}
   \fi
}

\def\sseq@getstackentry@#1#2{
   \ifnum#2=\z@\@xp\@firstoftwo\else\@xp\@secondoftwo\fi
       { \sseq@stackitem{#1} }
       { \exp_args:Nco\sseq@getstackentry@ { sseq.\[email protected].#1.next } { \the\numexpr#2-1 } }
}


\protected\def\sseq@pushstack(#1){
   \bgroup
   \sseq@parsecoord@allownonexisting\temp{#1}{}
   \sseq@pushstack@\temp
   \sseq@breakpoint
   \egroup
}

% Note that \class directly calls pushstack@ to avoid reparsing the coordinate
\def\sseq@pushstack@{\@xp\sseq@pushstack@@}

\def\sseq@pushstack@@(#1,#2,#3){
   %\def\temp{#1,#2,#3}\show\temp
   \global\advance\sseq@stackdepth\@ne
   \@xp\gdef\csname sseq.\[email protected].\the\[email protected]\endcsname{#1}
   \@xp\gdef\csname sseq.\[email protected].\the\[email protected]\endcsname{#2}
   \@xp\xdef\csname sseq.\[email protected].\the\[email protected]\endcsname{lastclass.\the\sseq@stackdepth}
   \sseq@obj@gdef{class.namedclass.lastclass.\the\sseq@stackdepth}{#1,#2,#3}
   \global\@xp\let\csname sseq.\[email protected].\the\[email protected]\endcsname\sseq@stacktop
   \xdef\sseq@stacktop{\the\sseq@stackdepth}
}


\newcount\sseq@userstacksavecount
\protected\def\sseq@savestack{
   \global\advance\sseq@userstacksavecount\@ne
   \sseq@savestack@name{usersave@\the\sseq@userstacksavecount}
}
\protected\def\sseq@restorestack{
   \sseq@restorestack@name{usersave@\the\sseq@userstacksavecount}
   \global\advance\sseq@userstacksavecount\m@ne
}

\def\sseq@savestack@name#1{\sseq@obj@xdef{stack.save#1}{\sseq@stacktop}}

\def\sseq@restorestack@name#1{\xdef\sseq@stacktop{\sseq@obj{stack.save#1}}}

\def\sseq@lastx#1{
   % \romannumeral is testing here whether #1 is a nonnegative integer
   % if #1 consists of a single nonnegative integer then -0#1 will be turned into some nonpositive integer
   % and romannumeral produces no output when handed a nonpositive integer, so the result will be empty.
   % If #1 has any nonnumerical tokens or is negative, there will be left over stuff.
   %
   % We also have to subtract off \sseq@x so that this behaves correctly inside of a scope (the \lastx value should be unshifted)
   \@xp\sseq@ifempty\@xp{\romannumeral-0#1}{
       \the\numexpr\sseq@getstackentry{#1}{lastx}-\sseq@x\relax
   }{
       \the\numexpr\sseq@getstackentry{0}{lastx}-\sseq@x\relax#1 % #1 isn't a number so put it back
   }
}
\def\sseq@lasty#1{
   \@xp\sseq@ifempty\@xp{\romannumeral-0#1}{
       \the\numexpr\sseq@getstackentry{#1}{lasty}-\sseq@y\relax
   }{
       \the\numexpr\sseq@getstackentry{0}{lasty}-\sseq@y\relax#1 % #1 isn't a number so put it back
   }
}

\def\sseq@lastclass#1{
   \@xp\sseq@ifempty\@xp{\romannumeral-0#1}{
       \sseq@getstackentry{#1}{lastclass}
   }{
       \sseq@getstackentry{0}{lastclass}#1 % #1 isn't a number so put it back
   }
}


\sseq@DeclareDocumentCommand\nameclass {mr()} {
   \bgroup
   \sseq@setthiscall{\sseq@nameclass#1(#2)}
   \let\sseq@possibleoninputlinepar\empty
   \sseq@parsecoord\coord{#2}{}
   \sseq@cleanup@obj{class.namedclass.#1}
   \sseq@obj@xdef{class.namedclass.#1}{\coordnopar}
   \sseq@breakpoint
   \egroup
}

\sseq@DeclareDocumentCommand\tagclass{mr()}{
   \bgroup
   \sseq@setthiscall{\tagclass#1(#2)}
   \let\sseq@possibleoninputlinepar\empty
   \def\sseq@class@tag{#1}
   \sseq@parsecoord\coord{#2}{}%
   \sseq@obj@ifdef{partcoord.(\sseq@xycoord).tag.\sseq@class@tagprefix\sseq@class@tag}{%
       \sseq@error@nn{class-tag-already-defined}{\sseq@class@tagprefix\sseq@class@tag}{(\sseq@xycoord)}% could be warning
   }%
   \sseq@cleanup@obj{class.\coord.tag}%
   \sseq@obj@xdef{class.\coord.tag}{\sseq@class@tagprefix\sseq@class@tag}%
   \sseq@cleanup@obj{partcoord.(\sseq@xycoord).tag.\sseq@class@tagprefix\sseq@class@tag}%
   \sseq@obj@xdef{partcoord.(\sseq@xycoord).tag.\sseq@class@tagprefix\sseq@class@tag}{\sseq@index}%
   \sseq@breakpoint
   \egroup
}

\sseq@DeclareDocumentCommand\gettag{mr()}{
   \bgroup
   \sseq@setthiscall{\gettag#1(#2)}
   \let\sseq@possibleoninputlinepar\empty
   \sseq@parsecoord\coord{#2}{}
   \sseq@obj@ifdef{class.\coord.tag}{
       \xdef#1{\sseq@obj{class.\coord.tag}}
   }{
       \sseq@error@n{class-no-tag}{(#2)}
   }
   \sseq@breakpoint
   \egroup
}

\prg_new_conditional:Npnn \sseq_if_empty:n #1 {T,F,TF} {
   \sseq@ifempty{\prg_return_true:}{\prg_return_false:}
}

\let\SseqIfEmptyTF\sseq_if_empty:nTF
\let\SseqIfEmptyT\sseq_if_empty:nT
\let\SseqIfEmptyF\sseq_if_empty:nF

% Test if a class exists.
\prg_new_conditional:Npnn \sseq_if_exists:n #1 { T ,  F , TF } {
   \bgroup
   \sseq@tempiftrue
   \sseq@quiet@parsecoord
   \sseq@parsecoord\coord{#1}{}
   \@gobbletwo\sseq@breakpoint\sseq@tempiffalse % this executes \sseq@tempiffalse if we broke, otherwise it gets gobbled
   \ifsseq@tempif
       \egroup
       \prg_return_true:
   \else
       \egroup
       \prg_return_false:
   \fi
}

% Test if a class is out of bounds. Return false if the class doesn't exist.
\prg_new_conditional:Npnn \sseq_if_out_of_bounds:n #1 { T ,  F , TF } {
   \bgroup
   \sseq@tempiftrue
   \sseq@quiet@parsecoord
   \sseq@parsecoord\coord{#1}{}
   \@gobbletwo\sseq@breakpoint\sseq@tempiffalse % this executes \sseq@tempiffalse if we broke, otherwise it gets gobbled
   \ifsseq@tempif
       \sseq_if_out_of_bounds_inner:nnTF { \xcoord } { \ycoord }{\egroup\prg_return_true:}{\egroup\prg_return_false:}
   \else
       \egroup
       \prg_return_false:
   \fi
}

% For internal use b/c it's faster not to call \sseq@parsecoord
% Make sure to add \sseq@x and \sseq@y to the coordinate before passing along
% to if_out_of_bounds_inner to correctly account for translations.
\prg_new_conditional:Npnn \sseq_if_out_of_bounds_noparse:nn #1#2 {TF} {
   \sseq_if_out_of_bounds_inner:nnTF { #1 + \sseq@x } { #2 + \sseq@y }
       { \prg_return_true: }
       { \prg_return_false: }
}


\prg_new_conditional:Npnn \sseq_if_out_of_bounds_inner:nn #1#2 {TF} {
   \bool_lazy_all:nTF {
       { \int_compare_p:nNn { #1 } < { \sseq@xmaxpp } }
       { \int_compare_p:nNn { #1 } > { \sseq@xminmm } }
       { \int_compare_p:nNn { #2 } < { \sseq@ymaxpp } }
       { \int_compare_p:nNn { #2 } > { \sseq@yminmm } }
   }
       { \prg_return_false: }
       { \prg_return_true: }
}

\prg_new_conditional:Npnn \sseq_if_alive:nn #1 #2 { T, F, TF } {
   \bgroup
   \sseq@tempiftrue
   \sseq@quiet@parsecoord
   \sseq@parsecoord\coord{#2}{}
   \@gobbletwo\sseq@breakpoint\sseq@tempiffalse
   \ifsseq@tempif
       \sseq@obj@pagetogen{class.\coord}{#1}
       \ifnum\sseq@gen>-1\relax
               \egroup
               \prg_return_true:
       \else
               \egroup
               \prg_return_false:
       \fi
   \else
       \egroup
       \prg_return_false:
   \fi
}


\protected\def\sseq@DrawIfValidDifferential{\sseq@DrawIfValidDifferential@{}{}}
\protected\def\sseq@DrawIfValidDifferentialT{\sseq@DrawIfValidDifferential@{T}{}}
\protected\def\sseq@DrawIfValidDifferentialF{\sseq@DrawIfValidDifferential@{}{F}}
\protected\def\sseq@DrawIfValidDifferentialTF{\sseq@DrawIfValidDifferential@{T}{F}}

\DeclareDocumentCommand\sseq@DrawIfValidDifferential@{mmO{}}{%
   \begingroup
   \sseq@loadinputline
   \def\sseq@dtype{d}
   \def\sseq@trueclause{#1}
   \def\sseq@falseclause{#2}
   \def\sseq@doptions{#3}
   \sseq@d@grabpage\sseq@DrawIfValidDifferential@@
}


% #4 -- first coord
% #5 -- possible second coord
\DeclareDocumentCommand \sseq@DrawIfValidDifferential@@ { d() d() } {%
   \ifx\sseq@trueclause\pgfutil@empty
       \@xp\@firstoftwo
   \else
       \@xp\@secondoftwo
   \fi{\sseq@DrawIfValidDifferential@@@{#1}{#2}{}}
      {\sseq@DrawIfValidDifferential@@@{#1}{#2}}
}

% #1 -- first coord
% #2 -- possible second coord
% #3 -- rest of true clause
\def \sseq@DrawIfValidDifferential@@@#1#2#3{
   \sseq@eval{\endgroup%\@nx\tracingall
       \exp_not:c{sseq_if_valid_differential:nnT\sseq@falseclause}{\sseq@dpage}{\IfNoValueTF{#1}{\lastclass0}{\unexpanded{#1}}}{\unexpanded{#2}}{%
           \@nx\d[\exp_not:o{\sseq@doptions}]\sseq@dpage\IfNoValueF{#1}{(\unexpanded{#1})}\IfNoValueF{#2}{(\unexpanded{#2})}%
           \unexpanded{#3}%
       }%
   }%
}

\protected\def\sseq@IfValidDifferentialTF{\sseq@IfValidDifferential{TF}}
\protected\def\sseq@IfValidDifferentialT{\sseq@IfValidDifferential{T}}
\protected\def\sseq@IfValidDifferentialF{\sseq@IfValidDifferential{F}}

\protected\def\sseq@IfValidDifferential#1{%
   \bgroup
   \def\sseq@truefalseclauses{#1}
   \sseq@d@grabpage{\sseq@IfValidDifferential@}
}

\DeclareDocumentCommand \sseq@IfValidDifferential@ { d() d() } {%
   \sseq@eval{\egroup\exp_not:c{sseq_if_valid_differential:nn\sseq@truefalseclauses}{\sseq@dpage}{\IfNoValueTF{#1}{\lastclass0}{\unexpanded{#1}}}{\unexpanded{#2}}}%
}

\prg_new_conditional:Npnn \sseq_if_valid_differential:nn #1 #2 #3 { T, F, TF } {
   \bgroup
   \sseq@tempiftrue
   \sseq@ifintexpr{#1}{%
       \edef\sseq@pagenum{\the\numexpr#1\relax}
   }{%
       \sseq@break% return false
   }%
   \sseq@quiet@parsecoord
   \msg_redirect_name:nnn {spectralsequences} {d-wrong-degree}              {none}
   \msg_redirect_name:nnn {spectralsequences} {d-target-index-target-coord} {none}
   \msg_redirect_name:nnn {spectralsequences} {d-named-coord-two-indexes}   {none}
   \msg_redirect_name:nnn {spectralsequences} {d-hit-wrong-order}           {none}
   \msg_redirect_name:nnn {spectralsequences} {d-class-already-hit}         {none}
   \msg_redirect_name:nnn {spectralsequences} {d-hit-same-page-replaceclass}{none}
   \sseq@dparsecoord{\sseq@pagenum}{#2}{#3}
   \let\sseq@obj@xdef\@gobbletwo
   \sseq@d@setpageclass{class.\source}{\sseq@pagenum}{source}
   \sseq@d@setpageclass{class.\target}{\sseq@pagenum}{target}
   \@gobbletwo\sseq@breakpoint\sseq@tempiffalse
   \ifsseq@tempif
               \egroup
               \prg_return_true:
   \else
       \egroup
       \prg_return_false:
   \fi
}



\sseq@DeclareDocumentCommand \IfExistsTF { r() } { \sseq_if_exists:nTF { #1 } }
\sseq@DeclareDocumentCommand \IfExistsT  { r() } { \sseq_if_exists:nT  { #1 } }
\sseq@DeclareDocumentCommand \IfExistsF  { r() } { \sseq_if_exists:nF  { #1 } }

\sseq@DeclareDocumentCommand \IfOutOfBoundsTF { r() } { \sseq_if_out_of_bounds:nTF { #1 } }
\sseq@DeclareDocumentCommand \IfOutOfBoundsT  { r() } { \sseq_if_out_of_bounds:nT  { #1 } }
\sseq@DeclareDocumentCommand \IfOutOfBoundsF  { r() } { \sseq_if_out_of_bounds:nF  { #1 } }
\sseq@DeclareDocumentCommand \IfInBoundsTF { r() mm } { \sseq_if_out_of_bounds:nTF { #1 } { #3 } { #2 } }
\sseq@DeclareDocumentCommand \IfInBoundsT  { r() } { \sseq_if_out_of_bounds:nF  { #1 } }
\sseq@DeclareDocumentCommand \IfInBoundsF  { r() } { \sseq_if_out_of_bounds:nT  { #1 } }

\sseq@DeclareDocumentCommand \IfAliveTF { mr() }{ \sseq_if_alive:nnTF{#1}{#2}}
\sseq@DeclareDocumentCommand \IfAliveT { mr() } { \sseq_if_alive:nnT{#1}{#2}}
\sseq@DeclareDocumentCommand \IfAliveF { mr() } { \sseq_if_alive:nnF{#1}{#2}}


%%%%%%
%%%
%%%   Tikz Primitives
%%%
%%%%%%

% Replace a tikz command with a command that saves the command on savedpaths

\def\sseq@modtikzcommands{%
   \let\scope\sseq@scope
   \let\endscope\sseq@endscope
   \@xp\sseq@modtikzcommands@\sseq@tikzcommands\sseq@nil
}
\def\sseq@modtikzcommands@#1{%
   \ifx#1\sseq@nil\else
       \protected\edef#1{\@xp\@nx\csname\sseq@macroname#1\space\endcsname\@nx#1}%
       \@xp\let\csname\sseq@macroname#1\space\endcsname\sseq@defer@tikzcommand % This is just for error reporting so that it will say "Paragraph ended before \draw  was complete"
       \@xp\sseq@modtikzcommands@
   \fi
}

\def\sseq@defer@tikzcommand#1{%
   \begingroup
   \let\sseq@isaliveprotect\sseq@isaliveprotect@protect
   \sseq@setinputline
   \sseq@loadinputline
   \sseq@callas{#1}%
   \gdef\sseq@thepathsofar{#1[/utils/exec={\sseq@thesseqstyle\sseq@thetikzprimitivestyle\the\sseq@scope@toks\sseq@savedoptioncode}]}%
   \xdef\sseq@whattheusersaid{\string#1}
   \sseq@defer@tikzcommand@
}

\def\sseq@defer@tikzcommand@{%
   \futurelet\testtok\sseq@defer@tikzcommand@@
}

% This serves as a marker to break out of parser.
% TODO: support \pgfextra? Should we pass \pgfextra along to be handled by tikz parser?
\def\sseq@defer@tikzcommand@escape{sseq@defer@tikzcommand@escape}
\def\sseq@defer@tikzcommand@@{%
   \ifx\testtok;
       \let\next\sseq@defer@tikzcommand@finish
   \else
       \ifx\testtok[%
           \let\next\sseq@defer@tikzcommand@option
       \else
           \ifx\testtok(%
               \let\next\sseq@defer@tikzcommand@coord
           \else
               \@xp\ifx\space\testtok
                   \let\next\sseq@defer@tikzcommand@space
               \else
                   % TODO: also support "foreach" keyword without the backslash.
                   \ifx\testtok\foreach
                       \let\next\sseq@defer@tikzcommand@foreach
                   \else
                       \ifx\testtok\sseq@defer@tikzcommand@escape % escape is like \pgfextra, breaks out of the parsing.
                           \let\next\@gobble
                       \else
                           \ifx\testtok\bgroup
                               \let\next\sseq@defer@tikzcommand@group
                           \else
                               \let\next\sseq@defer@tikzcommand@other
                           \fi
                       \fi
                   \fi
               \fi
           \fi
       \fi
   \fi
   \sseq@call{\next}%
}


\def\sseq@defer@tikzcommand@foreach{
   \def\pgffor@beginhook{\expandafter\sseq@defer@tikzcommand@\pgfutil@firstofone}
   \def\pgffor@endhook{\sseq@defer@tikzcommand@escape}
   \def\pgffor@afterhook{\sseq@defer@tikzcommand@}
}

\def\sseq@defer@tikzcommand@option[#1]{%
   \sseq@processoptions{tikz ~ primitives}{#1}%
   \ifx\sseq@savedoptioncode\pgfutil@empty\else
       \sseq@x@addto@macro\sseq@thepathsofar{[/utils/exec={\unexpanded\@xp{\@xp\sseq@options@bothpassmode\sseq@savedoptioncode}}]}%
   \fi
   \sseq@g@addto@macro\sseq@whattheusersaid{[#1]}
   \sseq@defer@tikzcommand@
}

\def\sseq@defer@tikzcommand@coord(#1){
   \sseq@tikzprimitives@coord(#1)
   \sseq@g@addto@macro\sseq@whattheusersaid{(#1)}
   \sseq@defer@tikzcommand@
}

% When do groups occur in tikz commands? should we try to parse the inside?
\def\sseq@defer@tikzcommand@group#1{
   \sseq@g@addto@macro\sseq@whattheusersaid{{#1}}
   \sseq@xprotected@addto@macro\sseq@thepathsofar{{#1}}%
   \sseq@defer@tikzcommand@
}

\long\def\sseq@defer@tikzcommand@other#1{
   \ifcat$\@xp\@gobble\string#1$ % test for control word. Won't catch active characters.
       \@xp\use_i:nnn
   \else
       \@xp\ifx\csname sseq@illegalintikz@\string#1\endcsname\relax
           \exp_last_unbraced:Nf \use_ii:nnn
       \else
           \exp_last_unbraced:Nf \use_iii:nnn
       \fi
   \fi{  % case i: it's not a control word. Just add it to the saved path
       \sseq@g@addto@macro\sseq@whattheusersaid{#1}
       \sseq@g@addto@macro\sseq@thepathsofar{#1}%
       \sseq@defer@tikzcommand@
   }{ % case ii: it's some different control word. Let's try full expanding it.
      % note that here we cannot figure out what the user actually said, so we just have to report the f-expanded version.
       \def\tempa{#1} % save the current value
       \exp_last_unbraced:Nf \sseq@defer@tikzcommand@other@cs#1
   }{ % case iii: it's an illegal control word (e.g., \class, \d, \begin, \end, ...) throw an error.
       \sseq@error@xx{incomplete-tikz}{\unexpanded\@xp{\sseq@whattheusersaid}}{
           \ifx\par#1 the ~ start ~ of ~ a ~ new ~ paragraph
           \else \string#1\fi
       }
       \sseq@defer@tikzcommand@finish@ % finish@ doesn't try to grab a semicolon, which is good because there isn't one.
       #1 % Reinsert the token that is causing us to stop
   }
}

\def\sseq@defer@tikzcommand@other@cs#1{ % so we f expanded the control sequence, now we test if that did anything
   \def\tempb{#1} % get the first f expanded token
   \ifx\tempa\tempb
       \@xp\@firstoftwo
   \else
       \@xp\@secondoftwo
   \fi{% it didn't get expanded any more, so just add it to the stored stuff
       \sseq@g@addto@macro\sseq@whattheusersaid{#1}
       \sseq@g@addto@macro\sseq@thepathsofar{#1}
       \sseq@defer@tikzcommand@
   }{% it got expanded. Run it through the main loop again.
       \sseq@defer@tikzcommand@#1
   }
}

% Illegal control words:
\long\def\sseq@setillegalcontrolwords#1{\sseq@setillegalcontrolwords@#1\sseq@nil}
\long\def\sseq@setillegalcontrolwords@#1{
   \ifx#1\sseq@nil\else
       \@xp\def\csname sseq@illegalintikz@\string#1\endcsname{}
       \@xp\sseq@setillegalcontrolwords@
   \fi
}

% We missing anything here?
\sseq@setillegalcontrolwords{
   \class\classoptions\replaceclass\d\doptions\structline\structlineoptions\circleclasses
   \savestack\restorestack\pushstack\nameclass\foreach\begin\end\par
   \clip\coordinate\draw\fill\filldraw
   \graph\matrix\node\path\pattern
   \shade\shadedraw\useasboundingbox
}


\@xp\def\@xp\sseq@defer@tikzcommand@space\space{%
   \sseq@g@addto@macro\sseq@thepathsofar{~}%
   \sseq@g@addto@macro\sseq@whattheusersaid{~}
   \sseq@defer@tikzcommand@
}

\def\sseq@defer@tikzcommand@finish;{
   \sseq@g@addto@macro\sseq@whattheusersaid{;}
   \sseq@defer@tikzcommand@finish@
}

% If the expression was incomplete, we'll jump here to avoid adding the semicolon to the error printout
\def\sseq@defer@tikzcommand@finish@{
   \sseq@g@addto@macro\sseq@thepathsofar{;}
   %\show\sseq@thepathsofar
   \global\sseq@thiscalltoks\@xp{\sseq@whattheusersaid}
   \ifx\sseq@pageconstraint\sseq@pageconstraint@true
       %\show\sseq@thepathsofar
       \sseq@savedpaths@xaddtikzpath{\unexpanded\@xp{\sseq@thepathsofar}}%
   \else
       \sseq@savedpaths@xaddtikzpath{%
           \@nx\sseq@tikzcommand@conditionaldraw{\unexpanded\@xp{\sseq@thepathsofar}}{\unexpanded\@xp{\sseq@pageconstraint}}
       }%
   \fi
   \endgroup
}


\def\sseq@tikzcommand@conditionaldraw#1#2{%
   \sseq@pgfmathparse@rescan{#2}%
   \ifnum\pgfmathresult>\z@ #1 \fi
}

\def\sseq@pgfmathparse@rescan#1{\makeatletter\catcode`\&=12\relax\scantokens{\pgfmathparse{#1}}}

%%% Coordinate parser, copied with huge simplifications from \tikz@@scan@@no@calculator, tikz.code.tex line 4994.
%%% We don't need to handle any of the weird cases, we just need to know about them so we can give up and let tikz do the work later.
% TODO: do same coordinate fixing for coordinates in calculations (yeah right! not even clear this is a good idea...)
\def\sseq@tikzprimitives@coord(#1){
   \begingroup
   \let\next\sseq@tikzprimitives@coords@maybenamedclass
   \ifsseq@tikzprims@integershift
       \pgfutil@in@${#1}
       \ifpgfutil@in@
           \let\next\sseq@tikzprimitives@coords@handlemath
       \else
           \pgfutil@in@ :{#1}
           \ifpgfutil@in@\else
               \pgfutil@in@{intersection }{#1}
               \ifpgfutil@in@\else
                   \pgfutil@in@|{#1}%
                   \ifpgfutil@in@\else
                       \pgfutil@in@,{#1}
                       \ifpgfutil@in@
                           \let\next\sseq@tikzprimitives@coords@maybeclass
                       \fi
                   \fi
               \fi
           \fi
       \fi
   \fi
   \next{#1}
   \endgroup
}
\def\sseq@tikzprimitives@coords@maybeclass#1{
   \let\next\sseq@tikzprimitives@coords@notaclass % most branches do this.
   % First check whether there are any of the protect "to be determined later" variables like \xmax, etc. If there are, it's not a class
   \sseq@protected@edef\sseq@temp@i{#1}
   \edef\sseq@temp@ii{#1}
   \ifx\sseq@temp@i\sseq@temp@ii
       \@xp\sseq@tikzprimitive@getcoord@anchor#1.\sseq@nil % puts coord into \sseq@tempcoord, anchor if any into \sseq@tempanchor
       \exp_args:NNo\pgfutil@in@.{\sseq@tempanchornopt} % If there's an extra . in the "anchor", it's not an anchor, and this is not a class
       \ifpgfutil@in@\else
           \exp_args:NNo \pgfutil@in@,{\sseq@tempcoord} % If the . we used to delineate the "anchor" was in the x-coordinate, it's not an anchor and this is not a class
           \ifpgfutil@in@
               \exp_args:NNo \pgfutil@in@,{\sseq@tempanchornopt} % If there is a comma in the "anchor" it's not an anchor and this is not a class
               \ifpgfutil@in@\else
                   \ifx\sseq@tempanchor\pgfutil@empty
                       \sseq@tempiftrue
                   \else % If there's an "anchor" we need to test whether the expression is a valid decimal coordinate. If it is, we're going to treat it as not a class
                       % outputs into sseq@tempif, sets sseq@tempiffalse if it IS valid math, b/c then we're not a anchor
                       \sseq@anchortrue % If this ends up getting handled as a tikz coordinate, we'll have to add an "anchor ignored" error
                       \sseq@tikzprimitives@testlastcoord@validmathexpression#1,\sseq@nil
                   \fi
                   \ifsseq@tempif
                       \@xp\sseq@tikzprimitives@ifintcoords\@xp{\sseq@tempcoord}{ % check we're all integer coordinates
                           \sseq@parsecoord@allownonexisting\coord{\sseq@tempcoord}{tikz ~ primitive}%
                           \ifx\sseq@index\pgfutil@empty\else
                               \sseq@x@addto@macro\sseq@thepathsofar{(sseq{\sseq@removeparens\coord}\sseq@tempanchor)}% Okay, we're all set, it's a class
                               \let\next\@gobble % don't run \sseq@tikzprimitives@notaclass
                           \fi
                       }{}%
                   \fi
               \fi
           \fi
       \fi
   \fi
   \next{#1}
}

% Sets tempiffalse if if the second coordinate IS a valid math expression -- then t
\def\sseq@tikzprimitives@testlastcoord@validmathexpression#1,#2,#3\sseq@nil{
   \sseq@ifpgfmathexpr{#2}{
       \sseq@tempiffalse
   }{
       \sseq@tempiftrue
   }
}

\def\sseq@tikzprimitives@coords@maybenamedclass#1{%
   \sseq@tikzprimitive@getcoord@anchor#1.\sseq@nil % puts coord into \sseq@tempcoord, anchor if any into \sseq@tempanchor
   \protected@edef\sseq@tempcoord{\sseq@tempcoord}%
   % need this detokenize here to prevent it from throwing errors when there's a command inside...
   \sseq@obj@ifdef{class.namedclass.\detokenize\@xp{\sseq@tempcoord}}{
       \sseq@x@addto@macro\sseq@thepathsofar{(sseq{\sseq@obj{class.namedclass.\detokenize\@xp{\sseq@tempcoord}}\sseq@tempanchor})}%
   }{%
       \sseq@tikzprimitives@coords@notaclass{#1}%
   }%
}

\let\sseq@tikzprimitives@coords@maybeclass@save\sseq@tikzprimitives@coords@maybeclass


\def\sseq@tikzprimitives@coords@notaclass#1{
   \def\next{\sseq@tikzprimitives@coords@notaclass@leavetotikz{#1}}
   \pgfutil@in@${#1}
   \ifpgfutil@in@\else
       \pgfutil@in@ :{#1}
       \ifpgfutil@in@\else
           \pgfutil@in@{intersection }{#1}
           \ifpgfutil@in@\else
               \pgfutil@in@|{#1}%
               \ifpgfutil@in@\else
                   \pgfutil@in@,{#1}
                   \ifpgfutil@in@
                       \def\next{\sseq@tikzprimitives@coords@notaclass@handle{#1}}
                   \fi
               \fi
           \fi
       \fi
   \fi
   \next
}

\def\sseq@tikzprimitives@coords@notaclass@leavetotikz#1{
   \sseq@g@addto@macro\sseq@thepathsofar{(#1)}
}

\def\sseq@tikzprimitives@coords@notaclass@handle#1{
   \ifsseq@anchor
       % Still seems impossible to trigger this?
       \sseq@error@xxx{anchor-ignored}{(#1)}{(\unexpanded\@xp{\sseq@tempcoord})}{\sseq@tempanchor}
       \@xp\sseq@tikzprimitives@coords@notaclass@handle@\sseq@tempcoord,\sseq@nil
   \else
       \sseq@tikzprimitives@coords@notaclass@handle@#1,\sseq@nil
   \fi
}

\def\sseq@tikzprimitives@coords@notaclass@handle@#1,#2,#3\sseq@nil{
   \sseq@ifempty{#3}{
       \let\sseq@index\pgfutil@empty
   }{
       \edef\sseq@index{,\unexpanded\@xp{\sseq@removecomma#3\sseq@nil}}
       \edef\sseq@indexnocomma{\unexpanded\@xp{\sseq@removecomma#3\sseq@nil}}
   }
   \sseq@ifpgfmathexpr{#1}{%
       % Decide whether we can keep the result, which is stored in \sseq@mathresult
       \protected@edef\sseq@tempa{#1}
       \edef\sseq@tempb{#1}
       \ifx\sseq@tempa\sseq@tempb
           \let\sseq@tempx\sseq@mathresult
       \else
           \def\sseq@tempx{#1}
       \fi
   }{
       \sseq@error@xx{invalid-tikz-coord}{(#1,#2\sseq@index)}{x}
       \def\sseq@defer@tikzcommand@finish;{\endgroup}
   }
   \sseq@ifpgfmathexpr{#2}{
       % Decide whether we can keep the result, which is stored in \sseq@mathresult
       \protected@edef\sseq@tempa{#2}
       \edef\sseq@tempb{#2}
       \ifx\sseq@tempa\sseq@tempb
           \let\sseq@tempy\sseq@mathresult
       \else
           \def\sseq@tempy{#2}
       \fi
   }{
       \sseq@error@xx{invalid-tikz-coord}{(#1,#2\sseq@index)}{y}
       \def\sseq@defer@tikzcommand@finish;{\endgroup}
   }
   \def\sseq@tempa{#1}
   \ifx\sseq@index\pgfutil@empty\else
       \sseq@error@xxx{index-ignored}{(\unexpanded{#1,#2}\unexpanded\@xp{\sseq@index})}{\unexpanded{(#1,#2)}}{\unexpanded\@xp{\sseq@indexnocomma}}
   \fi
   \sseq@xprotected@addto@macro\sseq@thepathsofar{(\sseq@tempx,\sseq@tempy)}
}

\def\sseq@tikzprimitives@ifintcoords#1{\sseq@tikzprimitives@ifintcoords@#1,\sseq@nil}
\def\sseq@tikzprimitives@ifintcoords@#1,#2,#3\sseq@nil{%
   \sseq@ifintexpr{#1}{%
       \sseq@ifintexpr{#2}{%
           \@firstoftwo
       }{\@secondoftwo}%
   }{\@secondoftwo}%
}
\def\sseq@tikzprimitives@coords@handlemath#1{\sseq@tikzprimitives@coords@handlemath@(#1)}
\def\sseq@tikzprimitives@coords@handlemath@#1$#2$){\sseq@g@addto@macro\sseq@thepathsofar{#1$#2$)}}
\def\sseq@tikzprimitive@getcoord@anchor#1.#2\sseq@nil{
   \def\sseq@tempcoord{#1}
   \ifx\sseq@nil#2\sseq@nil
       \def\sseq@tempanchor{}
       \def\sseq@tempanchornopt{}
   \else
       \edef\sseq@tempanchor{.\sseq@tikzprimitive@getcoord@anchor@eatdot#2}
       \edef\sseq@tempanchornopt{\sseq@tikzprimitive@getcoord@anchor@eatdot#2}
   \fi
}
\def\sseq@tikzprimitive@getcoord@anchor@eatdot#1.{#1}
\def\sseq@uptopt#1.#2\sseq@nil{#1}
%%% Page constraint and \isalive
% #1 -- the new page constraint
% #2 -- a binary logical operator (&& or ||).
\def\sseq@updatepageconstraint#1#2{
   \def\sseq@isaliveprotect{}
   \let\sseq@isalive@\sseq@isalive@active
   \bgroup
   % Was pretty hard to get \isalive to report errors correctly. And to work in general >_<
   \let\sseq@isalive@parens\sseq@isalive@parens@check
   \sseq@d@addto@macro\sseq@error@hook{\let\protect\relax}%
   \let\protect\@unexpandable@protect
   \edef\sseq@error@annotation{\unexpanded{.^^J(In page constraint "#1")}\unexpanded\@xp{\sseq@error@annotation}}
   \selectfont\sseq@restorefont
   \setbox0=\hbox{#1}
   \egroup
   \sseq@protected@edef\sseq@pageconstraint{(\unexpanded\@xp{\sseq@pageconstraint})#2(#1)}
}


\def\sseq@updatepageconstraintrange{%
   \sseq@protected@edef\sseq@pageconstraint{%
       (\unexpanded\@xp{\sseq@pageconstraint})&&(\temp<=\page \ifx\tempmax\empty\else&&\page<=\tempmax\fi)%
   }%
}

% This protect variant allows us to delay evaluation of \isalive, just so that we can
% capture something close to the original argument to (does this matter anymore?)
\let\sseq@isaliveprotect\relax
\def\sseq@isaliveprotect@protect{\@nx\sseq@isaliveprotect\@nx}
\def\sseq@isalive{\sseq@isaliveprotect\sseq@isalive@}
\def\sseq@isalive@{\sseq@isalive@error}
\def\sseq@isalive@error{\sseq@error{is-alive-illegal-here}}
\def\sseq@isalive@active#1{%
   \@xp\ifx\@xp$\@gobble#1$%
       \@xp\sseq@isalive@parens\@xp#1%
   \else
       \sseq@isalive@list#1\sseq@nil
   \fi
}
\def\sseq@isalive@list(#1)#2{%
   \sseq@isalive@parens(#1)%
   \ifx\sseq@nil#2\else
       &&\@xp\sseq@isalive@list\@xp#2%
   \fi
}

\def\sseq@isalive@parens@check(#1){
   \sseq@parsecoord\coord{#1}{\string\isalive}
}
\def\sseq@isalive@parens(#1){\sseq@parsecoordex\sseq@isalive@parens@(#1)}
\def\sseq@isalive@parens@(#1,#2,#3){\@nx\sseq@isalive@final{#1}{#2}{#3}{\sseq@obj{class.(#1,#2,#3).num}}}
\def\sseq@isalive@final#1#2#3#4{%
   \ifnum\sseq@obj{class.(#1,#2,#3)[#4].page}<\sseq@thepagecount
       0%
   \else
       \ifnum#4=\z@
           1%
       \else
           \ifnum\sseq@obj{class.(#1,#2,#3)[\the\numexpr #4-1\relax].page}=\sseq@thepagecount
               0%
           \else
               1%
           \fi
       \fi
   \fi
}





%%%
%%% This is a macro for typesetting monomials.
%%%

% We need to check for math subscript characters
\char_set_catcode_math_subscript:N \_

\def\sseq@support@std{}
\protected\def\SseqNormalizeMonomialSetVariables#1{%
   \bgroup
   \gdef\sseq@support@std{}%
   \def\sseqnormalizemonomial@add{%
       \def\temp{1}%
       \ifx\sseq@var\temp\else
           \edef\sseq@var{\unexpanded\@xp{\sseq@var}\unexpanded\@xp{\sseq@subscript}}%
           \@ifundefined{\sseqnormalizemonomial@varcs}{%
               \@xp\xdef\csname\sseqnormalizemonomial@varcs\endcsname{0}%
               \sseq@x@addto@macro\sseq@support@std{\@nx\\{\unexpanded\@xp{\sseq@var}}{\sseqnormalizemonomial@varcs}}%
           }{}%
       \fi
       \sseqnormalizemonomial@testend
   }%
   \SseqNormalizeMonomial{#1}%
   \egroup
}


\protected\def\SseqNormalizeMonomial#1{%
   \bgroup
   \def\sseq@ourinput{#1}%
   \let\sseq@support\sseq@support@std
   \sseq@ifempty{#1}{\egroup\def\result{1}}{%
       \sseqnormalizemonomial@#1\sseq@nil
   }%
}
\def\sseqnormalizemonomial@#1{%
   \pgfkeys@spdef\sseq@var{#1}%
   \def\sseq@power{1}%
   \def\sseq@subscript{}%
   \futurelet\testtok\sseqnormalizemonomial@@
}

\def\sseqnormalizemonomial@@{%
   \ifx\testtok^%
       \let\next\sseqnormalizemonomial@sup
   \else
       \ifx\testtok_%
           \let\next\sseqnormalizemonomial@sub
       \else
           \let\next\sseqnormalizemonomial@add
       \fi
   \fi
   \next
}

\def\sseqnormalizemonomial@sup^#1{%
   \sseq@ifintexpr{#1}{%
       \edef\sseq@power{\the\numexpr#1\relax}%
   }{%
       \sseq@error@xxx{NormalizeMonomial-invalid-exponent}{\unexpanded{#1}}{\unexpanded\@xp{\sseq@var}}{\unexpanded\@xp{\sseq@ourinput}}
       \let\result\sseq@ourinput
       \sseq@gobble@to@nil
   }
   \futurelet\testtok\sseqnormalizemonomial@@
}

\def\sseqnormalizemonomial@sub_#1{%
   \def\sseq@subscript{_{#1}}%
   \futurelet\testtok\sseqnormalizemonomial@@
}

\def\sseqnormalizemonomial@add{%
   \def\temp{1}%
   \ifx\sseq@var\temp\else
       \edef\sseq@var{\unexpanded\@xp{\sseq@var}\unexpanded\@xp{\sseq@subscript}}%
       \@ifundefined{\sseqnormalizemonomial@varcs}{%
           \@xp\edef\csname\sseqnormalizemonomial@varcs\endcsname{\sseq@power}%
           \sseq@e@addto@macro\sseq@support{\@nx\\{\unexpanded\@xp{\sseq@var}}{\sseqnormalizemonomial@varcs}}%
       }{%
           \@xp\edef\csname\sseqnormalizemonomial@varcs\endcsname{\the\numexpr\csname\sseqnormalizemonomial@varcs\endcsname + \sseq@power}%
       }%
   \fi
   \sseqnormalizemonomial@testend
}


\def\sseqnormalizemonomial@testend{%
   \ifx\testtok\sseq@nil
       \sseqnormalizemonomial@done
       \sseq@smuggle@macro\result
       \egroup
       \let\next\@gobble
   \else
       \@xp\ifx\space\testtok
           \def\next{\@xp\futurelet\@xp\testtok\@xp\sseqnormalizemonomial@testend\romannumeral-`0}%
       \else
           \let\next\sseqnormalizemonomial@
       \fi
   \fi
   \next
}

\def\sseqnormalizemonomial@varcs{sseqnormalizemonomial@var@\detokenize\@xp{\sseq@var}}

\def\sseqnormalizemonomial@done{%
   \def\result{}%
   \def\\##1##2{%
       \sseq@tempcount=\csname ##2\endcsname\relax
       \ifnum\sseq@tempcount=\z@
       \else
           \ifnum\sseq@tempcount=\@ne
               \sseq@d@addto@macro\result{##1}%
           \else
               \sseq@e@addto@macro\result{\unexpanded{##1}^{\the\sseq@tempcount}}%
           \fi
       \fi
   }%
   \sseq@support
   \ifx\result\pgfutil@empty % use 1 for empty monomial
       \def\result{1}%
   \fi
}

% Restore catcode of underscore to letter
\catcode`\_ = 11\relax


\def\SseqAHSSNameHandler#1{
   \pgfutil@in@[{#1}
   \ifpgfutil@in@
       \@xp\@firstofone
   \else
       \sseq@error{AHSSNameHandler-missing-cell}{#1}
       \def\result{#1}
       \@xp\@gobble
   \fi{
       \SseqAHSSNameHandler@#1\sseq@nil
   }
}


\def\SseqAHSSNameHandler@#1[#2\sseq@nil{
   \pgfutil@in@]{#2}
   \ifpgfutil@in@
       \@xp\@firstofone
   \else
       \sseq@error{AHSSNameHandler-missing-cell}{#1[#2}
       \def\result{#1[#2}
       \@xp\@gobble
   \fi{
       \SseqAHSSNameHandler@@{#1}#2\sseq@nil
   }
}

\def\SseqAHSSNameHandler@@#1#2]#3\sseq@nil{
       \SseqNormalizeMonomial{#1#3}
   \sseq@ifintexpr{#2}{
           \edef\result{\unexpanded\@xp{\result}[\the\numexpr#2+\sseq@y]}
   }{
       \sseq@error{AHSSNameHandler-invalid-integer}{#2}{#1[#2]#3}
       \edef\result{\unexpanded\@xp{\result[#2]}}
   }
}




\ExplSyntaxOff