% \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>
\providecommand\bibfolder{../../lib/bib}
\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}
%
% 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}{\_stex_term_math_oms:nnnn,\_stex_term_math_oma:nnnn,\_stex_term_math_omb:nnnn}
%   \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}{\_stex_term_math_arg:nnn}
%   \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}{\_stex_term_math_assoc_arg:nnnn}
%   \begin{syntax} \cs{stex_term_arg:nnn}\meta{int}\meta{prec}\meta{notation}\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}{\stex_highlight_term:nn}
%   \begin{syntax} \cs{stex_highlight_term:nn}\Arg{URI}\Arg{args}\end{syntax}
% Establishes a context for \cs{comp}. Stores the URI in a variable
% so that \cs{comp} knows which symbol governs the current notation.
% \end{function}
%
% \begin{function}{\comp, \compemph,\compemph@uri, \defemph, \defemph@uri, \symrefemph,\symrefemph@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~invocation~#1~not~allowed~in~notation~component~of~#2
}

%    \end{macrocode}
% \subsection{Symbol Invocations}
%
%
% \begin{macro}{\stex_invoke_symbol:n}
%
%  Invokes a semantic macro
%
%    \begin{macrocode}
\keys_define:nn { stex / terms } {
  lang    .tl_set_x:N = \l_@@_lang_str ,
  variant .tl_set_x:N = \l_@@_variant_str ,
  unknown .code:n     = \str_set:Nx 
      \l_@@_variant_str \l_keys_key_str
}

\cs_new_protected:Nn \_@@_args:n {
  \str_clear:N \l_@@_lang_str
  \str_clear:N \l_@@_variant_str
  
  \keys_set:nn { stex / terms } { #1 }
}

\cs_new:Nn \_@@_reset:N {
  \tl_if_exist:NTF #1 {
    \def \exp_not:N #1 { \exp_args:No \exp_not:n #1 }
  }{
    \let \exp_not:N #1 \exp_not:N \undefined
  }
}

\bool_new:N \l_@@_allow_semantic_bool
\bool_set_true:N \l_@@_allow_semantic_bool

\cs_new_protected:Nn \stex_invoke_symbol:n {
  \bool_if:NTF \l_@@_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}{\l_stex_current_symbol_str}
  }
}

\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 {
    \str_set:Nn \l_stex_current_symbol_str { #1 }
    \bool_set_false:N \l_@@_allow_semantic_bool
    \_stex_term_oms:nnn {#1 \c_hash_str\c_hash_str}{#1}{
      \comp{ #2 }
    }
  }{
    \_@@_reset:N \l_stex_current_symbol_str
    \bool_set_true:N \l_@@_allow_semantic_bool
  }
}

\cs_new_protected:Nn \_@@_find_notation:nn {
  \str_set:Nn \l_stex_current_symbol_str { #1 }
  \_@@_args:n { #2 }
  \seq_if_empty:cTF {
    l_stex_symdecl_ #1 _notations 
  } {
    \msg_error:nnxx{stex}{error/nonotation}{#1}{s}
  } {
    \bool_lazy_all:nTF {
      {\str_if_empty_p:N \l_@@_variant_str}
      {\str_if_empty_p:N \l_@@_lang_str}
    }{
      \seq_get_left:cN {l_stex_symdecl_#1_notations}\l_@@_variant_str
    }{
      \seq_if_in:cxTF {l_stex_symdecl_#1_notations}{
        \l_@@_variant_str \c_hash_str \l_@@_lang_str
      }{
        \str_set:Nx \l_@@_variant_str { \l_@@_variant_str \c_hash_str \l_@@_lang_str }
      }{
        \msg_error:nnxx{stex}{error/nonotation}{#1}{
          ~\l_@@_variant_str \c_hash_str \l_@@_lang_str
        }
      }
    }
  }
}

\cs_new_protected:Npn \_@@_invoke_op_notation:nw #1 [#2] {
  \_@@_find_notation:nn { #1 }{ #2 }
  \bool_set_false:N \l_@@_allow_semantic_bool
  \cs_if_exist:cTF {
    stex_op_notation_ #1 \c_hash_str \l_@@_variant_str _cs
  }{
    \use:c{stex_op_notation_ #1 \c_hash_str \l_@@_variant_str _cs}
  }{
    \msg_error:nnxx{stex}{error/noop}{#1}{\l_@@_variant_str}
  }
  \bool_set_true:N \l_@@_allow_semantic_bool
}

\cs_new_protected:Npn \_@@_invoke_notation:nw #1 [#2] {
  \_@@_find_notation:nn { #1 }{ #2 }
  \cs_if_exist:cTF {
    stex_notation_ #1 \c_hash_str \l_@@_variant_str _cs
  }{
    \tl_set:Nx \stex_symbol_after_invocation_tl {
      \_@@_reset:N \stex_symbol_after_invocation_tl
      \_@@_reset:N \l_stex_current_symbol_str
      \bool_set_true:N \l_@@_allow_semantic_bool
    }
    \bool_set_false:N \l_@@_allow_semantic_bool
    \use:c{stex_notation_ #1 \c_hash_str \l_@@_variant_str _cs}
  }{
    \msg_error:nnxx{stex}{error/nonotation}{#1}{
      ~\l_@@_variant_str
    }
  }
}

\prop_new:N \l_@@_custom_args_prop

\cs_new_protected:Nn \_@@_invoke_custom:nn {
  \exp_args:Nnx \use:nn {
    \bool_set_false:N \l_@@_allow_semantic_bool
    \str_set:Nn \l_stex_current_symbol_str { #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
    \prop_put:Nno \l_@@_custom_args_prop {args} \l_tmpa_str
    \tl_set:Nn \arg { \_@@_arg: }
    \str_if_empty:NTF \l_tmpa_str {
      \_stex_term_oms:nnn {#1}{#1}{#2}
    }{
      \str_if_in:NnTF \l_tmpa_str b {
        \_stex_term_ombind:nnn {#1}{#1}{#2}
      }{
        \str_if_in:NnTF \l_tmpa_str B {
          \_stex_term_ombind:nnn {#1}{#1}{#2}
        }{
          \_stex_term_oma:nnn {#1}{#1}{#2}
        }
      }
    }
    % TODO check that all arguments exist
  }{
    \_@@_reset:N \l_stex_current_symbol_str
    \_@@_reset:N \arg
    \_@@_reset:N \l_@@_custom_args_prop
    \bool_set_true:N \l_@@_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 }
    \exp_args:NNx \prop_if_in:NnT \l_@@_custom_args_prop {\int_use:N \l_tmpa_int} {
      % TODO throw error
    }
  }
  \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} {
    % TODO throw error
  }
  \IfBooleanTF#1{
    \stex_annotate_invisible:n {
      \exp_args:No \_stex_term_arg:nn {\l_stex_current_symbol_str}{#3}
    }
  }{
    \exp_args:No \_stex_term_arg:nn {\l_stex_current_symbol_str}{#3}
  }
}


\cs_new_protected:Nn \_stex_term_arg:nn {
  \exp_args:Nnx \use:nn {
    \bool_set_true:N \l_@@_allow_semantic_bool
    \stex_annotate:nnn{ arg }{ #1 }{ #2 }
  }{
    \bool_set_false:N \l_@@_allow_semantic_bool
  }
}

\cs_new_protected:Nn \_stex_term_math_arg:nnn {
  \exp_args:Nnx \use:nn
    { \int_set:Nn \l_@@_downprec { #2 } 
        \_stex_term_arg:nn { #1 }{ #3 }
    }
    { \int_set:Nn \exp_not:N \l_@@_downprec { \int_use:N \l_@@_downprec } }
}


%    \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}{\_stex_term_math_oms:nnnn}
%    \begin{macrocode}
\cs_new_protected:Nn \_stex_term_oms:nnn {
  \stex_annotate:nnn{ OMID }{ #2 }{
    \stex_highlight_term:nn { #1 } { #3 } 
  }
}

\cs_new_protected:Nn \_stex_term_math_oms:nnnn {
  \_@@_maybe_brackets:nn { #3 }{ 
    \_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{ OMID }{ #1 }{
    \stex_highlight_term:nn { #1 } { #2 } 
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\_stex_term_math_oma:nnnn}
%    \begin{macrocode}
\cs_new_protected:Nn \_stex_term_oma:nnn {
  \stex_annotate:nnn{ OMA }{ #2 }{
    \stex_highlight_term:nn { #1 } { #3 } 
  }
}

\cs_new_protected:Nn \_stex_term_math_oma:nnnn {
  \_@@_maybe_brackets:nn { #3 }{ 
    \_stex_term_oma:nnn { #1 } { #1\c_hash_str#2 } { #4 }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\_stex_term_math_omb:nnnn}
%    \begin{macrocode}
\cs_new_protected:Nn \_stex_term_ombind:nnn {
  \stex_annotate:nnn{ OMBIND }{ #2 }{
    \stex_highlight_term:nn { #1 } { #3 }
  }
}

\cs_new_protected:Nn \_stex_term_math_omb:nnnn {
  \_@@_maybe_brackets:nn { #3 }{ 
    \_stex_term_ombind:nnn { #1 } { #1\c_hash_str#2 } { #4 }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\_stex_term_math_assoc_arg:nnnn}
%    \begin{macrocode}
\cs_new_protected:Nn \_stex_term_math_assoc_arg:nnnn {
  % TODO sequences
  \clist_set:Nn \l_tmpa_clist{ #3 }
  \int_compare:nNnTF { \clist_count:N \l_tmpa_clist } < 2 {
    \tl_set:Nn \l_tmpa_tl { #3 }
  }{
    \cs_set:Npn \l_tmpa_cs ##1 ##2 { #4 }
    \clist_reverse:N \l_tmpa_clist
    \clist_pop:NN \l_tmpa_clist \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 { ##1 } \l_tmpa_tl 
      }
    }
  }
  \exp_args:Nnno
   \_stex_term_math_arg:nnn{#1}{#2}\l_tmpa_tl
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\stex_term_custom:nn}
%    \begin{macrocode}
\cs_new_protected:Nn \stex_term_custom:nn {
  \str_set:Nn \l_@@_custom_uri { #1 }
  \str_set:Nn \l_tmpa_str { #2 }
  \tl_clear:N \l_tmpa_tl
  \int_zero:N \l_tmpa_int
  \int_set:Nn \l_tmpb_int { \str_count:N \l_tmpa_str }
  \_@@_custom_loop:
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\_@@_custom_loop:}
%    \begin{macrocode}
\cs_new_protected:Nn \_@@_custom_loop: {
  \bool_set_false:N \l_tmpa_bool
  \bool_while_do:nn {
    \str_if_eq_p:ee X {
      \str_item:Nn \l_tmpa_str { \l_tmpa_int + 1 }
    }
  }{
    \int_incr:N \l_tmpa_int
  }

  \peek_charcode:NTF [ {
    % notation/text component
    \_@@_custom_component:w
  } {
    \int_compare:nNnTF \l_tmpa_int = \l_tmpb_int {
      % all arguments read => finish
      \_@@_custom_final:
    } {
      % arguments missing
      \peek_charcode_remove:NTF * {
        % invisible, specific argument position or both
        \peek_charcode:NTF [ {
          % visible specific argument position
          \_@@_custom_arg:wn
        } {
          % invisible
          \peek_charcode_remove:NTF * {
            % invisible specific argument position
            \_@@_custom_arg_inv:wn
          } {
            % invisible next argument
            \_@@_custom_arg_inv:wn [ \l_tmpa_int + 1 ]
          }
        } 
      } {
        % next normal argument
        \_@@_custom_arg:wn [ \l_tmpa_int + 1 ]
      }
    }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\_@@_custom_arg_inv:wn}
%    \begin{macrocode}
\cs_new_protected:Npn \_@@_custom_arg_inv:wn [ #1 ] #2 {
  \bool_set_true:N \l_tmpa_bool
  \_@@_custom_arg:wn [ #1 ] { #2 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\_@@_custom_arg:wn}
%    \begin{macrocode}
\cs_new_protected:Npn \_@@_custom_arg:wn [ #1 ] #2 {
  \str_set:Nx \l_tmpb_str { 
    \str_item:Nn \l_tmpa_str { #1 }
  }
  \str_case:VnTF \l_tmpb_str {
    { X } {
      \msg_error:nnx{stex}{error/notationarg}{\l_@@_custom_uri}
    }
    { i } { \_@@_custom_set_X:n { #1 } }
    { b } { \_@@_custom_set_X:n { #1 } }
    { a } { \_@@_custom_set_X:n { #1 } } % TODO ?
    { B } { \_@@_custom_set_X:n { #1 } } % TODO ?
  }{}{
    \msg_error:nnx{stex}{error/notationarg}{\l_@@_custom_uri}
  }

  \bool_if:nTF \l_tmpa_bool {
    \tl_put_right:Nx \l_tmpa_tl {
      \stex_annotate_invisible:n {
        \_stex_term_arg:nn { \int_eval:n { #1 } } 
          \exp_not:n { { #2 } }
      }
    }
  } {
    \tl_put_right:Nx \l_tmpa_tl {
      \_stex_term_arg:nn { \int_eval:n { #1 } } 
        \exp_not:n { { #2 } }
    }
  }

  \_@@_custom_loop:
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\_@@_custom_set_X:n}
%    \begin{macrocode}
\cs_new_protected:Nn \_@@_custom_set_X:n {
  \str_set:Nx \l_tmpa_str {
    \str_range:Nnn \l_tmpa_str 1 { #1 - 1 }
    X
    \str_range:Nnn \l_tmpa_str { #1 + 1 } { -1 }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\_@@_custom_component:}
%    \begin{macrocode}
\cs_new_protected:Npn \_@@_custom_component:w [ #1 ] {
  \tl_put_right:Nn \l_tmpa_tl { \comp{ #1 } }
  \_@@_custom_loop:
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\_@@_custom_final:}
%    \begin{macrocode}
\cs_new_protected:Nn \_@@_custom_final: {
  \int_compare:nNnTF \l_tmpb_int = 0 {
    \exp_args:Nnno \_stex_term_oms:nnn
  }{
    \str_if_in:NnTF \l_tmpa_str {b} {
      \exp_args:Nnno \_stex_term_ombind:nnn
    } {
      \exp_args:Nnno \_stex_term_oma:nnn
    }
  }
  { \l_@@_custom_uri } { \l_@@_custom_uri } { \l_tmpa_tl }
}
%    \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 }!{
    \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 }!{
    \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}{\stex_highlight_term:nn}
%    \begin{macrocode}

\str_new:N \l_stex_current_symbol_str
\cs_new_protected:Nn \stex_highlight_term:nn {
  \exp_args:Nnx
  \use:nn {
    \str_set:Nx \l_stex_current_symbol_str { #1 }
    #2
  } {
    \str_set:Nx \exp_not:N \l_stex_current_symbol_str
      { \l_stex_current_symbol_str }
  }
}

\cs_new_protected:Nn \stex_unhighlight_term:n {
%  \latexml_if:TF {
%    #1
%  } {
%    \rustex_if:TF {
%      #1
%    } {
      #1 %\iffalse{{\fi}} #1 {{\iffalse}}\fi
%    }
%  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\comp,\compemph@uri,\compemph,\defemph,\defemph@uri,\symrefemph,\symrefemph@uri}
%    \begin{macrocode}
\cs_new_protected:Npn \comp #1 {
  \str_if_empty:NF \l_stex_current_symbol_str {
    \rustex_if:TF {
      \stex_annotate:nnn { comp }{ \l_stex_current_symbol_str }{ #1 }
    }{
      \exp_args:Nnx \compemph@uri { #1 } { \l_stex_current_symbol_str }
    }
  }
}

\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 {
    \textbf{#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 {
  %TODO
}


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

\cs_new_protected:Nn \_@@_invoke_op:n {
  \cs_if_exist:cTF {
    stex_var_op_notation_ #1 _cs
  }{
    \use:c{stex_var_op_notation_ #1  _cs }
  }{
    \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
  }{
    \str_set:Nn \l_stex_current_symbol_str { #1 }
    \use:c{stex_var_notation_#1_cs}
  }{
    \msg_error:nnxx{stex}{error/nonotation}{variable~#1}{s}
  }
}
%    \end{macrocode}
% \end{macro}
%
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex

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