# -*- CPERL -*-
# /=====================================================================\ #
# |  amsmath                                                            | #
# | Implementation for LaTeXML                                          | #
# |=====================================================================| #
# | Part of LaTeXML:                                                    | #
# |  Public domain software, produced as part of work done by the       | #
# |  United States Government & not subject to copyright in the US.     | #
# |---------------------------------------------------------------------| #
# | Bruce Miller <bruce.miller@nist.gov>                        #_#     | #
# | http://dlmf.nist.gov/LaTeXML/                              (o o)    | #
# \=========================================================ooo==U==ooo=/ #

#**********************************************************************
# See amsldoc

# Currently only a random collection of things I need for DLMF chapters.
# Eventually, go through the doc and implement it all.
#**********************************************************************
package LaTeXML::Package::Pool;
use strict;
use LaTeXML::Package;
no warnings 'redefine';

# TODO:
#   Interesting options for limits placement
#   And TESTING!!!!!

# sub-packages:
RequirePackage('amsbsy');
RequirePackage('amstext');
RequirePackage('amsopn');

# Optional packages
#   amscd
#   amsxtra

DefMacroI('\AmSfont',undef,Tokens());
DefMacroI('\AmS',undef,"AmS");

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Section 3:  Displayed equations
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# General implementation comments:
#   Some of these environments are intended for breaking up single equations
# into multiple lines, while others are for presenting several equations in a group.
# [some environments may be more ambiguous]
# In any case, there may be specific relative alignment expected between the lines.
#
# Our primary objective, in LaTeXML, is to get at the semantics of the document,
# and secondarily, to preserve enough of the author's intent to generate
# presentation MathML that has the originally desired appearance.

# Thus, our first concern is to recognize the portions of the input which represent
# individual equations.  These sequences can then be passed to the math parser
# and hopefully recognized.
#
# We'll try to leverage the equationgroup/equation/MathFork arrangement
# to achieve the secondary objective.
# Where this doesn't work out, we'll insert additional hint or punctuation tokens
# that indicate the requested alignment points or linebreaks.
#  Currently hints are discarded before parsing.

Let('\notag','\nonumber');
#DefPrimitive('\tag OptionalMatch:* {}', sub {
#	       AssignValue(EQUATIONROW_NUMBER=>ToString(Digest($_[2])), 'global'); });

DefConstructor('\tag OptionalMatch:* {}', '',
	       afterDigest=>sub {
#		 AssignValue(EQUATIONROW_NUMBER=>ToString(Digest($_[2])), 'global'); },
		 AssignValue(EQUATIONROW_NUMBER=>ToString($_[2]), 'global'); },
	       mode=>'text');

DefMacro('\@ams@intertext{}',
	 '\@alignment@newline\multicolumn{\@alignment@ncolumns}{l}{\@@ams@intertext{#1}}\nonumber\@alignment@newline');
DefConstructor('\@@ams@intertext{}',
	       "<ltx:block class='intertext'>#1</ltx:block>", mode=>'text');

sub amsalignBindings {
  my($template)=@_;
#  my $alignment = LaTeXML::Util::Alignment->new(containerElement=>'ltx:equationgroup',
#						rowElement=>'ltx:equation',
#						colElement=>'_Capture_');
  my $alignment = LaTeXML::Util::Alignment
    ->new(openContainer =>sub{ $_[0]->openElement('ltx:equationgroup',@_[1..$#_]); },
	  closeContainer=>sub{ $_[0]->closeElement('ltx:equationgroup'); },
	  openRow       =>sub{ $_[0]->openElement('ltx:equation',@_[1..$#_]); },
	  closeRow      =>sub{ $_[0]->closeElement('ltx:equation'); },
	  openColumn    =>sub{ $_[0]->openElement('_Capture_',@_[1..$#_]); },
	  closeColumn   =>sub{ $_[0]->closeElement('_Capture_'); });

  AssignValue(Alignment=>$alignment);
  $alignment->setTemplate($template);
  Let(T_ALIGN,        T_CS('\@alignment@align'));
  Let(T_CS("\\\\"),   T_CS('\@alignment@newline'));
  Let(T_CS('\cr'),    T_CS('\@alignment@cr'));
#  Let('\span',        T_CS('\@alignment@span'));
  Let(T_CS('\@open@row'),T_CS('\@equationgroup@open@row'));
  Let(T_CS('\@close@row'),T_CS('\@equationgroup@close@row'));
  Let(T_CS('\intertext'),T_CS('\@ams@intertext'));
  return; }

#======================================================================
# Section 3.1 introduction

#======================================================================
# Section 3.2 Single equations

#  equation, equation*

#======================================================================
# Section 3.3 Split equations without alignment

# Multiline is for single equations, but split on multiple lines, using \\ to separate lines.
# Justifies the 1st line left, last line right, and middle ones centered.
# Very useful when you are trying to fit a long equation into a known space,
# but preserving the alignment seems less useful in the vaguer XML context,
# particularly since there's no real alignment of columns that convey symmetry.
# So... For now, we'll just turn into a single equation, ignoring the line breaks.
DefEnvironment('{multline}',
	       "<ltx:equation refnum='#refnum' xml:id='#id'>"
	       . "<ltx:Math mode='display'>"
	       .  "<ltx:XMath>#body</ltx:XMath>"
	       . "</ltx:Math>"
	       ."</ltx:equation>",
	       mode=>'display_math',
	       beforeDigest=>sub {   Let(T_MATH,T_CS('\@math@alignment$')); },
	       properties=> sub { RefStepCounter('equation') });
DefEnvironment('{multline*}',
	       "<ltx:equation>"
	       . "<ltx:Math mode='display'>"
	       .  "<ltx:XMath>#body</ltx:XMath>"
	       . "</ltx:Math>"
	       ."</ltx:equation>",
	       beforeDigest=>sub {   Let(T_MATH,T_CS('\@math@alignment$')); },
	       mode=>'display_math');

#======================================================================
# Section 3.4 Split equations with alignment

# split is used within other math environments to provide line breaks and alignment.
# Since it's already within math, the MathFork branching doesn't work here.
# Should we use a math alignment stucture?
# [in which case it isn't clear how to get the high-level presentation vs. semantic]
# Or just turn the markup into XMHint's; effectively ignoring them.
# The latter, for now.
DefEnvironment('{split}',
	       "<ltx:XMHint name='split-begin'/>#body<ltx:XMHint name='split-end'/>",
	       beforeDigest=>sub{
		 # Just dummy up these definitions; they shouldn't do much special now.
		 DefConstructor("&","<ltx:XMHint name='align'/>");
		 DefConstructor("\\\\","<ltx:XMHint name='newline'/>",
				reversion=>Tokens(T_CS("\\\\"),T_CR)); 
		 DefConstructor('\intertext{}',
				"<ltx:block class='intertext'>#1</ltx:block>", mode=>'text'); });

#======================================================================
# Section 3.5 Equation groups without alignment

# NOTE: Does this need provision to deal with metadata?
DefConstructor('\@@amsgather SkipSpaces DigestedBody',
	       sub {
		 my($document,$body,%props)=@_;
		 processAMSGatherRows($document,constructAlignment($document,$body,
								 class=>'gather')); },
	       beforeDigest=>sub { $_[0]->bgroup; });
DefPrimitive('\end@amsgather',sub{ $_[0]->egroup; });

# Set up single centered column.
DefPrimitive('\@amsgather@bindings', sub {
  my $col = {before=>Tokens(T_CS('\hfil'),T_MATH,T_CS('\displaystyle')),
	      after=>Tokens(T_MATH,T_CS('\hfil'))};
  amsalignBindings(LaTeXML::AlignmentTemplate->new(columns=>[$col]));
});

# Each equation row (except intertext) consists of pairs (LHS, =RHS); group accordingly.
# Since each column is a single equation, we'll skip the MathFork stuff,
# and just pull the math content up past the _Capture_
sub processAMSGatherRows {
  my($document,$equationgroup)=@_;
  foreach my $equation ($document->getChildElements($equationgroup)){
    my @cells = $document->getChildElements($equation);
    my @cell1cont = $document->getChildElements($cells[0]);
    # Check if this equation is really an intertext
    if((scalar(@cells)==1) && (scalar(@cell1cont)==1)
       && ($document->getNodeQName($cell1cont[0]) eq 'ltx:block')){
      $equation->replaceNode($cell1cont[0]); } # Replace equation with the block.
    elsif((scalar(@cells)==1) && (scalar(@cell1cont)==0)){ # Empty row? Remove it!
      $equationgroup->removeChild($equation); }
    else {
      equationgroupFlattenCols($document,$equation); }}}

# Note that some people use align or gather inside equation, which seems to "work"
# So, we'll treat align as aligned in such cases.
DefMacro('\gather',
	 '\ifmmode\let\endgather\endgathered\gathered\else'
	 .'\@amsgather@bindings\@@amsgather\@equationgroup@number\@start@alignment\fi');
DefMacro('\endgather',
	 '\@finish@alignment\end@amsgather');
DefMacro('\csname gather*\endcsname',
	 '\ifmmode\expandafter\let\csname endgather*\endcsname\endgathered\gathered\else'
	 .'\@amsgather@bindings\@@amsgather\@equationgroup@nonumber\@start@alignment\fi');
DefMacro('\csname endgather*\endcsname',
	 '\@finish@alignment\end@amsgather');

#======================================================================
# Section 3.6 Equation groups with mutual alignment

# This environment can contain multiple columns, but apparently the intension is 
# that each pair should constitute an equation:
#    lhs & = rhs & lhs & = rhs ...
# where each lhs is right aligned, and rhs is left aligned.
# We'll use the equationgroup/equation/MathFork mechanism
# similar to eqnarray.


DefConstructor('\@@amsalign SkipSpaces DigestedBody',
	       sub {
		 my($document,$body,%props)=@_;
		 processAMSAlignRows($document,constructAlignment($document,$body,
								 class=>'align')); },
	       beforeDigest=>sub { $_[0]->bgroup; });
DefPrimitive('\end@amsalign',sub{ $_[0]->egroup; });

# Set up repeated pairs of columns.
DefPrimitive('\@amsalign@bindings', sub {
  my $col1 = {before=>Tokens(T_CS('\hfil'),T_MATH,T_CS('\displaystyle')),
	      after=>Tokens(T_MATH)};
  my $col2 = {before=>Tokens(T_MATH,T_CS('\displaystyle')),
	      after=>Tokens(T_MATH,T_CS('\hfil'))};
  amsalignBindings(LaTeXML::AlignmentTemplate->new(repeated=>[$col1,$col2]));
});

# Each equation row (except intertext) consists of pairs (LHS, =RHS); group accordingly.
sub processAMSAlignRows {
  my($document,$equationgroup)=@_;
  foreach my $equation ($document->getChildElements($equationgroup)){
    my @cells = $document->getChildElements($equation);
    shift(@cells) if $document->getNodeQName($cells[0]) eq 'ltx:metadata';
    my @cell1cont = $document->getChildElements($cells[0]);
    # Check if this equation is really an intertext
    if((scalar(@cells)==1) && (scalar(@cell1cont)==1)
       && ($document->getNodeQName($cell1cont[0]) eq 'ltx:block')){
      $equation->replaceNode($cell1cont[0]); } # Replace equation with the block.
    elsif((scalar(@cells)==1) && (scalar(@cell1cont)==0)){ # Empty row? Remove it!
      $equationgroup->removeChild($equation); }
    else {
      equationgroupJoinCols($document,2,$equation); }}}

# Note that some people use align or gather inside equation, which seems to "work"
# So, we'll treat align as aligned in such cases.
DefMacro('\align',
	 '\ifmmode\let\endalign\endaligned\aligned\else'
	 .'\@amsalign@bindings\@@amsalign\@equationgroup@number\@start@alignment\fi');
DefMacro('\endalign',
	 '\@finish@alignment\end@amsalign');
DefMacro('\csname align*\endcsname',
	 '\ifmmode\expandafter\let\csname endalign*\endcsname\endaligned\aligned\else'
	 .'\@amsalign@bindings\@@amsalign\@equationgroup@nonumber\@start@alignment\fi');
DefMacro('\csname endalign*\endcsname',
	 '\@finish@alignment\end@amsalign');

# flalign typesets in the full column width (seems perverse to me).
# So, for the time being, it's treated exactly like align.
DefMacro('\flalign',
	 '\ifmmode\let\endfalign\endaligned\aligned\else'
	 .'\@amsalign@bindings\@@amsalign\@equationgroup@number\@start@alignment\fi');
DefMacro('\endflalign',
	 '\@finish@alignment\end@amsalign');
DefMacro('\csname flalign*\endcsname',
	 '\ifmmode\expandafter\let\csname endfalign*\endcsname\endaligned\aligned\else'
	 .'\@amsalign@bindings\@@amsalign\@equationgroup@nonumber\@start@alignment\fi');
DefMacro('\csname endflalign*\endcsname',
	 '\@finish@alignment\end@amsalign');

# alignat doesn't stretch the columns out as much (?)
# and takes the number of column pairs (which we don't need?)
# We'll ignore these distinctions for now.
DefMacro('\alignat{}',
	 '\ifmmode\let\endalignat\endalignedat\alignedat{#1}\else'
	 .'\@amsalign@bindings\@@amsalign\@equationgroup@number\@start@alignment\fi');
DefMacro('\endalignat',
	 '\@finish@alignment\end@amsalign');
DefMacro('\csname alignat*\endcsname{}',
	 '\ifmmode\expandafter\let\csname endalignat*\endcsname\endalignedat\alignedat{#1}\else'
	 .'\@amsalign@bindings\@@amsalign\@equationgroup@nonumber\@start@alignment\fi');
DefMacro('\csname endalignat*\endcsname',
	 '\@finish@alignment\end@amsalign');

DefMacro('\xalignat{}',
	 '\ifmmode\let\endalignat\endalignedat\alignedat{#1}\else'
	 .'\@amsalign@bindings\@@amsalign\@equationgroup@number\@start@alignment\fi');
DefMacro('\endxalignat',
	 '\@finish@alignment\end@amsalign');
DefMacro('\csname xalignat*\endcsname{}',
	 '\ifmmode\expandafter\let\csname endalignat*\endcsname\endalignedat\alignedat{#1}\else'
	 .'\@amsalign@bindings\@@amsalign\@equationgroup@nonumber\@start@alignment\fi');
DefMacro('\csname endxalignat*\endcsname',
	 '\@finish@alignment\end@amsalign');

DefMacro('\xxalignat{}',
	 '\ifmmode\let\endalignat\endalignedat\alignedat{#1}\else'
	 .'\@amsalign@bindings\@@amsalign\@equationgroup@number\@start@alignment\fi');
DefMacro('\endxxalignat',
	 '\@finish@alignment\end@amsalign');

#======================================================================
# Section 3.7. Alignmnet building blocks
#    gathered, aligned alignedat
# These are intended to be used within math environments, but do they have the same
# `semanitic' intent as far as separating equations?
# aligned/alignedat perhaps do, since the alignment doesn't make much sense otherwise
# [except for a single column, but then split should be used]
# gathered could make sense as arranging a single subexpression into multiple lines within
# a larger expression.
#   On the other hand, we'll already be inside of a math environment, so delineating
# these potentially separate equations will be awkward anyway!

# So, we just leave Hint markers for & and \\
# Hmm...
DefMacro('\@noop@newline', sub {
  my($gullet)=@_;
  readNewlineArgs($gullet);	# ignore
  (T_CS('\@noop@newline@marker')); });

DefConstructor('\@noop@newline@marker',
	       "?#isMath(<ltx:XMHint name='newline'/>)(\n)",
	       properties=>{isSpace=>1},
	       reversion=>"\\\\");

DefEnvironment('{gathered}[]',
	       "<ltx:XMHint name='gathered-begin'/>"
	       . "#body"
	       ."<ltx:XMHint name='gathered-end'/>",
	      beforeDigest=>sub{
		Let(T_CS('\\\\'),T_CS('\@noop@newline')); });

DefMacro('\aligned[]',    '\@@amsaligned\@start@alignment');
DefMacro('\endaligned',   '\@finish@alignment\@end@amsaligned');
DefMacro('\alignedat{}[]','\@@amsaligned\@start@alignment');
DefMacro('\endalignedat', '\@finish@alignment\@end@amsaligned');

# NOTE: If this is the only child of an equation, it would seem better
# to rewrite the thing into an equationgroup/equation/MathFork construct!
# Besides, the MathML alignment (at least in firefox), pretty much sucks.
DefPrimitive('\@end@amsaligned',sub{ $_[0]->egroup; });
DefConstructor('\@@amsaligned DigestedBody',
	       sub { my($document,$body,%props)=@_;
		     constructAlignment($document,$body,attributes=>{name=>'aligned'}); },
	       beforeDigest=>sub { $_[0]->bgroup;
				   my $col1 = {before=>Tokens(T_CS('\hfil'),
							      T_CS('\displaystyle'))};
				   my $col2 = {before=>Tokens(T_CS('\displaystyle')),
					       after=>Tokens(T_CS('\hfil'))};
				   my $template
				     = LaTeXML::AlignmentTemplate->new(repeated=>[$col1,$col2]);
				   alignmentBindings($template); },
	       reversion=>'\begin{aligned}#1\end{aligned}');


DefMacro('\cases',   '\@@cases\@start@alignment');
DefMacro('\endcases', '\@finish@alignment\@end@cases');
DefPrimitive('\@end@cases',sub{ $_[0]->egroup; });
DefConstructor('\@@cases DigestedBody',
	       sub { my($document,$body,%props)=@_;
		     constructAlignment($document,$body,attributes=>{meaning=>'cases',open=>'{'}); },
	       beforeDigest=>sub { $_[0]->bgroup; alignmentBindings('ll'); },
	       reversion=>'\begin{cases}#1\end{cases}');

#======================================================================
# Section 3.8 Adjusting tag placement
DefMacro('\raisetag{Dimension}',''); # Ignorable

#======================================================================
# Section 3.9 Vertical spacing and page breaks in multiline display
DefMacro('\displaybreak[]','');	# Ignorable

#======================================================================
# Section 3.10 Interrupting a display

# default when not used inside an appropriate alignment.
DefConstructor('\intertext{}', "<ltx:block class='intertext'>#1</ltx:block>", mode=>'text');

#======================================================================
# Section 3.11 Equation numbering

# Section 3.11.1 Numbering hierarchy
DefPrimitive('\numberwithin[]{}{}',sub {
  my($ignore,$format,$counter,$within)=@_;
  $format = ($format ? ToString($format) : '\arabic');
  $counter = ToString($counter); $within = ToString($within);
  NewCounter($counter,$within);
  DefMacroI("\\the$counter",undef,
	    "\\csname the$within\\endcsname.$format\{$counter\}", scope=>'global');
 });

# Section 3.11.2 Cross references to equation numbers
DefConstructor('\eqref Semiverbatim', "(<ltx:ref labelref='#label'/>)",
	       properties=>sub { (label=>CleanLabel($_[1])); });


# Section 3.11.3 Subordinate numbering sequences.
DefEnvironment('{subequations}',"<ltx:equationgroup refnum='#refnum' xml:id='#id'>#body</ltx:equationgroup>",
	       afterDigestBegin=>sub {
		 my($stomach,$whatsit)=@_;
		 my %eqn = RefStepCounter('equation');
		 AssignValue(SAVED_EQUATION_NUMBER=>LookupValue('\c@equation'));
		 $whatsit->setProperties(%eqn);
		 ResetCounter('equation');
		 DefMacro('\theequation',UnTeX($eqn{refnum}).'\alph{equation}');
		 DefMacro('\theequation@ID',UnTeX($eqn{id}).'.\@equation@ID');
	       },
	       afterDigest =>sub{ 
		 AssignValue('\c@equation',LookupValue('SAVED_EQUATION_NUMBER'),'global'); });

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Section 4: Miscellaneous mathematical features
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#======================================================================
# Section 4.1 Matrices

DefMacro('\matrix',    '\@@matrix\@start@alignment');
DefMacro('\endmatrix', '\@finish@alignment\@end@matrix');
DefPrimitive('\@end@matrix',sub{ $_[0]->egroup; });
DefConstructor('\@@matrix DigestedBody',
	       sub { my($document,$body,%props)=@_;
		     constructAlignment($document,$body,attributes=>{name=>'Matrix'}); },
	       beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); },
	       reversion=>'\begin{matrix}#1\end{matrix}');

DefMacro('\pmatrix',    '\@@pmatrix\@start@alignment');
DefMacro('\endpmatrix', '\@finish@alignment\@end@pmatrix');
DefPrimitive('\@end@pmatrix',sub{ $_[0]->egroup; });
DefConstructor('\@@pmatrix DigestedBody',
	       sub { my($document,$body,%props)=@_;
		     constructAlignment($document,$body,attributes=>{name=>'Matrix',
								     open=>'(',close=>')'}); },
	       beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); },
	       reversion=>'\begin{pmatrix}#1\end{pmatrix}');

DefMacro('\bmatrix',    '\@@bmatrix\@start@alignment');
DefMacro('\endbmatrix', '\@finish@alignment\@end@bmatrix');
DefPrimitive('\@end@bmatrix',sub{ $_[0]->egroup; });
DefConstructor('\@@bmatrix DigestedBody',
	       sub { my($document,$body,%props)=@_;
		     constructAlignment($document,$body,attributes=>{name=>'Matrix',
								     open=>'[',close=>']'}); },
	       beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); },
	       reversion=>'\begin{bmatrix}#1\end{bmatrix}');

DefMacro('\Bmatrix',    '\@@Bmatrix\@start@alignment');
DefMacro('\endBmatrix', '\@finish@alignment\@end@Bmatrix');
DefPrimitive('\@end@Bmatrix',sub{ $_[0]->egroup; });
DefConstructor('\@@Bmatrix DigestedBody',
	       sub { my($document,$body,%props)=@_;
		     constructAlignment($document,$body,attributes=>{name=>'Matrix',
								     open=>'{',close=>'}'}); },
	       beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); },
	       reversion=>'\begin{Bmatrix}#1\end{Bmatrix}');

DefMacro('\vmatrix',    '\@@vmatrix\@start@alignment');
DefMacro('\endvmatrix', '\@finish@alignment\@end@vmatrix');
DefPrimitive('\@end@vmatrix',sub{ $_[0]->egroup; });
DefConstructor('\@@vmatrix DigestedBody',
	       sub { my($document,$body,%props)=@_;
		     constructAlignment($document,$body,attributes=>{name=>'Matrix',
								     open=>'|',close=>'|'}); },
	       beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); },
	       reversion=>'\begin{vmatrix}#1\end{vmatrix}');

DefMacro('\Vmatrix',    '\@@Vmatrix\@start@alignment');
DefMacro('\endVmatrix', '\@finish@alignment\@end@Vmatrix');
DefPrimitive('\@end@Vmatrix',sub{ $_[0]->egroup; });
DefConstructor('\@@Vmatrix DigestedBody',
	       sub { my($document,$body,%props)=@_;
		     constructAlignment($document,$body,attributes=>{name=>'Matrix',
								     open=>"\x{2225}",
								     close=>"\x{2225}"});},
	       beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); },
	       reversion=>'\begin{Vmatrix}#1\end{Vmatrix}');

DefMacro('\smallmatrix',    '\@hidden{\scriptsize}\@@smallmatrix\@start@alignment');
DefMacro('\endsmallmatrix', '\@finish@alignment\@end@smallmatrix');
DefPrimitive('\@end@smallmatrix',sub{ $_[0]->egroup; });
DefConstructor('\@@smallmatrix DigestedBody',
	       sub { my($document,$body,%props)=@_;
		     constructAlignment($document,$body,attributes=>{name=>'Matrix'}); },
	       beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); },
	       reversion=>'\begin{smallmatrix}#1\end{smallmatrix}');

#======================================================================
# Section 4.2 Math spacing commands
# \, == \thinspace
# \: == \medspace
# \; == \thickspace
# \quad
# \qquad
# \! == \negthinspace
# \negmedspace
# \negthickspace
# I think only these are new
DefConstructor('\medspace',"?#isMath(<ltx:XMHint name='medspace'/>)(\x{2005})");  # FOUR-PER-EM SPACE
DefConstructor('\negthinspace',"?#isMath(<ltx:XMHint name='negthinspace'/>)()");
DefConstructor('\negmedspace',"?#isMath(<ltx:XMHint name='negmedspace'/>)()");
DefConstructor('\negthickspace',"?#isMath(<ltx:XMHint name='negthickspace'/>)()");

DefConstructor('\mspace{MuDimension}',"<ltx:XMHint name='#1'/>");

#======================================================================
# Section 4.3 Dots
# Nice idea, but not sure what I really should do about it.
# In principle, a processor has access to the context....
DefMacroI('\dotsc',undef,'\ldots');	# Dots with commas
DefMacroI('\dotsb',undef,'\cdots');	# Dots with binary operators/relations
DefMacroI('\dotsm',undef,'\cdots');	# multiplication dots
DefMacroI('\dotsi',undef,'\cdots');	# Dots with integrals
DefMacroI('\dotso',undef,'\ldots');	# other dots (??)

# Not really clear when these get set to something other than \relax, in amsfonts.sty
DefMacroI('\DOTSB',undef,Tokens());
DefMacroI('\DOTSI',undef,Tokens());
DefMacroI('\DOTSX',undef,Tokens());
Let(T_CS('\hdots'),T_CS('\ldots'));
# \hdotsfor ???

#======================================================================
# Section 4.4 Nonbreaking dashes
# \nobreakdash
DefMacro('\nobreakdash','');	# Ignorable
#======================================================================
# Section 4.5 Accents in math
DefMath('\dddot{}', "\x{02D9}\x{02D9}\x{02D9}",         operator_role=>'OVERACCENT'); # DOT ABOVE
DefMath('\ddddot{}',"\x{02D9}\x{02D9}\x{02D9}\x{02D9}", operator_role=>'OVERACCENT'); # DOT ABOVE

# In amsxtra
#  \sphat \sptilde

#======================================================================
# Section 4.6 Roots
# It would be nice to carry this info through to mathml, but ignore for now.
DefMacro('\leftroot{}','');
DefMacro('\uproot{}','');

#======================================================================
# Section 4.7 Boxed formulas

DefConstructor('\boxed{}',
	       "<ltx:XMWrap style='boxed'><ltx:XMArg>#1</ltx:XMArg></ltx:XMWrap>");
DefMath('\implies',  "\x{27F9}", role=>'ARROW', meaning=>'implies');
DefMath('\impliedby',"\x{27F8}", role=>'ARROW', meaning=>'implied-by');
#======================================================================
# Section 4.8 Over and under arrows

# Should be in LaTeX (& TeX): \overrightarrow, \overleftarrow
DefMath('\underrightarrow{}',    "\x{2192}", operator_role=>'UNDERACCENT');
DefMath('\underleftarrow{}',     "\x{2190}", operator_role=>'UNDERACCENT');
DefMath('\overleftrightarrow{}', "\x{2194}", operator_role=>'OVERACCENT');
DefMath('\underleftrightarrow{}',"\x{2194}", operator_role=>'UNDERACCENT');

#======================================================================
# Section 4.9 Extensible arrows
#  \xleftarrow, \xrightarrow

DefConstructor('\xleftarrow[]{}',
	       "<ltx:XMApp role='ARROW'>"
	       . "<ltx:XMTok role='STACKED'/>"
	       . "<ltx:XMArg>#2</ltx:XMArg>"
	       . "<ltx:XMTok>\x{2190}</ltx:XMTok>"
	       . "?#1(<ltx:XMArg>#1</ltx:XMArg>)"
	       ."</ltx:XMApp>");
DefConstructor('\xrightarrow[]{}',
	       "<ltx:XMApp role='ARROW'>"
	       . "<ltx:XMTok role='STACKED'/>"
	       . "<ltx:XMArg>#2</ltx:XMArg>"
	       . "<ltx:XMTok>\x{2192}</ltx:XMTok>"
	       . "?#1(<ltx:XMArg>#1</ltx:XMArg>)"
	       ."</ltx:XMApp>");

#======================================================================
# Section 4.10 Affixing symbols to other symbols

DefConstructor('\overset{}{}',
	       "<ltx:XMApp>"
	       . "<ltx:XMWrap role='OVERACCENT'>#1</ltx:XMWrap>"
	       . "<ltx:XMArg>#2</ltx:XMArg>"
	       ."</ltx:XMApp>");
DefConstructor('\underset{}{}',
	       "<ltx:XMApp>"
	       . "<ltx:XMWrap role='UNDERACCENT'>#1</ltx:XMWrap>"
	       . "<ltx:XMArg>#2</ltx:XMArg>"
	       ."</ltx:XMApp>");

#======================================================================
# Section 4.11 Fractions and related commands

# Section 4.11.1 The \frac, \dfrac, and \tfrac commands

DefConstructor('\tfrac{}{}',
	       "<ltx:XMApp>"
	       . "<ltx:XMTok meaning='divide' role='MULOP' style='#style'/>"
	       . "<ltx:XMArg>#1</ltx:XMArg><ltx:XMArg>#2</ltx:XMArg>"
	       ."</ltx:XMApp>",
	       beforeDigest=>\&beforeTFrac, afterDigest =>\&afterTFrac);
DefConstructor('\dfrac{}{}',
	       "<ltx:XMApp>"
	       . "<ltx:XMTok meaning='divide' role='MULOP' style='#style'/>"
	       . "<ltx:XMArg>#1</ltx:XMArg><ltx:XMArg>#2</ltx:XMArg>"
	       ."</ltx:XMApp>",
	       beforeDigest=>\&beforeDFrac, afterDigest =>\&afterDFrac);
DefConstructor('\ifrac{}{}',
	       "<ltx:XMApp>"
	       . "<ltx:XMTok meaning='divide' role='MULOP' style='inline'/>"
	       . "<ltx:XMArg>#1</ltx:XMArg><ltx:XMArg>#2</ltx:XMArg>"
	       ."</ltx:XMApp>",
	       beforeDigest=>\&beforeFrac, afterDigest =>\&afterFrac);

# Section 4.11.2 The \binom, \dbinom, and \tbinom commands
DefConstructor('\binom{}{}',
	       "<ltx:XMApp open='(' close=')'>"
	       . "<ltx:XMTok meaning='binomial' role='STACKED' style='#style'/>"
	       . "<ltx:XMArg>#1</ltx:XMArg><ltx:XMArg>#2</ltx:XMArg>"
	       ."</ltx:XMApp>",
	       beforeDigest=>\&beforeFrac, afterDigest =>\&afterFrac);

DefConstructor('\tbinom{}{}',
	       "<ltx:XMApp open='(' close=')'>"
	       . "<ltx:XMTok meaning='binomial' role='STACKED' style='#style'/>"
	       . "<ltx:XMArg>#1</ltx:XMArg><ltx:XMArg>#2</ltx:XMArg>"
	       ."</ltx:XMApp>",
	       beforeDigest=>\&beforeTFrac, afterDigest =>\&afterTFrac);
DefConstructor('\dbinom{}{}',
	       "<ltx:XMApp open='(' close=')'>"
	       . "<ltx:XMTok meaning='binomial' role='STACKED' style='#style'/>"
	       . "<ltx:XMArg>#1</ltx:XMArg><ltx:XMArg>#2</ltx:XMArg>"
	       ."</ltx:XMApp>",
	       beforeDigest=>\&beforeDFrac, afterDigest =>\&afterDFrac);

# Section 4.11.3 The \genfrac command
DefConstructor('\genfrac{}{}{Dimension}{}{}{}',
	       "<ltx:XMApp open='#open' close='#close'>"
	       . "<ltx:XMTok ?&IsZero(#3)(role='STACKED')(role='MULOP' meaning='divide')"
	       .           " thickness='#3' style='?#4(#4)(#style)'/>"
	       . "<ltx:XMArg>#5</ltx:XMArg>"
	       . "<ltx:XMArg>#6</ltx:XMArg>"
	       ."</ltx:XMApp>",
	      afterDigest=>sub{ my($stomach,$whatsit)=@_;
				my $open  = ToString($whatsit->getArg(1));
				my $close = ToString($whatsit->getArg(2));
				if(my $entry = LaTeXML::Package::Pool::lookup_delimiter($open)){
				  $open = $$entry{char}; }
				if(my $entry = LaTeXML::Package::Pool::lookup_delimiter($close)){
				  $close = $$entry{char}; }
				$whatsit->setProperties(open=>$open,
							close=>$close,
							style=>LookupValue('mathstyle')); });

#======================================================================
# Section 4.12 Continued fractions
# I think \cfracstyle my own invention? (I know I've redefined \cfrac in DLMFmath)
# XMDual doesn't seem quite appropriate, since the args (denominators) get
# divided up so oddly in the inline case.
# I've left it to a special case in conversion to pmml.
DefConstructor('\cfrac{}{}',
	       "<ltx:XMApp>"
	       . "<ltx:XMTok name='cfrac' style='#style' meaning='continued-fraction'/>"
	       . "<ltx:XMArg>#1</ltx:XMArg>"
	       . "<ltx:XMArg>#2</ltx:XMArg>"
	       ."</ltx:XMApp>",
	      properties=>sub{ (style=>LookupValue('CFRACSTYLE')); });
AssignValue(CFRACSTYLE=>'display');
# This should get incorporated into any \cfrac's that are constructed in scope.
DefConstructor('\cfracstyle{}','',
	       afterDigest=>sub{ 
		 my $style = ToString($_[1]->getArg(1));
		 $style = ($style eq 'd' ? 'display' : ($style eq 'i' ? 'inline' : $style));
		 AssignValue(CFRACSTYLE=>$style); });

#======================================================================
# Section 4.13 Smash options
DefConstructor('\smash[]{}',"#2"); # well, what?

#======================================================================
# Section 4.14 Delimiters

# Section 4.14.1 Delimiter sizes
# Redefinitions(?) of \bigl, \bigr, \Bigl,\Bigr, \biggl, \biggr, \Biggl, \Biggr

# Section 4.14.2 Vertical bar notations
DefMath('\lvert','|', role=>'OPEN');
DefMath('\lVert',"\x{2225}", role=>'OPEN'); # PARALLEL TO
DefMath('\rvert','|', role=>'CLOSE');
DefMath('\rVert',"\x{2225}", role=>'CLOSE'); # PARALLEL TO

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Section 5  Operator names
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#======================================================================
# Section 5.1 Defining new operator names

# See package amsopn (included by default)

#======================================================================
# Section 5.2 \mod and it's relatives
# \bmod, \pmod which are already in LaTeX
DefMath('\mod',    'mod', role=>'MODIFIEROP', meaning=>'modulo');
DefMath('\pod{}', '(#1)', role=>'MODIFIER',   meaning=>'modulo'); # Well, sorta postfix..

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Section 6 The \text command
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# See package amstext, included by default.

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Section 7 Integrals and sums
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#======================================================================
# Section 7.1 Multiline subscripts and superscripts
#  \substack, \begin{subarray}
# These make the combining operator be list, but often formulae would be better
DefConstructor('\substack{}',
	       "<ltx:XMApp>"
	       . "<ltx:XMTok name='list' role='STACKED'/>"
	       . "<ltx:XMArg>#1</ltx:XMArg>"
	       ."</ltx:XMApp>",
	       bounded=>1, beforeDigest=>sub{ DefConstructor("\\\\ OptionalMatch:* [Dimension]",
							     "</ltx:XMArg><ltx:XMArg>",
							     reversion=>Tokens(T_CS("\\\\"),T_CR)); });
DefEnvironment('{subarray}[]',
	       "<ltx:XMApp>"
	       . "<ltx:XMTok name='list' alignment='#1'/>"
	       . "<ltx:XMArg>#body</ltx:XMArg>"
	       ."</ltx:XMApp>",
	       beforeDigest=>sub{ DefConstructor("\\\\ OptionalMatch:* [Dimension]",
						 "</ltx:XMArg><ltx:XMArg>",
						 reversion=>Tokens(T_CS("\\\\"),T_CR)); });

#======================================================================
# Section 7.2 the \sideset command

# This is intended to be a modifier for \sum or \prod
# NOTE that there can be at most one subscript in each of the pre & post, ditto for superscript.
# Thus, our representation is: sideset(presub,presup,postsub,postsup,object)
# Note, also, that this is quite ugly, but since it is a rather peculiar special case.... ?

# try by nesting...
DefConstructor('\sideset{}{}{}', sub {
  my($document,$pre,$post,$base,%props)=@_;
  my @scripts = (undef,undef,undef,undef);

  my $node = $document->insertElement('ltx:XMArg',$base);
  my $ch   = $document->getFirstChildElement($node);
  my ($opx,$ignore)
    = ($ch && $ch->getAttribute('scriptpos')||'post') =~ /^(pre|mid|post)?(\d+)?$/;
  my $level = $props{level}||0;
  my $x  = 'pre';
  foreach my $group ($pre,$post){ # Best order?
    foreach my $script ($group->unlist){
      my $y;
      if((ref $script eq 'LaTeXML::Whatsit')
	 && (( ($script->getDefinition eq
		$STATE->lookupMeaning(T_CS('\@@FLOATINGSUPERSCRIPT')))
	       && ($y='SUPER'))
	     || (($script->getDefinition eq
		  $STATE->lookupMeaning(T_CS('\@@FLOATINGSUBSCRIPT')))
		&& ($y='SUB')))){
	my $new = $document->openElement('ltx:XMApp');
	$document->insertElement('ltx:XMTok',undef,
				 role=>$y.'SCRIPTOP',scriptpos=>"$x$level");
	$new->appendChild($node);
	$document->insertElement('ltx:XMWrap',$script->getArg(1));
	$document->closeElement('ltx:XMApp');
	$node = $new; }
      else { warn("Non sub/superscript in \\sideset: ".Stringify($script)); }}
    $x = 'post'; }
  $document->setAttribute($node,scriptpos=>$opx) if $opx;
});

#======================================================================
# Section 7.3 Placement of subscripts and limits
# \limits and \nolimits; already in TeX

#======================================================================
# Section 7.4 Multiple integral signs

DefMath('\iint', "\x{222C}", meaning=>'double-integral', role=>'INTOP'); # DOUBLE INTEGRAL
DefMath('\iiint',"\x{222D}", meaning=>'triple-integral', role=>'INTOP'); # TRIPLE INTEGRAL
DefMath('\iiiint',"\x{2A0C}", meaning=>'quadruple-integral', role=>'INTOP');
DefMath('\idotsint',"\x{222B}\x{22EF}\x{222B}", meaning=>'multiple-integral', role=>'INTOP');

DefMacro('\MultiIntegral{}',sub {
  my($gullet,$n)=@_;
  $n = ToString($n);
  (($n==0 ? T_CS('\idotsint'):($n==1?T_CS('\int'):($n==2?T_CS('\iint'):($n==3?T_CS('\iiint'):T_CS('\iiiint'))))));});

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Section 8 Commutative diagrams
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Separately in amscd
# CD environment
# with commands @>.., @<<<, @VVV, @AAA to give right, left, down, up arrows...

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Section 9 Using math fonts
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#======================================================================
# Section 9.1 Introduction
# See amsfonts, euscript

#======================================================================
# Section 9.2 Recommended use of math font commands

#======================================================================
# Section 9.3 Bold math symbols
# See package amsbsy (included by default)

#======================================================================
# Section 9.4 Italic Greek letters
# I think this is sufficient:

DefMath('\varGamma',   "\x{0393}",font=>{shape=>'italic'});
DefMath('\varSigma',   "\x{03A3}",font=>{shape=>'italic'});
DefMath('\varDelta',   "\x{0394}",font=>{shape=>'italic'});
DefMath('\varUpsilon', "\x{03A5}",font=>{shape=>'italic'});
DefMath('\varTheta',   "\x{0398}",font=>{shape=>'italic'});
DefMath('\varPhi',     "\x{03A6}",font=>{shape=>'italic'});
DefMath('\varLambda',  "\x{039B}",font=>{shape=>'italic'});
DefMath('\varPsi',     "\x{03A8}",font=>{shape=>'italic'});
DefMath('\varXi',      "\x{039E}",font=>{shape=>'italic'});
DefMath('\varOmega',   "\x{03A9}",font=>{shape=>'italic'});
DefMath('\varPi',      "\x{03A0}",font=>{shape=>'italic'});

#======================================================================
# And some random other weird naming
Let('\Hat', '\hat');
Let('\Check', '\check');
Let('\Tilde', '\tilde');
Let('\Acute', '\acute');
Let('\Grave', '\grave');
Let('\Dot', '\dot');
Let('\Ddot', '\ddot');
Let('\Breve', '\breve');
Let('\Bar', '\bar');
Let('\Vec', '\vec');

# And where does this go?
DefPrimitive('\allowdisplaybreaks[]', undef);
#======================================================================
DefMacroI('\mintagsep',undef,Tokens());
DefMacroI('\minalignsep',undef,"10pt");
DefRegister('\multlinegap'=>Glue('10pt'));
DefRegister('\multlinetaggap'=>Glue('10pt'));
DefMacro('\primfrac{}',Tokens());

# \shoveleft, \shoveright should do something about eqn number placement?
DefMacro('\shoveleft{}','#1');
DefMacro('\shoveright{}','#1');

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1;

