\RequirePackage{expl3,xparse} \ProvidesExplPackage{semantex}{2020/05/30}{0.1alpha}{} % IMPORTANT: % Because of the definition of \semantexnormalscaling, the package now requires amsmath % Think about changing “upper” etc. into “supper”, whereas what is now % “upper” could be called “uppernosep” or something similar. % Fix left sub- and superscripts, e.g. the right spacing % Allow “.” (nothing) as delimiter, even in the case of normal or \big etc % Instead of checking if you are equal to semantexvarible when doing % inheritance, check if you are your own parent. This allows multiple % “primitive” classes. % Also remove commands like \newsemantexvariable etc. % in order to force people to create their own classes % Create 2valuekeys, 3valuekeys etc. % Test if \exp_not:n can be removed in #1 (=\keyvalue) if % another \exp_not:n is added in the data manipulation commands. % Build groups and \ext_args:NV around the definition of % \l_semantex_key_value_temp in order to only % define this command locally. % Allow two keys, nopar and absolutelynopar. The difference is that % nopar becomes par if there is more than one argument % Allow left arguments! % LIST OF BUGS: %IM A change has been made in catlimits. It shows the existence of a %IM kind of bug in semantex %IM Removed \!\!\!\! in catlimits \msg_new:nnnn { semantex } { keyval_not_found } { Unknown~key~#1~passed~to~object~#2~on~input~line~\msg_line_number: } {} \msg_new:nnnn { semantex } { arg_valuekey_not_found } { Unknown~argument~key~#1~passed~to~object~#2~on~input~line~\msg_line_number: } {} \msg_new:nnnn { semantex } { tl_not_found } { Unknown~data~#1~passed~to~object~#2~on~input~line~\msg_line_number: } {} %IM should be changed so that this is passed to the actual object, not %IM the parent object, e.g., by having a third argument containing the %IM actual object in \g_semantex_data_tl_get:nn \msg_new:nnnn { semantex } { parent_not_found } { Unknown~class~#1~set~as~parent~of~object~#2~on~input~line~\msg_line_number: } {} \msg_new:nnnn { semantex } { data_tl_not_found } { Unknown~data~#1~passed~to~object~#2~on~input~line~\msg_line_number: } {} % Extra cs variants we need: \cs_generate_variant:Nn \keyval_parse:NNn { cco } \cs_generate_variant:Nn \tl_if_blank:nTF { vTF } \tl_set:Nn \semantexbullet {\raisebox{-0.25ex}{\scalebox{1.2}{$\cdot$}}} \tl_set:Nn \semantexdoublebullet {\semantexbullet\semantexbullet} \tl_set:Nn \semantexslot { \mathord{-} } \DeclareDocumentCommand\newbinaryclass{mO{}} % new binary-type class { % #1 = class name % #2 = options \semantexnewclass { #1 } { #2 } \exp_args:Nc\DeclareDocumentCommand{#1}{mo}{ % the actual \#1 command \IfValueTF{##2} { \semantexrenderclass { #1 } { ifoutput=true, symbol = { ##1 }, ##2 } } { \semantexrenderclass { #1 } { symbol = { ##1 } } } } \exp_args:Nc\DeclareDocumentCommand{#1withoptions}{mmo}{ \IfValueTF{##3} { \semantexrenderclass { #1 } { ifoutput=true, symbol = { ##2 }, ##1, ##3 } } { \semantexrenderclass { #1 } { symbol = { ##2 }, ##1 } } } \exp_args:Nc\DeclareDocumentCommand{new#1}{mgO{}} { % the command for creating a new object of class #1 % ##1 = command name, with backslash % ##2 = symbol % ##3 = options \IfValueTF{##2} { \semantexnewobject { #1 } ##1 { parent = #1, symbol = { ##2 }, ##3 } } { \semantexnewobject { #1 } ##1 { parent = #1, ##3 } } % create the object with name ##1 \DeclareDocumentCommand{##1}{o}{ % the actual \##1 command \IfValueTF { ####1 } { \semantexrenderobject { ##1 } { ifoutput=true,####1 } } { \semantexrenderobject { ##1 } { } } } } } %IM Consider using \semantexIfNoValueOrDotTF on the argument \DeclareDocumentCommand\newvariableclass{mO{}} % new variable-type class { % #1 = class name % #2 = options \semantexnewclass { #1 } { #2 } \exp_args:Nc\DeclareDocumentCommand{#1}{mog}{ % the actual \#1 command \IfValueTF { ##2 } { \IfValueTF { ##3 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1},##2,arg={##3} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1},##2} } } { \IfValueTF { ##3 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1},arg={##3} } } { \semantexrenderclass { #1 } { symbol={##1} } } } } \exp_args:Nc\DeclareDocumentCommand{#1withoptions}{mmog}{ \IfValueTF { ##3 } { \IfValueTF { ##4 }{ \semantexrenderclass { #1 } { ifoutput=true,symbol={##2}, ##1, ##3,arg={##4} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##2}, ##1, ##3 } } } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##2}, ##1,arg={##4} } } { \semantexrenderclass { #1 } { symbol={##2}, ##1 } } } } \exp_args:Nc\DeclareDocumentCommand{new#1}{mgO{}} { % the command for creating a new object of class #1 % ##1 = command name, with backslash % ##2 = symbol % ##3 = options \IfValueTF{##2} { \semantexnewobject { #1 } ##1 { parent = #1, symbol = { ##2 }, ##3 } } { \semantexnewobject { #1 } ##1 { parent = #1, ##3 } } % creates the object with name ##1 \DeclareDocumentCommand{##1}{og}{ % the actual \##1 command \IfValueTF{####1}{ \IfValueTF{####2} { \semantexrenderobject { ##1 } { ifoutput=true,####1, arg={####2} } } { \semantexrenderobject { ##1 } { ifoutput=true,####1} } } { \IfValueTF{####2} { \semantexrenderobject { ##1 } { ifoutput=true,arg={####2} } } { \semantexrenderobject { ##1 } {} } } } } } \DeclareDocumentCommand\newcohomologyclass{mO{}} % new cohomology-type class % The intention is to phase this out; use variable type instead, %for the sake of consistency in notation. { % #1 = class name % #2 = options \semantexnewclass { #1 } { #2 } \exp_args:Nc\DeclareDocumentCommand{#1}{mogg}{ % the actual \#1 command \IfValueTF{##2} { \IfValueTF { ##3 } { \semantexifeqTF { ##3 }{ * } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, ##2, *, arg={##4} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, ##2, * } } } { \semantexifeqTF { ##3 }{ ** } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, ##2, **, arg={##4} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, ##2, ** } } } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, ##2, degreedefault={##3}, arg={##4} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, ##2, degreedefault={##3} } } } } } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, ##2, arg={##4} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, ##2 } } } } { \IfValueTF { ##3 } { \semantexifeqTF { ##3 }{ * } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true, symbol={##1}, *, arg={##4} } } { \semantexrenderclass { #1 } { ifoutput=true, symbol={##1}, *} } } { \semantexifeqTF { ##3 }{ ** } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, **, arg={##4} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, ** } } } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, degreedefault={##3}, arg={##4} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, degreedefault={##3} } } } } } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##1}, arg={##4} } } { \semantexrenderclass { #1 } { symbol={##1}, arg={##4} } } } } } \exp_args:Nc\DeclareDocumentCommand{#1withoptions}{mmogg}{ \IfValueTF{##3} { \IfValueTF { ##4 } { \semantexifeqTF { ##4 }{ * } { \IfValueTF { ##5 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##2}, ##1, ##3, *, arg={##5} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##2}, ##1, ##3, * } } } { \semantexifeqTF { ##4 }{ ** } { \IfValueTF { ##5 } { \semantexrenderclass { #1 } {ifoutput=true, symbol={##2}, ##1, ##3, **, arg={##5} } } { \semantexrenderclass { #1 } {ifoutput=true, symbol={##2}, ##1, ##3, ** } } } { \IfValueTF { ##5 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##2}, ##1,##3, degreedefault={##4}, arg={##5} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##2}, ##1,##3, degreedefault={##4} } } } } } { \IfValueTF { ##5 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##2}, ##1, ##3, arg={##5} } } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##2}, ##1, ##3 } } } } { \IfValueTF { ##4 } { \semantexifeqTF { ##4 }{ * } { \IfValueTF { ##5 } { \semantexrenderclass { #1 } { ifoutput=true, symbol={##2} ,##1, *, arg={##5} } } { \semantexrenderclass { #1 } { ifoutput=true, symbol={##2} ,##1, *} } } { \semantexifeqTF { ##4 }{ ** } { \IfValueTF { ##5 } { \semantexrenderclass { #1 } { ifoutput=true, symbol={##2} , ##1, **, arg={##5} } } { \semantexrenderclass { #1 } { ifoutput=true, symbol={##2} , ##1, ** } } } { \IfValueTF { ##5 } { \semantexrenderclass { #1 } { ifoutput=true, symbol={##2}, ##1, degreedefault={##4}, arg={##5} } } { \semantexrenderclass { #1 } { ifoutput=true, symbol={##2}, ##1, degreedefault={##4} } } } } } { \IfValueTF { ##5 } { \semantexrenderclass { #1 } { ifoutput=true,symbol={##2}, ##1, arg={##5} } } { \semantexrenderclass { #1 } { symbol={##2}, ##1 } } } } } \exp_args:Nc\DeclareDocumentCommand{new#1}{mgO{}} { % the command for creating a new object of class #1 % ##1 = command name, with backslash % ##2 = symbol % ##3 = options \IfValueTF{##2} { \semantexnewobject { #1 } { ##1 }{ parent = #1, symbol = { ##2 }, ##3 } } { \semantexnewobject { #1 } { ##1 }{ parent = #1, ##3 } } % creates the object with name ##1 \DeclareDocumentCommand{##1}{ogg}{ % the actual \##1 command \IfValueTF{####1} { \IfValueTF{####2} { \semantexifeqTF { ####2 } { * } { \IfValueTF{####3} { \semantexrenderobject { ##1 } { ifoutput=true,####1, *, arg={ ####3 } } } { \semantexrenderobject { ##1 } { ifoutput=true,####1, * } } } { \semantexifeqTF { ####2 } { ** } { \IfValueTF{####3} { \semantexrenderobject { ##1 } { ifoutput=true, ####1, **, arg={ ####3 } } } { \semantexrenderobject { ##1 } { ifoutput=true, ####1, ** } } } { \IfValueTF{####3} { \semantexrenderobject { ##1 } { ifoutput=true,####1, degreedefault={ ####2 }, arg={ ####3 } } } { \semantexrenderobject { ##1 } { ifoutput=true,####1, degreedefault={ ####2 } } } } } } { \IfValueTF{####3} { \semantexrenderobject { ##1 } { ifoutput=true,####1, arg={ ####3 } } } { \semantexrenderobject { ##1 } { ifoutput=true,####1 } } } } { \IfValueTF{####2} { \semantexifeqTF { ####2 } { * } { \IfValueTF{####3} { \semantexrenderobject { ##1 } { ifoutput=true, *, arg={ ####3 } } } { \semantexrenderobject { ##1 } { ifoutput=true, * } } } { \semantexifeqTF { ####2 } { ** } { \IfValueTF{####3} { \semantexrenderobject { ##1 } { ifoutput=true,**, arg={ ####3 } } } { \semantexrenderobject { ##1 } { ifoutput=true,** } } } { \IfValueTF{####3} { \semantexrenderobject { ##1 } { ifoutput=true,degreedefault={ ####2 }, arg={ ####3 } } } { \semantexrenderobject { ##1 } { ifoutput=true,degreedefault={ ####2 } } } } } } { \IfValueTF{####3} { \semantexrenderobject { ##1 } { ifoutput=true, arg={ ####3 } } } { \semantexrenderobject { ##1 } { } } } } } } } %\DeclareDocumentCommand\newtupleclass{mO{}} % new tuple-type class %{ % % #1 = class name % % #2 = options % \semantexnewclass { #1 } { #2 } % \exp_args:Nc\DeclareDocumentCommand{#1}{mog}{ % % the actual \#1 command % % (maybe this does not even make sense for tuples) % \IfValueTF { ##2 } % { % \IfValueTF { ##3 } % { % \semantexrenderclass { #1 }{ ifoutput=true,symbol = { ##1 },##2, arg = { ##3 } } % } % { % \semantexrenderclass { #1 }{ ifoutput=true,symbol = { ##1 },##2 } % } % } % { % \IfValueTF { ##3 } % { % \semantexrenderclass { #1 }{ ifoutput=true,symbol = { ##1 }, arg = { ##3 } } % } % { % \semantexrenderclass { #1 }{ symbol = { ##1 } } % } % } % } % \exp_args:Nc\DeclareDocumentCommand{#1withoptions}{mmog}{ % \IfValueTF { ##3 } % { % \IfValueTF { ##4 } % { % \semantexrenderclass { #1 }{ ifoutput=true, symbol = { ##2 }, ##1, ##3, arg = { ##4 } } % } % { % \semantexrenderclass { #1 }{ ifoutput=true, symbol = { ##2 }, ##1, ##3 } % } % } % { % \IfValueTF { ##4 } % { % \semantexrenderclass { #1 }{ ifoutput=true, symbol = { ##2 }, ##1, arg = { ##4 } } % } % { % \semantexrenderclass { #1 }{ symbol = { ##2 }, ##1 } % } % } % } % \exp_args:Nc\DeclareDocumentCommand{new#1}{mmmmmO{}} % { % % the command for creating a new object of class #1 % % ##1 = command name, with backslash % % ##2 = symbol % % ##3 = options % \semantexnewobject { #1 } { ##1 } % creates the object with name ##1 % { parent = #1, leftpar = { ##2 }, argsep = { ##3 }, rightpar = { ##4 }, argdots = { ##5 }, ##6 } % \DeclareDocumentCommand{##1}{og}{ % % the actual \##1 command % \IfValueTF{####1} % { % \IfValueTF { ####2 } % { % \semantexrenderobject { ##1 } { ifoutput=true,####1, arg = { ####2 } } % } % { % \semantexrenderobject { ##1 } { ifoutput=true,####1 } % } % } % { % \IfValueTF { ####2 } % { % \semantexrenderobject { ##1 } { ifoutput=true, arg = { ####2 } } % } % { % \semantexrenderobject { ##1 } { } % } % } % } % } %} \DeclareDocumentCommand\newdelimiterclass{mO{}} % new delimiter-type class { % #1 = class name % #2 = options \semantexnewclass { #1 } { % valuekeys={ % {arg}{argwithoutkeyval={\l_semantex_key_value_temp}}, % %Currently, using no braces around \l_semantex_key_value_temp is necessary for \semantexdelimsize to work % % with par=auto % }, #2 } \exp_args:Nc\DeclareDocumentCommand{#1}{mog} % maybe this does not even make sense for delimiters { \IfValueTF { ##2 } { \IfValueTF { ##3 } { \semantexrenderclass { #1 } { ifoutput=true, symbol = { ##1 }, ##2, arg = { ##3 } } } { \semantexrenderclass { #1 } { ifoutput=true, symbol = { ##1 }, ##2 } } } { \IfValueTF { ##3 } { \semantexrenderclass { #1 } { ifoutput=true, symbol = { ##1 }, arg = { ##3 } } } { \semantexrenderclass { #1 } { symbol = { ##1 } } } } } % the actual \#1 command \exp_args:Nc\DeclareDocumentCommand{#1withoptions}{mmog} { \IfValueTF { ##3 } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true, symbol = { ##2 }, ##1, ##3, arg = { ##4 } } } { \semantexrenderclass { #1 } { ifoutput=true, symbol = { ##2 }, ##1, ##3 } } } { \IfValueTF { ##4 } { \semantexrenderclass { #1 } { ifoutput=true, symbol = { ##2 }, ##1, arg = { ##4 } } } { \semantexrenderclass { #1 } { symbol = { ##2 }, ##1 } } } } \exp_args:Nc\DeclareDocumentCommand{new#1}{mmmO{}} { % the command for creating a new object of class #1 % ##1 = command name, with backslash % ##2 = symbol % ##3 = options \semantexnewobject { #1 } { ##1 }{ parent = #1, leftpar = { ##2 }, rightpar = { ##3 }, ##4 } % creates the object with name ##1 \DeclareDocumentCommand{##1}{og}{ % the actual \##1 command \IfValueTF { ####1 } { \IfValueTF { ####2 } { \semantexrenderobject { ##1 } { ifoutput=true,####1, arg = { ####2 } } } { \semantexrenderobject { ##1 } { ifoutput=true,####1 } } } { \IfValueTF { ####2 } { \semantexrenderobject { ##1 } { ifoutput=true, arg = { ####2 } } } { \semantexrenderobject { ##1 } { } } } } } } \cs_generate_variant:Nn \tl_if_eq:nnTF { xnTF } \cs_generate_variant:Nn \tl_if_eq:nnF { xnF } \cs_generate_variant:Nn \tl_if_eq:nnT { xnT } \DeclareDocumentCommand{\semantexifblankordotTF}{mmm} { \tl_if_blank:nTF { #1 } { #2 } { \tl_if_eq:xnTF { \tl_trim_spaces:n { #1 } } { . } { #2 } { #3 } } } \DeclareDocumentCommand{\semantexifblankordotT}{mm} { \tl_if_blank:nTF { #1 } { #2 } { \tl_if_eq:xnT { \tl_trim_spaces:n { #1 } } { . } { #2 } } } \DeclareDocumentCommand{\semantexifblankordotF}{mm} { \tl_if_blank:nF { #1 } { \tl_if_eq:xnF { \tl_trim_spaces:n { #1 } } { . } { #2 } } } \cs_set_eq:NN\semantexifeqTF\tl_if_eq:nnTF \cs_set_eq:NN\semantexifeqT\tl_if_eq:nnT \cs_set_eq:NN\semantexifeqF\tl_if_eq:nnF \cs_new:Npn \g_semantex_new_class:nn#1#2{ % create a new class % #1 = name of class % #2 = standard keyval setup; the parent class by default is semantexvariable \g_semantex_new_object:nnn { semantexvariable } { #1 } { #2 } } \cs_set_eq:NN\semantexnewclass\g_semantex_new_class:nn \seq_new:N \semantex_all_objects_seq \seq_put_right:Nn \semantex_all_objects_seq { semantexvariable } \cs_new:Npn \g_semantex_new_object:nnn#1#2#3{ % create new object % #1 = class of command % #2 = name of command, without backslash % #3 = standard keyval setup \g_semantex_data_tl_provide:nn { #2 } { parent } \g_semantex_data_tl_set:nnn {#2 } { parent } { semantexvariable } \cs_set:cpn { g_semantex_data_cs_#2_valuekey:nn } ##1##2 % command controlling valuekeys { \g_semantex_valuekey:nnn { ##2 } { ##1 } { #2 } } \cs_set:cpn { g_semantex_data_cs_#2_novaluekey:n } ##1 % command controlling novaluekeys { \g_semantex_novaluekey:nn { ##1 } { #2 } } % Now a similar collection of keyval commands for the *argument* \cs_set:cpn { g_semantex_data_cs_#2_arg_valuekey:nn } ##1##2 { \g_semantex_arg_valuekey:nnn { ##2 } { ##1 }{ #2 } } \cs_set:cpn { g_semantex_data_cs_#2_arg_novaluekey:n } ##1 { \g_semantex_arg_novaluekey:nn { ##1 } { #2 } } % initially sets up the keyval interface of the object \g_semantex_keys_set:nn { #2 } { parent=#1, #3 } \seq_put_right:Nx \semantex_all_objects_seq { #2 } } \cs_generate_variant:Nn \g_semantex_new_object:nnn { nxn } \cs_set:Npn \semantexnewobject#1#2#3 { \g_semantex_new_object:nxn { #1 }{ \cs_to_str:N #2 } { #3 } } %------------------------------- % Commands for rendering: \tl_new:N\l__semantex_symbol_temp \cs_new_protected:Npn \g_semantex_render:nn#1#2 { % the main command for rendering an object % #1 = name of object % #2 = options \group_begin: \g_semantex_data_tl_inherit:nn { #1 } { symbol } \g_semantex_keys_set:nn { #1 } { #2 } \g_semantex_primitive_valuekey_parse:nn { #1 } { } % not the right place to run this? \g_semantex_data_bool_get:nnTF { #1 } { output } { \g_semantex_primitive_valuekey_innerreturn:nn { #1 }{} \g_semantex_data_bool_get:nnTF { #1 } { rightreturnbeforerender } { \g_semantex_primitive_valuekey_rightreturn:nn { #1 }{} } { % do nothing } \tl_set:Nx\l__semantex_render_symbol_temp { \g_semantex_data_tl_get:nn { #1 } { symbol } } %IM chang to "store" solution \g_semantex_data_tl_get_store:nnN { #1 } { upper_index } \l__semantex_render_upper_index_temp \g_semantex_data_tl_get_store:nnN { #1 } { lower_index } \l__semantex_render_lower_index_temp \g_semantex_data_tl_get_store:nnN { #1 } { upper_left_index } \l__semantex_render_upper_left_index_temp \g_semantex_data_tl_get_store:nnN { #1 } { lower_left_index } \l__semantex_render_lower_left_index_temp \g_semantex_data_tl_get_store:nnN { #1 } { preupper } \l__semantex_render_preupper_temp \g_semantex_data_tl_get_store:nnN { #1 } { postupper } \l__semantex_render_postupper_temp \g_semantex_data_tl_get_store:nnN { #1 } { prelower } \l__semantex_render_prelower_temp \g_semantex_data_tl_get_store:nnN { #1 } { postlower } \l__semantex_render_postlower_temp \g_semantex_data_tl_get_store:nnN { #1 } { preupperleft } \l__semantex_render_preupperleft_temp \g_semantex_data_tl_get_store:nnN { #1 } { postupperleft } \l__semantex_render_postupperleft_temp \g_semantex_data_tl_get_store:nnN { #1 } { prelowerleft } \l__semantex_render_prelowerleft_temp \g_semantex_data_tl_get_store:nnN { #1 } { postlowerleft } \l__semantex_render_postlowerleft_temp \g_semantex_data_tl_get_store:nnN { #1 } { texclass } \l__semantex_render_texclass_temp \tl_set:Nx \l__semantex_render_temp { \exp_not:c { \g_semantex_data_tl_get:nn { #1 } { output }withoptions } { upperaddleft={\exp_not:V\l__semantex_render_upper_index_temp}, loweraddleft={\exp_not:V\l__semantex_render_lower_index_temp}, upperleftaddright={\exp_not:V\l__semantex_render_upper_left_index_temp}, lowerleftaddright={\exp_not:V\l__semantex_render_lower_left_index_temp}, preupper={\exp_not:V\l__semantex_render_preupper_temp}, postupper={\exp_not:V\l__semantex_render_postupper_temp}, prelower={\exp_not:V\l__semantex_render_prelower_temp}, postlower={\exp_not:V\l__semantex_render_postlower_temp}, preupperleft={\exp_not:V\l__semantex_render_preupperleft_temp}, postupperleft={\exp_not:V\l__semantex_render_postupperleft_temp}, prelowerleft={\exp_not:V\l__semantex_render_prelowerleft_temp}, postlowerleft={\exp_not:V\l__semantex_render_postlowerleft_temp}, texclass={\l__semantex_render_texclass_temp}, \g_semantex_data_tl_get_exp_not:nn { #1 } { output_options }, } { \exp_not:V \l__semantex_render_symbol_temp } } } { \g_semantex_primitive_valuekey_return:nn { #1 }{} % \tl_set:Nx \l__semantex_render_temp { \exp_not:V \l__semantex_symbol_temp } % \tl_set:Nx\l__semantex_render_temp { \g_semantex_data_tl_get:nn { #1 } { symbol } } % this is the ordinary solution that generally just works %\tl_set:Nx\l__semantex_render_temp { \exp_not:n{\exp_not:v { semantex_data_tl_#1_symbol } }} % \g_semantex_data_tl_get_store:nnN { #1 } { symbol } \l__semantex_render_symbol_temp \tl_if_blank:xTF { \g_semantex_data_tl_get:nn { #1 } { texclass } }{ \tl_set:Nx\l__semantex_render_symbol_temp { \g_semantex_data_tl_get:nn { #1 } { symbol } } } { \tl_set:Nx\l__semantex_render_symbol_temp { \g_semantex_data_tl_get:nn { #1 } { texclass } { \g_semantex_data_tl_get:nn { #1 } { symbol } } } } \tl_set:Nx\l__semantex_render_temp { \exp_not:V \l__semantex_render_symbol_temp } } \exp_last_unbraced:NV \group_end: \l__semantex_render_temp } \cs_set_eq:NN\semantexrenderclass\g_semantex_render:nn % a front-end command \cs_set:Npn\semantexrenderobject#1#2 { \g_semantex_render:nn { \cs_to_str:N #1 } { #2 } } \cs_generate_variant:Nn\tl_if_blank:nTF { xTF } \cs_new:Npn \g_semantex_right_indices:nnnnnn#1#2#3#4#5#6 { \tl_if_blank:nF { #2 } { \sp{#1 #2 #3} } \tl_if_blank:nF { #5 } { \sb{#4 #5 #6} } % Using x here was the source of a very long % debugging; inputting underbrace in the index % caused problems } \cs_new:Npn \g_semantex_left_indices:nnnnnn#1#2#3#4#5#6 { \tl_if_blank:nTF { #2 } { \tl_if_blank:nF { #5 } { {}\sb{#4 #5 #6} } } { {} \sp{#1 #2 #3} \tl_if_blank:nF { #5 } { \sb{#4 #5 #6} } } } \tl_new:N\semantexdelimsize %So far, this is experimental: %\makeatletter %this part requires amsmath \newcommand{\semantexnormalscaling}{\bBigg@{0.8}} \newcommand{\semantexnormalscalingl}{\mathopen\semantexnormalscaling} \newcommand{\semantexnormalscalingr}{\mathclose\semantexnormalscaling} \newcommand{\semantexnormalscalingm}{\mathrel\semantexnormalscaling} %\makeatother \cs_new:Npn \g_semantex_parentheses:nnnnnn#1#2#3#4#5#6 { \tl_if_blank:nF { #5 } { \str_case:nnF { #1 } { { normal } { \group_begin: %\semantexnormalscalingl#2 #4 #5 #6 \semantexnormalscalingr#3 \mathopen#2 #4 #5 #6 \mathclose#3 \group_end: } { auto } { \group_begin: \tl_set:Nn\semantexdelimsize{\middle} %\tl_set_eq:NN\semantexdelimsize\middle \mathopen{}\mathclose\bgroup\left#2 #4 #5 #6 \aftergroup\egroup\right#3 \group_end: } { * } { \group_begin: \tl_set:Nn\semantexdelimsize{\middle} %\tl_set_eq:NN\semantexdelimsize\middle \mathopen{}\mathclose\bgroup\left#2 #4 #5 #6 \aftergroup\egroup\right#3 \group_end: } % { \big } { % \group_begin: % \tl_set_eq:NN\semantexdelimsize\big % \mathopen\big#2 #4 \mathclose\big#3 % \group_end: % } % { \Big } { % \group_begin: % \tl_set_eq:NN\semantexdelimsize\Big % \mathopen\Big#2 #4 \mathclose\Big#3 % \group_end: % } % { \bigg } { % \group_begin: % \tl_set_eq:NN\semantexdelimsize\bigg % \mathopen\bigg#2 #4 \mathclose\bigg#3 % \group_end: % } % { \Bigg } { % \group_begin: % \tl_set_eq:NN\semantexdelimsize\Bigg % \mathopen\Bigg#2 #4 \mathclose\Bigg#3 % \group_end: % } } { \group_begin: \tl_set_eq:NN\semantexdelimsize#1 %\tl_set:Nx\semantexdelimsize{\exp_not:N#1} \mathopen#1#2 #4 #5 #6 \mathclose#1#3 \group_end: } } } \cs_new:Npn \g_semantex_no_parentheses:nnn#1#2#3 { \tl_if_blank:nF { #2 } { \group_begin: \tl_clear:N\semantexdelimsize #1 #2 #3 \group_end: } } \cs_new:Npn \g_semantex_symbol_parentheses:nnnn#1#2#3#4 { \tl_if_blank:nF { #4 } { \str_case:nnF { #1 } { { normal } { \mathopen#2 #4 \mathclose#3 } { auto } { \mathopen{}\mathclose\bgroup\left#2 #4 \aftergroup\egroup\right#3 } { * } { \mathopen{}\mathclose\bgroup\left#2 #4 \aftergroup\egroup\right#3 } } { \mathopen#1#2 #4 \mathclose#1#3 } } } %-------------------------------------------- % Commands to modify and obtain data \cs_generate_variant:Nn \str_if_eq:nnTF { fnTF , onTF } %\cs_new:Npn \g_semantex_data_tl_get_proto:nnn#1#2#3 %{ % % #1 = name of object % % #2 = the data to get % % #3 = also the name of object, but being stored % % when passing to the parent, in order to make % % error messages meaningful % \tl_if_exist:cTF { semantex_data_tl_#1_#2 } % { % \use:c { semantex_data_tl_#1_#2 } % } % { % \tl_if_eq:nnTF { #1 } { semantexvariable } % { % \msg_error:nnnn { semantex } { data_tl_not_found } { #2 } { #3 } % } % { % \g_semantex_data_tl_get_proto:nnn { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } { #1 } % } % } %} % %\cs_new:Npn \g_semantex_data_tl_get:nn#1#2 %{ % \g_semantex_data_tl_get_proto:nnn { #1 } { #2 } { #1 } %} \cs_new:Npn \g_semantex_data_tl_get:nn#1#2 { % #1 = name of object % #2 = the data to get % #3 = also the name of object, but being stored % when passing to the parent, in order to make % error messages meaningful \tl_if_exist:cTF { semantex_data_tl_#1_#2 } { \use:c { semantex_data_tl_#1_#2 } } { \g_semantex_data_tl_get:nn { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } } } \cs_new:Npn \g_semantex_data_tl_get_exp_not:nn#1#2 { % #1 = name of object % #2 = the data to get \tl_if_exist:cTF { semantex_data_tl_#1_#2 } { \exp_not:v { semantex_data_tl_#1_#2 } } { \g_semantex_data_tl_get:nn { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } } } %\cs_generate_variant:Nn \g_semantex_data_tl_get:nn { cn } \cs_new:Npn \g_semantex_data_tl_get_store:nnN#1#2#3% maybe should be PROTECTED?? { % #1 = name of object % #2 = the data to get % #3 = where to store it \tl_if_exist:cTF { semantex_data_tl_#1_#2 } { \tl_set_eq:Nc #3 { semantex_data_tl_#1_#2 } } { \g_semantex_data_tl_get_store:nnN { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } #3 } } \cs_generate_variant:Nn \g_semantex_data_tl_get_store:nnN { nnc } \cs_new:Npn\g_semantex_data_tl_provide:nn#1#2 { \tl_if_exist:cF { semantex_data_tl_#1_#2 } { \tl_set:cn { semantex_data_tl_#1_#2 } {} } } \cs_new:Npn\g_semantex_data_tl_inherit:nn#1#2 { % #1 = object % #2 = piece of token list data % Takes the data #2 from the parent of #1 and saves it locally % to the object #1. After this, no more inheritance is taking place % from the parent, and the data can be changed locally on the level % of #1. \tl_if_exist:cF { semantex_data_tl_#1_#2 } { \g_semantex_data_tl_get_store:nnc { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } { semantex_data_tl_#1_#2 } } { \g_semantex_data_tl_get_store:nnc { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } { semantex_data_tl_#1_#2 } %IM could be replaced by simply { #1 } { #2 } once the check is made %IM based on "if_provided" } } \cs_new:Npn\g_semantex_data_tl_inherit_x:nn#1#2 { % The same as inherit; historically, this one did an x type % expansion first, but after changes in other places, this % no longer appeard to be necessary. I decided to keep up the % separation of the two, just in case. \tl_if_exist:cF { semantex_data_tl_#1_#2 } { \g_semantex_data_tl_get_store:nnc { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } { semantex_data_tl_#1_#2 } } { \g_semantex_data_tl_get_store:nnc { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } { semantex_data_tl_#1_#2 } %IM could be replaced by simply { #1 } { #2 } once the check is made %IM based on "if_provided" } } \cs_new:Npn \g_semantex_data_tl_set:nnn#1#2#3 { %\g_semantex_data_tl_provide:nn { #1 } { #2 } \tl_set:cn { semantex_data_tl_#1_#2 } { #3 } } \cs_generate_variant:Nn \g_semantex_data_tl_set:nnn { nnx } \cs_new:Npn \g_semantex_data_tl_put_right:nnn#1#2#3 { \g_semantex_data_tl_inherit:nn { #1 } { #2 } \tl_put_right:cn { semantex_data_tl_#1_#2 } { #3 } } \cs_generate_variant:Nn \g_semantex_data_tl_put_right:nnn { nnx } \cs_new:Npn \g_semantex_data_tl_put_left:nnn#1#2#3 { \g_semantex_data_tl_inherit:nn { #1 } { #2 } \tl_put_left:cn { semantex_data_tl_#1_#2 } { #3 } } \cs_generate_variant:Nn \g_semantex_data_tl_put_left:nnn { nnx } \cs_new:Npn \g_semantex_data_tl_clear:nn#1#2 { \g_semantex_data_tl_provide:nn { #1 } { #2 } \tl_clear:c { semantex_data_tl_#1_#2 } } \cs_new:Npn \g_semantex_data_seq_get_store:nnN#1#2#3{% maybe should be PROTECTED?? % #1 = name of object % #2 = the sequence to get % #3 = the command to store it in \bool_if_exist:cTF { semantex_data_seq_#1_#2_bool_if_provided } { \bool_if:cTF { semantex_data_seq_#1_#2_bool_if_provided } { \seq_set_eq:Nc#3 { semantex_data_seq_#1_#2 } } { \g_semantex_data_seq_get_store:vnN{ semantex_data_tl_#1_parent }{#2}#3 } } { \g_semantex_data_seq_get_store:nnN{ \g_semantex_data_tl_get:nn { #1 } { parent } }{#2}#3% } } \cs_generate_variant:Nn \g_semantex_data_seq_get_store:nnN { vnN, nnc, vnc } \cs_new:Npn\g_semantex_data_seq_provide:nn#1#2 { \bool_if_exist:cTF { semantex_data_seq_#1_#2_bool_if_provided } { \bool_if:cF { semantex_data_seq_#1_#2_bool_if_provided } { \seq_new:c { semantex_data_seq_#1_#2 } \bool_set_true:c { semantex_data_seq_#1_#2_bool_if_provided } } } { \bool_new:c { semantex_data_seq_#1_#2_bool_if_provided } \bool_set_true:c { semantex_data_seq_#1_#2_bool_if_provided } \seq_if_exist:cF { semantex_data_seq_#1_#2 } { \seq_new:c { semantex_data_seq_#1_#2 } } } } \cs_new:Npn\g_semantex_data_seq_inherit:nn#1#2 { \bool_if_exist:cTF { semantex_data_seq_#1_#2_bool_if_provided } { \bool_if:cF { semantex_data_seq_#1_#2_bool_if_provided } { \g_semantex_data_seq_get_store:vnc { semantex_data_tl_#1_parent } { #2 } { semantex_data_seq_#1_#2 } \bool_set_true:c { semantex_data_seq_#1_#2_bool_if_provided } } } { \bool_new:c { semantex_data_seq_#1_#2_bool_if_provided } \bool_set_true:c { semantex_data_seq_#1_#2_bool_if_provided } \seq_if_exist:cF { semantex_data_seq_#1_#2 } { \seq_new:c { semantex_data_seq_#1_#2 } } \g_semantex_data_seq_get_store:vnc { semantex_data_tl_#1_parent } { #2 } { semantex_data_seq_#1_#2 } } } \cs_new:Npn\g_semantex_data_seq_put_right:nnn#1#2#3 { \g_semantex_data_seq_inherit:nn { #1 } { #2 } \seq_put_right:cn { semantex_data_seq_#1_#2 } { #3 } } \cs_new:Npn \g_semantex_data_prop_provide:nn#1#2 { % #1 = name of the object % #2 = name of the prop \prop_if_exist:cF { semantex_data_prop_#1_#2 } { \prop_new:c { semantex_data_prop_#1_#2 } } } \cs_new:Npn \g_semantex_data_prop_put:nnnn#1#2#3#4 { \prop_put:cnn { semantex_data_prop_#1_#2 } { #3 } { #4 } } \cs_new:Npn \g_semantex_valuekey_get:nnNTF#1#2#3#4#5{% % #1 = name of the object % #2 = keyval data to get % #3 = command to store possible data in % #4 = if true (not to be used) % #5 = if false \prop_get:cnNTF { semantex_data_prop_#1_custom_valuekeys } { #2 }#3%\l_semantex_valuekey_get_temp { #4 } { \tl_if_eq:nnTF { #1 } { semantexvariable } { #5 } { \g_semantex_valuekey_get:xnNTF { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } #3 { #4 } { #5 } } } } \cs_generate_variant:Nn \g_semantex_valuekey_get:nnNTF { vnNTF, xnNTF } \cs_new:Npn \g_semantex_novaluekey_get:nnNTF#1#2#3#4#5{% % #1 = name of the object % #2 = singlekey data to get % #3 = command to store possible data in % #4 = if true (not to be used) % #5 = if false \prop_get:cnNTF { semantex_data_prop_#1_custom_novaluekeys } { #2 } #3 { #4 } { \tl_if_eq:nnTF { #1 } { semantexvariable } { #5 } { \g_semantex_novaluekey_get:xnNTF { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } #3 { #4 } { #5 } } } } \cs_generate_variant:Nn \g_semantex_novaluekey_get:nnNTF { vnNTF, xnNTF } %\cs_new:N\l_semantex_arg_valuekey_get_parent_temp \cs_new:Npn \g_semantex_arg_valuekey_get:nnNTF#1#2#3#4#5{% % #1 = name of the object % #2 = keyval data to get % #3 = command to store possible data in % #4 = if true (not to be used) % #5 = if false \prop_get:cnNTF { semantex_data_prop_#1_custom_arg_valuekeys } { #2 }#3%\l_semantex_valuekey_get_temp { #4 } { \tl_if_eq:nnTF { #1 } { semantexvariable } { #5 } { \g_semantex_arg_valuekey_get:xnNTF { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } #3 { #4 } { #5 } } } } \cs_generate_variant:Nn \g_semantex_arg_valuekey_get:nnNTF { vnNTF, xnNTF } \prop_new:N\l_semantex_arg_valuekey_get_temp \cs_new:Npn \g_semantex_arg_novaluekey_get:nnNTF#1#2#3#4#5{% % #1 = name of the object % #2 = singlekey data to get % #3 = command to store possible data in % #4 = if true (not to be used) % #5 = if false \prop_get:cnNTF { semantex_data_prop_#1_custom_arg_novaluekeys } { #2 } #3 { #4 } { \tl_if_eq:nnTF { #1 } { semantexvariable } { #5 } { \g_semantex_arg_novaluekey_get:xnNTF { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } #3 { #4 } { #5 } } } } \cs_generate_variant:Nn \g_semantex_arg_novaluekey_get:nnNTF { vnNTF, xnNTF } \cs_new:Npn\g_semantex_data_bool_get:nnTF#1#2#3#4 { % #1 = name of the object % #2 = boolean to get % #3 = if true % #4 = if false \bool_if_exist:cTF { semantex_data_bool_#1_if_#2_bool_if_provided } { \bool_if:cTF { semantex_data_bool_#1_if_#2_bool_if_provided } { \bool_if:cTF { semantex_data_bool_#1_if_#2 } { #3 } { #4 } } { \tl_if_eq:nnTF { #1 } { semantexvariable } { #4 } { \g_semantex_data_bool_get:xnTF { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } { #3 } { #4 } } } } { \tl_if_eq:nnTF { #1 } { semantexvariable } { #4 } { \g_semantex_data_bool_get:xnTF { \g_semantex_data_tl_get:nn { #1 } { parent } } { #2 } { #3 } { #4 } } } } \cs_generate_variant:Nn \g_semantex_data_bool_get:nnTF { xnTF, vnTF } \cs_new:Npn\g_semantex_data_bool_provide:nn#1#2 { % #1 = name of the object % #2 = boolean to provide \bool_if_exist:cTF { semantex_data_bool_#1_if_#2_bool_if_provided } { \bool_if:cF { semantex_data_bool_#1_if_#2_bool_if_provided } { \bool_set_true:c { semantex_data_bool_#1_if_#2_bool_if_provided } } } { \bool_new:c { semantex_data_bool_#1_if_#2 } \bool_new:c { semantex_data_bool_#1_if_#2_bool_if_provided } \bool_set_true:c { semantex_data_bool_#1_if_#2_bool_if_provided } } } \cs_new:Npn\g_semantex_data_bool_set_true:nn#1#2 { % #1 = name of the object % #2 = boolean to provide \g_semantex_data_bool_provide:nn { #1 } { #2 } \bool_set_true:c { semantex_data_bool_#1_if_#2 } } \cs_new:Npn\g_semantex_data_bool_set_false:nn#1#2 { % #1 = name of the object % #2 = boolean to provide \g_semantex_data_bool_provide:nn { #1 } { #2 } \bool_set_false:c { semantex_data_bool_#1_if_#2 } } \cs_new:Npn\g_semantex_data_cs_get:nnn#1#2#3 { % #1 = name of the object % #2 = command sequence to get % #3 = what to apply said command sequence to \cs_if_exist:cTF { g_semantex_data_cs_#1_#2:n } { \use:c { g_semantex_data_cs_#1_#2:n } { #3 } } { \tl_if_eq:nnTF { #1 } { semantexvariable } { % should probably throw an error by now, but later! } { \g_semantex_data_cs_get:xnn { \g_semantex_data_tl_get:nn{#1}{parent} } { #2 } { #3 } } } } \cs_generate_variant:Nn \g_semantex_data_cs_get:nnn { xnn } \cs_new:Npn \g_semantex_keys_set:nn#1#2 { % #1 = object % #2 = keys \keyval_parse:cco %IM think about wthether o-type is really necessary. { g_semantex_data_cs_#1_novaluekey:n } { g_semantex_data_cs_#1_valuekey:nn } { #2 } } \cs_new:Npn \g_semantex_arg_keys_set:nn#1#2 { % #1 = object % #2 = keys \keyval_parse:cco %IM -||- { g_semantex_data_cs_#1_arg_novaluekey:n } { g_semantex_data_cs_#1_arg_valuekey:nn } { #2 } } \cs_generate_variant:Nn \clist_map_function:nN { nc } \cs_new:Npn \g_semantex_arg_novaluekeys_set:nn#1#2 { \clist_map_function:nc {#2} { g_semantex_data_cs_#1_arg_novaluekey:n } } \DeclareDocumentCommand\setupclass{mm}{ % a user-level command for setting up the object % #1 = class % #2 = setup %\exp_args:Nx \g_semantex_keys_set:nn { #1 }{ #2 } } \DeclareDocumentCommand\setupobject{mm}{% % #1 = object % #2 = setup \g_semantex_keys_set:nn { \cs_to_str:N #1 } { #2 } } % Now for the commands that implement the keyval interface. % These commands are used by the command \g_semantex_data_cs_#1_keys_set, see % above. % There is a fixed collection of primitive commands. % Furthermore, the user has the option to create a collection % of new commands, which are all stored in the property list % called \semantex_data_prop_#1_custom_valuekeys % These valuekeys contain code that must be executable by other keys % (e.g., primitive ones) % The key value is accessible to the user via the temporary command % \l_semantex_key_value_temp \providecommand\semantexdataprovide{} \providecommand\semantexdataset{} \providecommand\semantexdatasetx{} \providecommand\semantexdataputright{} \providecommand\semantexdataputrightx{} \providecommand\semantexdataputleft{} \providecommand\semantexdataputleftx{} \providecommand\semantexdataget{} \providecommand\semantexdatagetexpnot{} \providecommand\semantexdataclear{} \providecommand\semantexsetkeys{} \providecommand\semantexsetkeysx{} \providecommand\semantexstrifeq{} \providecommand\semantexboolprovide{} \providecommand\semantexboolsettrue{} \providecommand\semantexboolsetfalse{} \providecommand\semantexboolif{} % CHANGE TO CAMEL CASE! \cs_generate_variant:Nn\str_if_eq:nnTF {xxTF,ooTF} \cs_new:Npn\g_semantex_primitive_valuekey_execute:nn#1#2 { \renewcommand\semantexdataprovide[1]{\g_semantex_data_tl_provide:nn{#1}{##1}} \renewcommand\semantexdataset[2]{\g_semantex_data_tl_set:nnn{#1}{##1}{##2}} \renewcommand\semantexdatasetx[2]{\g_semantex_data_tl_set:nnx{#1}{##1}{##2}} \renewcommand\semantexdataputright[2]{\g_semantex_data_tl_put_right:nnn{#1}{##1}{##2}} \renewcommand\semantexdataputrightx[2]{\g_semantex_data_tl_put_right:nnx{#1}{##1}{##2}} \renewcommand\semantexdataputleft[2]{\g_semantex_data_tl_put_left:nnn{#1}{##1}{##2}} \renewcommand\semantexdataputleftx[2]{\g_semantex_data_tl_put_left:nnx{#1}{##1}{##2}} \renewcommand\semantexdataget[1]{\g_semantex_data_tl_get:nn{#1}{##1}} \renewcommand\semantexdatagetexpnot[1]{\g_semantex_data_tl_get_exp_not:nn{#1}{##1}} \renewcommand\semantexdataclear[1]{\g_semantex_data_tl_clear:nn{#1}{##1}} \renewcommand\semantexsetkeys[1]{\g_semantex_keys_set:nn{#1}{##1}} \renewcommand\semantexsetkeysx[1]{\g_semantex_keys_set:nx{#1}{##1}} \renewcommand\semantexstrifeq[4]{\str_if_eq:xxTF{##1}{##2}{##3}{##4}} \renewcommand\semantexboolprovide[1]{\g_semantex_data_bool_provide:nn{#1}{##1}} \renewcommand\semantexboolsettrue[1]{\g_semantex_data_bool_set_true:nn{#1}{##1}} \renewcommand\semantexboolsetfalse[1]{\g_semantex_data_bool_set_false:nn{#1}{##1}} \renewcommand\semantexboolif[3]{\g_semantex_data_bool_get:nnTF{#1}{##1}{##2}{##3}} %\exp_not:n{#2} % how about erase and forget? #2 } \cs_new:Npn\g_semantex_primitive_valuekey_parse:nn#1#2 { \g_semantex_data_tl_inherit:nn { #1 } { parseoptions } % But we need to also reset this, plus all data variables that % it used; nope, not necessary \g_semantex_keys_set:nx { #1 } { \g_semantex_data_tl_get_exp_not:nn { #1 } { parseoptions } } } \cs_new:Npn\g_semantex_primitive_valuekey_parseoptions:nn#1#2 { \g_semantex_data_tl_put_right:nnn { #1 } { parseoptions } { #2 } } \cs_new:Npn\g_semantex_primitive_valuekey_return:nn#1#2 { \g_semantex_primitive_valuekey_innerreturn:nn { #1 }{} \g_semantex_primitive_valuekey_rightreturn:nn { #1 }{} \g_semantex_primitive_valuekey_leftreturn:nn { #1 }{} } \cs_new:Npn\g_semantex_primitive_valuekey_innerreturn:nn#1#2 { \g_semantex_data_tl_inherit:nn { #1 } { symbol } \g_semantex_data_seq_inherit:nn { #1 } { commands_sequence } \g_semantex_data_seq_get_store:nnN { #1 } { commands_sequence } \l__semantex_data_seq_commands_sequence_temp %\seq_map_inline:cn { semantex_data_seq_#1_commands_sequence } \seq_map_inline:Nn \l__semantex_data_seq_commands_sequence_temp { \g_semantex_data_tl_set:nnx { #1 } { symbol } { \exp_not:n {\exp_not:N ##1} { \g_semantex_data_tl_get_exp_not:nn { #1 } { symbol } } % This was the solution that happened to solve % the expansion issues best } } \seq_clear:c { semantex_data_seq_#1_commands_sequence } } \tl_new:N\l__semantex_rightreturn_par_temp \tl_new:N\l__semantex_rightreturn_nopar_temp \cs_generate_variant:Nn \g_semantex_keys_set:nn { nx , no } \cs_new:Npn\g_semantex_primitive_valuekey_rightreturn:nn#1#2 { \g_semantex_data_tl_inherit_x:nn { #1 } { upper_index } \g_semantex_data_tl_inherit_x:nn { #1 } { lower_index } \g_semantex_data_tl_inherit_x:nn { #1 } { preupper } \g_semantex_data_tl_inherit_x:nn { #1 } { postupper } \g_semantex_data_tl_inherit_x:nn { #1 } { prelower } \g_semantex_data_tl_inherit_x:nn { #1 } { postlower } \g_semantex_data_tl_inherit_x:nn { #1 } { arg } \g_semantex_data_tl_get_store:nnN { #1 } { upper_index } \l__semantex_rightreturn_upper_index_temp \g_semantex_data_tl_get_store:nnN { #1 } { lower_index } \l__semantex_rightreturn_lower_index_temp \g_semantex_data_tl_get_store:nnN { #1 } { symbol } \l__semantex_rightreturn_symbol_temp \g_semantex_data_tl_get_store:nnN { #1 } { preupper } \l__semantex_rightreturn_preupper_temp \g_semantex_data_tl_get_store:nnN { #1 } { postupper } \l__semantex_rightreturn_postupper_temp \g_semantex_data_tl_get_store:nnN { #1 } { prelower } \l__semantex_rightreturn_prelower_temp \g_semantex_data_tl_get_store:nnN { #1 } { postlower } \l__semantex_rightreturn_postlower_temp \g_semantex_data_tl_set:nnx { #1 } { symbol } { \exp_not:V \l__semantex_rightreturn_symbol_temp % Setup indices: \exp_not:N\g_semantex_right_indices:nnnnnn { \exp_not:V \l__semantex_rightreturn_preupper_temp } { \exp_not:V \l__semantex_rightreturn_upper_index_temp } { \exp_not:V \l__semantex_rightreturn_postupper_temp } { \exp_not:V \l__semantex_rightreturn_prelower_temp } { \exp_not:V \l__semantex_rightreturn_lower_index_temp } { \exp_not:V \l__semantex_rightreturn_postlower_temp } } \g_semantex_data_bool_get:nnTF { #1 } { par } { \g_semantex_data_tl_get_store:nnN { #1 } { par_size } \l__semantex_rightreturn_par_size_temp \g_semantex_data_tl_get_store:nnN { #1 } { par_open } \l__semantex_rightreturn_par_open_temp \g_semantex_data_tl_get_store:nnN { #1 } { par_close } \l__semantex_rightreturn_par_close_temp \g_semantex_data_tl_get_store:nnN { #1 } { arg } \l__semantex_rightreturn_arg_temp \g_semantex_data_tl_get_store:nnN { #1 } { prearg } \l_semantex_rightreturn_prearg_temp \g_semantex_data_tl_get_store:nnN { #1 } { postarg } \l_semantex_rightreturn_postarg_temp \tl_set:Nx\l__semantex_rightreturn_par_temp { { \exp_not:V \l__semantex_rightreturn_par_size_temp } { \exp_not:V \l__semantex_rightreturn_par_open_temp } { \exp_not:V \l__semantex_rightreturn_par_close_temp } { \exp_not:V \l_semantex_rightreturn_prearg_temp } { \exp_not:V \l__semantex_rightreturn_arg_temp } { \exp_not:V \l_semantex_rightreturn_postarg_temp } } \tl_put_left:Nn\l__semantex_rightreturn_par_temp { \exp_not:N \g_semantex_parentheses:nnnnnn } \g_semantex_data_tl_put_right:nnx { #1 } { symbol } { \exp_not:V\l__semantex_rightreturn_par_temp } } { \tl_set:Nx\l__semantex_rightreturn_nopar_temp { { \g_semantex_data_tl_get_exp_not:nn { #1 } { prearg } } { \g_semantex_data_tl_get_exp_not:nn { #1 } { arg } } { \g_semantex_data_tl_get_exp_not:nn { #1 } { postarg } } } \tl_put_left:Nn\l__semantex_rightreturn_nopar_temp { \exp_not:N \g_semantex_no_parentheses:nnn } \g_semantex_data_tl_put_right:nnx { #1 } { symbol } { \exp_not:V\l__semantex_rightreturn_nopar_temp } } \g_semantex_data_tl_clear:nn { #1 } { upper_index } \g_semantex_data_bool_provide:nn { #1 } { first_upper } \g_semantex_data_bool_set_true:nn { #1 } { first_upper } \g_semantex_data_tl_clear:nn { #1 } { lower_index } \g_semantex_data_bool_provide:nn { #1 } { first_lower } \g_semantex_data_bool_set_true:nn { #1 } { first_lower } \g_semantex_data_tl_clear:nn { #1 } { arg } \g_semantex_data_bool_provide:nn { #1 } { first_arg } \g_semantex_data_bool_set_true:nn { #1 } { first_arg } \g_semantex_data_tl_clear:nn { #1 } { preupper } \g_semantex_data_tl_clear:nn { #1 } { postupper } \g_semantex_data_tl_clear:nn { #1 } { prelower } \g_semantex_data_tl_clear:nn { #1 } { postlower } %IM maybe one should enclose the new symbol in another group %IM Maybe should also reset stuff like par size %IM reset leftpar, rightpar, parsize etc. also } \cs_new:Npn\g_semantex_primitive_valuekey_leftreturn:nn#1#2 { \g_semantex_data_tl_inherit_x:nn { #1 } { upper_left_index } \g_semantex_data_tl_inherit_x:nn { #1 } { lower_left_index } \g_semantex_data_tl_inherit_x:nn { #1 } { preupperleft } \g_semantex_data_tl_inherit_x:nn { #1 } { postupperleft } \g_semantex_data_tl_inherit_x:nn { #1 } { prelowerleft } \g_semantex_data_tl_inherit_x:nn { #1 } { postlowerleft } %IMPLEMENT THIS!!! % Clean up the following names \g_semantex_data_tl_get_store:nnN { #1 } { upper_left_index } \l__semantex_leftreturn_upper_left_index_temp \g_semantex_data_tl_get_store:nnN { #1 } { lower_left_index } \l__semantex_leftreturn_lower_left_index_temp \g_semantex_data_tl_get_store:nnN { #1 } { symbol } \l__semantex_leftreturn_symbol_temp \g_semantex_data_tl_get_store:nnN { #1 } { preupperleft } \l__semantex_leftreturn_preupperleft_temp \g_semantex_data_tl_get_store:nnN { #1 } { postupperleft } \l__semantex_leftreturn_postupperleft_temp \g_semantex_data_tl_get_store:nnN { #1 } { prelowerleft } \l__semantex_leftreturn_prelowerleft_temp \g_semantex_data_tl_get_store:nnN { #1 } { postlowerleft } \l__semantex_leftreturn_postlowerleft_temp \g_semantex_data_tl_set:nnx { #1 } { symbol } { % Setup indices: \exp_not:N\g_semantex_left_indices:nnnnnn { \exp_not:V \l__semantex_leftreturn_preupperleft_temp } { \exp_not:V \l__semantex_leftreturn_upper_left_index_temp } { \exp_not:V \l__semantex_leftreturn_postupperleft_temp } { \exp_not:V \l__semantex_leftreturn_prelowerleft_temp } { \exp_not:V \l__semantex_leftreturn_lower_left_index_temp } { \exp_not:V \l__semantex_leftreturn_postlowerleft_temp } \exp_not:V \l__semantex_leftreturn_symbol_temp } \g_semantex_data_tl_clear:nn { #1 } { upper_left_index } \g_semantex_data_bool_provide:nn { #1 } { first_upper_left } \g_semantex_data_bool_set_true:nn { #1 } { first_upper_left } \g_semantex_data_tl_clear:nn { #1 } { lower_left_index } \g_semantex_data_bool_provide:nn { #1 } { first_lower_left } \g_semantex_data_bool_set_true:nn { #1 } { first_lower_left } \g_semantex_data_tl_clear:nn { #1 } { preupperleft } \g_semantex_data_tl_clear:nn { #1 } { postupperleft } \g_semantex_data_tl_clear:nn { #1 } { prelowerleft } \g_semantex_data_tl_clear:nn { #1 } { postlowerleft } } \cs_new:Npn\g_semantex_primitive_valuekey_parent:nn#1#2{ % Must inherit everything from the parent class %\tl_clear_new:c { semantex_data_tl_#1_parent } %\g_semantex_data_tl_provide:nn { #1 } { parent } %IM This should always be declared, so no need for if_provided checks %IM This does not work, for unknown reasons: % \seq_if_in:NxTF \semantex_all_objects_seq { #2 } % { \tl_set:cn { semantex_data_tl_#1_parent } { #2 } } % { \msg_error:nnnn { semantex } { parent_not_found } { #2 } { #1 } } %IM control if exists! %\tl_set:cn { semantex_data_tl_#1_parent } { #2 } \g_semantex_data_tl_set:nnn { #1 } { parent } { #2 } } \cs_set_eq:NN\g_semantex_primitive_valuekey_class:nn\g_semantex_primitive_valuekey_parent:nn \cs_new:Npn\g_semantex_primitive_valuekey_copy:nn#1#2{ % Must inherit everything from the parent class \g_semantex_primitive_valuekey_parent:nn{#1}{ \cs_to_str:N #2 } } \cs_new:Npn\g_semantex_primitive_valuekey_valuekeys:nn#1#2{ % Add new valuekeys via the interface % valuekeys={ % {key1}{do something with \l_semantex_key_value_temp}, % {key2}{g=\l_semantex_key_value_temp,i=\l_semantex_key_value_temp}, % } \g_semantex_data_prop_provide:nn { #1 } { custom_valuekeys } \clist_map_inline:nn { #2 }{ \g_semantex_valuekey_equality_format:nnn{#1}##1 } } \cs_generate_variant:Nn\g_semantex_data_prop_put:nnnn {nnno} \cs_new:Npn \g_semantex_valuekey_equality_format:nnn#1#2#3 { \cs_set:Npn\l__semantex_valuekey_equality_format_temp:n##1{#3} \g_semantex_data_prop_put:nnno {#1} {custom_valuekeys} {#2} {\l__semantex_valuekey_equality_format_temp:n{\l_semantex_key_value_temp}} %IM Remove spaces in #2 } \cs_new:Npn\g_semantex_primitive_valuekey_novaluekeys:nn#1#2{ % Add sinple keys, taking no values, via the % interface % novaluekeys={ % {key1}{print something}, % {key2}{d=42,i=42}, % } \g_semantex_data_prop_provide:nn { #1 } { custom_novaluekeys } \clist_map_inline:nn { #2 }{ \g_semantex_valuekey_noequality_format:nnn{#1}##1 } } \cs_new:Npn \g_semantex_valuekey_noequality_format:nnn#1#2#3{ %\prop_put:cnn { semantex_data_prop_#1_custom_novaluekeys }{#2}{#3} \g_semantex_data_prop_put:nnnn {#1} {custom_novaluekeys} {#2} {#3} } \cs_new:Npn\g_semantex_primitive_valuekey_argvaluekeys:nn#1#2{ % Add new valuekeys via the interface % valuekeys={ % {key1}{do something with \l_semantex_key_value_temp}, % {key2}{g=\l_semantex_key_value_temp,i=\l_semantex_key_value_temp}, % } \g_semantex_data_prop_provide:nn { #1 } { custom_arg_valuekeys } \clist_map_inline:nn { #2 }{ \g_semantex_arg_valuekey_equality_format:nnn{#1}##1 } } \cs_new:Npn \g_semantex_arg_valuekey_equality_format:nnn#1#2#3{ %\prop_put:cnn { semantex_data_prop_#1_custom_arg_valuekeys }{#2}{#3} \cs_set:Npn\l__semantex_arg_valuekey_equality_format_temp:n##1{#3} \g_semantex_data_prop_put:nnno {#1} {custom_arg_valuekeys} {#2} {\l__semantex_arg_valuekey_equality_format_temp:n{\l_semantex_arg_key_value_temp}} } \cs_new:Npn\g_semantex_primitive_valuekey_argnovaluekeys:nn#1#2{ % Add sinple keys, taking no values, via the % interface % novaluekeys={ % {key1}{print something}, % {key2}{g=42,i=42}, % } \g_semantex_data_prop_provide:nn { #1 } { custom_arg_novaluekeys } \clist_map_inline:nn { #2 }{ \g_semantex_arg_valuekey_noequality_format:nnn{#1}##1 } } \cs_new:Npn \g_semantex_arg_valuekey_noequality_format:nnn#1#2#3{ \g_semantex_data_prop_put:nnnn {#1} {custom_arg_novaluekeys} {#2} {#3} } \cs_new:Npn\g_semantex_primitive_valuekey_symbol:nn#1#2{ % Sets the value of the symbol \g_semantex_data_tl_set:nnn { #1 } { symbol } { \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_texclass:nn#1#2{ % Sets the value of the symbol \g_semantex_data_tl_set:nnn { #1 } { texclass } { \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_slot:nn#1#2{ % Sets the value of the symbol \g_semantex_data_tl_set:nnn { #1 } { slot } { \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_symbolputright:nn#1#2{ \g_semantex_data_tl_put_right:nnn { #1 } { symbol } { \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_symbolputleft:nn#1#2{ \g_semantex_data_tl_put_left:nnn { #1 } { symbol } { \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_command:nn#1#2{ % Adds one entry on the left of the command % sequence to be applied to the symbol \g_semantex_data_seq_put_right:nnn { #1 } { commands_sequence } { #2 } %IM maybe \exp_not:n { #2 }? } \cs_new:Npn\g_semantex_primitive_valuekey_argwithkeyval:nn#1#2{ % Sets the argument (printed in parentheses % after the symbol) \g_semantex_arg_keys_set:nn { #1 } {{{ #2 }}} %IM for unknown reasons, one needs these extra braces. %IM This should be moved to the arg valuekeys themselves %IM where ifoutput=true is also declared } \cs_new:Npn\g_semantex_primitive_valuekey_argwithnovaluekeys:nn#1#2{ % Sets the argument (printed in parentheses % after the symbol) \g_semantex_arg_novaluekeys_set:nn { #1 } { #2 } } \cs_new:Npn\g_semantex_primitive_valuekey_argwithonenovaluekey:nn#1#2{ % Sets the argument (printed in parentheses % after the symbol) \use:c { g_semantex_data_cs_#1_arg_novaluekey:n } {{{{ #2 }}}} } \cs_new:Npn\g_semantex_primitive_valuekey_argwithoutkeyval:nn#1#2{ \g_semantex_data_tl_put_right:nnn { #1 } { arg } { \exp_not:n { #2 } } \g_semantex_primitive_valuekey_ifrightreturnbeforerender:nn{#1}{true} } %\cs_new:Npn\g_semantex_primitive_valuekey_useargwithkeyval:nn#1#2 %{ %% \g_semantex_primitive_valuekey_valuekeys:nn { #1 } %% { %% {arg} { argwithkeyval={ \l_semantex_key_value_temp } }, %% } % \g_semantex_keys_set:nn { #1 }{ % \exp_not:n{valuekeys={ % {arg}{ argwithkeyval={\l_semantex_key_value_temp} }, % },} % } %} \cs_new:Npn\g_semantex_primitive_valuekey_argsep:nn#1#2 { %\g_semantex_data_tl_provide:nn { #1 } { argsep } \g_semantex_data_tl_set:nnn { #1 } { argsep } { \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_argdots:nn#1#2 { % \g_semantex_data_tl_provide:nn { #1 } { argdots } \g_semantex_data_tl_set:nnn { #1 } { argdots } { \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_prearg:nn#1#2{ \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_left:nnn { #1 } { prearg } { \exp_not:n { #2 } } } } \cs_new:Npn\g_semantex_primitive_valuekey_postarg:nn#1#2{ \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_right:nnn { #1 } { postarg } { \exp_not:n{ #2 } } } } \cs_new:Npn\g_semantex_primitive_valuekey_output:nn#1#2 { \g_semantex_data_tl_set:nnn { #1 } { output } { #2 } % Maybe allow output=self } \cs_new:Npn\g_semantex_primitive_valuekey_outputoptions:nn#1#2{ \g_semantex_data_tl_put_right:nnn { #1 } { output_options } { #2, } } \cs_new:Npn\g_semantex_primitive_valuekey_ifrightreturnbeforerender:nn#1#2{ % tells whether to use the output class or not \str_if_eq:nnTF { #2 } { true } { \g_semantex_data_bool_set_true:nn { #1 } { rightreturnbeforerender } } { \str_if_eq:nnTF { #2 } { false } { \g_semantex_data_bool_set_false:nn { #1 } { rightreturnbeforerender } } { %IM do nothing right now, but should %IM probably throw an error } } } \cs_new:Npn\g_semantex_primitive_valuekey_ifoutput:nn#1#2{ %IMPLEMENT THIS % tells whether to output or not \str_if_eq:nnTF { #2 } { true } { \g_semantex_data_bool_set_true:nn { #1 } { output } } { \str_if_eq:nnTF { #2 } { false } { \g_semantex_data_bool_set_false:nn { #1 } { output } } { %IM do nothing right now, but should %IM probably throw an error } } } \cs_new:Npn\g_semantex_primitive_valuekey_gradingpos:nn#1#2{ % tells whether to use upper or lower indices \g_semantex_data_bool_provide:nn { #1 } { upper_grading } \str_case:nnTF { #2 } { { upper } { \g_semantex_data_bool_set_true:nn { #1 } { upper_grading } } { lower } { \g_semantex_data_bool_set_false:nn { #1 } { upper_grading } } } { % do nohting } { % do nothing at the moment, but should probably throw an error } } \cs_set_eq:NN \g_semantex_primitive_valuekey_gradingposition:nn \g_semantex_primitive_valuekey_gradingpos:nn % Upper and lower right indices: \cs_new:Npn\g_semantex_primitive_valuekey_upper:nn#1#2{ % adds to the upper index \tl_if_blank:nF{#2}{ \g_semantex_data_tl_put_right:nnn { #1 } { upper_index } { \exp_not:n{ #2 } } % For a long time, when using x type expansions when checking % if indices were empty, two \exp_not:n's were necessary here. % Thankfully, I can now happily remove them again, it seems. %\g_semantex_data_bool_provide:nn { #1 } { first_upper } \g_semantex_data_bool_set_false:nn { #1 } { first_upper } } } \cs_new:Npn\g_semantex_primitive_valuekey_supper:nn#1#2{ % adds to the upper index, with a separator \tl_if_blank:nF{#2} { \g_semantex_data_bool_get:nnTF { #1 } { first_upper } { \g_semantex_data_tl_put_right:nnn { #1 } { upper_index } { \exp_not:n { #2 } } } { \g_semantex_data_tl_put_right:nnx { #1 } { upper_index } { \exp_not:n { \g_semantex_data_tl_get:nn { #1 } { uppersep } } } \g_semantex_data_tl_put_right:nnn { #1 } { upper_index } { \exp_not:n { #2 } } } \g_semantex_data_bool_set_false:nn { #1 } { first_upper } } } \cs_new:Npn\g_semantex_primitive_valuekey_upperaddleft:nn#1#2{ % adds to the upper index \tl_if_blank:nF{#2}{ \g_semantex_data_tl_put_left:nnn { #1 } { upper_index } { \exp_not:n{ #2 } } \g_semantex_data_bool_set_false:nn { #1 } { first_upper } } } \cs_new:Npn\g_semantex_primitive_valuekey_preupper:nn#1#2{ \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_left:cn { #1 } { preupper } { \exp_not:n{ #2 } } } } \cs_new:Npn\g_semantex_primitive_valuekey_postupper:nn#1#2{ \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_right:nnn { #1 } { postupper } { \exp_not:n{ #2 } } } } \cs_new:Npn\g_semantex_primitive_valuekey_lower:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_right:nnn { #1 } { lower_index } { \exp_not:n { #2 } } \g_semantex_data_bool_set_false:nn { #1 } { first_lower } } } \cs_new:Npn\g_semantex_primitive_valuekey_slower:nn#1#2{ % adds to the lower index, with a separator \tl_if_blank:nF{#2} { \g_semantex_data_bool_get:nnTF { #1 } { first_lower } { \g_semantex_data_tl_put_right:nnn { #1 } { lower_index } { \exp_not:n { #2 } } } { \g_semantex_data_tl_put_right:nnx { #1 } { lower_index } { \exp_not:n { \g_semantex_data_tl_get:nn { #1 } { lowersep } } } \g_semantex_data_tl_put_right:nnn { #1 } { lower_index } { \exp_not:n { #2 } } } \g_semantex_data_bool_set_false:nn { #1 } { first_lower } } } \cs_new:Npn\g_semantex_primitive_valuekey_loweraddleft:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_left:nnn { #1 } { lower_index } { \exp_not:n { #2 } } \g_semantex_data_bool_set_false:nn { #1 } { first_lower } } } \cs_new:Npn\g_semantex_primitive_valuekey_prelower:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_left:nnn { #1 } { prelower } { \exp_not:n { #2 } } } } \cs_new:Npn\g_semantex_primitive_valuekey_postlower:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_right:nnn { #1 } { postlower } { \exp_not:n{ #2 } } } } \cs_generate_variant:Nn \tl_if_blank:nTF { vTF } \cs_new:Npn \g_semantex_primitive_upper_lower_auxiliary_first_arg:nn#1#2 { #1 } \cs_new:Npn \g_semantex_primitive_upper_lower_auxiliary_second_arg:nn#1#2 { #2 } \cs_new:Npn\g_semantex_primitive_valuekey_uppersep:nn#1#2{ % uppersep={separator}{contents} adds contents to the upper index % with the appropriate index separator \g_semantex_data_bool_inherit:nn { #1 } { first_upper } \g_semantex_data_bool_get:nnTF { #1 } { first_upper } { \g_semantex_data_tl_put_right:nnn { #1 } { upper_index } { \exp_not:n { \g_semantex_primitive_upper_lower_auxiliary_second_arg:nn #2 } } } { \g_semantex_data_tl_put_right:nnn { #1 } { upper_index } { \exp_not:n { \g_semantex_primitive_upper_lower_auxiliary_first_arg:nn #2 \g_semantex_primitive_upper_lower_auxiliary_second_arg:nn #2 } } } \g_semantex_data_bool_set_false:nn { #1 } { first_upper } } \cs_new:Npn\g_semantex_primitive_valuekey_lowersep:nn#1#2{ % lowersep={separator}{contents} adds contents to the lower index % with the appropriate index separator \g_semantex_data_bool_get:nnTF { #1 } { first_lower } { \g_semantex_data_tl_put_right:nnn { #1 } { lower_index } { \exp_not:n { \g_semantex_primitive_upper_lower_auxiliary_second_arg:nn #2 } } } { \g_semantex_data_tl_put_right:nnn { #1 } { lower_index } { \exp_not:n { \g_semantex_primitive_upper_lower_auxiliary_first_arg:nn #2 \g_semantex_primitive_upper_lower_auxiliary_second_arg:nn #2 } } } \g_semantex_data_bool_set_false:nn { #1 } { first_lower } } \cs_new:Npn\g_semantex_primitive_valuekey_cupper:nn#1#2{ % adds to the upper index, with a comma as separator \tl_if_blank:nF{#2} { \g_semantex_data_bool_get:nnTF { #1 } { first_upper } { \g_semantex_data_tl_put_right:nnn { #1 } { upper_index } { \exp_not:n { #2 } } } { \g_semantex_data_tl_put_right:nnn { #1 } { upper_index } { , \exp_not:n { #2 } } } \g_semantex_data_bool_set_false:nn { #1 } { first_upper } } } \cs_new:Npn\g_semantex_primitive_valuekey_clower:nn#1#2{ % adds to the lower index, with a comma as separator \tl_if_blank:nF{#2} { \g_semantex_data_bool_get:nnTF { #1 } { first_lower } { \g_semantex_data_tl_put_right:nnn { #1 } { lower_index } { \exp_not:n { #2 } } } { \g_semantex_data_tl_put_right:nnn { #1 } { lower_index } { , \exp_not:n { #2 } } } \g_semantex_data_bool_set_false:nn { #1 } { first_lower } } } \cs_new:Npn\g_semantex_primitive_valuekey_iffirstupper:nn#1#2 { \tl_if_eq:nnTF { #2 } { true } { \g_semantex_data_bool_set_true:nn { #1 } { first_upper } } { \tl_if_eq:nnTF { #2 } { false } { \g_semantex_data_bool_set_false:nn { #1 } { first_upper } } { %IM Throw error later } } } \cs_new:Npn\g_semantex_primitive_valuekey_iffirstlower:nn#1#2 { \tl_if_eq:nnTF { #2 } { true } { \g_semantex_data_bool_set_true:nn { #1 } { first_lower } } { \tl_if_eq:nnTF { #2 } { false } { \g_semantex_data_bool_set_false:nn { #1 } { first_lower } } { %IM Throw error later } } } \cs_new:Npn\g_semantex_primitive_valuekey_setuppersep:nn#1#2 { \g_semantex_data_tl_set:nnn { #1 } { uppersep } { \exp_not:n { #2 }} } \cs_new:Npn\g_semantex_primitive_valuekey_setlowersep:nn#1#2 { \g_semantex_data_tl_set:nnn { #1 } { lowersep } { \exp_not:n { #2 }} } %--------------- Left indices: \cs_new:Npn\g_semantex_primitive_valuekey_upperleft:nn#1#2{ % adds to the upper left index \tl_if_blank:nF{#2}{ \g_semantex_data_tl_put_left:nnn { #1 } { upper_left_index } { \exp_not:n{ #2 } } \g_semantex_data_bool_set_false:nn { #1 } { first_upper_left } } } \cs_new:Npn\g_semantex_primitive_valuekey_supperleft:nn#1#2{ \tl_if_blank:nF{#2} { \g_semantex_data_bool_get:nnTF { #1 } { first_upper_left } { \g_semantex_data_tl_put_left:nnn { #1 } { upper_left_index } { \exp_not:n { #2 } } } { \g_semantex_data_tl_put_left:nnn { #1 } { upper_left_index } { \exp_not:n { #2 } } \g_semantex_data_tl_put_left:nnx { #1 } { upper_left_index } { \exp_not:n { \g_semantex_data_tl_get:nn { #1 } { uppersep } } } } \g_semantex_data_bool_set_false:nn { #1 } { first_upper_left } } } \cs_new:Npn\g_semantex_primitive_valuekey_upperleftaddright:nn#1#2{ % adds to the upper index \tl_if_blank:nF{#2}{ \g_semantex_data_tl_put_right:nnn { #1 } { upper_left_index } { \exp_not:n{ #2 } } \g_semantex_data_bool_set_false:nn { #1 } { first_upper_left } } } \cs_new:Npn\g_semantex_primitive_valuekey_preupperleft:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_left:nnn { #1 } { preupperleft } { \exp_not:n{ #2 } } } } \cs_new:Npn\g_semantex_primitive_valuekey_postupperleft:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_right:nnn { #1 } { postupperleft } { \exp_not:n{ #2 } } } } \cs_new:Npn\g_semantex_primitive_valuekey_lowerleft:nn#1#2{ % adds to the lower left index \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_left:nnn { #1 } { lower_left_index } { \exp_not:n{ #2 } } \g_semantex_data_bool_set_false:nn { #1 } { first_lower_left } } } \cs_new:Npn\g_semantex_primitive_valuekey_slowerleft:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} { \g_semantex_data_bool_get:nnTF { #1 } { first_lower_left } { \g_semantex_data_tl_put_left:nnn { #1 } { lower_left_index } { \exp_not:n { #2 } } } { \g_semantex_data_tl_put_left:nnn { #1 } { lower_left_index } { \exp_not:n { #2 } } \g_semantex_data_tl_put_left:nnx { #1 } { lower_left_index } { \exp_not:n { \g_semantex_data_tl_get:nn { #1 } { lowerleftsep } } } } \g_semantex_data_bool_set_false:nn { #1 } { first_lower_left } } } \cs_new:Npn\g_semantex_primitive_valuekey_lowerleftaddright:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} %This test really shouldn’t be made. { \g_semantex_data_tl_put_right:nnn { #1 } { lower_left_index } { \exp_not:n{ #2 } } \g_semantex_data_bool_set_false:nn { #1 } { first_lower_left } } } \cs_new:Npn\g_semantex_primitive_valuekey_prelowerleft:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_left:nnn { #1 } { prelowerleft } { \exp_not:n{ #2 } } } } \cs_new:Npn\g_semantex_primitive_valuekey_postlowerleft:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} { \g_semantex_data_tl_put_right:nnn { #1 } { postlowerleft } { \exp_not:n{ #2 } } } } \cs_new:Npn\g_semantex_primitive_valuekey_upperleftsep:nn#1#2{ % adds to the upper index \g_semantex_data_bool_get:nnTF { #1 } { first_left_upper } { \g_semantex_data_tl_put_left:nnn { #1 } { upper_left_index } { \exp_not:n { \g_semantex_primitive_upper_lower_auxiliary_second_arg:nn #2 } } } { \g_semantex_data_tl_put_left:nnn { #1 } { upper_left_index } { \exp_not:n { \g_semantex_primitive_upper_lower_auxiliary_second_arg:nn #2 \g_semantex_primitive_upper_lower_auxiliary_first_arg:nn #2 } } } \g_semantex_data_bool_set_false:nn { #1 } { first_left_upper } } \cs_new:Npn\g_semantex_primitive_valuekey_lowerleftsep:nn#1#2{ % adds to the lower index \g_semantex_data_bool_get:nnTF { #1 } { first_lower_left } { \g_semantex_data_tl_put_left:nnn { #1 } { lower_left_index } { \exp_not:n { \g_semantex_primitive_upper_lower_auxiliary_second_arg:nn #2 } } } { \g_semantex_data_tl_put_left:nnn { #1 } { lower_left_index } { \exp_not:n { \g_semantex_primitive_upper_lower_auxiliary_second_arg:nn #2 \g_semantex_primitive_upper_lower_auxiliary_first_arg:nn #2 } } } \g_semantex_data_bool_set_false:nn { #1 } { first_lower_left } } \cs_new:Npn\g_semantex_primitive_valuekey_cupperleft:nn#1#2{ % adds to the upper index \tl_if_blank:nF{#2} { \g_semantex_data_bool_get:nnTF { #1 } { first_upper_left } { \g_semantex_data_tl_put_left:nnn { #1 } { upper_left_index } { \exp_not:n { #2 } } } { \g_semantex_data_tl_put_left:nnn { #1 } { upper_left_index } { \exp_not:n { #2 } , } } \g_semantex_data_bool_set_false:nn { #1 } { first_upper_left } } } \cs_new:Npn\g_semantex_primitive_valuekey_clowerleft:nn#1#2{ % adds to the lower index \tl_if_blank:nF{#2} { \g_semantex_data_bool_get:nnTF { #1 } { first_lower_left } { \g_semantex_data_tl_put_left:nnn { #1 } { lower_left_index } { \exp_not:n { #2 } } } { \g_semantex_data_tl_put_left:nnn { #1 } { lower_left_index } { \exp_not:n { #2 } , } } \g_semantex_data_bool_set_false:nn { #1 } { first_lower_left } } } \cs_new:Npn\g_semantex_primitive_valuekey_iffirstupperleft:nn#1#2 { \tl_if_eq:nnTF { #2 } { true } { \g_semantex_data_bool_set_true:nn { #1 } { first_upper_left } } { \tl_if_eq:nnTF { #2 } { false } { \g_semantex_data_bool_set_false:nn { #1 } { first_upper_left } } { %IM Throw error later } } } \cs_new:Npn\g_semantex_primitive_valuekey_iffirstlowerleft:nn#1#2 { \tl_if_eq:nnTF { #2 } { true } { \g_semantex_data_bool_set_true:nn { #1 } { first_lower_left } } { \tl_if_eq:nnTF { #2 } { false } { \g_semantex_data_bool_set_false:nn { #1 } { first_lower_left } } { %IM Throw error later } } } \cs_new:Npn\g_semantex_primitive_valuekey_setupperleftsep:nn#1#2 { \g_semantex_data_tl_set:nnn { #1 } { upperleftsep } { \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_setlowerleftsep:nn#1#2 { \g_semantex_data_tl_set:nnn { #1 } { lowerleftsep } { \exp_not:n { #2 } } } %--------------- % Contrary to what you might think, the following commands ARE % sometimes needed. \cs_new:Npn\g_semantex_primitive_valuekey_iffirstd:nn#1#2 { \g_semantex_data_bool_get:nnTF { #1 } { upper_grading } { \g_semantex_primitive_valuekey_iffirstupper:nn { #1 } { #2 } } { \g_semantex_primitive_valuekey_iffirstlower:nn { #1 } { #2 } } } \cs_set_eq:NN\g_semantex_primitive_valuekey_iffirstdeg:nn\g_semantex_primitive_valuekey_iffirstd:nn \cs_set_eq:NN\g_semantex_primitive_valuekey_iffirstdegree:nn\g_semantex_primitive_valuekey_iffirstd:nn \cs_new:Npn\g_semantex_primitive_valuekey_iffirsti:nn#1#2 { \g_semantex_data_bool_get:nnTF { #1 } { upper_grading } { \g_semantex_primitive_valuekey_iffirstlower:nn { #1 } { #2 } } { \g_semantex_primitive_valuekey_iffirstupper:nn { #1 } { #2 } } } \cs_set_eq:NN\g_semantex_primitive_valuekey_iffirstindex:nn\g_semantex_primitive_valuekey_iffirsti:nn \cs_new:Npn\g_semantex_primitive_valuekey_d:nn#1#2 { % adds to the d-index (upper by default) % I added an \exp_not:n here and in similar commands to % take care of \underbrace expansion issues. However, % I am puzzled as to why it was necessary. %\bool_if:cTF { semantex_data_bool_#1_if_upper_grading } \g_semantex_data_bool_get:nnTF { #1 } { upper_grading } { \g_semantex_primitive_valuekey_upper:nn { #1 } { #2 } } { \g_semantex_primitive_valuekey_lower:nn { #1 } { #2 } } } \cs_set_eq:NN\g_semantex_primitive_valuekey_deg:nn\g_semantex_primitive_valuekey_d:nn \cs_set_eq:NN\g_semantex_primitive_valuekey_degree:nn\g_semantex_primitive_valuekey_d:nn \cs_new:Npn\g_semantex_primitive_valuekey_sd:nn#1#2 { % adds to the d-index (upper by default) \g_semantex_data_bool_get:nnTF { #1 } { upper_grading } { \g_semantex_primitive_valuekey_supper:nn { #1 } { #2 } } { \g_semantex_primitive_valuekey_slower:nn { #1 } { #2 } } } \cs_set_eq:NN\g_semantex_primitive_valuekey_sdeg:nn\g_semantex_primitive_valuekey_sd:nn \cs_set_eq:NN\g_semantex_primitive_valuekey_sdegree:nn\g_semantex_primitive_valuekey_sd:nn \cs_new:Npn\g_semantex_primitive_valuekey_cd:nn#1#2{ %IM Maybe remove this. % adds to the d-index (upper by default) \g_semantex_data_bool_get:nnTF { #1 } { upper_grading } { \g_semantex_primitive_valuekey_cupper:nn { #1 } { #2 } } { \g_semantex_primitive_valuekey_clower:nn { #1 } { #2 } } } \cs_set_eq:NN\g_semantex_primitive_valuekey_cdeg:nn\g_semantex_primitive_valuekey_cd:nn \cs_set_eq:NN\g_semantex_primitive_valuekey_cdegree:nn\g_semantex_primitive_valuekey_cd:nn \cs_new:Npn\g_semantex_primitive_valuekey_i:nn#1#2{ % adds to the i-index (lower by default) %\bool_if:cTF { semantex_data_bool_#1_if_upper_grading } \g_semantex_data_bool_get:nnTF { #1 } { upper_grading } { \g_semantex_primitive_valuekey_lower:nn { #1 } { #2 } } { \g_semantex_primitive_valuekey_upper:nn { #1 } { #2 } } } \cs_set_eq:NN\g_semantex_primitive_valuekey_index:nn\g_semantex_primitive_valuekey_i:nn \cs_new:Npn\g_semantex_primitive_valuekey_si:nn#1#2{ % adds to the i-index (lower by default) \g_semantex_data_bool_get:nnTF { #1 } { upper_grading } { \g_semantex_primitive_valuekey_slower:nn { #1 } { #2 } } { \g_semantex_primitive_valuekey_supper:nn { #1 } { #2 } } } \cs_set_eq:NN\g_semantex_primitive_valuekey_sindex:nn\g_semantex_primitive_valuekey_si:nn \cs_new:Npn\g_semantex_primitive_valuekey_ci:nn#1#2{ % adds to the i-index (lower by default) %\bool_if:cTF { semantex_data_bool_#1_if_upper_grading } \g_semantex_data_bool_get:nnTF { #1 } { upper_grading } { \g_semantex_primitive_valuekey_clower:nn { #1 } { #2 } } { \g_semantex_primitive_valuekey_cupper:nn { #1 } { #2 } } } \cs_set_eq:NN\g_semantex_primitive_valuekey_cindex:nn\g_semantex_primitive_valuekey_ci:nn \cs_new:Npn\g_semantex_primitive_valuekey_par:nn#1#2{ % sets the size of the parentheses \g_semantex_data_tl_set:nnn { #1 } { par_size }{ \exp_not:n { #2 } } \g_semantex_primitive_valuekey_ifpar:nn { #1 } { true } } \cs_new:Npn\g_semantex_primitive_valuekey_parsize:nn#1#2{ % sets the size of the parentheses \g_semantex_data_tl_set:nnn { #1 } { par_size }{ \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_leftpar:nn#1#2{ % \g_semantex_data_tl_set:nnn { #1 } { par_open }{ \exp_not:n { #2 } } \tl_set:cn { semantex_data_tl_#1_par_open }{ \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_rightpar:nn#1#2{ \g_semantex_data_tl_set:nnn { #1 } { par_close }{ \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_ifpar:nn#1#2{ %IMPLEMENT THIS % tells whether to use the output class or not \g_semantex_data_bool_provide:nn { #1 } { par } \str_if_eq:nnTF { #2 } { true } { \g_semantex_data_bool_set_true:nn { #1 } { par } } { \str_if_eq:nnTF { #2 } { false } { \g_semantex_data_bool_set_false:nn { #1 } { par } } { %IM do nothing right now, but should %IM probably throw an error } } } \cs_new:Npn\g_semantex_primitive_valuekey_spar:nn#1#2 { \tl_if_blank:nTF { #2 } { \g_semantex_primitive_valuekey_return:nn { #1 }{} \g_semantex_data_tl_set:nnx { #1 } { symbol } { { \g_semantex_data_tl_get_exp_not:nn { #1 } { spar_size } } %IM like in _return { \g_semantex_data_tl_get:nn { #1 } { spar_open } } { \g_semantex_data_tl_get:nn { #1 } { spar_close } } { \g_semantex_data_tl_get_exp_not:nn { #1 } { symbol } } % { \l__semantex_spar_symbol_temp } } \g_semantex_data_tl_put_left:nnn { #1 } { symbol } { \exp_not:N \g_semantex_symbol_parentheses:nnnn } } { \g_semantex_data_tl_inherit:nn { #1 } { symbol } \g_semantex_primitive_valuekey_return:nn { #1 }{} \g_semantex_data_tl_set:nnx { #1 } { symbol } { { \exp_not:n { \exp_not:n { #2 } } } { \g_semantex_data_tl_get:nn { #1 } { spar_open } } { \g_semantex_data_tl_get:nn { #1 } { spar_close } } { \g_semantex_data_tl_get_exp_not:nn { #1 } { symbol } } } \g_semantex_data_tl_put_left:nnn { #1 } { symbol } { \exp_not:N \g_semantex_symbol_parentheses:nnnn } } } \cs_new:Npn\g_semantex_primitive_valuekey_iffirstarg:nn#1#2 { \tl_if_eq:nnTF { #2 } { true } { \g_semantex_data_bool_set_true:nn { #1 } { first_arg } } { \tl_if_eq:nnTF { #2 } { false } { \g_semantex_data_bool_set_false:nn { #1 } { first_arg } } { %IM Throw error later } } } \cs_new:Npn\g_semantex_auxiliary_first_arg:nn#1#2 { #1 } \cs_new:Npn\g_semantex_auxiliary_second_arg:nn#1#2 { #2 } %\cs_new:Npn\g_semantex_primitive_valuekey_otherspar:nn#1#2 %{ % \g_semantex_data_tl_inherit:nn { #1 } { spar_size } % \g_semantex_data_tl_inherit:nn { #1 } { symbol } % \g_semantex_primitive_novaluekey_return:n { #1 } %% \tl_set:Nn\l__semantex_spar_temp %% { %% \exp_not:N %% \g_semantex_symbol_parentheses:nnnn %% } %% \tl_put_right:Nx\l__semantex_spar_temp %% { %% { \exp_not:v { semantex_data_tl_#1_spar_size } } %% { \g_semantex_auxiliary_first_arg:nn#2 } %% { \g_semantex_auxiliary_second_arg:nn#2 } %% { \exp_not:v { semantex_data_tl_#1_symbol } } %% } %% \tl_set:cx { semantex_data_tl_#1_symbol } { \exp_not:V\l__semantex_spar_temp } % \tl_set:cx { semantex_data_tl_#1_symbol } % { % %{ \exp_not:c { semantex_data_tl_#1_spar_size } } % { \exp_not:n { \use:c { semantex_data_tl_#1_spar_size } } } % { \g_semantex_auxiliary_first_arg:nn #2 } % { \g_semantex_auxiliary_second_arg:nn #2 } % { \exp_not:v { semantex_data_tl_#1_symbol } } % } % \tl_put_left:cn { semantex_data_tl_#1_symbol } % { % \exp_not:N % \g_semantex_symbol_parentheses:nnnn % } %} \cs_new:Npn\g_semantex_primitive_valuekey_otherspar:nn#1#2 { \g_semantex_primitive_valuekey_otherspar_auxiliary:nnn { #1 } #2 } \cs_new:Npn\g_semantex_primitive_valuekey_otherspar_auxiliary:nnn#1#2#3 { %IM DOES NOT WORK!!!!! \g_semantex_data_tl_inherit:nn { #1 } { spar_size } \g_semantex_data_tl_get_store:nnN { #1 } { spar_size } \l__semantex_otherspar_spar_size_temp \g_semantex_data_tl_inherit:nn { #1 } { symbol } \g_semantex_primitive_valuekey_return:nn { #1 }{} % \tl_set:Nn\l__semantex_spar_temp % { % \exp_not:N % \g_semantex_symbol_parentheses:nnnn % } % \tl_put_right:Nx\l__semantex_spar_temp % { % { \exp_not:v { semantex_data_tl_#1_spar_size } } % { \g_semantex_auxiliary_first_arg:nn#2 } % { \g_semantex_auxiliary_second_arg:nn#2 } % { \exp_not:v { semantex_data_tl_#1_symbol } } % } % \tl_set:cx { semantex_data_tl_#1_symbol } { \exp_not:V\l__semantex_spar_temp } \g_semantex_data_tl_set:nnx { #1 } { symbol } { %{ \exp_not:c { semantex_data_tl_#1_spar_size } } %{ \exp_not:n { \use:c { semantex_data_tl_#1_spar_size } } } %{ normal } %{ \exp_not:n { \exp_not:v { semantex_data_tl_#1_spar_size } } } { \exp_not:V \l__semantex_otherspar_spar_size_temp } { \exp_not:n { \exp_not:n { #2 } } } { \exp_not:n { \exp_not:n { #3 } } } { \g_semantex_data_tl_get_exp_not:nn { #1 } { symbol } } } \g_semantex_data_tl_put_left:nnn { #1 } { symbol } { \exp_not:N \g_semantex_symbol_parentheses:nnnn } % \tl_put_left:cx { g_auomath_#1_symbol } % { % \exp_not:N % \g_semantex_symbol_parentheses:nnnn % } %\tl_put_left:cn { semantex_data_tl_#1_symbol } %{ % \exp_not:N % \g_semantex_symbol_parentheses:nnnn %} } \cs_new:Npn\g_semantex_primitive_valuekey_sparsize:nn#1#2{ % sets the size of the parentheses \g_semantex_data_tl_set:nnn { #1 } { spar_size }{ \exp_not:n { #2 } } } \cs_new:Npn\g_semantex_primitive_valuekey_leftspar:nn#1#2{ \g_semantex_data_tl_set:nnn { #1 } { spar_open }{ \exp_not:n { \exp_not:n { #2 } } } %IM Two \exp_not necessary for unknown reasons %IM Doing the same at leftpar yields an error. } \cs_new:Npn\g_semantex_primitive_valuekey_rightspar:nn#1#2{ \g_semantex_data_tl_set:nnn { #1 } { spar_close }{ \exp_not:n { \exp_not:n { #2 } } } %IM Two \exp_not necessary for unknown reasons %IM Doing the same at leftpar yields an error. } %\msg_new:nnnn { semantex } { singlekey_not_found } { Unknown~key~#1~passed~to~object~#2~on~input~line~\msg_line_number: } {} \cs_generate_variant:Nn \g_semantex_keys_set:nn { nx, no, nV } \cs_generate_variant:Nn \exp_args:Nnx { cnx } \cs_new:Npn \g_semantex_valuekey:nnn#1#2#3{ % Takes care of valuekeys, keys with a value % For the sake of implementation, the arguments % come in a strange order % #1 = value of key % #2 = name of the key % #3 = object %\tl_set:Nn\l_semantex_key_value_temp{#1} \tl_set:Nn\l_semantex_key_value_temp{\exp_not:n{#1}} %\tl_set:Nx\l_semantex_key_value_temp{\exp_not:n{\exp_not:n{#1}}} % stores the content of the key in the temporary command \l_semantex_key_value_temp %\tl_set:Nn\l_semantex_key_value_temp{#1} %\tl_set:No\l_semantex_key_value_temp{\exp_not:n{#1}} % stores the content of the key in the temporary command \l_semantex_key_value_temp %IM think about using extra {...} to avoid interference with keyval str \g_semantex_valuekey_get:nnNTF { #3 } { #2 } \l_semantex_custom_valuekey_temp { \g_semantex_keys_set:nx { #3 } { \l_semantex_custom_valuekey_temp } } { \cs_if_exist:cTF { g_semantex_primitive_valuekey_#2:nn } { \use:c { g_semantex_primitive_valuekey_#2:nn }{ #3 }{ #1 } } { \msg_error:nnnn { semantex } { keyval_not_found } { #2 } { #3 } } } } \cs_generate_variant:Nn \g_semantex_keys_set:nn { nx } \cs_new:Npn \g_semantex_novaluekey:nn#1#2 { % #1 = name of the key % #2 = object % % takes care of single keys, keys without a value \g_semantex_novaluekey_get:nnNTF { #2 } { #1 } \l_semantex_custom_novaluekey_temp { \g_semantex_keys_set:nx { #2 } { \l_semantex_custom_novaluekey_temp } } { \g_semantex_keys_set:nn { #2 } { default = { #1 } } } } %IMplement the same thing for upper, lower?? Probably not. \cs_new:Npn \g_semantex_arg_primitive_valuekey_sep_auxiliary_function_withsep:nn#1#2 { #1#2 } \cs_new:Npn \g_semantex_arg_primitive_valuekey_sep_auxiliary_function_withoutsep:nn#1#2 { #2 } \cs_new:Npn \g_semantex_primitive_arg_valuekey_sep:nn#1#2 { \g_semantex_data_bool_get:nnTF { #1 } { first_arg } { \g_semantex_data_tl_put_right:nnn { #1 } { arg } { \exp_not:n { \g_semantex_arg_primitive_valuekey_sep_auxiliary_function_withoutsep:nn #2 } } %IM These do not use :x, unlike the ones below } { \g_semantex_data_tl_put_right:nnn { #1 } { arg } { \exp_not:n { \g_semantex_arg_primitive_valuekey_sep_auxiliary_function_withsep:nn #2 } } } \g_semantex_primitive_valuekey_ifrightreturnbeforerender:nn{#1}{true} \g_semantex_data_bool_set_false:nn { #1 } { first_arg } } \cs_new:Npn \g_semantex_primitive_arg_valuekey_standardsep:nn#1#2 { \g_semantex_data_bool_get:nnTF { #1 } { first_arg } { \g_semantex_data_tl_put_right:nnn { #1 } { arg } { \exp_not:n { #2 } } %IM Recently corrected % Previously, this was cx, but I didn’t see any point of this; % this was mostly to create symmetry with the below case where % cx is strictly necessary. } { \g_semantex_data_tl_put_right:nnx { #1 } { arg } { \exp_not:n { \g_semantex_data_tl_get:nn { #1 } { argsep } } } \g_semantex_data_tl_put_right:nnn { #1 } { arg } {\exp_not:n { #2 } } % As an experiment, I tried changing cx to cn, and it failed % when changing the separator on the fly. } % \g_semantex_primitive_valuekey_ifoutput:nn { #1 } { true } \g_semantex_primitive_valuekey_ifrightreturnbeforerender:nn{#1}{true} \g_semantex_data_bool_set_false:nn { #1 } { first_arg } } \cs_new:Npn \g_semantex_primitive_arg_valuekey_dots:nn#1#2 { \g_semantex_primitive_arg_valuekey_standardsep:nn { #1 } { \g_semantex_data_tl_get:nn { #1 } { argdots } } } \cs_new:Npn \g_semantex_primitive_arg_valuekey_slot:nn#1#2 { \g_semantex_primitive_arg_valuekey_standardsep:nn { #1 } { \g_semantex_data_tl_get:nn { #1 } { slot } } } \cs_generate_variant:Nn \g_semantex_arg_keys_set:nn { nx } \cs_new:Npn \g_semantex_arg_valuekey:nnn#1#2#3 { % Takes care of valuekeys, keys with a value % For the sake of implementation, the arguments % come in a strange order % #1 = value of key % #2 = name of the key % #3 = object \tl_set:Nn\l_semantex_arg_key_value_temp{\exp_not:n{#1}} % stores the content of the key in the temporary command \l_semantex_key_value_temp \g_semantex_arg_valuekey_get:nnNTF { #3 } { #2 } \l_semantex_custom_arg_valuekey_temp { \g_semantex_arg_keys_set:nx { #3 } { \l_semantex_custom_arg_valuekey_temp } } { \cs_if_exist:cTF { g_semantex_primitive_arg_valuekey_#2:nn } { \use:c { g_semantex_primitive_arg_valuekey_#2:nn }{ #3 }{ #1 }% } { \msg_error:nnnn { semantex } { arg_valuekey_not_found } { #2 } { #3 } } } } \cs_new:Npn \g_semantex_arg_novaluekey:nn#1#2 { % #1 = name of the key % #2 = object % % takes care of single keys, keys without a value % the class key is not actually necessary \g_semantex_arg_novaluekey_get:nnNTF { #2 } { #1 } \l_semantex_custom_arg_novaluekey_temp { %\exp_args:NNno %\exp_args:Nno %\use:c { g_semantex_data_cs_#3_arg:n } \g_semantex_arg_keys_set:nx { #2 } { \l_semantex_custom_arg_novaluekey_temp } } { \g_semantex_data_tl_inherit_x:nn { #2 } { arg } \g_semantex_arg_keys_set:nn { #2 } { default={\exp_not:n { #1 } }} %\g_semantex_arg_keys_set:nn { #3 } { default={#1}} %IM THis \exp_not:n was added late, might be needed elsewhere, too. } } \g_semantex_data_tl_provide:nn { semantexvariable } { output } \g_semantex_data_tl_set:nnn { semantexvariable } { output } { semantexvariable } \g_semantex_data_tl_provide:nn { semantexvariable } { upper_index } \g_semantex_data_tl_provide:nn { semantexvariable } { uppersep } \g_semantex_data_tl_set:nnn { semantexvariable } { uppersep } { , } %IM Also, need commands like forgetupperindex, reverting to the class standard \g_semantex_data_tl_provide:nn { semantexvariable } { lower_index } \g_semantex_data_tl_provide:nn { semantexvariable } { lowersep } \g_semantex_data_tl_set:nnn { semantexvariable } { lowersep } { , } \g_semantex_data_tl_provide:nn { semantexvariable } { preupper } \g_semantex_data_tl_provide:nn { semantexvariable } { postupper } \g_semantex_data_tl_provide:nn { semantexvariable } { prelower } \g_semantex_data_tl_provide:nn { semantexvariable } { postlower } \g_semantex_data_tl_provide:nn { semantexvariable } { upper_left_index } \g_semantex_data_tl_provide:nn { semantexvariable } { upperleftsep } \g_semantex_data_tl_set:nnn { semantexvariable } { upperleftsep } { , } %IM do the same with all the others, INCLUDING if_upper_grading and symbol %IM Also, need commands like forgetupperindex, reverting to the class standard \g_semantex_data_tl_provide:nn { semantexvariable } { lower_left_index } \g_semantex_data_tl_provide:nn { semantexvariable } { lowerleftsep } \g_semantex_data_tl_set:nnn { semantexvariable } { lowerleftsep } { , } \g_semantex_data_tl_provide:nn { semantexvariable } { preupperleft } \g_semantex_data_tl_provide:nn { semantexvariable } { postupperleft } \g_semantex_data_tl_provide:nn { semantexvariable } { prelowerleft } \g_semantex_data_tl_provide:nn { semantexvariable } { postlowerleft } \g_semantex_data_bool_provide:nn { semantexvariable } { first_upper_left } \g_semantex_data_bool_set_true:nn { semantexvariable } { first_upper_left } \g_semantex_data_bool_provide:nn { semantexvariable } { first_lower_left } \g_semantex_data_bool_set_true:nn { semantexvariable } { first_lower_left } \g_semantex_data_tl_provide:nn { semantexvariable } { prearg } \g_semantex_data_tl_provide:nn { semantexvariable } { postarg } %IMplement these later \g_semantex_data_tl_provide:nn { semantexvariable } { arg } \g_semantex_data_tl_provide:nn { semantexvariable } { argsep } \g_semantex_data_tl_set:nnn { semantexvariable } { argsep } {,} \g_semantex_data_tl_provide:nn { semantexvariable } { slot } \g_semantex_data_tl_set:nnn { semantexvariable } { slot } { \semantexslot } \g_semantex_data_tl_provide:nn { semantexvariable } { argdots } \g_semantex_data_tl_set:nnn { semantexvariable } { argdots } {\dots} \g_semantex_data_tl_provide:nn { semantexvariable } { symbol } \g_semantex_data_seq_provide:nn { semantexvariable } { commands_sequence } \g_semantex_data_bool_provide:nn { semantexvariable } { upper_grading } \g_semantex_data_bool_set_true:nn { semantexvariable } { upper_grading } \g_semantex_data_bool_provide:nn { semantexvariable } { output } \g_semantex_data_tl_provide:nn { semantexvariable } { output_options } \g_semantex_data_bool_provide:nn { semantexvariable } { first_arg } \g_semantex_data_bool_set_true:nn { semantexvariable } { first_arg } \g_semantex_data_bool_provide:nn { semantexvariable } { first_upper } \g_semantex_data_bool_set_true:nn { semantexvariable } { first_upper } \g_semantex_data_bool_provide:nn { semantexvariable } { first_lower } \g_semantex_data_bool_set_true:nn { semantexvariable } { first_lower } \g_semantex_data_bool_provide:nn { semantexvariable } { par } \g_semantex_data_bool_set_true:nn { semantexvariable } { par } \g_semantex_data_bool_provide:nn { semantexvariable } { rightreturnbeforerender } \g_semantex_data_tl_provide:nn { semantexvariable } { parseoptions } \g_semantex_data_tl_provide:nn { semantexvariable } { texclass } %\tl_set:Nn\g_objectmath_semantexvariable_upper_index { hej } %\tl_set:Nn \g_semantexvariable_output { semantexvariable } %\bool_new:N \g_semantexvariable_output_if_provided %\bool_set_true:N \g_semantexvariable_output_if_provided \newvariableclass{semantexvariable}[ %parent=semantexvariable, symbol=, gradingpos=upper, %upper=, %lower=, leftpar=(, rightpar=), par=normal, leftspar=(, rightspar=), sparsize=normal, %arg=, ifoutput=false, output=semantexvariable, novaluekeys={ {bullet}{d={\noexpand\semantexbullet}}, {doublebullet}{d={\noexpand\semantexdoublebullet}}, {prime}{upper={\prime}}, {'}{prime}, {''}{prime,prime}, {'''}{prime,prime,prime}, {ibullet}{i={\noexpand\semantexbullet}}, {idoublebullet}{i={\noexpand\semantexdoublebullet}}, {*}{bullet}, {**}{doublebullet}, {i*}{ibullet}, {i**}{idoublebullet}, {smash}{command=\noexpand\smash}, % (widebar}{command=\noexpand\widebar},%For unknown reasons, this only seems to work when run as a primitive {tilde}{command=\noexpand\tilde}, {widetilde}{command=\widetilde}, {overline}{command=\noexpand\overline}, {bar}{command=\noexpand\bar}, {bold}{command=\noexpand\mathbf}, {roman}{command=\noexpand\mathrm}, {mathord}{texclass=\mathord}, {mathbin}{texclass=\mathbin}, {mathop}{texclass=\mathop}, {mathrel}{texclass=\mathrel}, {leftreturn}{leftreturn=}, {innerreturn}{innerreturn=}, {rightreturn}{rightreturn=}, {return}{return=}, {spar}{spar=}, {parse}{parse=}, {par}{ifpar=true}, {nopar}{ifpar=false}, % The following four commands do not work due to expansion issues: % {useargwithkeyval}{useargwithkeyval=}, % {argwithkeyval}{ % valuekeys={ % {arg}{argwithkeyval={\noexpand\l_semantex_key_value_temp}}, % }, % }, % {argwithnovaluekeys}{ % valuekeys={ % {arg}{argwithnovaluekeys={\noexpand\l_semantex_key_value_temp}}, % }, % }, % {argwithoutkeyval}{ % valuekeys={ % {arg}{argwithoutkeyval={\noexpand\l_semantex_key_value_temp}}, % }, % }, % {argwithonenovaluekey}{ % valuekeys={ % {arg}{argwithonenovaluekey={\noexpand\l_semantex_key_value_temp}}, % }, % }, }, valuekeys={ {default}{si={#1}}, % {arg}{argwithkeyval={#1}}, {arg}{argwithnovaluekeys={#1}}, {degreedefault}{sd={#1}}, {parseoptions}{ execute={ \semantexdataputright{parseoptions}{#1} }, }, }, % argwithnovaluekeys, argvaluekeys={ {default}{standardsep={#1}}, }, argnovaluekeys={ {slot}{slot=}, {-}{slot=}, {*}{slot=}, {...}{dots=}, }, %command=, % useargwithkeyval, ]