%%
%% Package: spectralsequences v1.3.3 2023-01-28
%% Author: Hood Chatham
%% Email: [email protected]
%% Date: 2023-01-28
%% License: Latex Project Public License
%%
%% File: sseqmacromakers.code.tex
%% Exposes: \DeclareSseqCommand, \NewSseqCommand, \DeclareSseqGroup, \NewSseqGroup
%%
%%   Set up commands to define other commands, both the internal macros, and the external ones.
%%   Also the internal macros \sseq@DeclareDocumentCommandAs and \sseq@DeclareDocumentCommand
%%   For the user commands, sets up call stack, thiscall, etc
%%

\ExplSyntaxOn

%%% Install user commands
% copy commands into user namespace by removing sseq@ prefixes
% given a list of commands, \let\thiscommand\sseq@thiscommand on each one
\def\sseq@installmacros{\@xp\sseq@installmacros@\sseq@macrolist\sseq@nil}
\def\sseq@installmacros@#1{%
   \ifx#1\sseq@nil\else % if so, that was the last command in the list
       \@xp\let\@xp#1\csname sseq@\sseq@macroname#1\endcsname
       \@xp\sseq@installmacros@
   \fi %
}

% Capital U argument type is "Until" but puts back the token when it's done.

% So xparse changed a bunch between the copy pushed to CTAN on February 7th and the copy pushed on February 9th
\newtoks\sseq@patchxparseUnewcode
\sseq@patchxparseUnewcode{
   \cs_new_protected:Npn \sseq__xparse_grab_U:w #1#2 \__xparse_run_code:
     { \sseq__xparse_grab_U_aux:nnN {#1} {#2} \cs_set_protected_nopar:Npn }
   \cs_new_protected:Npn \sseq__xparse_grab_U_aux:nnN #1#2#3
     {
       \tl_set:Nn \l__xparse_signature_tl {#2}
       \exp_after:wN #3 \l__xparse_fn_tl ##1 #1
         { \__xparse_add_arg:n {##1} #1 }
       \l__xparse_fn_tl
     }
   \ifx\__xparse_add_grabber_mandatory:N\undefined
       \let \__xparse_add_grabber_mandatory:N \__xparse_add_grabber:N
   \fi
   \cs_new_protected:Npn \sseq__xparse_add_type_U:w #1
     {
       \__xparse_flush_m_args:
       \__xparse_add_default:
       \__xparse_add_grabber_mandatory:N U
       \tl_put_right:Nn \l__xparse_signature_tl { {#1} }
       \__xparse_prepare_signature:N
     }
%
%
   \cs_new_protected:Npn \sseq__cmd_grab_U:w #1#2 \__cmd_run_code:
     { \sseq__cmd_grab_U_aux:nnN {#1} {#2} \cs_set_protected_nopar:Npn }
   \cs_new_protected:Npn \sseq__cmd_grab_U_aux:nnN #1#2#3
     {
       \tl_set:Nn \l__cmd_signature_tl {#2}
       \exp_after:wN #3 \l__cmd_fn_tl ##1 #1
         { \__cmd_add_arg:n {##1} #1 }
       \l__cmd_fn_tl
     }
   \cs_new_protected:Npn \sseq__cmd_add_type_U:w #1
     {
       \__cmd_flush_m_args:
       \__cmd_add_default:
       \__cmd_add_grabber:N U
       \tl_put_right:Nn \l__cmd_signature_tl { {#1} }
       \__cmd_prepare_signature:N
     }
}

\@ifpackagelater{xparse}{2017/02/08}{
   \@ifpackagelater{xparse}{2018/10/17}{
       \ifsseq@patchxparseU
           \the\sseq@patchxparseUnewcode
       \else
           % Assumptions failed, so just make U give an error (this isn't such a big deal since we don't use it for \d anymore).
           \cs_new_protected:Npn \sseq__cmd_add_type_U:w #1
             {
               \sseq@error{U-xparse-incompatible}
             }
           \cs_new_eq:NN \sseq__xparse_add_type_U:w \sseq__cmd_add_type_U
       \fi
   }{
       \the\sseq@patchxparseUnewcode
   }
}{
   % OLD CODE
   \cs_new_protected:Npn \sseq__xparse_grab_U:w #1#2 \l__xparse_args_tl
     { \sseq__xparse_grab_U_aux:nnN {#1} {#2} \cs_set_protected_nopar:Npn }
   \cs_new_protected:Npn \sseq__xparse_grab_U_aux:nnN #1#2#3
     {
       \exp_after:wN #3 \l__xparse_fn_tl ##1 #1
         {
           \__xparse_add_arg:n {##1}
           #2\l__xparse_args_tl #1
         }
       \l__xparse_fn_tl
     }
   \cs_new_protected:Npn \sseq__xparse_add_type_U:w #1
     {
       \__xparse_flush_m_args:
       \__xparse_add_grabber_mandatory:N U
       \tl_put_right:Nn \l__xparse_signature_tl { {#1} }
       \__xparse_prepare_signature:N
     }
}% END \@ifpackagelater

% On 2018/10/01, the commit "Reimplement the ignore_spaces peek functions in terms of peek_spaces" did what it says.
% Inside of \sseq@DeclareDocumentCommandAs we \let \peek_meaning to \peek_meaning_ignore_spaces
% which is bad news if \peek_meaning_ignore_spaces is defined in terms of \peek_meaning. This fixes this bug by
% redefining \peek_meaning_ignore_spaces in terms of a copy of \peek_meaning.
\@ifpackagelater{expl3}{2018/10/01}{
   \cs_set_eq:NN\sseq__copy_of_peek_meaning:NTF\peek_meaning:NTF
   \cs_set:Npn\sseq__peek_meaning_ignore_spaces:NTF#1#2#3{\peek_remove_spaces:n{\sseq__copy_of_peek_meaning:NTF#1{#2}{#3}}}
   \cs_set_eq:NN\sseq__copy_of_peek_meaning_remove:NTF\peek_meaning_remove:NTF
   \cs_set:Npn\sseq__peek_meaning_remove_ignore_spaces:NTF#1#2#3{\peek_remove_spaces:n{\sseq__copy_of_peek_meaning_remove:NTF#1{#2}{#3}}}
}{
   \cs_set_eq:NN\sseq__peek_meaning_ignore_spaces:NTF\peek_meaning_ignore_spaces:NTF
   \cs_set_eq:NN\sseq__peek_meaning_remove_ignore_spaces:NTF\peek_meaning_remove_ignore_spaces:NTF
}

\@ifpackagelater{xparse}{2018/10/17}{
   \cs_new_protected:Npn \sseq__xparse_normalize_type_U:w #1 {
       \quark_if_recursion_tail_stop_do:nn {#1} { \__xparse_bad_arg_spec:wn }
       \__xparse_normalize_check_lu:N U
       \__xparse_add_arg_spec_mandatory:n { U {#1} }
       \__xparse_normalize_arg_spec_loop:n
   }

   \cs_new_protected:Npn \sseq__cmd_normalize_type_U:w #1 {
       \quark_if_recursion_tail_stop_do:nn {#1} { \__cmd_bad_arg_spec:wn }
       \__cmd_normalize_check_lu:N U
       \__cmd_add_arg_spec_mandatory:n { U {#1} }
       \__cmd_normalize_arg_spec_loop:n
   }
}{
   \cs_new_protected:Npn \sseq__xparse_normalize_type_U:w #1 {
       \quark_if_recursion_tail_stop_do:nn {#1} { \__xparse_bad_arg_spec:wn }
       \__xparse_normalize_check_lu:N U
       \__xparse_add_arg_spec:n { U {#1} }
       \int_incr:N \l__xparse_mandatory_args_int
       \tl_clear:N \l__xparse_last_delimiters_tl
       \__xparse_normalize_arg_spec_loop:n
   }
}
% Expandable commands are a menace to us because they define a bunch of helper commands that we then have to keep track of.
% We are too lazy to do this, so force \l__cmd_grab_expandably_bool to be false.
% This is backwards compatible (I think) because \bool_set_false:N just performs a chardef (no existence check)
% so in old versions, \l__cmd_grab_expandably_bool will be created harmlessly.
\let\sseq__cmd_prepare_signature:n\__cmd_prepare_signature:n
\ifx\sseq__cmd_prepare_signature:n\undefined
   \let\sseq__cmd_prepare_signature:n\__xparse_prepare_signature:n
\fi
\pretocmd\sseq__cmd_prepare_signature:n {
   \bool_set_false:N \l__cmd_grab_expandably_bool
   \bool_set_false:N \l__xparse_grab_expandably_bool
}{}{\error}

% I would like to patch the \__xparse_grab_U:w's in my commands into \sseq__xparse_grab_U:w's but I can't because of -NoValue-.
\def\sseq@install@xparse@Uarggrabber{%
   \cs_set_eq:NN \__xparse_grab_U:w \sseq__xparse_grab_U:w
   \cs_set_eq:NN \__cmd_grab_U:w \sseq__cmd_grab_U:w
}

%%% \sseq@DeclareDocumentCommand
%
% \sseq@DeclareDocumentCommand\somecommand is shorthand for \sseq@DeclareDocumentCommandAs\sseq@somecommand\somecommand
%
% so the result is that it defines \sseq@somecommand intended to be \let to \somecommand later.

\cs_new_protected:Npn\sseq@DeclareDocumentCommand#1{%
   \exp_args:Nc \sseq@DeclareDocumentCommandAs@setinputline { sseq @ \cs_to_str:N #1 }#1
}

\cs_new_protected:Npn\sseq@DeclareDocumentCommandAs@setinputline#1{
  \protected\edef #1 { \@nx\sseq@setinputline \@xp\@nx\csname \cs_to_str:N #1 @@unique@@ start \endcsname }
   \exp_args:Nc \sseq@DeclareDocumentCommandAs { \cs_to_str:N #1 @@unique@@ start }
}

%%% \sseq@DeclareDocumentCommandAs
%
% #1 - the command to define
% #2 - the command to use in argument parsing errors
% #3 - parameters (\NewDocumentCommand style)
% #4 - code
%
% See my stack exchange question: https://tex.stackexchange.com/questions/350596/control-error-messages-made-by-commands-defined-with-newdocumentcommand

\cs_new_protected:Npn\sseq@DeclareDocumentCommandAs#1#2#3#4{
   \group_begin:
   \cs_set_eq:NN \__cmd_add_type_U:w \sseq__cmd_add_type_U:w
   \cs_set_eq:NN \__xparse_add_type_U:w \sseq__xparse_add_type_U:w
   \cs_set_eq:NN \__cmd_normalize_type_U:w \sseq__cmd_normalize_type_U:w
   \cs_set_eq:NN \__xparse_normalize_type_U:w \sseq__xparse_normalize_type_U:w
   \cs_set_eq:NN \__cmd_prepare_signature:n \sseq__cmd_prepare_signature:n
   \cs_set_eq:NN \__xparse_prepare_signature:n \sseq__cmd_prepare_signature:n
   %\cs_set:Npn   \__cmd_declare_cmd_code:Nnn {\bool_set_false:N \l__cmd_grab_expandably_bool\__cmd_declare_cmd_code_aux:Nnn}
   \sseq@installmsghooks
   \def\sseq@error@setup{}
   \def\sseq@error@cleanup{\sseq@errortrue}
   \let\sseq@error@annotation\empty
   \DeclareDocumentCommand #2 { #3 } { #4 }
   \ifsseq@error
       \group_end:
       \sseq@errortrue % This only happens if it came from user code, so don't set error to be false so it can break out too.
       \@xp\sseq@break
   \fi
   \cs_if_exist:cTF{ \cs_to_str:N #2 \c_space_tl code }{
       \cs_gset:Npx #1{
           \begingroup
           \exp_not:N \cs_set_eq:NN  % force xparse to always ignore spaces!
               \exp_not:N \peek_meaning:NTF
               \exp_not:N \sseq__peek_meaning_ignore_spaces:NTF
           \exp_not:N \cs_set_eq:NN  % force xparse to always ignore spaces!
               \exp_not:N \peek_meaning_remove:NTF
               \exp_not:N \sseq__peek_meaning_remove_ignore_spaces:NTF
           % Not sure why we use set_eq:cc and exp_not:n here but I'm concerned that something will break if I change it...
           \exp_not:N \cs_set_eq:cc
               \exp_not:n {{ \cs_to_str:N #2 \c_space_tl code }}
               \exp_not:n {{ \cs_to_str:N #1 \c_space_tl code }}
           \exp_not:N \cs_set_eq:NN
               \exp_not:c { \cs_to_str:N #2 \c_space_tl }
               \exp_not:c { \cs_to_str:N #1 \c_space_tl }
           \exp_not:c { \cs_to_str:N #1 \c_space_tl inner }
       }
       \pretocmd:cnnn { \cs_to_str:N #2 \c_space_tl code } { \endgroup{} } { } { \sseq@error@x { macro-patch-failed } { \string#1 } }
       \cs_gset_eq:cN { \cs_to_str:N #1 \c_space_tl inner } #2
       \cs_gset_eq:cc { \cs_to_str:N #1 \c_space_tl code } { \cs_to_str:N #2 \c_space_tl code }
       \cs_gset_eq:cc { \cs_to_str:N #1 \c_space_tl }{ \cs_to_str:N #2 \c_space_tl } % sometimes the new version of xparse stores stuff in #2<space>
   }{
       \cs_gset_eq:NN #1 #2
   }
   \group_end: % In this case, I want to pass \sseq@errortrue out of the block, so I close the group before I break.
   \sseq@breakpoint % So this breakpoint definitely should be after the \endgroup.
}

\cs_set_eq:NN \patchcmd:Nnnnn \patchcmd
\cs_set_eq:NN \pretocmd:Nnnn  \pretocmd
\cs_generate_variant:Nn \patchcmd:Nnnnn {cnfnn}
\cs_generate_variant:Nn \pretocmd:Nnnn  {cfnn}
\cs_generate_variant:Nn \pretocmd:Nnnn  {cnnn}

\cs_new_protected:Npn\NewSseqCommand#1{%
   \cs_if_free:cTF { sseq @ usermacro @ \cs_to_str:N #1 } { \DeclareSseqCommand#1 } { \sseq@error@x{usermacro-not-free}{\string#1} \use_none:nn }
}
\let\begingroupa\begingroup
\let\begingroupb\begingroup
\newtoks\sseq@macro@setthiscall@toks
\newtoks\sseq@macro@defaultarggetters@toks

\cs_new_protected:Npn\DeclareSseqCommand#1#2#3{%
   \cs_if_exist:cTF { sseq @ \cs_to_str:N #1 @@unique@@ start} {\sseq@error@x{wont-override-builtin}{\string#1}\sseq@break} {}
   \cs_if_free:cT { sseq @ usermacro @ \cs_to_str:N #1 } {
       \sseq@x@addto@macro { \sseq@installmacros } { \let \exp_not:N #1 \exp_not:c { sseq @ usermacro @ \cs_to_str:N #1 } }
   }
   % Make sure \cs_if_exist doesn't pass because there was a previously defined user macro with same name
   \cs_undefine:c { sseq @ usermacro @ \cs_to_str:N #1 \c_space_tl code }
   \exp_args:Nc \sseq@DeclareDocumentCommandAs@setinputline { sseq @ usermacro @ \cs_to_str:N #1 } #1 { #2 } {%
           \sseq@loadinputline
           \sseq@atbeginusermacro@msgsetup
               {}#3{} % prevent space patching space hazards with these {}'s
           \endgroup
       }%
   \ifsseq@error
       \global\sseq@errorfalse
       \@xp\sseq@break
   \fi
   \sseq@parseargspec{#1}{#2}%
   % You might think we could skip this patching, and it's probably possible.
   % However, this is responsible for turning the #'s of catcode other into #'s of catcode arg. I don't have as good of a way to do that.
   % Also, this allows me to use \sseq@parseargspec after defining the command, so I don't have to run any error checking inside of it
   % because if the argspec is invalid, \DeclareDocumentCommand will let me know.
   \cs_if_exist:cTF{ sseq @ usermacro @ \cs_to_str:N #1 @@unique@@ start \c_space_tl code }{
       \patchcmd:cnfnn{ sseq @ usermacro @ \cs_to_str:N #1 @@unique@@ start \c_space_tl code }{\endgroup{}}{
           \@xp\endgroup
           \@xp\begingroupa
           \the\sseq@macro@setthiscall@toks
       }{}{\sseq@error@x{usermacro-failed-patch}{\string#1}}
       \cs_gset_eq:cc { sseq @ usermacro @ \cs_to_str:N #1 @@unique@@ start \c_space_tl code } { sseq @ usermacro @ \cs_to_str:N #1 @@unique@@ start \c_space_tl code}
   }{
       \pretocmd:cfnn{ sseq @ usermacro @ \cs_to_str:N #1 @@unique@@ start }{
           \@xp\begingroupb
           \the\sseq@macro@setthiscall@toks
       }{}{\sseq@error@x{usermacro-failed-patch}{\string#1}}
   }
   \cs_gset_eq:cc { sseq @ usermacro @ \cs_to_str:N #1 } { sseq @ usermacro @ \cs_to_str:N #1 }
   \cs_gset_eq:cc { sseq @ usermacro @ \cs_to_str:N #1 @@unique@@ start } { sseq @ usermacro @ \cs_to_str:N #1 @@unique@@ start}
   \ifsseq@inprogress
       \cs_set_eq:Nc #1 { sseq @ usermacro @ \cs_to_str:N #1 }
   \fi
   \sseq@breakpoint
}

%%% Commands to help the user define "groups" of commands to be reused
% #1 -- command
% #2 -- argspec
% #3 -- body of function (long)
\NewDocumentCommand\NewSseqGroup{mm+m}{\DeclareSseqGroup@\NewSseqCommand{#1}{#2}{#3}}
\NewDocumentCommand\DeclareSseqGroup{mm+m}{\DeclareSseqGroup@\DeclareSseqCommand{#1}{#2}{#3}}

% #1 -- \NewSseqCommand or \DeclareSseqCommand
% #2 -- command
% #3 -- argspec
% #4 -- body of function (long)
\long\def\DeclareSseqGroup@#1#2#3#4{%
   \group_begin:
   \let\sseq@parseargspec\@gobbletwo % Get rid of argparse so we can change what gets added for setting up thiscall
% why are we doing these things here?
   \sseq@installmsghooks
   \def\sseq@error@setup{}
   \def\sseq@error@cleanup{\sseq@errortrue}
   \let\sseq@error@annotation\empty
%
% undefine so we can tell whether we need to patch \command<space>code or \command
   \cs_undefine:c { sseq @ usermacro @ \cs_to_str:N #2 @ helper  \c_space_tl code }
   \exp_args:Nc \sseq@DeclareDocumentCommandAs { sseq @ usermacro @ \cs_to_str:N #2 @ helper } #2 { #3 } {
       \sseq@loadinputline
       \sseq@usermacro@esetthiscall{\the\sseq@groupthiscalltoks}
       \sseq@atbeginusermacro@msgsetup % the stack push happens in here
       \sseq@scopecall
           {}#4{}
       \end{scope}
       \endgroup
       \sseq@breakpoint
   }%
   \ifsseq@error
       \@xp\sseq@break
   \fi
   \sseq@macro@setthiscall@toks\@xp{\sseq@SseqGroup@argspec} % This gets added to the command by DeclareSseqCommand
   #1#2{od()}{%
       %can't use \sseq@atbeginusermacro@msgsetup until next spot b/c don't know what the whole call looks like yet
       \IfNoValueTF{##1}{\def\sseq@options{}}{\def\sseq@options{##1}}%
       \IfNoValueTF{##2}{%
           \edef\sseq@scopecall{\@nx\begin{scope}[\unexpanded\@xp{\sseq@options}]}
       }{%
           \sseqnewgroup@splitcoord##2\sseq@nil
       }%
       \csname sseq @ usermacro @ \sseq@macroname #2 @ helper \@xp\endcsname\@gobbletwo % This gobble eats the endgroup added by sseqDeclareDocumentCommand
   }
   \sseq@parseargspec@newgroup{#2}{#3}%
   % You might think we could skip this patching, and it's probably possible.
   % However, this is responsible for turning the #'s of catcode other into #'s of catcode arg. I don't have as good of a way to do that.
   \cs_if_exist:cTF{ sseq @ usermacro @ \cs_to_str:N #2 @ helper \c_space_tl code }{
       \pretocmd:cfnn { sseq @ usermacro @ \cs_to_str:N #2 @ helper \c_space_tl code }{
           \the\sseq@macro@setthiscall@toks
       }{}{\sseq@error@x{usermacro-failed-patch}{\string#1}}
       % globalize definition:
       \cs_gset_eq:cc { sseq @ usermacro @ \cs_to_str:N #2 @ helper \c_space_tl code } { sseq @ usermacro @ \cs_to_str:N #2 @ helper \c_space_tl code }
   }{
       \pretocmd:cfnn { sseq @ usermacro @ \cs_to_str:N #2 @ helper }{
           \the\sseq@macro@setthiscall@toks
       }{}{\sseq@error@x{usermacro-failed-patch}{\string#1}}
   }
   \cs_gset_eq:cc { sseq @ usermacro @ \cs_to_str:N #2 @ helper } { sseq @ usermacro @ \cs_to_str:N #2 @ helper } % globalize definition
   \let\sseq@parseargspec\sseq@parseargspec@normal
   \sseq@breakpoint
   \group_end:
}

\def\sseqnewgroup@splitcoord#1,#2\sseq@nil{
   \sseq@ifintexpr{#1}{}{
       \def\sseq@scopecall{\sseq@error@n{invalid-coordinate}{x~}\sseq@break}
       \sseq@break
   }
   \sseq@ifintexpr{#2}{}{
       \def\sseq@scopecall{\sseq@error@n{invalid-coordinate}{y~}\sseq@break}
       \sseq@break
   }
   \edef\sseq@scopecall{
       \@nx\begin{scope}[xshift=\the\numexpr#1\relax,yshift=\the\numexpr#2\relax,\unexpanded\@xp{\sseq@options}]
   }
   \sseq@breakpoint
}


\newtoks\sseq@groupargspectoks
\newtoks\sseq@groupthiscalltoks
\bgroup\catcode`\#=12\relax
   \gdef\sseq@SseqGroup@argspec{
       \sseq@eval{\global\sseq@groupargspectoks{\IfNoValueF{#1}{\unexpanded{[#1]}}\IfNoValueF{#2}{\unexpanded{(#2)}}}}
       \@gobbletwo % What does this \@gobbletwo do?
   }
   \gdef\sseq@thearg{#\the\sseq@tempcount}
\egroup


% When there are arguments with default values (O, D, R, G), we need to put them
% into temporary macros to compare them and see if they are the default value
% that's what \sseq@macro@defaultarggetters@toks is for.
\def\sseq@parseargspec#1#2{%
   \sseq@tempcount=\z@
   \sseq@temptoks{\@nx#1}% Holds the stuff that goes in \esetthiscall (so most stuff)
   \sseq@macro@defaultarggetters@toks{}
   \sseq@parseargspec@#2\sseq@nil
   \sseq@eval{\sseq@macro@setthiscall@toks{\the\sseq@macro@defaultarggetters@toks\@nx\sseq@usermacro@esetthiscall{\the\sseq@temptoks}}}
}

% For NewGroup:
\let\sseq@parseargspec@normal\sseq@parseargspec
\def\sseq@parseargspec@newgroup#1#2{%
   \sseq@tempcount=\z@
   \sseq@temptoks{}
   \sseq@macro@defaultarggetters@toks{}%
   \sseq@parseargspec@#2\sseq@nil
   \sseq@eval{
       \sseq@macro@setthiscall@toks{
           \the\sseq@macro@defaultarggetters@toks
           \@nx\sseq@esetthiscall{
               \@nx\@nx\@nx#1
               \@nx\the\sseq@groupargspectoks
               \the\sseq@temptoks
           }
           \global\sseq@groupthiscalltoks\@nx\@xp{\@nx\the\sseq@thiscalltoks}
       }
   }
}


\def\sseq@parseargspec@#1{
   \advance\sseq@tempcount\@ne
   \ifx#1\sseq@nil\else
       \@xp\ifx\csname sseq@parseargspec@#1\@xp\endcsname\relax
           \sseq@error@n{usermacro-unsupported-argument-type}{#1}
       \else
           \csname sseq@parseargspec@#1\@xptwo\endcsname
       \fi
   \fi
}


% Have to use \@alph to convert the number to a letter. Using a number here doesn't work because the control sequence gets retokenized
% so we can only use letters in control sequences (another option would be to not expand the \csnames till later, but that would be harder).
\def\sseq@parseargspec@ifargisnotdefault{%
       \@nx\ifx
           \@xp\@nx\csname sseq@parseargspec@temparg\@alph\sseq@tempcount\endcsname
           \@xp\@nx\csname sseq@parseargspec@tempdefault\@alph\sseq@tempcount\endcsname
   \unexpanded{%
           \@xp\@gobble
       \else
           \@xp\@firstofone
       \fi
   }%
}

\def\sseq@parseargspec@setargdefault#1{%
   \sseq@e@addto@toks\sseq@macro@defaultarggetters@toks{%
       \def\@xp\@nx\csname sseq@parseargspec@temparg\@alph\sseq@tempcount\endcsname{\sseq@thearg}%
       \def\@xp\@nx\csname sseq@parseargspec@tempdefault\@alph\sseq@tempcount\endcsname{\unexpanded{#1}}%
   }
}

% v, E, and e are illegal

% Mandatory
\def\sseq@parseargspec@m{%
   \sseq@e@addto@temptoks{{\@nx\unexpanded{\sseq@thearg}}}
   \sseq@parseargspec@
}
\def\sseq@parseargspec@l{%
   \sseq@e@addto@temptoks{\@nx\unexpanded{\sseq@thearg}}
   \sseq@parseargspec@
}

\def\sseq@parseargspec@u#1{%
   \sseq@e@addto@temptoks{\@nx\unexpanded{\sseq@thearg}\unexpanded{\unexpanded{#1}}}
   \sseq@parseargspec@
}

\def\sseq@parseargspec@U#1{%
   \sseq@e@addto@temptoks{\@nx\unexpanded{\sseq@thearg}}
   \sseq@parseargspec@
}

% Optional no default
\def\sseq@parseargspec@o{%
   \sseq@e@addto@temptoks{\@nx\IfNoValueF{\sseq@thearg}{[\@nx\unexpanded{\sseq@thearg}]}}
   \sseq@parseargspec@
}

\def\sseq@parseargspec@d#1#2{%
   \sseq@e@addto@temptoks{\@nx\IfNoValueF{\sseq@thearg}{\@nx\unexpanded{#1\sseq@thearg#2}}}
   \sseq@parseargspec@
}

\def\sseq@parseargspec@r#1#2{ % technically required, but behaves like optional
   \sseq@e@addto@temptoks{#1\@nx\unexpanded{\sseq@thearg}#2}
   \sseq@parseargspec@
}


\def\sseq@parseargspec@g{%
   \sseq@e@addto@temptoks{\@nx\IfNoValueF{\sseq@thearg}{\@nx\unexpanded{{\sseq@thearg}}}}
   \sseq@parseargspec@
}

\def\sseq@parseargspec@s{%
   \sseq@e@addto@temptoks{\@nx\IfBooleanT{\sseq@thearg}{*}}
   \sseq@parseargspec@
}

\def\sseq@parseargspec@t#1{%
   \sseq@e@addto@temptoks{\@nx\IfBooleanT{\sseq@thearg}{#1}}
   \sseq@parseargspec@
}

% Optional with default

\def\sseq@parseargspec@O#1{
   \sseq@parseargspec@setargdefault{#1}%
   \sseq@e@addto@temptoks{\sseq@parseargspec@ifargisnotdefault{\@nx\unexpanded{[\sseq@thearg]}}}%
   \sseq@parseargspec@
}
\def\sseq@parseargspec@D#1#2#3{%
   \sseq@parseargspec@setargdefault{#3}%
   \sseq@e@addto@temptoks{\sseq@parseargspec@ifargisnotdefault{\@nx\unexpanded{#1\sseq@thearg#2}}}%
   \sseq@parseargspec@
}
\def\sseq@parseargspec@R#1#2#3{%
   \sseq@parseargspec@setargdefault{#3}%
   \sseq@e@addto@temptoks{\sseq@parseargspec@ifargisnotdefault{\@nx\unexpanded{#1\sseq@thearg#2}}}%
   \sseq@parseargspec@
}
\def\sseq@parseargspec@G#1{%
   \sseq@parseargspec@setargdefault{#1}%
   \sseq@e@addto@temptoks{\sseq@parseargspec@ifargisnotdefault{\@nx\unexpanded{{\sseq@thearg}}}}%
   \sseq@parseargspec@
}

\ExplSyntaxOff

%