%%
%% 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
%