summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/semantex/semantex.sty
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/semantex/semantex.sty')
-rw-r--r--macros/latex/contrib/semantex/semantex.sty3101
1 files changed, 3101 insertions, 0 deletions
diff --git a/macros/latex/contrib/semantex/semantex.sty b/macros/latex/contrib/semantex/semantex.sty
new file mode 100644
index 0000000000..8e8361c8dc
--- /dev/null
+++ b/macros/latex/contrib/semantex/semantex.sty
@@ -0,0 +1,3101 @@
+\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,
+] \ No newline at end of file