\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,
]