%% %% Package: spectralsequences v1.3.2 2022-02-19 %% Author: Hood Chatham %% Email: hood@mit.edu %% Date: 2022-02-19 %% 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 }{ \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 \commandcode 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 %