% \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-Structural Features
% 	\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-features} 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-features}
% \fi
%
% \begin{documentation}\label{pkg:features:doc}
% \changes{3.1.0}{2022/03/03}{Implemented mathstructures and instantiations}
%
% Code related to structural features
%
% \section{Macros and Environments}\label{pkg:features:doc:macros}
%
% \subsection{Structures}
%
% \begin{environment}{mathstructure}
%   TODO
% \end{environment}
%
% \end{documentation}
%
% \begin{implementation}\label{pkg:features:impl}
%
% \section{\sTeX-Structural Features Implementation}
%
%    \begin{macrocode}
%<*package>

%%%%%%%%%%%%%   features.dtx   %%%%%%%%%%%%%

%    \end{macrocode}
%
% Warnings and error messages
%
%    \begin{macrocode}
\msg_new:nnn{stex}{error/copymodule/notallowed}{
  Symbol~#1~can~not~be~assigned~in~copymodule~#2
}
\msg_new:nnn{stex}{error/interpretmodule/nodefiniens}{
  Symbol~#1~not~assigned~in~interpretmodule~#2
}

\msg_new:nnn{stex}{error/unknownstructure}{
  No~structure~#1~found!
}

\msg_new:nnn{stex}{error/unknownfield}{
  No~field~#1~in~instance~#2~found!\\#3
}

\msg_new:nnn{stex}{error/keyval}{
  Invalid~key=value~pair:#1
}
\msg_new:nnn{stex}{error/instantiate/missing}{
  Assignments~missing~in~instantiate:~#1
}
\msg_new:nnn{stex}{error/incompatible}{
  Incompatible~signature:~#1~(#2)~and~#3~(#4)
}

%    \end{macrocode}
%
% \subsection{Imports with modification}
%
%    \begin{macrocode}
%<@@=stex_copymodule>
\cs_new_protected:Nn \stex_get_symbol_in_seq:nn {
  \tl_if_head_eq_catcode:nNTF { #1 } \relax {
    \tl_set:Nn \l_tmpa_tl { #1 }
    \_@@_get_symbol_from_cs:
  }{
    % argument is a string
    % is it a command name?
    \cs_if_exist:cTF { #1 }{
      \cs_set_eq:Nc \l_tmpa_tl { #1 }
      \str_set:Nx \l_tmpa_str { \cs_argument_spec:N \l_tmpa_tl }
      \str_if_empty:NTF \l_tmpa_str {
        \exp_args:Nx \cs_if_eq:NNTF {
          \tl_head:N \l_tmpa_tl
        } \stex_invoke_symbol:n {
          \_@@_get_symbol_from_cs:n{ #2 }
        }{
          \_@@_get_symbol_from_string:nn { #1 }{ #2 }
        }
      } {
        \_@@_get_symbol_from_string:nn { #1 }{ #2 }
      }
    }{
      % argument is not a command name
      \_@@_get_symbol_from_string:nn { #1 }{ #2 }
      % \l_stex_all_symbols_seq
    }
  }
}

\cs_new_protected:Nn \_@@_get_symbol_from_string:nn {
  \str_set:Nn \l_tmpa_str { #1 }
  \bool_set_false:N \l_tmpa_bool
  \bool_if:NF \l_tmpa_bool {
    \tl_set:Nn \l_tmpa_tl {
      \msg_error:nnn{stex}{error/unknownsymbol}{#1}
    }
    \str_set:Nn \l_tmpa_str { #1 }
    \int_set:Nn \l_tmpa_int { \str_count:N \l_tmpa_str }
    \seq_map_inline:Nn #2 {
      \str_set:Nn \l_tmpb_str { ##1 }
      \str_if_eq:eeT { \l_tmpa_str } {
        \str_range:Nnn \l_tmpb_str { -\l_tmpa_int } { -1 }
      } {
        \seq_map_break:n {
          \tl_set:Nn \l_tmpa_tl {
            \str_set:Nn \l_stex_get_symbol_uri_str {
              ##1
            }
          }
        }
      }
    }
    \l_tmpa_tl
  }
}

\cs_new_protected:Nn \_@@_get_symbol_from_cs:n {
  \exp_args:NNx \tl_set:Nn \l_tmpa_tl 
    { \tl_tail:N \l_tmpa_tl }
  \tl_if_single:NTF \l_tmpa_tl {
    \exp_args:No \tl_if_head_is_group:nTF \l_tmpa_tl {
      \exp_after:wN \str_set:Nn \exp_after:wN
        \l_stex_get_symbol_uri_str \l_tmpa_tl
      \_@@_get_symbol_check:n { #1 }
    }{
      % TODO
      % tail is not a single group
    }
  }{
    % TODO
    % tail is not a single group
  }
}

\cs_new_protected:Nn \_@@_get_symbol_check:n {
  \exp_args:NNx \seq_if_in:NnF #1 \l_stex_get_symbol_uri_str {
    \msg_error:nnxx{stex}{error/copymodule/notallowed}{\l_stex_get_symbol_uri_str}{
      :~\seq_use:Nn #1 {,~}
    }
  }
}

\cs_new_protected:Nn \stex_copymodule_start:nnnn {
  % import module
  \stex_import_module_uri:nn { #1 } { #2 }
  \str_set:Nx \l_stex_current_copymodule_name_str {#3}
  \stex_import_require_module:nnnn 
    { \l_stex_import_ns_str } { \l_stex_import_archive_str } 
    { \l_stex_import_path_str } { \l_stex_import_name_str }

  \stex_collect_imports:n {\l_stex_import_ns_str ?\l_stex_import_name_str }
  \seq_set_eq:NN \l_@@_copymodule_modules_seq \l_stex_collect_imports_seq

  % fields
  \seq_clear:N \l_@@_copymodule_fields_seq
  \seq_map_inline:Nn \l_@@_copymodule_modules_seq {
    \seq_map_inline:cn {c_stex_module_##1_constants}{
      \exp_args:NNx \seq_put_right:Nn \l_@@_copymodule_fields_seq {
        ##1 ? ####1
      }
    }
  }

  % setup prop
  \seq_clear:N \l_tmpa_seq
  \exp_args:NNx \prop_set_from_keyval:Nn \l_stex_current_copymodule_prop {
    name      = \l_stex_current_copymodule_name_str ,
    module    = \l_stex_current_module_str ,
    from      = \l_stex_import_ns_str ?\l_stex_import_name_str ,
    includes  = \l_tmpa_seq %,
  %  fields    = \l_tmpa_seq
  }
  \stex_debug:nn{copymodule}{#4~for~module~{\l_stex_import_ns_str ?\l_stex_import_name_str}
    as~\l_stex_current_module_str?\l_stex_current_copymodule_name_str}
    \stex_debug:nn{copymodule}{modules:\seq_use:Nn \l_@@_copymodule_modules_seq {,~}}
  \stex_debug:nn{copymodule}{fields:\seq_use:Nn \l_@@_copymodule_fields_seq {,~}}

  \stex_if_do_html:T {
    \begin{stex_annotate_env} {#4} {
      \l_stex_current_module_str?\l_stex_current_copymodule_name_str
    }
    \stex_annotate_invisible:nnn{domain}{\l_stex_import_ns_str ?\l_stex_import_name_str}{}
  }
}

\cs_new_protected:Nn \stex_copymodule_end:n {
  % apply to every field
  \def \l_tmpa_cs ##1 ##2 {#1}
  
  \tl_clear:N \_@@_module_tl
  \tl_clear:N \_@@_exec_tl

  %\prop_get:NnN \l_stex_current_copymodule_prop {fields} \l_tmpa_seq
  \seq_clear:N \_@@_fields_seq

  \seq_map_inline:Nn \l_@@_copymodule_modules_seq {
    \seq_map_inline:cn {c_stex_module_##1_constants}{

      \tl_clear:N \_@@_curr_symbol_tl % <- wrap in current symbol html
      \l_tmpa_cs{##1}{####1}

      \str_if_exist:cTF {l_@@_copymodule_##1?####1_name_str} {
        \str_set_eq:Nc \_@@_curr_name_str {l_@@_copymodule_##1?####1_name_str}
        \stex_if_do_html:T {
          \tl_put_right:Nx \_@@_curr_symbol_tl {
            \stex_annotate_invisible:nnn{alias}{\use:c{l_@@_copymodule_##1?####1_name_str}}{}
          }
        }
      }{
        \str_set:Nx \_@@_curr_name_str { \l_stex_current_copymodule_name_str / ####1 }
      }

      \prop_set_eq:Nc \l_tmpa_prop {l_stex_symdecl_ ##1?####1 _prop}
      \prop_put:Nnx \l_tmpa_prop { name } \_@@_curr_name_str
      \prop_put:Nnx \l_tmpa_prop { module } \l_stex_current_module_str

      \tl_if_exist:cT {l_@@_copymodule_##1?####1_def_tl}{
        \stex_if_do_html:T {
          \tl_put_right:Nx \_@@_curr_symbol_tl {
            $\stex_annotate_invisible:nnn{definiens}{}{\exp_after:wN \exp_not:N\csname l_@@_copymodule_##1?####1_def_tl\endcsname}$
          }
        }
        \prop_put:Nnn \l_tmpa_prop { defined } { true }
      }

      \stex_add_constant_to_current_module:n \_@@_curr_name_str
      \tl_put_right:Nx \_@@_module_tl {
        \seq_clear:c {l_stex_symdecl_ \l_stex_current_module_str ? \_@@_curr_name_str _notations}
        \prop_set_from_keyval:cn {
          l_stex_symdecl_\l_stex_current_module_str ? \_@@_curr_name_str _prop
        }{
          \prop_to_keyval:N \l_tmpa_prop
        }
      }

      \str_if_exist:cT {l_@@_copymodule_##1?####1_macroname_str} {
        \stex_if_do_html:T {
          \tl_put_right:Nx \_@@_curr_symbol_tl {
            \stex_annotate_invisible:nnn{macroname}{\use:c{l_@@_copymodule_##1?####1_macroname_str}}{}
          }
        }
        \tl_put_right:Nx \_@@_module_tl {
          \tl_set:cx {\use:c{l_@@_copymodule_##1?####1_macroname_str}}{
            \stex_invoke_symbol:n {
              \l_stex_current_module_str ? \_@@_curr_name_str
            }
          }
        }
      }

      \seq_put_right:Nx \_@@_fields_seq {\l_stex_current_module_str ? \_@@_curr_name_str }

      \tl_put_right:Nx \_@@_exec_tl {
        \stex_copy_notations:nn {\l_stex_current_module_str ? \_@@_curr_name_str} { ##1 ? ####1 }
      }

      \tl_put_right:Nx \_@@_exec_tl {
        \stex_if_do_html:TF{
          \stex_annotate_invisible:nnn{assignment} {##1?####1} { \exp_after:wN \exp_not:n \exp_after:wN {\_@@_curr_symbol_tl} }
        }{
          \exp_after:wN \exp_not:n \exp_after:wN {\_@@_curr_symbol_tl}
        }
      }
    }
  }


  \prop_put:Nno \l_stex_current_copymodule_prop {fields} \_@@_fields_seq
  \tl_put_left:Nx \_@@_module_tl {
    \prop_set_from_keyval:cn {
      l_stex_copymodule_ \l_stex_current_module_str?\l_stex_current_copymodule_name_str _prop
    }{
      \prop_to_keyval:N \l_stex_current_copymodule_prop
    }
  }

  \seq_gput_right:cx{c_stex_module_\l_stex_current_module_str _copymodules}{
    \l_stex_current_module_str?\l_stex_current_copymodule_name_str
  }

  \exp_args:No \stex_execute_in_module:n \_@@_module_tl
  \stex_debug:nn{copymodule}{result:\meaning \_@@_module_tl}
  \stex_debug:nn{copymodule}{output:\meaning \_@@_exec_tl}

  \_@@_exec_tl
  \stex_if_do_html:T {
    \end{stex_annotate_env}
  }
}

\NewDocumentEnvironment {copymodule} { O{} m m}{
  \stex_copymodule_start:nnnn { #1 }{ #2 }{ #3 }{ copymodule }
  \stex_deactivate_macro:Nn \symdecl {module~environments}
  \stex_deactivate_macro:Nn \symdef {module~environments}
  \stex_deactivate_macro:Nn \notation {module~environments}
  \stex_reactivate_macro:N \assign
  \stex_reactivate_macro:N \renamedecl
  \stex_reactivate_macro:N \donotcopy
  \stex_smsmode_do:
}{
  \stex_copymodule_end:n {}
}

\NewDocumentEnvironment {interpretmodule} { O{} m m}{
  \stex_copymodule_start:nnnn { #1 }{ #2 }{ #3 }{ interpretmodule }
  \stex_deactivate_macro:Nn \symdecl {module~environments}
  \stex_deactivate_macro:Nn \symdef {module~environments}
  \stex_deactivate_macro:Nn \notation {module~environments}
  \stex_reactivate_macro:N \assign
  \stex_reactivate_macro:N \renamedecl
  \stex_reactivate_macro:N \donotcopy
  \stex_smsmode_do:
}{
  \stex_copymodule_end:n {
    \tl_if_exist:cF {
      l_@@_copymodule_##1?##2_def_tl
    }{
      \str_if_eq:eeF {
        \prop_item:cn{
          l_stex_symdecl_ ##1 ? ##2 _prop }{ defined }
      }{ true }{
        \msg_error:nnxx{stex}{error/interpretmodule/nodefiniens}{
          ##1?##2
        }{\l_stex_current_copymodule_name_str}
      }
    }
  }
}

\iffalse \begin{stex_annotate_env} \fi
\NewDocumentEnvironment {realization} { O{} m}{
  \stex_copymodule_start:nnnn { #1 }{ #2 }{ #2 }{ realize }
  \stex_deactivate_macro:Nn \symdecl {module~environments}
  \stex_deactivate_macro:Nn \symdef {module~environments}
  \stex_deactivate_macro:Nn \notation {module~environments}
  \stex_reactivate_macro:N \donotcopy
  \stex_reactivate_macro:N \assign
  \stex_smsmode_do:
}{
  \stex_import_module_uri:nn { #1 } { #2 }
  \tl_clear:N \_@@_exec_tl
  \tl_set:Nx \_@@_module_tl {
    \stex_import_require_module:nnnn 
      { \l_stex_import_ns_str } { \l_stex_import_archive_str } 
      { \l_stex_import_path_str } { \l_stex_import_name_str }
  }
  \exp_args:Nx \stex_add_import_to_current_module:n{
    \l_stex_import_ns_str ? \l_stex_import_name_str
  }
  
  \seq_map_inline:Nn \l_@@_copymodule_modules_seq {
    \seq_map_inline:cn {c_stex_module_##1_constants}{
      \str_set:Nx \_@@_curr_name_str { \l_stex_current_copymodule_name_str / ####1 }
      \tl_if_exist:cT {l_@@_copymodule_##1?####1_def_tl}{
        \stex_if_do_html:T {
          \tl_put_right:Nx \_@@_exec_tl {
            \stex_annotate_invisible:nnn{assignment} {##1?####1} {
              $\stex_annotate_invisible:nnn{definiens}{}{\exp_after:wN \exp_not:N\csname l_@@_copymodule_##1?####1_def_tl\endcsname}$
             }
          }
        }
        \tl_put_right:Nx \_@@_module_tl {
          \prop_put:cnn {l_stex_symdecl_##1?####1_prop}{ defined }{ true }
        }
      }
  }}

  \exp_args:No \stex_execute_in_module:n \_@@_module_tl

  \_@@_exec_tl
  \stex_if_do_html:T {\end{stex_annotate_env}}
}

\NewDocumentCommand \donotcopy { m }{
  \str_clear:N \l_stex_import_name_str
  \str_set:Nn \l_tmpa_str { #1 }
  \int_set:Nn \l_tmpa_int { \str_count:N \l_tmpa_str }
  \seq_map_inline:Nn \l_stex_all_modules_seq {
    \str_set:Nn \l_tmpb_str { ##1 }
    \str_if_eq:eeT { \l_tmpa_str } {
      \str_range:Nnn \l_tmpb_str { -\l_tmpa_int } { -1 }
    } {
      \seq_map_break:n {
        \stex_if_do_html:T {
          \stex_if_smsmode:F {
            \stex_annotate_invisible:nnn{donotcopy}{##1}{
              \stex_annotate:nnn{domain}{##1}{}
            }
          }
        }
        \str_set_eq:NN \l_stex_import_name_str \l_tmpb_str
      }
    }
    \seq_map_inline:cn {c_stex_module_##1_copymodules}{
      \str_set:Nn \l_tmpb_str { ####1 }
      \str_if_eq:eeT { \l_tmpa_str } {
        \str_range:Nnn \l_tmpb_str { -\l_tmpa_int } { -1 }
      } {
        \seq_map_break:n {\seq_map_break:n {
          \stex_if_do_html:T {
            \stex_if_smsmode:F {
              \stex_annotate_invisible:nnn{donotcopy}{####1}{
                \stex_annotate:nnn{domain}{
                  \prop_item:cn {l_stex_copymodule_ ####1 _prop}{module}
                }{}
              }
            }
          }
          \str_set:Nx \l_stex_import_name_str {
            \prop_item:cn {l_stex_copymodule_ ####1 _prop}{module}
          }
        }}
      }
    }
  }
  \str_if_empty:NTF \l_stex_import_name_str {
    % TODO throw error
  }{
    \stex_collect_imports:n {\l_stex_import_name_str }
    \seq_map_inline:Nn \l_stex_collect_imports_seq {
      \seq_remove_all:Nn \l_@@_copymodule_modules_seq { ##1 }
      \seq_map_inline:cn {c_stex_module_##1_constants}{
        \seq_remove_all:Nn \l_@@_copymodule_fields_seq { ##1 ? ####1 }
        \bool_lazy_any:nT {
          { \cs_if_exist_p:c {l_@@_copymodule_##1?####1_name_str}}
          { \cs_if_exist_p:c {l_@@_copymodule_##1?####1_macroname_str}}
          { \cs_if_exist_p:c {l_@@_copymodule_##1?####1_def_tl}}
        }{
          % TODO throw error
        }
      }
    }
    \prop_get:NnN \l_stex_current_copymodule_prop { includes } \l_tmpa_seq
    \seq_put_right:Nx \l_tmpa_seq {\l_stex_import_name_str }
    \prop_put:Nno \l_stex_current_copymodule_prop {includes} \l_tmpa_seq
  }
  \stex_smsmode_do:
}

\NewDocumentCommand \assign { m m }{
  \stex_get_symbol_in_seq:nn {#1} \l_@@_copymodule_fields_seq
  \stex_debug:nn{assign}{defining~{\l_stex_get_symbol_uri_str}~as~\detokenize{#2}}
  \tl_set:cn {l_@@_copymodule_\l_stex_get_symbol_uri_str _def_tl}{#2}
  \stex_smsmode_do:
}

\keys_define:nn { stex / renamedecl } {
  name        .str_set_x:N  = \l_stex_renamedecl_name_str
}
\cs_new_protected:Nn \_@@_renamedecl_args:n {
  \str_clear:N \l_stex_renamedecl_name_str
  \keys_set:nn { stex / renamedecl } { #1 }
}

\NewDocumentCommand \renamedecl { O{} m m}{
  \_@@_renamedecl_args:n { #1 }
  \stex_get_symbol_in_seq:nn {#2} \l_@@_copymodule_fields_seq
  \stex_debug:nn{renamedecl}{renaming~{\l_stex_get_symbol_uri_str}~to~#3}
  \str_set:cx {l_@@_copymodule_\l_stex_get_symbol_uri_str _macroname_str}{#3}
  \str_if_empty:NTF \l_stex_renamedecl_name_str {
    \tl_set:cx { #3 }{ \stex_invoke_symbol:n {
      \l_stex_get_symbol_uri_str
    } }
  } {
    \str_set:cx {l_@@_copymodule_\l_stex_get_symbol_uri_str _name_str}{\l_stex_renamedecl_name_str}
    \stex_debug:nn{renamedecl}{@~\l_stex_current_module_str ? \l_stex_renamedecl_name_str}
    \prop_set_eq:cc {l_stex_symdecl_ 
      \l_stex_current_module_str ? \l_stex_renamedecl_name_str
      _prop
    }{l_stex_symdecl_ \l_stex_get_symbol_uri_str _prop}
    \seq_set_eq:cc {l_stex_symdecl_ 
      \l_stex_current_module_str ? \l_stex_renamedecl_name_str
      _notations
    }{l_stex_symdecl_ \l_stex_get_symbol_uri_str _notations}
    \prop_put:cnx {l_stex_symdecl_ 
      \l_stex_current_module_str ? \l_stex_renamedecl_name_str
      _prop
    }{ name }{ \l_stex_renamedecl_name_str }
    \prop_put:cnx {l_stex_symdecl_ 
      \l_stex_current_module_str ? \l_stex_renamedecl_name_str
      _prop
    }{ module }{ \l_stex_current_module_str }
    \exp_args:NNx \seq_put_left:Nn \l_@@_copymodule_fields_seq {
      \l_stex_current_module_str ? \l_stex_renamedecl_name_str
    }
    \tl_set:cx { #3 }{ \stex_invoke_symbol:n {
      \l_stex_current_module_str ? \l_stex_renamedecl_name_str
    } }
  }
  \stex_smsmode_do:
}

\stex_deactivate_macro:Nn \assign {copymodules}
\stex_deactivate_macro:Nn \renamedecl {copymodules}
\stex_deactivate_macro:Nn \donotcopy {copymodules}


%    \end{macrocode}
%
%
% \subsection{The feature environment}
%
% \begin{environment}{structural@feature}
%    \begin{macrocode}
%<@@=stex_features>

\NewDocumentEnvironment{structural_feature_module}{ m m m }{
  \stex_if_in_module:F {
    \msg_set:nnn{stex}{error/nomodule}{
      Structural~Feature~has~to~occur~in~a~module:\\
      Feature~#2~of~type~#1\\
      In~File:~\stex_path_to_string:N \g_stex_currentfile_seq
    }
    \msg_error:nn{stex}{error/nomodule}
  }

  \str_set_eq:NN \l_stex_feature_parent_str \l_stex_current_module_str

  \stex_module_setup:nn{meta=NONE}{#2 - #1}

  \stex_if_do_html:T {
    \begin{stex_annotate_env}{ feature:#1 }{\l_stex_feature_parent_str ? #2 - #1}
      \stex_annotate_invisible:nnn{header}{}{ #3 }
  }
}{
  \str_gset_eq:NN \l_stex_last_feature_str \l_stex_current_module_str
  \prop_gput:cnn {c_stex_module_ \l_stex_current_module_str _prop}{feature}{#1}
  \stex_debug:nn{features}{
    Feature: \l_stex_last_feature_str
  }
  \stex_if_do_html:T {
    \end{stex_annotate_env}
  }
}
%    \end{macrocode}
% \end{environment}
%
% \subsection{Structure}
%
% \begin{environment}{structure}
%    \begin{macrocode}
%<@@=stex_structures>
\cs_new_protected:Nn \stex_add_structure_to_current_module:nn {
  \prop_if_exist:cF {c_stex_module_\l_stex_current_module_str _structures}{
    \prop_new:c {c_stex_module_\l_stex_current_module_str _structures}
  }
  \prop_gput:cxx{c_stex_module_\l_stex_current_module_str _structures}
    {#1}{#2}
}

\keys_define:nn { stex / features / structure } {
  name         .str_set_x:N  = \l_@@_name_str ,
}

\cs_new_protected:Nn \_@@_structure_args:n {
  \str_clear:N \l_@@_name_str
  \keys_set:nn { stex / features / structure } { #1 }
}
\NewDocumentEnvironment{mathstructure}{m O{}}{
  \begin{mathstructure_inner}{#1}[#2]
    \stex_smsmode_do:
    \ignorespacesandpars
  }{\end{mathstructure_inner}}
\NewDocumentEnvironment{mathstructure_inner}{m O{}}{
  \_@@_structure_args:n { #2 }
  \str_if_empty:NT \l_@@_name_str {
    \str_set:Nx \l_@@_name_str { #1 }
  }
  \stex_suppress_html:n {
    \bool_set_true:N \l_stex_symdecl_make_macro_bool
    \exp_args:Nx \stex_symdecl_do:nn {
      name = \l_@@_name_str ,
      def  = {\STEXsymbol{module-type}{
        \STEXInternalTermMathOMSiiii { 
          \prop_item:cn {c_stex_module_\l_stex_current_module_str _prop}
            { ns } ? 
            \prop_item:cn {c_stex_module_\l_stex_current_module_str _prop}
              { name } / \l_@@_name_str - structure
         }{}{0}{}
      }}
    }{ #1 }
  }
  \exp_args:Nnnx
  \begin{structural_feature_module}{ structure }
    { \l_@@_name_str }{}
}{
  \end{structural_feature_module}
  \_stex_reset_up_to_module:n \l_stex_last_feature_str
  \exp_args:No \stex_collect_imports:n \l_stex_last_feature_str
  \seq_clear:N \l_tmpa_seq
  \seq_map_inline:Nn \l_stex_collect_imports_seq {
    \seq_map_inline:cn{c_stex_module_##1_constants}{
      \seq_put_right:Nn \l_tmpa_seq { ##1 ? ####1 }
    }
  }
  \exp_args:Nnno
  \prop_gput:cnn {c_stex_module_ \l_stex_last_feature_str _prop}{fields}\l_tmpa_seq
  \stex_debug:nn{structure}{Fields:~\seq_use:Nn \l_tmpa_seq ,}
  \stex_add_structure_to_current_module:nn
    \l_@@_name_str
    \l_stex_last_feature_str
    
  \stex_execute_in_module:x {
    \tl_set:cn { #1 }{
      \exp_not:N \stex_invoke_structure:nn {\l_stex_current_module_str }{ \l_@@_name_str}
    }
  }
}

\cs_new:Nn \stex_invoke_structure:nn {
  \stex_invoke_symbol:n { #1?#2 }
}

\cs_new_protected:Nn \stex_get_structure:n {
  \tl_if_head_eq_catcode:nNTF { #1 } \relax {
    \tl_set:Nn \l_tmpa_tl { #1 }
    \_@@_get_from_cs:
  }{
    \cs_if_exist:cTF { #1 }{
      \cs_set_eq:Nc \l_tmpa_cs { #1 }
      \str_set:Nx \l_tmpa_str {\cs_argument_spec:N \l_tmpa_cs }
      \str_if_empty:NTF \l_tmpa_str {
        \cs_if_eq:NNTF { \tl_head:N \l_tmpa_cs} \stex_invoke_structure:nn {
          \_@@_get_from_cs:
        }{
          \_@@_get_from_string:n { #1 }
        }
      }{
        \_@@_get_from_string:n { #1 }
      }
    }{
      \_@@_get_from_string:n { #1 }
    }
  }
}

\cs_new_protected:Nn \_@@_get_from_cs: {
  \exp_args:NNx \tl_set:Nn \l_tmpa_tl 
    { \tl_tail:N \l_tmpa_tl }
  \str_set:Nx \l_tmpa_str {
    \exp_after:wN \use_i:nn \l_tmpa_tl
  }
  \str_set:Nx \l_tmpb_str {
    \exp_after:wN \use_ii:nn \l_tmpa_tl
  }
  \str_set:Nx \l_stex_get_structure_str {
    \l_tmpa_str ? \l_tmpb_str
  }
  \str_set:Nx \l_stex_get_structure_module_str {
    \exp_args:Nno \prop_item:cn {c_stex_module_\l_tmpa_str _structures}{\l_tmpb_str}
  }
}

\cs_new_protected:Nn \_@@_get_from_string:n {
  \tl_set:Nn \l_tmpa_tl {
    \msg_error:nnn{stex}{error/unknownstructure}{#1}
  }
  \str_set:Nn \l_tmpa_str { #1 }
  \int_set:Nn \l_tmpa_int { \str_count:N \l_tmpa_str }

  \seq_map_inline:Nn \l_stex_all_modules_seq {
    \prop_if_exist:cT {c_stex_module_##1_structures} {
      \prop_map_inline:cn {c_stex_module_##1_structures} {
        \exp_args:No \str_if_eq:nnT \l_tmpa_str {####1}{
        %\str_if_eq:eeT { \l_tmpa_str }{ \str_range:nnn {##1?####1}{-\l_tmpa_int}{-1}}{
          \prop_map_break:n{\seq_map_break:n{
            \tl_set:Nn \l_tmpa_tl {
              \str_set:Nn \l_stex_get_structure_str {##1?####1}
              \str_set:Nn \l_stex_get_structure_module_str {####2}
            }
          }}
        }
      }
    }
  }
  \l_tmpa_tl
}
%    \end{macrocode}
% \end{environment}
%
%
% \begin{macro}{\instantiate}
%    \begin{macrocode}

\NewDocumentEnvironment{usestructure}{m}{
  \stex_get_structure:n {#1}
  \exp_args:Nnx \stex_debug:nn{features}{using~structure:~\l_stex_get_structure_module_str}
  \exp_args:No \stex_activate_module:n \l_stex_get_structure_module_str
}{}

\keys_define:nn { stex / instantiate } {
  name        .str_set_x:N  = \l_@@_name_str
}
\cs_new_protected:Nn \_@@_instantiate_args:n {
  \str_clear:N \l_@@_name_str
  \keys_set:nn { stex / instantiate } { #1 }
}

\NewDocumentEnvironment{extstructure}{m m O{}}{
  \begin{mathstructure_inner}{#1}[#3]
    \seq_set_split:Nnn\_@@_extstructure_imports_seq,{#2}
    \seq_map_inline:Nn\_@@_extstructure_imports_seq {
      \stex_get_structure:n {##1}
      \exp_args:Nnx \stex_debug:nn{features}{importing~structure:~\l_stex_get_structure_module_str{}~into~\l_stex_current_module_str}
      \exp_args:No \stex_activate_module:n \l_stex_get_structure_module_str
      \stex_if_smsmode:F {
        \stex_annotate_invisible:nnn 
          {import} {\l_stex_get_structure_module_str} {}
      }
      \exp_args:Nx \stex_add_import_to_current_module:n {
        \l_stex_get_structure_module_str
      }
      \exp_args:Nx \stex_add_to_current_module:n {
        \exp_args:No \stex_activate_module:n \l_stex_get_structure_module_str
      }
    }
    \stex_smsmode_do:
    \ignorespacesandpars
}{
  \end{mathstructure_inner}
}

\NewDocumentEnvironment{extstructure*}{m m O{}}{
  % TODO
  \begin{extstructure}{#1}{#2}[#3]
}{
  \end{extstructure}
}

\NewDocumentCommand \instantiate {m O{} m m O{}}{
  \begingroup
    \stex_get_structure:n {#3}
    \_@@_instantiate_args:n { #2 }
    \str_if_empty:NT \l_@@_name_str {
      \str_set:Nn \l_@@_name_str { #1 }
    }
    \exp_args:No \stex_activate_module:n \l_stex_get_structure_module_str
    \seq_clear:N \l_@@_fields_seq
    \exp_args:Nx \stex_collect_imports:n \l_stex_get_structure_module_str
    \seq_map_inline:Nn \l_stex_collect_imports_seq {
      \seq_map_inline:cn {c_stex_module_##1_constants}{
        \seq_put_right:Nx \l_@@_fields_seq { ##1 ? ####1 }
      }
    }

    \tl_if_empty:nF{#5}{
      \seq_set_split:Nnn \l_tmpa_seq , {#5}
      \prop_clear:N \l_tmpa_prop
      \seq_map_inline:Nn \l_tmpa_seq {
        \seq_set_split:Nnn \l_tmpb_seq = { ##1 }
        \int_compare:nNnF { \seq_count:N \l_tmpb_seq } = 2 {
          \msg_error:nnn{stex}{error/keyval}{##1}
        }
        \exp_args:Nx \stex_get_symbol_in_seq:nn {\seq_item:Nn \l_tmpb_seq 1} \l_@@_fields_seq
        \str_set_eq:NN \l_@@_dom_str \l_stex_get_symbol_uri_str
        \exp_args:NNx \seq_remove_all:Nn \l_@@_fields_seq \l_stex_get_symbol_uri_str
        \exp_args:Nx \stex_get_symbol:n {\seq_item:Nn \l_tmpb_seq 2}
        \exp_args:Nxx \str_if_eq:nnF 
          {\prop_item:cn{l_stex_symdecl_\l_@@_dom_str _prop}{args}}
          {\prop_item:cn{l_stex_symdecl_\l_stex_get_symbol_uri_str _prop}{args}}{
          \msg_error:nnxxxx{stex}{error/incompatible}
            {\l_@@_dom_str}
            {\prop_item:cn{l_stex_symdecl_\l_@@_dom_str _prop}{args}}
            {\l_stex_get_symbol_uri_str}
            {\prop_item:cn{l_stex_symdecl_\l_stex_get_symbol_uri_str _prop}{args}}
        }
        \prop_put:Nxx \l_tmpa_prop {\seq_item:Nn \l_tmpb_seq 1} \l_stex_get_symbol_uri_str
      }
    }

    \seq_map_inline:Nn \l_@@_fields_seq {
      \str_set:Nx \l_tmpa_str {field:\l_@@_name_str . \prop_item:cn {l_stex_symdecl_##1_prop}{name} }
      \stex_debug:nn{instantiate}{Field~\l_tmpa_str :~##1}

      \stex_add_constant_to_current_module:n {\l_tmpa_str}
      \stex_execute_in_module:x {
        \prop_set_from_keyval:cn { l_stex_symdecl_ \l_stex_current_module_str?\l_tmpa_str _prop}{
          name   = \l_tmpa_str ,
          args   = \prop_item:cn {l_stex_symdecl_##1_prop}{args} ,
          arity  = \prop_item:cn {l_stex_symdecl_##1_prop}{arity} ,
          assocs = \prop_item:cn {l_stex_symdecl_##1_prop}{assocs} ,
          argnames = {\prop_item:cn {l_stex_symdecl_##1_prop}{argnames}}
        }
        \seq_clear:c {l_stex_symdecl_\l_stex_current_module_str?\l_tmpa_str _notations}
      }

      \seq_if_empty:cF{l_stex_symdecl_##1_notations}{
        \stex_find_notation:nn{##1}{}
        \stex_execute_in_module:x {
          \seq_put_right:cn {l_stex_symdecl_\l_stex_current_module_str?\l_tmpa_str _notations}{\l_stex_notation_variant_str}
        }

        \stex_copy_control_sequence_ii:ccN
          {stex_notation_\l_stex_current_module_str?\l_tmpa_str\c_hash_str \l_stex_notation_variant_str _cs}
          {stex_notation_##1\c_hash_str \l_stex_notation_variant_str _cs}
          \l_tmpa_tl
        \exp_args:No \stex_execute_in_module:n \l_tmpa_tl

        
        \cs_if_exist:cT{stex_op_notation_##1\c_hash_str \l_stex_notation_variant_str _cs}{
          \tl_set_eq:Nc \l_tmpa_cs {stex_op_notation_##1\c_hash_str \l_stex_notation_variant_str _cs}
          \stex_execute_in_module:x {
            \tl_set:cn
            {stex_op_notation_\l_stex_current_module_str?\l_tmpa_str\c_hash_str \l_stex_notation_variant_str _cs}
            { \exp_args:No \exp_not:n \l_tmpa_cs}
          }
        }

      }

      \prop_put:Nxx \l_tmpa_prop {\prop_item:cn {l_stex_symdecl_##1_prop}{name}}{\l_stex_current_module_str?\l_tmpa_str}
    }
    
    \stex_execute_in_module:x {
      \prop_set_from_keyval:cn {l_stex_instance_\l_stex_current_module_str?\l_@@_name_str _prop}{
        domain = \l_stex_get_structure_module_str ,
        \prop_to_keyval:N \l_tmpa_prop
      }
      \tl_set:cn{ #1 }{\stex_invoke_instance:n{ \l_stex_current_module_str?\l_@@_name_str} }
    }
    \stex_debug:nn{instantiate}{
      Instance~\l_stex_current_module_str?\l_@@_name_str \\
      \prop_to_keyval:N \l_tmpa_prop
    }
    \exp_args:Nxx \stex_symdecl_do:nn {
      type={\STEXsymbol{module-type}{
        \STEXInternalTermMathOMSiiii {
          \l_stex_get_structure_module_str
        }{}{0}{}
      }}
    }{\l_@@_name_str}
%    {
      \str_set:Nx \l_stex_get_symbol_uri_str {\l_stex_current_module_str?\l_@@_name_str}
      \tl_set:Nn \l_stex_notation_after_do_tl {\__stex_notation_final:}
      \stex_notation_do:nnnnn{}{0}{}{}{\comp{#4}}
 %   }
    %\exp_args:Nx \notation{\l_@@_name_str}{\comp{#5}}
  \endgroup
  \stex_smsmode_do:\ignorespacesandpars
}

\cs_new_protected:Nn \stex_symbol_or_var:n {
  \cs_if_exist:cTF{#1}{
    \cs_set_eq:Nc \l_tmpa_tl { #1 }
    \str_set:Nx \l_tmpa_str { \cs_argument_spec:N \l_tmpa_tl }
    \str_if_empty:NTF \l_tmpa_str {
      \exp_args:Nx \cs_if_eq:NNTF { \tl_head:N \l_tmpa_tl }
        \stex_invoke_variable:n {
          \bool_set_true:N \l_stex_symbol_or_var_bool
          \bool_set_false:N \l_stex_instance_or_symbol_bool
          \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
          \tl_set:Nx \l_tmpa_tl {\exp_after:wN \use:n \l_tmpa_tl}
          \str_set:Nx \l_stex_get_symbol_uri_str {
            \exp_after:wN \use:n \l_tmpa_tl
          }
        }{ % TODO \stex_invoke_varinstance:n
          \exp_args:Nx \cs_if_eq:NNTF { \tl_head:N \l_tmpa_tl } \stex_invoke_varinstance:n {
            \bool_set_true:N \l_stex_symbol_or_var_bool
            \bool_set_true:N \l_stex_instance_or_symbol_bool
            \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
            \tl_set:Nx \l_tmpa_tl {\exp_after:wN \use:n \l_tmpa_tl}
            \str_set:Nx \l_stex_get_symbol_uri_str {
              \exp_after:wN \use:n \l_tmpa_tl
            }
          }{
            \bool_set_false:N \l_stex_symbol_or_var_bool
            \stex_get_symbol:n{#1}
          }
        }
    }{
      \_@@_symbolorvar_from_string:n{ #1 }
    }
  }{
    \_@@_symbolorvar_from_string:n{ #1 }
  }
}

\cs_new_protected:Nn \_@@_symbolorvar_from_string:n {
  \prop_if_exist:cTF {l_stex_symdecl_var://#1 _prop}{
    \bool_set_true:N \l_stex_symbol_or_var_bool
    \str_set:Nn \l_stex_get_symbol_uri_str { #1 }
  }{
    \bool_set_false:N \l_stex_symbol_or_var_bool
    \stex_get_symbol:n{#1}
  }
}

\keys_define:nn { stex / varinstantiate } {
  name        .str_set_x:N  = \l_@@_name_str,
  bind        .choices:nn   =
      {forall,exists}
      {\str_set:Nx \l_@@_bind_str {\l_keys_choice_tl}}

}
\cs_new_protected:Nn \_@@_varinstantiate_args:n {
  \str_clear:N \l_@@_name_str
  \str_clear:N \l_@@_bind_str
  \keys_set:nn { stex / varinstantiate } { #1 }
}

\NewDocumentCommand \varinstantiate {m O{} m m O{}}{
  \begingroup
    \stex_get_structure:n {#3}
    \_@@_varinstantiate_args:n { #2 }
    \str_if_empty:NT \l_@@_name_str {
      \str_set:Nn \l_@@_name_str { #1 }
    }
    \stex_if_do_html:TF{
      \stex_annotate:nnn{varinstance}{\l_@@_name_str}
    }{\use:n}
    {
      \stex_if_do_html:T{
        \stex_annotate_invisible:nnn{domain}{\l_stex_get_structure_module_str}{}
      }
      \seq_clear:N \l_@@_fields_seq
      \exp_args:Nx \stex_collect_imports:n \l_stex_get_structure_module_str
      \seq_map_inline:Nn \l_stex_collect_imports_seq {
        \seq_map_inline:cn {c_stex_module_##1_constants}{
          \seq_put_right:Nx \l_@@_fields_seq { ##1 ? ####1 }
        }
      }
      \exp_args:No \stex_activate_module:n \l_stex_get_structure_module_str
      \prop_clear:N \l_tmpa_prop
      \tl_if_empty:nF {#5} {
        \seq_set_split:Nnn \l_tmpa_seq , {#5}
        \seq_map_inline:Nn \l_tmpa_seq {
          \seq_set_split:Nnn \l_tmpb_seq = { ##1 }
          \int_compare:nNnF { \seq_count:N \l_tmpb_seq } = 2 {
            \msg_error:nnn{stex}{error/keyval}{##1}
          }
          \exp_args:Nx \stex_get_symbol_in_seq:nn {\seq_item:Nn \l_tmpb_seq 1} \l_@@_fields_seq
          \str_set_eq:NN \l_@@_dom_str \l_stex_get_symbol_uri_str
          \exp_args:NNx \seq_remove_all:Nn \l_@@_fields_seq \l_stex_get_symbol_uri_str
          \exp_args:Nx \stex_symbol_or_var:n {\seq_item:Nn \l_tmpb_seq 2}
          \stex_if_do_html:T{
            \stex_annotate:nnn{assign}{\l_@@_dom_str,
            \bool_if:NTF\l_stex_symbol_or_var_bool{var://}{}\l_stex_get_symbol_uri_str}{}
          }
          \bool_if:NTF \l_stex_symbol_or_var_bool {
            \exp_args:Nxx \str_if_eq:nnF 
              {\prop_item:cn{l_stex_symdecl_\l_@@_dom_str _prop}{args}}
              {\prop_item:cn{l_stex_symdecl_var://\l_stex_get_symbol_uri_str _prop}{args}}{
              \msg_error:nnxxxx{stex}{error/incompatible}
                {\l_@@_dom_str}
                {\prop_item:cn{l_stex_symdecl_\l_@@_dom_str _prop}{args}}
                {\l_stex_get_symbol_uri_str}
                {\prop_item:cn{l_stex_symdecl_var://\l_stex_get_symbol_uri_str _prop}{args}}
            }
            \prop_put:Nxx \l_tmpa_prop {\seq_item:Nn \l_tmpb_seq 1} {\stex_invoke_variable:n {\l_stex_get_symbol_uri_str}}
          }{
            \exp_args:Nxx \str_if_eq:nnF 
              {\prop_item:cn{l_stex_symdecl_\l_@@_dom_str _prop}{args}}
              {\prop_item:cn{l_stex_symdecl_\l_stex_get_symbol_uri_str _prop}{args}}{
              \msg_error:nnxxxx{stex}{error/incompatible}
                {\l_@@_dom_str}
                {\prop_item:cn{l_stex_symdecl_\l_@@_dom_str _prop}{args}}
                {\l_stex_get_symbol_uri_str}
                {\prop_item:cn{l_stex_symdecl_\l_stex_get_symbol_uri_str _prop}{args}}
            }
            \prop_put:Nxx \l_tmpa_prop {\seq_item:Nn \l_tmpb_seq 1} {\stex_invoke_symbol:n {\l_stex_get_symbol_uri_str}}
          }
        }
      }
      \tl_gclear:N \g_@@_aftergroup_tl
      \seq_map_inline:Nn \l_@@_fields_seq {
        \str_set:Nx \l_tmpa_str {\l_@@_name_str . \prop_item:cn {l_stex_symdecl_##1_prop}{name} }
        \stex_debug:nn{varinstantiate}{Field~\l_tmpa_str :~##1}
        \seq_if_empty:cF{l_stex_symdecl_##1_notations}{
          \stex_find_notation:nn{##1}{}
          \cs_gset_eq:cc{g_@@_tmpa_\l_tmpa_str _cs}
            {stex_notation_##1\c_hash_str \l_stex_notation_variant_str _cs}
          \stex_debug:nn{varinstantiate}{Notation:~\cs_meaning:c{g_@@_tmpa_\l_tmpa_str _cs}}
          \cs_if_exist:cT{stex_op_notation_##1\c_hash_str \l_stex_notation_variant_str _cs}{
            \cs_gset_eq:cc {g_@@_tmpa_op_\l_tmpa_str _cs}
              {stex_op_notation_##1\c_hash_str \l_stex_notation_variant_str _cs}
              \stex_debug:nn{varinstantiate}{Operator~Notation:~\cs_meaning:c{g_@@_tmpa_op_\l_tmpa_str _cs}}
          }
        }

        \exp_args:NNx \tl_gput_right:Nn \g_@@_aftergroup_tl {
          \prop_set_from_keyval:cn { l_stex_symdecl_ var://\l_tmpa_str _prop}{
            name   = \l_tmpa_str ,
            args   = \prop_item:cn {l_stex_symdecl_##1_prop}{args} ,
            arity  = \prop_item:cn {l_stex_symdecl_##1_prop}{arity} ,
            assocs = \prop_item:cn {l_stex_symdecl_##1_prop}{assocs} ,
            argnames = {\prop_item:cn {l_stex_symdecl_##1_prop}{argnames}} ,
          }
          \cs_set_eq:cc {stex_var_notation_\l_tmpa_str _cs}
            {g_@@_tmpa_\l_tmpa_str _cs}
          \cs_set_eq:cc {stex_var_op_notation_\l_tmpa_str _cs}
            {g_@@_tmpa_op_\l_tmpa_str _cs}
        }
        \prop_put:Nxx \l_tmpa_prop {\prop_item:cn {l_stex_symdecl_##1_prop}{name}}{\stex_invoke_variable:n {\l_tmpa_str}}
      }
      \exp_args:NNx \tl_gput_right:Nn \g_@@_aftergroup_tl {
        \prop_set_from_keyval:cn {l_stex_varinstance_\l_@@_name_str _prop }{
          domain = \l_stex_get_structure_module_str ,
          \prop_to_keyval:N \l_tmpa_prop
        }
        \tl_set:cn { #1 }{\stex_invoke_varinstance:n {\l_@@_name_str}}
        \tl_set:cn {l_stex_varinstance_\l_@@_name_str _op_tl}{
          \exp_args:Nnx \exp_not:N \use:nn {
            \str_set:Nn \exp_not:N \STEXInternalCurrentSymbolStr {var://\l_@@_name_str}
            \_stex_term_omv:nn {var://\l_@@_name_str}{
              \exp_not:n{
                \_varcomp{#4}
              }
            }
          }{
            \exp_not:n{\_stex_reset:N \STEXInternalCurrentSymbolStr}
          }
        }
      }
    }
    \stex_debug:nn{varinstantiate}{\expandafter\detokenize\expandafter{\g_@@_aftergroup_tl}}
    \aftergroup\g_@@_aftergroup_tl
  \endgroup
  \stex_smsmode_do:\ignorespacesandpars
}

\cs_new_protected:Nn \stex_invoke_instance:n {
  \peek_charcode_remove:NTF ! {
    \stex_invoke_symbol:n{#1}
  }{
    \_stex_invoke_instance:nn {#1}
  }
}


\cs_new_protected:Nn \stex_invoke_varinstance:n {
  \peek_charcode_remove:NTF ! {
    \exp_args:Nnx \use:nn {
      \def\comp{\_varcomp}
      \use:c{l_stex_varinstance_#1_op_tl}
    }{
      \_stex_reset:N \comp
    }
  }{
    \_stex_invoke_varinstance:nn {#1}
  }
}

\cs_new_protected:Nn \_stex_invoke_instance:nn {
  \prop_if_in:cnTF {l_stex_instance_ #1 _prop}{#2}{
    \exp_args:Nx \stex_invoke_symbol:n {\prop_item:cn{l_stex_instance_ #1 _prop}{#2}}
  }{
    \prop_set_eq:Nc \l_tmpa_prop{l_stex_instance_ #1 _prop}
    \msg_error:nnxxx{stex}{error/unknownfield}{#2}{#1}{
      \prop_to_keyval:N \l_tmpa_prop
    }
  }
}

\cs_new_protected:Nn \_stex_invoke_varinstance:nn {
  \prop_if_in:cnTF {l_stex_varinstance_ #1 _prop}{#2}{
    \prop_get:cnN{l_stex_varinstance_ #1 _prop}{#2}\l_tmpa_tl
    \l_tmpa_tl
  }{
    \msg_error:nnnnn{stex}{error/unknownfield}{#2}{#1}{}
  }
}
%    \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\stex_invoke_structure:nnn}
%    \begin{macrocode}
% #1: URI of the instance
% #2: URI of the instantiated module
\cs_new_protected:Nn \stex_invoke_structure:nnn {
  \tl_if_empty:nTF{ #3 }{  
    \prop_set_eq:Nc \l_@@_structure_prop {
      c_stex_feature_ #2 _prop
    }
    \tl_clear:N \l_tmpa_tl
    \prop_get:NnN \l_@@_structure_prop { fields } \l_tmpa_seq
    \seq_map_inline:Nn \l_tmpa_seq {
      \seq_set_split:Nnn \l_tmpb_seq ? { ##1 }
      \seq_get_right:NN \l_tmpb_seq \l_tmpa_str
      \cs_if_exist:cT {
        stex_notation_ #1/\l_tmpa_str \c_hash_str\c_hash_str _cs
      }{
        \tl_if_empty:NF \l_tmpa_tl {
          \tl_put_right:Nn \l_tmpa_tl {,}
        }
        \tl_put_right:Nx \l_tmpa_tl {
          \stex_invoke_symbol:n {#1/\l_tmpa_str}!
        }
      }
    }
    \exp_args:No \mathstruct \l_tmpa_tl
  }{
    \stex_invoke_symbol:n{#1/#3}
  }
}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
% \ifinfulldoc\else\printbibliography\fi
%
% \PrintIndex
