% \iffalse meta-comment
% An Infrastructure for Semantic Macros and Module Scoping
% Copyright (c) 2019 Michael Kohlhase, all rights reserved
%                this file is released under the
%                LaTeX Project Public License (LPPL)
% 
% The original of this file is in the public repository at 
% http://github.com/sLaTeX/sTeX/
%
% TODO update copyright  
%
%<*driver>
\def\libfolder#1{../../lib/#1}
\input{../../doc/stex-docheader}

\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{ \sTeX-Terms
% 	\thanks{Version {\fileversion} (last revised {\filedate})} 
% }
%
% \author{Michael Kohlhase, Dennis Müller\\
% 	FAU Erlangen-Nürnberg\\
% 	\url{http://kwarc.info/}
% }
%
% \maketitle
%
%\ifinfulldoc\else
% This is the documentation for the \pkg{stex-terms} package.
% For a more high-level introduction, 
%  see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the
% \href{\basedocurl/stex.pdf}{full \sTeX documentation}.
%
% \input{../../doc/packages/stex-terms}
% \fi
%
% \begin{documentation}\label{pkg:terms:doc}
% \changes{3.1.0}{2022/03/01}{!-Notation now works for symbols with arity=0 without needing an op-notation}
% \changes{3.1.0}{2022/03/01}{Introduced \detokenize{\varemph, \varemph@uri}}
% \changes{3.1.0}{2022/02/28}{Fixed bug with \detokenize{\STEXInternalCurrentSymbolStr} in variable annotations}
%
% Code related to symbolic expressions, typesetting notations,
% notation components, etc.
%
% \section{Macros and Environments}\label{pkg:terms:doc:macros}
%
% \begin{function}{\STEXsymbol}
%   Uses \cs{stex_get_symbol:n} to find the symbol denoted by
%   the first argument and passes the result on to
%   \cs{stex_invoke_symbol:n}
% \end{function}
%
% \begin{function}{\symref}
%   \begin{syntax} \cs{symref}\Arg{symbol}\Arg{text} \end{syntax}
%   shortcut for \cs{STEXsymbol}\Arg{symbol}|![|\meta{text}|]|
% \end{function}
%
% \begin{function}{\stex_invoke_symbol:n}
%   Executes a semantic macro. Outside of math mode or if followed by |*|,
%   it continues to \cs{stex_term_custom:nn}. In math mode,
%   it uses the default or optionally provided notation of
%   the associated symbol.
%
%   If followed by |!|, it will invoke the symbol \emph{itself}
%   rather than its application (and continue to
%   \cs{stex_term_custom:nn}), i.e. it allows to refer to
%   |\plus![addition]| as an operation, rather than
%   |\plus[addition of]{some}{terms}|.
% \end{function}
%
% \begin{function}{\STEXInternalTermMathOMSiiii,\STEXInternalTermMathOMAiiii,\STEXInternalTermMathOMBiiii}
%   \begin{syntax} \meta{URI}\meta{fragment}\meta{precedence}\meta{body} \end{syntax}
%
% Annotates \meta{body} as an \omdoc-term (|OMID|, |OMA| or |OMBIND|, respectively) 
% with head symbol \meta{URI}, generated
% by the specific notation \meta{fragment} with (upwards) operator precedence
% \meta{precedence}. Inserts parentheses according to
% the current downwards precedence and operator precedence.
% \end{function}
%
% \begin{function}{\STEXInternalTermMathArgiii}
%   \begin{syntax} \cs{stex_term_arg:nnn}\meta{int}\meta{prec}\meta{body} \end{syntax}
% Annotates \meta{body} as the \meta{int}th argument of the current |OMA| or |OMBIND|,
% with (downwards) argument precedence \meta{prec}.
% \end{function}
%
% \begin{function}{\STEXInternalTermMathAssocArgiiiii}
%   \begin{syntax} \cs{stex_term_arg:nnn}\meta{int}\meta{prec}\meta{notation}\meta{type}\meta{body} \end{syntax}
% Annotates \meta{body} as the \meta{int}th (associative) \emph{sequence} argument
% (as comma-separated list of terms) of the current |OMA| or |OMBIND|,
% with (downwards) argument precedence \meta{prec} and associative
% notation \meta{notation}.
% 
% \end{function}
%
% \begin{variable}{\infprec, \neginfprec}
%   Maximal and minimal notation precedences.
% \end{variable}
%
% \begin{function}{\dobrackets}
%   \begin{syntax} \cs{dobrackets} \Arg{body} \end{syntax}
%   Puts \meta{body} in parentheses; scaled if in display mode
%   unscaled otherwise. Uses the current \sTeX brackets (by default |(| and |)|),
%   which can be changed temporarily using \cs{withbrackets}.
% \end{function}
%
% \begin{function}{\withbrackets}
%   \begin{syntax} \cs{withbrackets} \meta{left} \meta{right} \Arg{body} \end{syntax}
%   Temporarily (i.e. within \meta{body}) sets the brackets used by \sTeX for automated
%   bracketing (by default |(| and |)|) to \meta{left} and \meta{right}.
%
%   Note that \meta{left} and \meta{right} need to be allowed
%   after \cs{left} and \cs{right} in displaymode.
% \end{function}
%
% \begin{function}{\stex_term_custom:nn}
%   \begin{syntax} \cs{stex_term_custom:nn}\Arg{URI}\Arg{args}\end{syntax}
% Implements custom one-time notation.
% Invoked by \cs{stex_invoke_symbol:n} in text mode, or if
% followed by |*| in math mode, or whenever followed by |!|.
% \end{function}
%
% \begin{function}{\comp, \compemph,\compemph@uri, \defemph, \defemph@uri, \symrefemph,\symrefemph@uri,\varemph,\varemph@uri}
%   \begin{syntax} \cs{comp}\Arg{args}\end{syntax}
% Marks \meta{args} as a notation component of the current symbol for
% highlighting, linking, etc.
%
% The precise behavior is governed by \cs{@comp}, which takes as
% additional argument the URI of the current symbol. By default,
% \cs{@comp} adds the URI as a PDF tooltip and colors the highlighted part
% in blue.
%
% \cs{@defemph} behaves like \cs{@comp}, and can be similarly redefined,
% but marks an expression as \emph{definiendum} (used by \cs{definiendum})
% \end{function}
%
% \begin{function}{\STEXinvisible}
% Exports its argument as \omdoc (invisible), but does
% not produce PDF output. Useful e.g. for semantic macros
% that take arguments that are not part of the symbolic
% notation.
% \end{function}
%
% \begin{function}{\ellipses}
%   TODO
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}\label{pkg:terms:impl}
%
% \section{\sTeX-Terms Implementation}
%
%    \begin{macrocode}
%<*package>

%%%%%%%%%%%%%   terms.dtx   %%%%%%%%%%%%%

%<@@=stex_terms>
%    \end{macrocode}
%
% Warnings and error messages
%
%    \begin{macrocode}
\msg_new:nnn{stex}{error/nonotation}{
  Symbol~#1~invoked,~but~has~no~notation#2!
}
\msg_new:nnn{stex}{error/notationarg}{
  Error~in~parsing~notation~#1
}
\msg_new:nnn{stex}{error/noop}{
  Symbol~#1~has~no~operator~notation~for~notation~#2
}
\msg_new:nnn{stex}{error/notallowed}{
  Symbol~invokation~#1~not~allowed~in~notation~component~of~#2
}
\msg_new:nnn{stex}{error/doubleargument}{
  Argument~#1~of~symbol~#2~already~assigned
}
\msg_new:nnn{stex}{error/overarity}{
  Argument~#1~invalid~for~symbol~#2~with~arity~#3
}

%    \end{macrocode}
% \subsection{Symbol Invocations}
%
%
% \begin{macro}{\stex_invoke_symbol:n}
%
%  Invokes a semantic macro
%
%    \begin{macrocode}


\bool_new:N \l_stex_allow_semantic_bool
\bool_set_true:N \l_stex_allow_semantic_bool

\cs_new_protected:Nn \stex_invoke_symbol:n {
  \ifvmode\indent\fi
  \bool_if:NTF \l_stex_allow_semantic_bool {
    \str_if_eq:eeF {
      \prop_item:cn {
        l_stex_symdecl_#1_prop
      }{ deprecate }
    }{}{
      \msg_warning:nnxx{stex}{warning/deprecated}{
        Symbol~#1
      }{
        \prop_item:cn {l_stex_symdecl_#1_prop}{ deprecate }
      }
    }
    \if_mode_math:
      \exp_after:wN \_@@_invoke_math:n
    \else:
      \exp_after:wN \_@@_invoke_text:n
    \fi: { #1 }
  }{
    \msg_error:nnxx{stex}{error/notallowed}{#1}{\STEXInternalCurrentSymbolStr}
  }
}

\cs_new_protected:Nn \_@@_invoke_text:n {
  \peek_charcode_remove:NTF ! {
    \_@@_invoke_op_custom:nn {#1}
  }{
    \_@@_invoke_custom:nn {#1}
  }
}

\cs_new_protected:Nn \_@@_invoke_math:n {
  \peek_charcode_remove:NTF ! {
    % operator
    \peek_charcode_remove:NTF * {
      % custom op
      \_@@_invoke_op_custom:nn {#1}
    }{
      % op notation
      \peek_charcode:NTF [ {
        \_@@_invoke_op_notation:nw {#1}
      }{
        \_@@_invoke_op_notation:nw {#1}[]
      }
    }
  }{
    \peek_charcode_remove:NTF * {
      \_@@_invoke_custom:nn {#1}
      % custom
    }{
      % normal
      \peek_charcode:NTF [ {
        \_@@_invoke_notation:nw {#1}
      }{
        \_@@_invoke_notation:nw {#1}[]
      }
    }
  }
}


\cs_new_protected:Nn \_@@_invoke_op_custom:nn {
  \exp_args:Nnx \use:nn {
    \def\comp{\_comp}
    \str_set:Nn \STEXInternalCurrentSymbolStr { #1 }
    \bool_set_false:N \l_stex_allow_semantic_bool
    \stex_mathml_intent:nn{#1}{
      \_stex_term_oms:nnn {#1}{#1 \c_hash_str CUSTOM-}{
        \comp{ #2 }
      }
    }
  }{
    \_stex_reset:N \comp
    \_stex_reset:N \STEXInternalCurrentSymbolStr
    \bool_set_true:N \l_stex_allow_semantic_bool
  }
}

\keys_define:nn { stex / terms } {
%  lang    .tl_set_x:N = \l_stex_notation_lang_str ,
  variant .tl_set_x:N = \l_stex_notation_variant_str ,
  unknown .code:n     = \str_set:Nx 
      \l_stex_notation_variant_str \l_keys_key_str
}

\cs_new_protected:Nn \_@@_args:n {
 % \str_clear:N \l_stex_notation_lang_str
  \str_clear:N \l_stex_notation_variant_str
  
  \keys_set:nn { stex / terms } { #1 }
}

\cs_new_protected:Nn \stex_find_notation:nn {
  \_@@_args:n { #2 }
  \seq_if_empty:cTF {
    l_stex_symdecl_ #1 _notations 
  } {
    \msg_error:nnxx{stex}{error/nonotation}{#1}{s}
  } {
    \str_if_empty:NTF \l_stex_notation_variant_str {
      \seq_get_left:cN {l_stex_symdecl_#1_notations}\l_stex_notation_variant_str
    }{
      \seq_if_in:cxTF {l_stex_symdecl_#1_notations}{
        \l_stex_notation_variant_str
      }{
      %  \str_set:Nx \l_stex_notation_variant_str { \l_stex_notation_variant_str \c_hash_str \l_stex_notation_lang_str }
      }{
        \msg_error:nnxx{stex}{error/nonotation}{#1}{
          ~\l_stex_notation_variant_str
        }
      }
    }
  }
}

\cs_new_protected:Npn \_@@_invoke_op_notation:nw #1 [#2] {
  \exp_args:Nnx \use:nn {
    \def\comp{\_comp}
    \str_set:Nn \STEXInternalCurrentSymbolStr { #1 }
    \stex_find_notation:nn { #1 }{ #2 }
    \bool_set_false:N \l_stex_allow_semantic_bool
    \cs_if_exist:cTF {
      stex_op_notation_ #1 \c_hash_str \l_stex_notation_variant_str _cs
    }{
      \_stex_term_oms:nnn { #1 }{
        #1 \c_hash_str \l_stex_notation_variant_str
      }{
        \use:c{stex_op_notation_ #1 \c_hash_str \l_stex_notation_variant_str _cs}
      }
    }{
      \int_compare:nNnTF {\prop_item:cn {l_stex_symdecl_#1_prop}{arity}} = 0{
        \cs_if_exist:cTF {
          stex_notation_ #1 \c_hash_str \l_stex_notation_variant_str _cs
        }{
          \tl_set:Nx \STEXInternalSymbolAfterInvokationTL {
            \_stex_reset:N \comp
            \_stex_reset:N \STEXInternalSymbolAfterInvokationTL
            \_stex_reset:N \STEXInternalCurrentSymbolStr
            \bool_set_true:N \l_stex_allow_semantic_bool
          }
          \def\comp{\_comp}
          \str_set:Nn \STEXInternalCurrentSymbolStr { #1 }
          \bool_set_false:N \l_stex_allow_semantic_bool
          \use:c{stex_notation_ #1 \c_hash_str \l_stex_notation_variant_str _cs}
        }{
          \msg_error:nnxx{stex}{error/nonotation}{#1}{
            ~\l_stex_notation_variant_str
          }
        }
      }{
        \msg_error:nnxx{stex}{error/noop}{#1}{\l_stex_notation_variant_str}
      }
    }
  }{
    \_stex_reset:N \comp
    \_stex_reset:N \STEXInternalCurrentSymbolStr
    \bool_set_true:N \l_stex_allow_semantic_bool
  }
}

\cs_new_protected:Npn \_@@_invoke_notation:nw #1 [#2] {
  \stex_find_notation:nn { #1 }{ #2 }
  \cs_if_exist:cTF {
    stex_notation_ #1 \c_hash_str \l_stex_notation_variant_str _cs
  }{
    \tl_set:Nx \STEXInternalSymbolAfterInvokationTL {
      \_stex_reset:N \comp
      \_stex_reset:N \STEXInternalSymbolAfterInvokationTL
      \_stex_reset:N \STEXInternalCurrentSymbolStr
      \bool_set_true:N \l_stex_allow_semantic_bool
    }
    \def\comp{\_comp}
    \str_set:Nn \STEXInternalCurrentSymbolStr { #1 }
    \bool_set_false:N \l_stex_allow_semantic_bool
    \use:c{stex_notation_ #1 \c_hash_str \l_stex_notation_variant_str _cs}
  }{
    \msg_error:nnxx{stex}{error/nonotation}{#1}{
      ~\l_stex_notation_variant_str
    }
  }
}

\prop_new:N \l_@@_custom_args_prop
\clist_new:N \l_stex_argnames_seq
\seq_new:N \l_@@_tmp_seq

\cs_new_protected:Nn\_@@_custom_comp:n{\bool_set_false:N \l_stex_allow_semantic_bool\_comp{#1}\bool_set_true:N \l_stex_allow_semantic_bool}

\cs_new_protected:Nn \_@@_invoke_custom:nn {
  \exp_args:Nnx \use:nn {
    \def\comp{\_@@_custom_comp:n}
    \str_set:Nn \STEXInternalCurrentSymbolStr { #1 }
    \prop_clear:N \l_@@_custom_args_prop
    \prop_put:Nnn \l_@@_custom_args_prop {currnum} {1}
    \prop_get:cnN {
      l_stex_symdecl_#1 _prop
    }{ args } \l_tmpa_str
    \exp_args:NNx \seq_set_from_clist:Nn \l_stex_argnames_seq {
      \prop_item:cn {l_stex_symdecl_#1 _prop}{argnames}
    }
    \prop_put:Nno \l_@@_custom_args_prop {args} \l_tmpa_str
    \tl_set:Nn \arg { \_@@_arg: }
    \str_if_empty:NTF \l_tmpa_str {
      \stex_mathml_intent:nn{#1}{
        \_stex_term_oms:nnn {#1}{#1\c_hash_str CUSTOM-}{\ignorespaces#2}
      }
    }{
      \seq_clear:N \l_@@_tmp_seq
      \exp_args:Nx\int_step_inline:nn{\prop_item:cn{l_stex_symdecl_#1 _prop}{arity}}{
        \tl_set:Nx \l_@@_tmp_tl {\seq_item:Nn \l_stex_argnames_seq {##1}}
        \bool_lazy_or:nnT{
          \str_if_eq_p:nn{a}{\str_item:Nn\l_tmpa_str{##1}}
        }{
          \str_if_eq_p:nn{B}{\str_item:Nn\l_tmpa_str{##1}}
        }{
          \tl_put_right:Nn \l_@@_tmp_tl +
        }
        \seq_put_right:No \l_@@_tmp_seq \l_@@_tmp_tl
      }
      \stex_mathml_intent:nn{
        #1[\prop_item:cn {l_stex_symdecl_#1 _prop}{ args }](
          \seq_use:Nn \l_@@_tmp_seq ,
        )
      }{
        \str_if_in:NnTF \l_tmpa_str b {
          \_stex_term_ombind:nnn {#1}{#1\c_hash_str CUSTOM-\l_tmpa_str}{\ignorespaces#2}
        }{
          \str_if_in:NnTF \l_tmpa_str B {
            \_stex_term_ombind:nnn {#1}{#1\c_hash_str CUSTOM-\l_tmpa_str}{\ignorespaces#2}
          }{
            \_stex_term_oma:nnn {#1}{#1\c_hash_str CUSTOM-\l_tmpa_str}{\ignorespaces#2}
          }
        }
      }
    }
    % TODO check that all arguments exist
  }{
    \_stex_reset:N \l_stex_argnames_seq
    \_stex_reset:N \STEXInternalCurrentSymbolStr
    \_stex_reset:N \arg
    \_stex_reset:N \comp
    \_stex_reset:N \l_@@_custom_args_prop
    %\bool_set_true:N \l_stex_allow_semantic_bool
  }
}

\NewDocumentCommand \_@@_arg: { s O{} m}{
  \tl_if_empty:nTF {#2}{
    \int_set:Nn \l_tmpa_int {\prop_item:Nn \l_@@_custom_args_prop {currnum}}
    \bool_set_true:N \l_tmpa_bool
    \bool_do_while:Nn \l_tmpa_bool {
      \exp_args:NNx \prop_if_in:NnTF \l_@@_custom_args_prop {\int_use:N \l_tmpa_int} {
        \int_incr:N \l_tmpa_int
      }{
        \bool_set_false:N \l_tmpa_bool
      }
    }
  }{
    \int_set:Nn \l_tmpa_int { #2 }
  }
  \str_set:Nx \l_tmpa_str {\prop_item:Nn \l_@@_custom_args_prop {args} }
  \int_compare:nNnT \l_tmpa_int > {\str_count:N \l_tmpa_str} {
    \msg_error:nnxxx{stex}{error/overarity}
      {\int_use:N \l_tmpa_int}
      {\STEXInternalCurrentSymbolStr}
      {\str_count:N \l_tmpa_str}
  }
  \str_set:Nx \l_tmpa_str {\str_item:Nn \l_tmpa_str \l_tmpa_int}
  \exp_args:NNx \prop_if_in:NnT \l_@@_custom_args_prop {\int_use:N \l_tmpa_int} {
    \bool_lazy_any:nF {
      {\str_if_eq_p:Vn \l_tmpa_str {a}}
      {\str_if_eq_p:Vn \l_tmpa_str {B}}
    }{
      \msg_error:nnxx{stex}{error/doubleargument}
        {\int_use:N \l_tmpa_int}
        {\STEXInternalCurrentSymbolStr}
    }
  }
  \exp_args:NNx \prop_put:Nnn \l_@@_custom_args_prop {\int_use:N \l_tmpa_int} {\ignorespaces#3}
  \bool_if:NTF \l_stex_allow_semantic_bool \use_i:nn {
    \bool_set_true:N \l_stex_allow_semantic_bool  
    \use:nn
  }
  {
  \stex_mathml_arg:nn{\seq_item:Nn \l_stex_argnames_seq \l_tmpa_int}{
    \IfBooleanTF#1{
      \stex_annotate_invisible:n { %TODO
        \exp_args:No \_stex_term_arg:nn {\l_tmpa_str\int_use:N \l_tmpa_int}{\ignorespaces#3}
      }
    }{ %TODO
      \exp_args:No \_stex_term_arg:nn {\l_tmpa_str\int_use:N \l_tmpa_int}{\ignorespaces#3}
    }
  }}
  {\bool_set_false:N \l_stex_allow_semantic_bool}
}


\cs_new_protected:Nn \_stex_term_arg:nn {
  \bool_set_true:N \l_stex_allow_semantic_bool
  \stex_annotate:nnn{ arg }{ #1 }{ #2 }
  \bool_set_false:N \l_stex_allow_semantic_bool
}

\cs_new_protected:Npn \STEXInternalTermMathArgiii #1#2#3 {
  \exp_args:Nnx \use:nn
    { \int_set:Nn \l_@@_downprec { #2 } 
      \stex_mathml_arg:nn{\seq_item:Nn \l_stex_argnames_seq \l_tmpa_int}{
        \_stex_term_arg:nn { #1 }{ #3 }
      }
    }
    { \int_set:Nn \exp_not:N \l_@@_downprec { \int_use:N \l_@@_downprec } }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\STEXInternalTermMathAssocArgiiiii}
%    \begin{macrocode}
\cs_new_protected:Npn \STEXInternalTermMathAssocArgiiiii #1#2#3#4#5 {
  \cs_set:Npn \l_tmpa_cs ##1 ##2 { #4 }
  \tl_set:Nn \l_tmpb_tl {\STEXInternalTermMathArgiii{#5#1}{#2}}
  \tl_if_empty:nTF { #3 }{
    \STEXInternalTermMathArgiii{#5#1}{#2}{}
  }{
    \exp_args:Nx \tl_if_empty:nTF { \tl_tail:n{ #3 }}{
      \expandafter\if\expandafter\relax\noexpand#3
        \tl_set:Nn \l_tmpa_tl {\_@@_math_assoc_arg_maybe_sequence:Nnn#3{#1}{#5}}
      \else
        \tl_set:Nn \l_tmpa_tl {\_@@_math_assoc_arg_simple:nnn{#1}{#3}{#5}}
      \fi
      \l_tmpa_tl
    }{
      \_@@_math_assoc_arg_simple:nnn{#1}{#3}{#5}
    }
  }
}

\cs_new_protected:Nn \_@@_math_assoc_arg_maybe_sequence:Nnn {
  \str_set:Nx \l_tmpa_str { \cs_argument_spec:N #1 }
  \str_if_empty:NTF \l_tmpa_str {
    \exp_args:Nx \cs_if_eq:NNTF {
      \tl_head:N #1
    } \stex_invoke_sequence:n {
      \tl_set:Nx \l_tmpa_tl {\tl_tail:N #1}
      \str_set:Nx \l_tmpa_str {\exp_after:wN \use:n \l_tmpa_tl}
      \tl_set:Nx \l_tmpa_tl {\prop_item:cn {l_stex_symdecl_varseq://\l_tmpa_str _prop}{notation}}
      \exp_args:NNo \seq_set_from_clist:Nn \l_tmpa_seq \l_tmpa_tl
      \tl_set:Nx \l_tmpa_tl {{\exp_not:N \exp_not:n{
        \exp_not:n{\exp_args:Nnx \use:nn} {
          \exp_not:n {
            \def\comp{\_varcomp}
            \str_set:Nn \STEXInternalCurrentSymbolStr
          } {varseq://\l_tmpa_str}
          \exp_not:n{ ##1 }
        }{
          \exp_not:n {
            \_stex_reset:N \comp
            \_stex_reset:N \STEXInternalCurrentSymbolStr
          }
        }
      }}}
      \exp_args:Nno \use:n {\seq_set_map:NNn \l_tmpa_seq \l_tmpa_seq} \l_tmpa_tl
      \seq_reverse:N \l_tmpa_seq
      \seq_pop:NN \l_tmpa_seq \l_tmpa_tl
      \seq_map_inline:Nn \l_tmpa_seq {
        \exp_args:NNNo \exp_args:NNo \tl_set:No \l_tmpa_tl {
          \exp_args:Nno 
          \l_tmpa_cs { ##1 } \l_tmpa_tl 
        }
      }
      \tl_set:Nx \l_tmpa_tl {
        \_stex_term_omv:nn {varseq://\l_tmpa_str}{
          \exp_args:No \exp_not:n \l_tmpa_tl
        }
      }
      \exp_args:No\l_tmpb_tl\l_tmpa_tl
    }{
      \_@@_math_assoc_arg_simple:nnn{#2} { #1 }{#3}
    }
  } {
    \_@@_math_assoc_arg_simple:nnn{#2} { #1 }{#3}
  }

}

\cs_new_protected:Nn \_@@_math_assoc_arg_simple:nnn {
  \clist_set:Nn \l_tmpa_clist{ #2 }
  \int_compare:nNnTF { \clist_count:N \l_tmpa_clist } < 2 {
    \tl_set:Nn \l_tmpa_tl { 
      \stex_mathml_arg:nn{\seq_item:Nn \l_stex_argnames_seq #1}{
        \_stex_term_arg:nn{A#3#1}{ #2 } }
    }
  }{
    \clist_reverse:N \l_tmpa_clist
    \clist_pop:NN \l_tmpa_clist \l_tmpa_tl
    \tl_set:Nx \l_tmpa_tl { 
      \stex_mathml_arg:nn{\seq_item:Nn \l_stex_argnames_seq #1}{
        \_stex_term_arg:nn{A#3#1}{
        \exp_args:No \exp_not:n \l_tmpa_tl
      }
    }}
    \clist_map_inline:Nn \l_tmpa_clist {
      \exp_args:NNNo \exp_args:NNo \tl_set:No \l_tmpa_tl {
        \exp_args:Nno 
        \l_tmpa_cs { 
          \stex_mathml_arg:nn{\seq_item:Nn \l_stex_argnames_seq #1}{
            \_stex_term_arg:nn{A#3#1}{##1} 
          }
        } \l_tmpa_tl 
      }
    }
  }
  \exp_args:No\l_tmpb_tl\l_tmpa_tl
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Terms}
%
% Precedences:
% \begin{variable}{\infprec, \neginfprec, \l_@@_downprec}
%    \begin{macrocode}
\tl_const:Nx \infprec {\int_use:N \c_max_int}
\tl_const:Nx \neginfprec {-\int_use:N \c_max_int}
\int_new:N \l_@@_downprec
\int_set_eq:NN \l_@@_downprec \infprec
%    \end{macrocode}
% \end{variable}
%
% Bracketing:
%
% \begin{variable}{\l_@@_left_bracket_str, \l_@@_right_bracket_str}
%    \begin{macrocode}
\tl_set:Nn \l_@@_left_bracket_str (
\tl_set:Nn \l_@@_right_bracket_str )
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\_@@_maybe_brackets:nn}
%
% Compares precedences and insert brackets accordingly
%
%    \begin{macrocode}
\cs_new_protected:Nn \_@@_maybe_brackets:nn {
  \bool_if:NTF \l_@@_brackets_done_bool {
    \bool_set_false:N \l_@@_brackets_done_bool
    #2
  } {
    \int_compare:nNnTF { #1 } > \l_@@_downprec {
      \bool_if:NTF \l_stex_inparray_bool { #2 }{
        \stex_debug:nn{dobrackets}{\number#1 > \number\l_@@_downprec; \detokenize{#2}}
        \dobrackets { #2 }
      }
    }{ #2 }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\dobrackets}
%    \begin{macrocode}
\bool_new:N \l_@@_brackets_done_bool
%\RequirePackage{scalerel}
\cs_new_protected:Npn \dobrackets #1 {
  %\ThisStyle{\if D\m@switch
  %    \exp_args:Nnx \use:nn
  %    { \exp_after:wN \left\l_@@_left_bracket_str #1 } 
  %    { \exp_not:N\right\l_@@_right_bracket_str }
  %  \else
      \exp_args:Nnx \use:nn
      { 
        \bool_set_true:N \l_@@_brackets_done_bool
        \int_set:Nn \l_@@_downprec \infprec
        \l_@@_left_bracket_str 
        #1
      } 
      {
        \bool_set_false:N \l_@@_brackets_done_bool
        \l_@@_right_bracket_str 
        \int_set:Nn \l_@@_downprec { \int_use:N \l_@@_downprec }
      }
  %\fi}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\withbrackets}
%    \begin{macrocode}
\cs_new_protected:Npn \withbrackets #1 #2 #3 {
  \exp_args:Nnx \use:nn
  {  
    \tl_set:Nx \l_@@_left_bracket_str { #1 }
    \tl_set:Nx \l_@@_right_bracket_str { #2 }
    #3
  }
  {
    \tl_set:Nn \exp_not:N \l_@@_left_bracket_str 
      {\l_@@_left_bracket_str}
    \tl_set:Nn \exp_not:N \l_@@_right_bracket_str 
      {\l_@@_right_bracket_str}
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\STEXinvisible}
%    \begin{macrocode}
\cs_new_protected:Npn \STEXinvisible #1 {
  \stex_annotate_invisible:n { #1 }
}
%    \end{macrocode}
% \end{macro}
%
% \omdoc terms:
%
% \begin{macro}{\STEXInternalTermMathOMSiiii}
%    \begin{macrocode}
\cs_new_protected:Nn \_stex_term_oms:nnn {
  \stex_annotate:nnn{ OMID }{ #2 }{
    #3 
  }
}

\cs_new_protected:Npn \STEXInternalTermMathOMSiiii #1#2#3#4 {
  \_@@_maybe_brackets:nn { #3 }{ 
    \stex_mathml_intent:nn{#1} {
      \_stex_term_oms:nnn { #1 } { #1\c_hash_str#2 } { #4 }
    }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\_stex_term_math_omv:nn}
%    \begin{macrocode}
\cs_new_protected:Nn \_stex_term_omv:nn {
  \stex_annotate:nnn{ OMV }{ #1 }{
    #2
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\STEXInternalTermMathOMAiiii}
%    \begin{macrocode}
\cs_new_protected:Nn \_stex_term_oma:nnn {
  \stex_annotate:nnn{ OMA }{ #2 }{
    #3
  }
}

\cs_new_protected:Npn \STEXInternalTermMathOMAiiii #1#2#3#4 {
  \exp_args:Nnx \use:nn {
    \seq_clear:N \l_@@_tmp_seq
    \prop_if_exist:cT{l_stex_symdecl_#1 _prop}{
    \exp_args:NNx \seq_set_from_clist:Nn \l_stex_argnames_seq {
      \prop_item:cn {l_stex_symdecl_#1 _prop}{argnames}
    }
    \exp_args:Nx\int_step_inline:nn{\prop_item:cn{l_stex_symdecl_#1 _prop}{arity}}{
      \tl_set:Nx \l_@@_tmp_tl {\seq_item:Nn \l_stex_argnames_seq {##1}}
      \bool_lazy_or:nnT{
        \str_if_eq_p:nn{a}{\str_item:Nn\l_tmpa_str{##1}}
      }{
        \str_if_eq_p:nn{B}{\str_item:Nn\l_tmpa_str{##1}}
      }{
        \tl_put_right:Nn \l_@@_tmp_tl +
      }
      \seq_put_right:No \l_@@_tmp_seq \l_@@_tmp_tl
    }
  }
  \_@@_maybe_brackets:nn { #3 }{ 
    \stex_mathml_intent:nn{
      #1[\prop_item:cn {l_stex_symdecl_#1 _prop}{ args }](
        \seq_use:Nn \l_@@_tmp_seq ,
      )
    }{
      \_stex_term_oma:nnn { #1 } { #1\c_hash_str#2 } { #4 }
    }
  }
  }{
    \_stex_reset:N \l_stex_argnames_seq
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\STEXInternalTermMathOMBiiii}
%    \begin{macrocode}
\cs_new_protected:Nn \_stex_term_ombind:nnn {
  \stex_annotate:nnn{ OMBIND }{ #2 }{
    #3
  }
}

\cs_new_protected:Npn \STEXInternalTermMathOMBiiii #1#2#3#4 {
  \exp_args:Nnx \use:nn {
    \seq_clear:N \l_@@_tmp_seq
    \prop_if_exist:cT{l_stex_symdecl_#1 _prop}{
    \exp_args:NNx \seq_set_from_clist:Nn \l_stex_argnames_seq {
      \prop_item:cn {l_stex_symdecl_#1 _prop}{argnames}
    }
    \exp_args:Nx\int_step_inline:nn{\prop_item:cn{l_stex_symdecl_#1 _prop}{arity}}{
      \tl_set:Nx \l_@@_tmp_tl {\seq_item:Nn \l_stex_argnames_seq {##1}}
      \bool_lazy_or:nnT{
        \str_if_eq_p:nn{a}{\str_item:Nn\l_tmpa_str{##1}}
      }{
        \str_if_eq_p:nn{B}{\str_item:Nn\l_tmpa_str{##1}}
      }{
        \tl_put_right:Nn \l_@@_tmp_tl +
      }
      \seq_put_right:No \l_@@_tmp_seq \l_@@_tmp_tl
    }
  }
  \_@@_maybe_brackets:nn { #3 }{ 
    \stex_mathml_intent:nn{
      #1[\prop_item:cn {l_stex_symdecl_#1 _prop}{ args }](
        \seq_use:Nn \l_@@_tmp_seq ,
      )
    }{
      \_stex_term_ombind:nnn { #1 } { #1\c_hash_str#2 } { #4 }
    }
  }
  }{
    \_stex_reset:N \l_stex_argnames_seq
  }
}
%    \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\symref,\symname}
%    \begin{macrocode}
\cs_new:Nn \stex_capitalize:n { \uppercase{#1} }

\keys_define:nn { stex / symname } {
  pre     .tl_set_x:N    = \l_@@_pre_tl ,
  post    .tl_set_x:N    = \l_@@_post_tl ,
  root    .tl_set_x:N    = \l_@@_root_tl
}

\cs_new_protected:Nn \stex_symname_args:n {
  \tl_clear:N \l_@@_post_tl
  \tl_clear:N \l_@@_pre_tl
  \tl_clear:N \l_@@_root_str
  \keys_set:nn { stex / symname } { #1 }
}

\NewDocumentCommand \symref { m m }{
  \let\compemph_uri_prev:\compemph@uri
  \let\compemph@uri\symrefemph@uri
  \STEXsymbol{#1}!{ #2 }
  \let\compemph@uri\compemph_uri_prev:
}

\NewDocumentCommand \synonym { O{} m m}{
  \stex_symname_args:n { #1 }
  \let\compemph_uri_prev:\compemph@uri
  \let\compemph@uri\symrefemph@uri
  % TODO
  \STEXsymbol{#2}!{\l_@@_pre_tl #3 \l_@@_post_tl}
  \let\compemph@uri\compemph_uri_prev:
}

\NewDocumentCommand \symname { O{} m }{
  \stex_symname_args:n { #1 }
  \stex_get_symbol:n { #2 }
  \str_set:Nx \l_tmpa_str {
    \prop_item:cn { l_stex_symdecl_ \l_stex_get_symbol_uri_str _prop } { name }
  }
  \exp_args:NNno \str_replace_all:Nnn \l_tmpa_str {-} {~}
  
  \let\compemph_uri_prev:\compemph@uri
  \let\compemph@uri\symrefemph@uri
  \exp_args:NNx \use:nn
  \stex_invoke_symbol:n { { \l_stex_get_symbol_uri_str }!\ifmmode*\fi{
    \l_@@_pre_tl \l_tmpa_str \l_@@_post_tl
   } }
  \let\compemph@uri\compemph_uri_prev:
}

\NewDocumentCommand \Symname { O{} m }{
  \stex_symname_args:n { #1 }
  \stex_get_symbol:n { #2 }
  \str_set:Nx \l_tmpa_str {
    \prop_item:cn { l_stex_symdecl_ \l_stex_get_symbol_uri_str _prop } { name }
  }
  \exp_args:NNno \str_replace_all:Nnn \l_tmpa_str {-} {~}
  \let\compemph_uri_prev:\compemph@uri
  \let\compemph@uri\symrefemph@uri
  \exp_args:NNx \use:nn
  \stex_invoke_symbol:n { { \l_stex_get_symbol_uri_str }!\ifmmode*\fi{
    \exp_after:wN \stex_capitalize:n \l_tmpa_str
      \l_@@_post_tl
   } }
  \let\compemph@uri\compemph_uri_prev:
}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{Notation Components}
%    \begin{macrocode}
%<@@=stex_notationcomps>
%    \end{macrocode}
%
% \begin{macro}{\comp,\compemph@uri,\compemph,\defemph,\defemph@uri,\symrefemph,\symrefemph@uri,\varemph,\varemph@uri}
%    \begin{macrocode}
\cs_new_protected:Npn \_comp #1 {
  \str_if_empty:NF \STEXInternalCurrentSymbolStr {
    \stex_html_backend:TF {
      \stex_annotate:nnn { comp }{ \STEXInternalCurrentSymbolStr }{ #1 }
    }{
      \exp_args:Nnx \compemph@uri { #1 } { \STEXInternalCurrentSymbolStr }
    }
  }
}

\cs_new_protected:Npn \_varcomp #1 {
  \str_if_empty:NF \STEXInternalCurrentSymbolStr {
    \stex_html_backend:TF {
      \stex_annotate:nnn { varcomp }{ \STEXInternalCurrentSymbolStr }{ #1 }
    }{
      \exp_args:Nnx \varemph@uri { #1 } { \STEXInternalCurrentSymbolStr }
    }
  }
}

\def\comp{\_comp}

\cs_new_protected:Npn \compemph@uri #1 #2 {
    \compemph{ #1 }
}


\cs_new_protected:Npn \compemph #1 {
    #1
}

\cs_new_protected:Npn \defemph@uri #1 #2 {
    \defemph{#1}
}

\cs_new_protected:Npn \defemph #1 {
    \textbf{#1}
}

\cs_new_protected:Npn \symrefemph@uri #1 #2 {
    \symrefemph{#1}
}

\cs_new_protected:Npn \symrefemph #1 {
    \emph{#1}
}

\cs_new_protected:Npn \varemph@uri #1 #2 {
    \varemph{#1}
}

\cs_new_protected:Npn \varemph #1 {
    #1
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\ellipses}
%    \begin{macrocode}
\NewDocumentCommand \ellipses {} { \ldots }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\parray,\prmatrix,\parrayline,\parraylineh,\parraycell}
%    \begin{macrocode}
\bool_new:N \l_stex_inparray_bool
\bool_set_false:N \l_stex_inparray_bool
\NewDocumentCommand \parray { m m } {
  \begingroup 
  \bool_set_true:N \l_stex_inparray_bool
  \begin{array}{#1}
    #2
  \end{array}
  \endgroup
}

\NewDocumentCommand \prmatrix { m } {
  \begingroup 
  \bool_set_true:N \l_stex_inparray_bool
  \begin{matrix}
    #1
  \end{matrix}
  \endgroup
}

\def \maybephline {
  \bool_if:NT \l_stex_inparray_bool {\hline}
}

\def \parrayline #1 #2 {
  #1 #2 \bool_if:NT \l_stex_inparray_bool {\\}
}

\def \pmrow #1 { \parrayline{}{ #1 } }

\def \parraylineh #1 #2 {
  #1 #2 \bool_if:NT \l_stex_inparray_bool {\\\hline}
}

\def \parraycell #1 {
  #1 \bool_if:NT \l_stex_inparray_bool {&}
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Variables}
%    \begin{macrocode}
%<@@=stex_variables>
%    \end{macrocode}
%
% \begin{macro}{\stex_invoke_variable:n}
%
%  Invokes a variable
%
%    \begin{macrocode}
\cs_new_protected:Nn \stex_invoke_variable:n {
  \if_mode_math:
    \exp_after:wN \_@@_invoke_math:n
  \else:
    \exp_after:wN \_@@_invoke_text:n
  \fi: {#1}
}

\cs_new_protected:Nn \_@@_invoke_text:n {
  \peek_charcode_remove:NTF ! {
    \_@@_invoke_op_custom:nn {#1}
  }{
    \_@@_invoke_custom:nn {#1}
  }
}


\cs_new_protected:Nn \_@@_invoke_math:n {
  \peek_charcode_remove:NTF ! {
    \peek_charcode_remove:NTF ! {
      \peek_charcode:NTF [ {
        % TODO throw error
      }{
        \_@@_invoke_op_custom:nn
      }
    }{
      \_@@_invoke_op:n { #1 }
    }
  }{
    \peek_charcode_remove:NTF * {
      \_@@_invoke_custom:nn { #1 }
    }{
      \_@@_invoke_math_ii:n { #1 }
    }
  }
}

\cs_new_protected:Nn \_@@_invoke_op_custom:nn {
  \exp_args:Nnx \use:nn {
    \def\comp{\_varcomp}
    \str_set:Nn \STEXInternalCurrentSymbolStr { var://#1 }
    \bool_set_false:N \l_stex_allow_semantic_bool
    \_stex_term_omv:nn {var://#1}{
      \comp{ #2 }
    }
  }{
    \_stex_reset:N \comp
    \_stex_reset:N \STEXInternalCurrentSymbolStr
    \bool_set_true:N \l_stex_allow_semantic_bool
  }
}

\cs_new_protected:Nn \_@@_invoke_op:n {
  \cs_if_exist:cTF {
    stex_var_op_notation_ #1 _cs
  }{
    \exp_args:Nnx \use:nn {
      \def\comp{\_varcomp}
      \str_set:Nn \STEXInternalCurrentSymbolStr { var://#1 }
      \_stex_term_omv:nn { var://#1 }{
        \use:c{stex_var_op_notation_ #1 _cs }
      }
    }{
      \_stex_reset:N \comp
      \_stex_reset:N \STEXInternalCurrentSymbolStr
    }
  }{
    \int_compare:nNnTF {\prop_item:cn {l_stex_symdecl_var://#1_prop}{arity}} = 0{
      \_@@_invoke_math_ii:n {#1}
    }{
      \msg_error:nnxx{stex}{error/noop}{variable~#1}{}
    }
  }
}

\cs_new_protected:Npn \_@@_invoke_math_ii:n  #1 {
  \cs_if_exist:cTF {
    stex_var_notation_#1_cs
  }{
    \tl_set:Nx \STEXInternalSymbolAfterInvokationTL {
      \_stex_reset:N \comp
      \_stex_reset:N \STEXInternalSymbolAfterInvokationTL
      \_stex_reset:N \STEXInternalCurrentSymbolStr
      \bool_set_true:N \l_stex_allow_semantic_bool
    }
    \def\comp{\_varcomp}
    \str_set:Nn \STEXInternalCurrentSymbolStr { var://#1 }
    \bool_set_false:N \l_stex_allow_semantic_bool
    \use:c{stex_var_notation_#1_cs}
  }{
    \msg_error:nnxx{stex}{error/nonotation}{variable~#1}{s}
  }
}

\cs_new_protected:Nn \_@@_invoke_custom:nn {
  \exp_args:Nnx \use:nn {
    \def\comp{\_varcomp}
    \str_set:Nn \STEXInternalCurrentSymbolStr { var://#1 }
    \prop_clear:N \l__stex_terms_custom_args_prop
    \prop_put:Nnn \l__stex_terms_custom_args_prop {currnum} {1}
    \prop_get:cnN {
      l_stex_symdecl_var://#1 _prop
    }{ args } \l_tmpa_str
    \prop_put:Nno \l__stex_terms_custom_args_prop {args} \l_tmpa_str
    \tl_set:Nn \arg { \__stex_terms_arg: }
    \str_if_empty:NTF \l_tmpa_str {
      \_stex_term_omv:nn {var://#1}{\ignorespaces#2}
    }{
      \str_if_in:NnTF \l_tmpa_str b {
        \_stex_term_ombind:nnn {var://#1}{}{\ignorespaces#2}
      }{
        \str_if_in:NnTF \l_tmpa_str B {
          \_stex_term_ombind:nnn {var://#1}{}{\ignorespaces#2}
        }{
          \_stex_term_oma:nnn {var://#1}{}{\ignorespaces#2}
        }
      }
    }
    % TODO check that all arguments exist
  }{
    \_stex_reset:N \STEXInternalCurrentSymbolStr
    \_stex_reset:N \arg
    \_stex_reset:N \comp
    \_stex_reset:N \l__stex_terms_custom_args_prop
    %\bool_set_true:N \l_stex_allow_semantic_bool
  }
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Sequences}
%    \begin{macrocode}
%<@@=stex_sequences>

\cs_new_protected:Nn \stex_invoke_sequence:n {
  \peek_charcode_remove:NTF ! {
    \_stex_term_omv:nn {varseq://#1}{
      \exp_args:Nnx \use:nn {
        \def\comp{\_varcomp}
        \str_set:Nn \STEXInternalCurrentSymbolStr {varseq://#1}
        \prop_item:cn{l_stex_symdecl_varseq://#1_prop}{notation}
      }{
        \_stex_reset:N \comp
        \_stex_reset:N \STEXInternalCurrentSymbolStr
      }
    }
  }{
    \bool_set_false:N \l_stex_allow_semantic_bool
    \def\comp{\_varcomp}
    \str_set:Nn \STEXInternalCurrentSymbolStr {varseq://#1}
    \tl_set:Nx \STEXInternalSymbolAfterInvokationTL {
      \_stex_reset:N \comp
      \_stex_reset:N \STEXInternalSymbolAfterInvokationTL
      \_stex_reset:N \STEXInternalCurrentSymbolStr
      \bool_set_true:N \l_stex_allow_semantic_bool
    }
    \use:c { stex_varseq_#1_cs }
  }
}
%    \end{macrocode}

%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
% \ifinfulldoc\else\printbibliography\fi
%
% \PrintIndex

% \endinput
% Local Variables:
% mode: doctex
% TeX-master: t
% End:
