% \iffalse meta-comment
%
% Copyright 2011–2013 by Philipp Stephani
%
% This file may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either
% version 1.3c of this license or (at your option) any later
% version.  The latest version of this license is in:
%
%    http://www.latex-project.org/lppl.txt
%
% and version 1.3c or later is part of all distributions of
% LaTeX version 2009/09/24 or later.
%
% \fi
%
% \iffalse
%<*driver>
\documentclass[a4paper, 10pt, ngerman, american]{phst-doc}

\usepackage{lualatex-math}
\newcommand*{\thispackage}{\textsf{lualatex-math}\xspace}

%<!english>\excludecomment{english}
%<!german>\excludecomment{german}
%<!english>\OnlyDescription

\begin{document}

%<german>\selectlanguage{ngerman}

\DocInput{lualatex-math.dtx}
\PrintChanges
%<english>\PrintIndex

\end{document}
%</driver>
% \fi
%
% \CheckSum{960}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
%
% \begin{english}
%   \changes{v0.1}{2011/04/22}{Initial version}
%   \changes{v0.3a}{2011/09/13}{Updated for changes in \pkg{l3kernel}}
%   \changes{v1.0}{2012/08/27}{Switched to \pkg{l3docstrip}}
% \end{english}
%
% \begin{german}
%   \changes{v0.1}{2011/04/22}{Erste Version}
%   \changes{v0.3a}{2011/09/13}{Aktualisierung nach inkompatiblen Änderungen in \pkg{l3kernel}}
%   \changes{v1.0}{2012/08/27}{Umstellung auf \pkg{l3docstrip}}
% \end{german}
%
% \GetFileInfo{lualatex-math.sty}
%
% \begin{english}
%   \title{The \thispackage package\thanks{This document corresponds to
%       \thispackage{}~\fileversion, dated~\filedate.}}
% \end{english}
% \begin{german}
%   \title{Das Paket \thispackage\thanks{Dieses Dokument beschreibt
%       \thispackage{}~\fileversion vom~\filedate.}}
% \end{german}
%
% \author{Philipp Stephani \\ \texttt{p.stephani2@gmail.com}}
% \date{\filedate}
%
%
% \maketitle
% \tableofcontents
%
%
% \begin{english}
%   \section{Introduction}
%
%   \Hologo{LuaTeX} brings major improvements to all areas of \hologo{TeX}
%   typesetting and programming.  They are made available through new primitives
%   or the embedded Lua interpreter, and combining them with existing
%   \hologo{LaTeX2e} packages is not a task the average \hologo{LaTeX} user
%   should have to care about.  Therefore a multitude of \hologo{LaTeX2e}
%   packages have been written to bridge the gap between documents and the new
%   features.  The \thispackage package focuses on the additional possibilities
%   for mathematical typesetting.  The most eminent of the new features is the
%   ability to use Unicode and OpenType fonts, as provided by \Robertson’s
%   \pkg{unicode-math} package.  However, there is a smaller group of changes
%   unrelated to Unicode: these are to be dealt with in this package.  While in
%   principle most \hologo{TeX} documents written for traditional engines should
%   work just fine with \hologo{LuaTeX}, there is a small number of breaking
%   changes that require the attention of package authors.  The \thispackage
%   package tries to fix some of the issues encountered while porting traditional
%   macro packages to \hologo{LuaLaTeX}.
%
%   The decision to write patches for existing macro packages should not be
%   made lightly: monkey patching done by somebody different from the original
%   package author ties the patching package to the implementation details of
%   the patched functionality and breaks all rules of encapsulation.  However,
%   due to the lack of alternatives, it has become an accepted way of providing
%   new functionality in \hologo{LaTeX}.  To keep the negative impact as small
%   as possible, the \thispackage package patches only the \hologo{LaTeX2e}
%   kernel and a small number of popular packages.  In general, this package
%   should be regarded as a temporary kludge that should be removed once the
%   math-related packages are updated to be usable with \hologo{LuaTeX}.  By
%   its very nature, the package is likely to cause problems; in such cases,
%   please refer to the issue
%   tracker\footnote{\url{https://github.com/phst/lualatex-math/issues}}.
% \end{english}
%
% \begin{german}
%   \section{Einführung}
%
%   \Hologo{LuaTeX} bringt zahlreiche Verbesserungen für alle Gebiete des
%   Satzes und der Programmierung mit \hologo{TeX} mit sich.  Diese
%   Verbesserungen werden in Form von neuen primitiven Befehlen oder durch den
%   eingebetteten Lua-Interpreter zur Verfügung gestellt, und normale
%   \hologo{LaTeX}-Benutzer sollten sich nicht damit beschäftigen müssen, sie
%   in \hologo{LaTeX2e} zu integrieren.  Aus diesem Grund ist eine Vielzahl von
%   \hologo{LaTeX2e}-Paketen entstanden, um die Lücke zwischen existierenden
%   Dokumenten und den neuen Möglichkeiten zu schließen.  Das Paket
%   \thispackage beschäftigt sich mit den zusätzlichen Möglichkeiten für den
%   Mathematiksatz.  Die wichtigste davon ist die Möglichkeit, Unicode und
%   OpenType-Schriften zu benutzen, was durch \Robertson{}s
%   \pkg{unicode-math}-Paket ermöglicht wird.  Allerdings gibt es ein paar
%   Änderungen, die nicht in Bezug zu Unicode stehen: um diese kümmert sich das
%   vorliegende Paket.  Während prinzipiell die meisten \hologo{TeX}-Dokumente,
%   die zur Verwendung mit den althergebrachten Engines verfasst wurden, ohne
%   Probleme auch mit \hologo{LuaTeX} funktionieren sollten, gibt es ein paar
%   wenige inkompatible Änderungen, die die Aufmerksamkeit von Paketautoren
%   einfordern.  Das \thispackage-Paket versucht, einige der Probleme zu lösen,
%   die bei der Übertragung einiger vorhandener Makropakete nach
%   \hologo{LuaLaTeX} festgestellt wurden.
%
%   Im Allgemeinen sollte man nur nach sorgfältiger Abwägung Patches für
%   vorhandene Makropakete verfassen: das Patchen von Code durch jemand anderen
%   als den ursprünglichen Autor macht den neuen Code von der Implementation
%   der gepatchten Funktionalität abhänging, was dem Kapselungsprinzip
%   widerspricht.  Dennoch ist diese Art der Programmierung mangels
%   Alternativen zu einer akzeptierten Herangehensweise beim Implementieren
%   neuer Funktionalität für \hologo{LaTeX} geworden.  Um die negativen
%   Auswirkungen so gering wie möglich zu halten, verändert das
%   \thispackage-Paket nur den \hologo{LaTeX2e}-Kern und einige wenige bekannte
%   Pakete.  Generell sollte das vorliegende Paket als eine Zwischenlösung
%   angesehen werden, die zu entfernen ist, sobald die mathematiksatzbezogenen
%   Pakete aktualisiert wurden und korrekt unter \hologo{LuaTeX} funktionieren.
%   Aufgrund seiner Natur ist es wahrscheinlich, dass dieses Paket Probleme
%   verursacht; in diesen Fall benutze bitte den
%   Bugtracker\footnote{\url{https://github.com/phst/lualatex-math/issues}}.
% \end{german}
%
%
% \begin{english}
%   \section{Interface}
%
%   The \thispackage package can be loaded with \cmd{\usepackage} or
%   \cmd{\RequirePackage}, as usual.  It has no options and no public
%   interface; the patching is always done when the package is loaded and
%   cannot be controlled.  As a matter of course, the \thispackage package
%   needs \hologo{LuaLaTeX} to function; it will produce error messages and
%   refuse to load under other engines and formats.  The package depends on the
%   \pkg{expl3} bundle, the \pkg{etoolbox} package, the \pkg{luatexbase} bundle
%   and the \pkg{filehook} package.  The \thispackage package is independent of
%   the \pkg{unicode-math} package; the fixes provided here are valid for both
%   Unicode and legacy math typesetting.
%
%   Currently patches for the \hologo{LaTeX2e} kernel and the \pkg{amsmath},
%   \pkg{amsopn}, \pkg{mathtools} and \pkg{icomma} packages are provided.  It
%   is not relevant whether you load these packages before or after
%   \thispackage.  They should work as expected (and ideally you shouldn’t
%   notice anything), but if you load other packages that by themselves
%   overwrite commands patched by this package, bad things may happen, as it is
%   usual with \hologo{LaTeX}.
%
%   One user-visible change is that the new
%   \DescribeMacros{\mathstyle\luatexmathstyle}\cmd{\mathstyle} primitive
%   (usually called \cmd{\luatexmathstyle} in \hologo{LuaLaTeX}) should work in
%   all cases after the \thispackage package has been loaded, provided you use
%   the high-level macros \DescribeMacros{\frac\binom\genfrac}\cmd{\frac},
%   \cmd{\binom}, and \cmd{\genfrac}.  The fraction-like \hologo{TeX}
%   primitives like \cmd{\over} or \cmd{\atopwithdelims} and the
%   \hologo{plainTeX} leftovers like \cmd{\brack} or \cmd{\choose} cannot be
%   patched, and you shouldn’t use them.
% \end{english}
%
% \begin{german}
%   \section{Schnittstelle}
%
%   Das \thispackage-Paket kann wie üblich mit Hilfe von |\usepackage| oder
%   |\RequirePackage| geladen werden.  Es besitzt weder Optionen noch eine
%   öffentliche Schnittstelle; der Patchprozess wird automatisch durchgeführt,
%   sobald das Paket geladen wird.  Selbstverständlich funktioniert das
%   \thispackage-Paket nur unter \hologo{LuaLaTeX}; für andere Engines oder
%   Formate bricht das Laden mit einer Fehlermeldung ab.  Das Paket hängt von
%   der \pkg{expl3}-Sammlung, dem \pkg{etoolbox}-Paket, der
%   \pkg{luatexbase}-Sammlung und dem \pkg{filehook}-Paket ab.  Das
%   \thispackage-Paket ist unabhängig vom \pkg{unicode-math}-Paket; die hier
%   zur Verfügung gestellten Korrekturen sind sowohl für Unicode"~ als auch für
%   herkömmlichen Mathematiksatz gültig.
%
%   Aktuell werden Patches für den \hologo{LaTeX2e}-Kern sowie für die Pakete
%   \pkg{amsmath}, \pkg{amsopn}, \pkg{mathtools} und \pkg{icomma} angeboten.
%   Es spielt keine Rolle, ob diese Pakete vor oder nach \thispackage geladen
%   werden.  Sie sollten funktionieren wie erwartet (und idealerweise sollte
%   überhaupt keine Änderung bemerkbar sein), aber falls du andere Pakete, die
%   selbst Befehle überschreiben, die von dem vorliegenden Paket gepatcht
%   werden, lädst, können Probleme auftreten, wie bei \hologo{LaTeX} üblich.
%
%   Eine für den Benutzer sichtbare Änderung besteht darin, dass der neue
%   primitive Befehl \DescribeMacros{\mathstyle\luatexmathstyle}|\mathstyle|
%   (in \hologo{LuaLaTeX} allgemein als |\luatexmathstyle| bekannt) in allen
%   Fällen funktionieren sollte, nachdem \thispackage geladen wurde, unter der
%   Bedingung, dass die High-Level-Makros
%   \DescribeMacros{\frac\binom\genfrac}|\frac|, |\binom| und |\genfrac|
%   benutzt werden.  Die bruchartigen primitiven \hologo{TeX}-Befehle wie
%   |\over| oder |\atopwithdelims| und die Makros aus dem
%   \hologo{plainTeX}-Format wie |\brack| oder |\choose| können nicht gepatcht
%   werden und sollten allgemein vermieden werden.
% \end{german}
%
% \StopEventually{}
%
%
% \section{Implementation of the \hologo{LaTeX2e} package}
%
% \subsection{Requirements}
%
%    \begin{macrocode}
%<*package>
%<@@=lltxmath>
\NeedsTeXFormat{LaTeX2e}[2009/09/24]
\RequirePackage{expl3}[2012/08/14]
\ProvidesExplPackage{lualatex-math}{2013/08/03}{1.3}%
  {Patches for mathematics typesetting with LuaLaTeX}
\RequirePackage { etoolbox } [ 2007/10/08 ]
\RequirePackage { luatexbase } [ 2010/05/27 ]
\RequirePackage { filehook } [ 2011/03/09 ]
\RequireLuaModule { lualatex-math } [ 2013/08/03 ]
%    \end{macrocode}
%
% \begin{macro}{\@@_restore_catcode:N}
%   Executing the exhaustive expansion of
%   \cmd{\@@_restore_catcode:N}\meta{character token} restores the category
%   code of the \meta{character token} to its current value.
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_restore_catcode:N #1 {
  \char_set_catcode:nn { \int_eval:n { `#1 } }
    { \char_value_catcode:n { `#1 } }
}
%    \end{macrocode}
% \end{macro}
% We use the macro defined above to restore the category code of the dollar
% sign.  There are packages that make the dollar sign active; hopefully they
% get loaded after the packages we are trying to patch.
%    \begin{macrocode}
\exp_args:Nx \AtEndOfPackage {
  \@@_restore_catcode:N \$
}
\char_set_catcode_math_toggle:N \$
%    \end{macrocode}
%
%
% \subsection{Messages}
%
% \begin{l3message}{luatex-required}
%   Issued when not running under \hologo{LuaTeX}.
%    \begin{macrocode}
\msg_new:nnn { lualatex-math } { luatex-required } {
  The~ lualatex-math~ package~ requires~ LuaTeX. \\
  I~ will~ stop~ loading~ now.
}
%    \end{macrocode}
% \end{l3message}
%
% \begin{l3message}{different-meanings}
%   Issued when two control sequences have different meanings, but should not.
%    \begin{macrocode}
\msg_new:nnnn { lualatex-math } { different-meanings } {
  I've~ expected~ the~ control~ sequences \\
  #1~ and~ #3 \\
  to~ have~ the~ same~ meaning,~ but~ their~ meanings~ are~ different.
} {
  The~ meaning~ of~ #1~ is: \\
  #2 \\
  The~ meaning~ of~ #3~ is: \\
  #4
}
%    \end{macrocode}
% \end{l3message}
%
% \begin{l3message}{macro-expected}
%   Issued when trying to patch a non-macro.  The first argument must be the
%   detokenized macro name.
%    \begin{macrocode}
\msg_new:nnn { lualatex-math } { macro-expected } {
  I've~ expected~ that~ #1~ is~ a~ macro,~ but~ it~ isn't.
}
%    \end{macrocode}
% \end{l3message}
%
% \begin{l3message}{wrong-meaning}
%   Issued when trying to patch a macro with an unexpected meaning.  The first
%   argument must be the detokenized macro name; the second argument must be
%   the actual detokenized meaning; and the third argument must be the expected
%   detokenized meaning.
%    \begin{macrocode}
\msg_new:nnn { lualatex-math } { wrong-meaning } {
  I've~ expected~ #1~ to~ have~ the~ meaning \\
  #3, \\
  but~ it~ has~ the~ meaning \\
  #2.
}
%    \end{macrocode}
% \end{l3message}
%
% \begin{l3message}{patch-macro}
%   Issued when a macro is patched.  The first argument must be the detokenized
%   macro name.
%    \begin{macrocode}
\msg_new:nnn { lualatex-math } { patch-macro } {
  I'm~ going~ to~ patch~ macro~ #1.
}
%    \end{macrocode}
% \end{l3message}
%
%
% \subsection{Initialization}
%
% Unless we are running under \hologo{LuaTeX}, we issue an error and quit
% immediately.  Loading the \pkg{luatexbase} module will already have produced
% an error, but we issue another one for clarity.
%    \begin{macrocode}
\luatex_if_engine:F {
  \msg_error:nn { lualatex-math } { luatex-required }
  \endinput
}
%    \end{macrocode}
%
%
% \subsection{Patching}
%
% \begin{macro}{\@@_temp:w}
%   A scratch macro.
%    \begin{macrocode}
\cs_new_eq:NN \@@_temp:w \prg_do_nothing:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\luatexUmathcode}
% \begin{macro}{\luatexUmathcodenum}
% \begin{macro}{\luatexUmathchardef}
%   We need the extended versions of \cmd{\mathcode} and \cmd{\mathchardef}.
%   The command \cmd{\luatexbase@ensure@primitive}\marg{name} makes sure that
%   the \hologo{LuaTeX} primitive \cs{\meta{name}} is available under the
%   qualified name \cs{luatex\meta{name}}.
%    \begin{macrocode}
\luatexbase@ensure@primitive { Umathcode }
\luatexbase@ensure@primitive { Umathcodenum }
\luatexbase@ensure@primitive { Umathchardef }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_assert_eq:NN}
%   The macro \cmd{\@@_assert_eq:NN}\meta{first command}\meta{second command}
%   tests whether the control sequences \meta{first command} and \meta{second
%   command} have the same meaning, and prints an error message if they do not.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_assert_eq:NN #1 #2 {
  \cs_if_eq:NNF #1 #2 {
    \msg_error:nnxxxx { lualatex-math } { different-meanings }
      { \token_to_str:N #1 } { \token_to_meaning:N #1 }
      { \token_to_str:N #2 } { \token_to_meaning:N #2 }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_patch:NNnnn}
% \begin{macro}{\@@_patch:cNnnn}
%   The auxiliary macro \cmd{\@@_patch:NNnnn}\meta{command}\meta{factory
%   command}\marg{parameter text}\marg{expected replacement text}\marg{new
%   replacement text} tries to patch \meta{command}.  If \meta{command} is
%   undefined, do nothing.  Otherwise it must be a macro with the given
%   \meta{parameter text} and \meta{expected replacement text}, created by the
%   given \meta{factory command} or equivalent.  In this case it will be
%   overwritten using the \meta{parameter text} and the \meta{new replacement
%   text}.  Otherwise issue a warning and don’t overwrite.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_patch:NNnnn #1 #2 #3 #4 #5 {
  \cs_if_exist:NT #1 {
    \token_if_macro:NTF #1 {
      \group_begin:
      #2 \@@_temp:w #3 { #4 }
      \cs_if_eq:NNTF #1 \@@_temp:w {
        \msg_info:nnx { lualatex-math } { patch-macro }
          { \token_to_str:N #1 }
        \group_end:
        #2 #1 #3 { #5 }
      } {
        \msg_warning:nnxxx { lualatex-math } { wrong-meaning }
          { \token_to_str:N #1 } { \token_to_meaning:N #1 }
          { \token_to_meaning:N \@@_temp:w }
        \group_end:
      }
    } {
      \msg_warning:nnx { lualatex-math } { macro-expected }
        { \token_to_str:N #1 }
    }
  }
}
\cs_generate_variant:Nn \@@_patch:NNnnn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_set_mathchar:NN}
%   The macro \cmd{\@@_set_mathchar:NN}\meta{control sequence}\meta{token}
%   defines the \meta{control sequence} as an extended mathematical character
%   shorthand whose mathematical code is given by the mathematical code of the
%   character \texttt{\textasciigrave}\meta{token}.  We cannot use the
%   |\Umathcharnumdef| primitive here since we would then rely on the
%   |\Umathcodenum| primitive which is currently
%   broken.\footnote{\url{http://tug.org/pipermail/luatex/2012-October/003794.html}}
%   \changes{v0.3c}{2012/08/23}{\pkg{l3kernel} renamed \cs{lua_now:x} to
%   \cs{lua_now_x:n}}
%   \changes{v1.1}{2012/10/13}{Update reasoning why \cs{Umathcharnumdef} is not
%   used here}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_set_mathchar:NN #1 #2 {
  \luatexUmathchardef #1
  \lua_now_x:n {
    lualatex.math.print_class_fam_slot( \int_eval:n { `#2 } )
  }
  \scan_stop:
}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{\Hologo{LaTeX2e} kernel}
%
% \changes{v0.3}{2011/08/07}{Patched math group allocation to gain access to
% all families}
% In \hologo{LuaTeX}, we have 256 math families at our disposal.  Therefore we
% modify the \hologo{LaTeX} allocation macros \cmd{\newfam} and
% \cmd{\new@mathgroup} accordingly.
%
% First we test whether \cmd{\newfam} and \cmd{\new@mathgroup} are equal.
%    \begin{macrocode}
\@@_assert_eq:NN \newfam \new@mathgroup
%    \end{macrocode}
%
% \begin{macro}{\new@mathgroup}
%   It is enough to modify the maximum number of families known to the
%   allocation system; the macro \cmd{\alloc@} takes care of the rest.  This
%   would work even if the \pkg{etex} package weren’t loaded.
%    \begin{macrocode}
\@@_patch:NNnnn \new@mathgroup \cs_set_nopar:Npn { } {
%<@@=>
  \alloc@ 8 \mathgroup \chardef \sixt@@n
%<@@=lltxmath>
} {
  \alloc@ 8 \mathgroup \chardef \c_two_hundred_fifty_six
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\newfam}
%   We have to reset \cmd{\newfam} to equal \cmd{\new@mathgroup}.
%    \begin{macrocode}
\cs_set_eq:NN \newfam \new@mathgroup
%    \end{macrocode}
% \end{macro}
%
% \Hologo{LuaTeX} enables access to the current mathematical style via the
% \cmd{\mathstyle} primitive.  For this to work, fraction-like constructs (\eg,
% \meta{numerator} \cmd{\over} \meta{denominator}) have to be enclosed in a
% \cmd{\Ustack} group.  \cmd{\frac} can be patched to do this, but the
% \hologo{plainTeX} remnants \cmd{\choose}, \cmd{\brack} and \cmd{\brace}
% should be discouraged.
%
% \begin{macro}{\luatexUstack}
%   First we make sure that we can use the \cmd{\Ustack} primitive (under the
%   name \cmd{\luatexUstack}).
%    \begin{macrocode}
\luatexbase@ensure@primitive { Ustack }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\frac}
%   Here we assume that nobody except \pkg{amsmath} redefines \cmd{\frac}.
%   This is obviously not the case, but we ignore other packages (\eg,
%   \pkg{nath}) for the moment.  We only patch the \hologo{LaTeX2e} kernel
%   definition if the \pkg{amsmath} package is not loaded; the corresponding
%   patch for \pkg{amsmath} follows below.
%    \begin{macrocode}
\AtEndPreamble {
  \@ifpackageloaded { amsmath } { } {
    \@@_patch:NNnnn \frac \cs_set_nopar:Npn { #1 #2 } {
      {
        \begingroup #1 \endgroup \over #2
      }
    } {
%    \end{macrocode}
% To do: do we need the additional set of braces around \cmd{\Ustack}?
%    \begin{macrocode}
      {
        \luatexUstack { \group_begin: #1 \group_end: \over #2 }
      }
    }
  }
}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{\pkg{amsmath}}
%
% The popular \pkg{amsmath} package is subject to three \hologo{LuaTeX}-related problems:
% \begin{itemize}
% \item The \cmd{\mathcode} primitive is used several times, which fails for
%   Unicode math characters.  \cmd{\Umathcode} should be used instead.
% \item Legacy font dimensions are used for constructing stacks in the
%   \cmd{\substack} command and the \env{subarray} environment.  This doesn’t
%   work if a Unicode math font is selected.
% \item The fraction commands \cmd{\frac} and \cmd{\genfrac} don’t use the
%   \cmd{\Ustack} primitive.
% \end{itemize}
%
% \begin{macro}{\luatexalignmark}
% \begin{macro}{\luatexUstartmath}
% \begin{macro}{\luatexUstopmath}
%   We use the primitives corresponding to the alignment mark (\verb+#+) and to
%   the inline math switches; this is more semantical and might lead to better
%   error messages.
%    \begin{macrocode}
\luatexbase@ensure@primitive { alignmark }
\luatexbase@ensure@primitive { Ustartmath }
\luatexbase@ensure@primitive { Ustopmath }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\luatexUmathstacknumup}
% \begin{macro}{\luatexUmathstackdenomdown}
% \begin{macro}{\luatexUmathstackvgap}
%   Now we require the font parameters we will use.
%    \begin{macrocode}
\luatexbase@ensure@primitive { Umathstacknumup }
\luatexbase@ensure@primitive { Umathstackdenomdown }
\luatexbase@ensure@primitive { Umathstackvgap }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\c_@@_std_minus_mathcode_int}
% \begin{macro}{\c_@@_std_equal_mathcode_int}
%   These constants contain the standard \hologo{TeX} mathematical codes for
%   the minus and the equal signs.  We temporarily set the math codes to these
%   constants before loading the \pkg{amsmath} package so that it can request
%   the legacy math code without error.
%    \begin{macrocode}
\int_const:Nn \c_@@_std_minus_mathcode_int { "2200 }
\int_const:Nn \c_@@_std_equal_mathcode_int { "303D }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_char_dim:NN}
%   The macro \cmd{\@@_char_dim:NN}\meta{primitive}\meta{token} expands to a
%   \meta{dimen} whose value is the metric of the mathematical character
%   corresponding to the character \texttt{\textasciigrave}\meta{token}
%   specified by \meta{primitive}, which must be one of \cmd{\fontcharwd},
%   \cmd{\fontcharht} or \cmd{\fontchardp}, in the currently selected text
%   style font.
%   \changes{v0.3c}{2012/08/23}{\pkg{l3kernel} renamed \cs{lua_now:x} to
%   \cs{lua_now_x:n}}
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_char_dim:NN #1 #2 {
  #1 \textfont
  \lua_now_x:n {
    lualatex.math.print_fam_slot( \int_eval:n { `#2 } )
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_minus_mathchar}
% \begin{macro}{\l_@@_equal_mathchar}
%   These mathematical characters are saved before \pkg{amsmath} is loaded so
%   that we can temporarily assign the \hologo{TeX} values to the mathematical
%   codes of the minus and equals signs.  The \pkg{amsmath} package queries
%   these codes, and if they represent Unicode characters, the package loading
%   will fail.  If \pkg{amsmath} has already been loaded, there is nothing we
%   can do, therefore we use the non-starred version of
%   \cmd{\AtBeginOfPackageFile}.
%   \changes{v1.2}{2013/01/13}{Replace removed macro \cs{chk_if_free_cs:N}}
%    \begin{macrocode}
\tl_new:N \l_@@_minus_mathchar
\tl_new:N \l_@@_equal_mathchar
\AtBeginOfPackageFile { amsmath } {
  \@@_set_mathchar:NN \l_@@_minus_mathchar \-
  \@@_set_mathchar:NN \l_@@_equal_mathchar \=
%    \end{macrocode}
% \end{macro}
% \end{macro}
% Now we temporarily reset the mathematical codes.
%    \begin{macrocode}
  \char_set_mathcode:nn { `\- } { \c_@@_std_minus_mathcode_int }
  \char_set_mathcode:nn { `\= } { \c_@@_std_equal_mathcode_int }
  \AtEndOfPackageFile { amsmath } {
%    \end{macrocode}
% \begin{macro}{\std@minus}
% \begin{macro}{\std@equals}
%   The \pkg{amsmath} package defines the control sequences \cmd{\std@minus}
%   and \cmd{\std@equal} as mathematical character shorthands while loading,
%   but uses our restored mathematical codes, which must be fixed.
%    \begin{macrocode}
    \cs_set_eq:NN \std@minus \l_@@_minus_mathchar
    \cs_set_eq:NN \std@equal \l_@@_equal_mathchar
%    \end{macrocode}
% \end{macro}
% \end{macro}
% Finally, we restore the original mathematical codes of the two signs.
%    \begin{macrocode}
    \luatexUmathcodenum `\- \l_@@_minus_mathchar
    \luatexUmathcodenum `\= \l_@@_equal_mathchar
  }
}
%    \end{macrocode}
% All of the following fixes work even if \pkg{amsmath} is already loaded.
% \begin{macro}{\@begindocumenthook}
%   \changes{v0.3b}{2011/09/18}{Another update for a change in \pkg{l3kernel}}
%   \pkg{amsmath} repeats the definiton of \cmd{\std@minus} and
%   \cmd{\std@equal} at the beginning of the document, so we also have to patch
%   the internal kernel macro \cmd{\@begindocumenthook} which contains the hook
%   code.
%    \begin{macrocode}
\AtEndOfPackageFile * { amsmath } {
  \tl_replace_once:Nnn \@begindocumenthook {
    \mathchardef \std@minus \mathcode `\- \relax
    \mathchardef \std@equal \mathcode `\= \relax
  } {
    \@@_set_mathchar:NN \std@minus \-
    \@@_set_mathchar:NN \std@equal \=
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\resetMathstrut@}
%   \pkg{amsmath} uses the box \cmd{\Mathstrutbox@} for struts in mathematical
%   mode.  This box is defined to have the height and depth of the opening
%   parenthesis taken from the current text font.  The command
%   \cmd{\resetMathstrut@} is executed whenever the mathematical fonts are
%   changed and has to restore the correct dimensions.  The original definition
%   uses a temporary mathematical character shorthand definition whose meaning
%   is queried to extract the family and slot.  We can do this in Lua;
%   furthermore we can avoid a temporary box because \hologo{eTeX} allows us to
%   query glyph metrics directly.
%    \begin{macrocode}
  \@@_patch:NNnnn \resetMathstrut@ \cs_set_nopar:Npn { } {
    \setbox \z@ \hbox {
      \mathchardef \@tempa \mathcode `\( \relax % \)
      \def \@tempb ##1 "##2 ##3 { \the \textfont "##3 \char" }
      \expandafter \@tempb \meaning \@tempa \relax
    }
    \ht \Mathstrutbox@ \ht \z@
    \dp \Mathstrutbox@ \dp \z@
  } {
    \box_set_ht:Nn \Mathstrutbox@ {
      \@@_char_dim:NN \fontcharht \( % \)
    }
    \box_set_dp:Nn \Mathstrutbox@ {
      \@@_char_dim:NN \fontchardp \)
    }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{environment}{subarray}
%   The \env{subarray} environment uses legacy font dimensions.  We simply
%   patch it to use \hologo{LuaTeX} font parameters (and \hologo{LaTeX3}
%   expressions instead of \hologo{TeX} arithmetic).  Since subscript arrays
%   are conceptually vertical stacks, we use the sum of top and bottom shift
%   for the default vertical baseline distance (\cmd{\baselineskip}) and the
%   minimum vertical gap for stack for the minimum baseline distance
%   (\cmd{\lineskip}).
%    \begin{macrocode}
  \@@_patch:NNnnn \subarray \cs_set:Npn { #1 } {
    \vcenter
    \bgroup
    \Let@
    \restore@math@cr
    \default@tag
    \baselineskip \fontdimen 10~ \scriptfont \tw@
    \advance \baselineskip \fontdimen 12~ \scriptfont \tw@
%<@@=>
    \lineskip \thr@@ \fontdimen 8~ \scriptfont \thr@@
%<@@=lltxmath>
    \lineskiplimit \lineskip
    \ialign
    \bgroup
    \ifx c #1 \hfil \fi
    $ \m@th \scriptstyle ## $
    \hfil
    \crcr
  } {
    \vcenter
    \c_group_begin_token
    \Let@
    \restore@math@cr
    \default@tag
    \skip_set:Nn \baselineskip {
      \luatexUmathstacknumup \scriptstyle
      + \luatexUmathstackdenomdown \scriptstyle
    }
    \lineskip \luatexUmathstackvgap \scriptstyle
    \lineskiplimit \lineskip
    \ialign
    \c_group_begin_token
    \token_if_eq_meaning:NNT c #1 { \hfil }
    \luatexUstartmath
    \m@th
    \scriptstyle
    \luatexalignmark \luatexalignmark
    \luatexUstopmath
    \hfil
    \crcr
  }
%    \end{macrocode}
% \end{environment}
%
% \begin{macro}{\frac}
%   Since \cmd{\frac} is declared by \cmd{\DeclareRobustCommand}, we must patch
%   the macro \cmd{\frac\textvisiblespace}.
%    \begin{macrocode}
  \@@_patch:cNnnn { frac~ } \cs_set:Npn { #1 #2 } {
    {
%<@@=>
      \begingroup #1 \endgroup \@@over #2
    }
  } {
    {
      \luatexUstack { \group_begin: #1 \group_end: \@@over #2 }
%<@@=lltxmath>
    }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@genfrac}
%   Generalized fractions are typeset by the internal \cmd{\@genfrac} command.
%    \begin{macrocode}
  \@@_patch:NNnnn \@genfrac \cs_set_nopar:Npn {
    #1 #2 #3 #4 #5
  } {
    {
      #1 { \begingroup #4 \endgroup #2 #3 \relax #5 }
    }
  } {
    {
      #1 {
        \luatexUstack {
          \group_begin: #4 \group_end: #2 #3 \scan_stop: #5
        }
      }
    }
  }
}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{\pkg{amsopn}}
%
% \changes{v1.1}{2012/10/13}{Add fix and unit test for \pkg{amsopn}}
% The \pkg{amsopn} package can be used standalone, but is also loaded by
% \pkg{amsmath}.  It provides the \cmd{\DeclareMathOperator} command which
% breaks when the minus character is a Unicode math character; this issue was
% brought to my attention by \Burnol.
%
% \begin{macro}{\newmcodes@}
%   We only need to patch one usage of |\mathcode| in the internal macro
%   |\newmcodes@|, which is called by all user-defined operators.
%    \begin{macrocode}
\group_begin:
\char_set_catcode_other:N \"
\AtEndOfPackageFile * { amsopn } {
  \@@_patch:NNnnn \newmcodes@ \cs_gset_nopar:Npn { } {
    \mathcode `\' 39
    \mathcode `\* 42
    \mathcode `\. "613A
    \ifnum \mathcode `\- = 45 ~ \else
      \mathchardef \std@minus \mathcode `\- \relax
    \fi
    \mathcode `\- 45
    \mathcode `\/ 47
    \mathcode `\: "603A \relax
  } {
    \char_set_mathcode:nn { `\' } { 39 }
    \char_set_mathcode:nn { `\* } { 42 }
    \char_set_mathcode:nn { `\. } { "613A }
    \int_compare:nNnF { \luatexUmathcodenum `\- } = { 45 } {
      \@@_set_mathchar:NN \std@minus \-
    }
    \char_set_mathcode:nn { `\- } { 45 }
    \char_set_mathcode:nn { `\/ } { 47 }
    \char_set_mathcode:nn { `\: } { "603A }
  }
}
\group_end:
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{\pkg{mathtools}}
%
% \pkg{mathtools}’ \cmd{\cramped} command and others that make use of its
% internal version use a hack involving a null radical.  \Hologo{LuaTeX} has
% primitives for setting material in cramped mode, so we make use of them.
%
% \begin{macro}{\luatexcrampeddisplaystyle}
% \begin{macro}{\luatexcrampedtextstyle}
% \begin{macro}{\luatexcrampedscriptstyle}
% \begin{macro}{\luatexcrampedscriptscriptstyle}
%   First we make sure that the needed primitives for cramped styles are
%   available.
%    \begin{macrocode}
\luatexbase@ensure@primitive { crampeddisplaystyle }
\luatexbase@ensure@primitive { crampedtextstyle }
\luatexbase@ensure@primitive { crampedscriptstyle }
\luatexbase@ensure@primitive { crampedscriptscriptstyle }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\MT_cramped_internal:Nn}
%   The macro \cmd{\MT_cramped_internal:Nn}\meta{style}\marg{expression}
%   typesets the \meta{expression} in the cramped style corresponding to the
%   given \meta{style} (\cmd{\displaystyle} etc.); all we have to do in
%   \hologo{LuaTeX} is to select the correct primitive.  Rewriting the
%   user-level \cmd{\cramped} command and employing \cmd{\mathstyle} would be
%   possible as well, but we avoid this way since we want to patch only a
%   single command.
%    \begin{macrocode}
\AtEndOfPackageFile * { mathtools } {
  \@@_patch:NNnnn \MT_cramped_internal:Nn
    \cs_set_nopar:Npn { #1 #2 } {
    \sbox \z@ {
      $
      \m@th
      #1
      \nulldelimiterspace = \z@
      \radical \z@ { #2 }
      $
    }
    \ifx #1 \displaystyle
      \dimen@ = \fontdimen 8 \textfont 3
      \advance \dimen@ .25 \fontdimen 5 \textfont 2
    \else
      \dimen@ = 1.25 \fontdimen 8
      \ifx #1 \textstyle
        \textfont
      \else
        \ifx #1 \scriptstyle
          \scriptfont
        \else
          \scriptscriptfont
        \fi
      \fi
      3
    \fi
    \advance \dimen@ -\ht\z@
    \ht\z@ = -\dimen@
    \box\z@
  } {
%    \end{macrocode}
% Here the additional set of braces is absolutely necessary, otherwise the
% changed mathematical style would be applied to the material after the
% \cmd{\mathchoice} construct.
%    \begin{macrocode}
    {
      \use:c { luatexcramped \cs_to_str:N #1 } #2
    }
  }
}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{\pkg{icomma}}
%
% \changes{v0.2}{2011/07/03}{Added patch for the \pkg{icomma} package}
% The \pkg{icomma} package uses |\mathchardef| to save the mathematical code of
% the comma character.  This breaks for Unicode fonts.  The incompatibility was
% noticed by
% \Breitfeld.\footnote{\url{https://groups.google.com/forum/\#!topic/de.comp.text.tex/Cputk-AJS5I/discussion}}
%
% \begin{macro}{\mathcomma}
%   \pkg{icomma} defines the mathemathical character shorthand \cmd{\icomma} at
%   the beginning of the document, therefore we again patch
%   \cmd{\@begindocumenthook}.
%    \begin{macrocode}
\AtEndOfPackageFile * { icomma } {
  \tl_replace_once:Nnn \@begindocumenthook {
    \mathchardef \mathcomma \mathcode `\,
  } {
    \@@_set_mathchar:NN \mathcomma \,
  }
}
%</package>
%    \end{macrocode}
% \end{macro}
%
%
% \section{Implementation of the \hologo{LuaLaTeX} module}
%
% For the Lua module, we use the standard \pkg{luatexbase-modutils} template.
% \changes{v1.3}{2013/08/03}{Stop using the deprecated \func{module} function}
%    \begin{macrocode}
%<*lua>
require("luatexbase.modutils")
require("luatexbase.cctb")
lualatex = lualatex or {}
lualatex.math = lualatex.math or {}
local err, warn, info, log = luatexbase.provides_module({
  name = "lualatex-math",
  date = "2013/08/03",
  version = 1.3,
  description = "Patches for mathematics typesetting with LuaLaTeX",
  author = "Philipp Stephani",
  licence = "LPPL v1.3+"
})
%    \end{macrocode}
% \begin{function}{unpack}
%   \changes{v1.3}{2013/08/03}{Integrate Philipp Gesang’s patch to make the
%   \func{unpack} function compatible with Lua~5.2}
%   The function \func{unpack} needs to be treated specially as it got moved
%   around in Lua~5.2.
%    \begin{macrocode}
local unpack = unpack or table.unpack
%    \end{macrocode}
% \end{function}
%    \begin{macrocode}
local cctb = luatexbase.catcodetables
%    \end{macrocode}
%
% \begin{function}{print_fam_slot}
%   The function \func{print_fam_slot} takes one argument which must be a
%   number.  It interprets the argument as a Unicode code point whose
%   mathematical code is printed in the form
%   \meta{family}\texttt{\textvisiblespace}\meta{slot}, suitable for the
%   right-hand side of \eg \verb|\fontcharht\textfont|.
%    \begin{macrocode}
function lualatex.math.print_fam_slot(char)
  local code = tex.getmathcode(char)
  local class, family, slot = unpack(code)
  local result = string.format("%i %i ", family, slot)
  tex.sprint(cctb.string, result)
end
%    \end{macrocode}
% \end{function}
%
% \begin{function}{print_class_fam_slot}
%   The function \func{print_class_fam_slot} takes one argument which must be a
%   number.  It interprets the argument as a Unicode code point whose
%   mathematical code is printed in the form
%   \meta{class}\texttt{\textvisiblespace}\meta{family}\texttt{\textvisiblespace}\meta{slot},
%   suitable for the right-hand side of \cmd{\Umathchardef}.
%    \begin{macrocode}
function lualatex.math.print_class_fam_slot(char)
  local code = tex.getmathcode(char)
  local class, family, slot = unpack(code)
  local result = string.format("%i %i %i ", class, family, slot)
  tex.sprint(cctb.string, result)
end
%    \end{macrocode}
% \end{function}
%    \begin{macrocode}
return lualatex.math
%</lua>
%    \end{macrocode}
%
%
% \section{Test files}
%
% Finally six small test files—but not a real test suite.
%
%
% \subsection{Common definitions}
%
%    \begin{macrocode}
%<*test>
%<@@=test>
\documentclass[pagesize=auto]{scrartcl}
%    \end{macrocode}
% Only \pkg{xparse} starting with 2008/08/03 has \cmd{\NewDocumentCommand}.
%    \begin{macrocode}
\usepackage{xparse}[2008/08/03]
\usepackage{luacode}
\ExplSyntaxOn
\AtBeginDocument { \errorcontextlines = \c_fifteen }
%    \end{macrocode}
%
% \begin{l3message}{pass}
%   This message is issued when a test passed.
%    \begin{macrocode}
\msg_new:nnn { test } { pass } { #1 }
%    \end{macrocode}
% \end{l3message}
%
% \begin{macro}{\@@_pass:x}
%   The macro \cmd{\@@_pass:x}\marg{text} issues the \msg{pass} message with
%   description \meta{text}.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_pass:x #1 {
  \msg_info:nnx { test } { pass } { #1 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{l3message}{fail}
%   This message is issued when a test failed.
%    \begin{macrocode}
\msg_new:nnn { test } { fail } { #1 }
%    \end{macrocode}
% \end{l3message}
%
% \begin{macro}{\@@_fail:x}
%   The macro \cmd{\@@_fail:x}\marg{text} issues the \msg{fail} message with
%   description \meta{text}.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_fail:x #1 {
  \msg_error:nnx { test } { fail } { #1 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tl_const:Nx}
%   We need expanding constants.
%    \begin{macrocode}
\cs_generate_variant:Nn \tl_const:Nn { Nx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\c_@@_equal_tl}
% \begin{macro}{\c_@@_not_equal_tl}
%   Two shorthands for pretty-printing test results.
%    \begin{macrocode}
\tl_const:Nx \c_@@_equal_tl { \c_space_tl == \c_space_tl }
\tl_const:Nx \c_@@_not_equal_tl { \c_space_tl != \c_space_tl }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_equal_pass:nxnx}
%   The macro \cmd{\@@_equal_pass:nxnx}\marg{first expression}\marg{first
%   value}\marg{second expression}\marg{second value} is called when the two
%   values arising from the two expressions are equal.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_equal_pass:nxnx #1 #2 #3 #4 {
  \@@_pass:x {
    \exp_not:n { #1 }
    \c_@@_equal_tl
    #2
    \c_@@_equal_tl
    #4
    \c_@@_equal_tl
    \exp_not:n { #3 }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_equal_fail:nxnx}
%   The macro \cmd{\@@_equal_pass:nxnx}\marg{first expression}\marg{first
%   value}\marg{second expression}\marg{second value} is called when the two
%   values arising from the two expressions are not equal.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_equal_fail:nxnx #1 #2 #3 #4 {
  \@@_fail:x {
    \exp_not:n { #1 }
    \c_@@_equal_tl
    #2
    \c_@@_not_equal_tl
    #4
    \c_@@_equal_tl
    \exp_not:n { #3 }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_assert_equal:NNNNNnn}
% \begin{macro}{\@@_assert_equal:cccccnn}
%   The macro \cmd{\@@_assert_equal:NNNNNnn}\meta{set command}\meta{use
%   command}\meta{compare command}\meta{first temporary command}\meta{second
%   temporary command}\marg{first expression}\marg{second expression} asserts
%   that the two expressions are equal.  The \meta{set command} must have the
%   argument specification \texttt{Nn}, the \meta{use command} \texttt{N}, and
%   the \meta{compare command} \texttt{nNnTF}.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn
\@@_assert_equal:NNNNNnn #1 #2 #3 #4 #5 #6 #7 {
  #1 #4 { #6 }
  #1 #5 { #7 }
  #3 { #4 } = { #5 } {
    \@@_equal_pass:nxnx { #6 } { #2 #4 } { #7 } { #2 #5 }
  } {
    \@@_equal_fail:nxnx { #6 } { #2 #4 } { #7 } { #2 #5 }
  }
}
\cs_generate_variant:Nn \@@_assert_equal:NNNNNnn { ccccc }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_assert_equal:nnn}
%   The macro \cmd{\@@_assert_equal:nnn}\marg{data type}\marg{first
%   expression}\marg{second expression} is a simplified version of
%   \cmd{\@@_assert_equal:NNNNNnn} for data types following the \hologo{LaTeX3}
%   naming conventions; \meta{data type} must be \texttt{int}, \texttt{dim},
%   \etc
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_assert_equal:nnn #1 #2 #3 {
  \@@_assert_equal:cccccnn
    { #1 _set:Nn } { #1 _use:N } { #1 _compare:nNnTF }
    { l_@@_tmpa_ #1 } { l_@@_tmpb_ #1 } { #2 } { #3 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_tmpa_int}
% \begin{macro}{\l_@@_tmpb_int}
%   Scratch registers for numbers.
%    \begin{macrocode}
\int_new:N \l_@@_tmpa_int
\int_new:N \l_@@_tmpb_int
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\AssertIntEqual}
%   The command \cmd{\AssertIntEqual}\marg{first expression}\marg{second
%   expression} asserts that the two integral expressions are equal.
%    \begin{macrocode}
\NewDocumentCommand \AssertIntEqual { m m } {
  \@@_assert_equal:nnn { int } { #1 } { #2 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_tmpa_int}
% \begin{macro}{\l_@@_tmpb_int}
%   Scratch registers for dimensions.
%    \begin{macrocode}
\dim_new:N \l_@@_tmpa_dim
\dim_new:N \l_@@_tmpb_dim
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\AssertDimEqual}
%   The command \cmd{\AssertDimEqual}\marg{first expression}\marg{second
%   expression} asserts that the two dimension expressions are equal.
%    \begin{macrocode}
\NewDocumentCommand \AssertDimEqual { m m } {
  \@@_assert_equal:nnn { dim } { #1 } { #2 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\AssertMathStyle}
%   The command \cmd{\AssertMathStyle}\marg{expression} asserts that the
%   current mathematical style is equal to the value of the integral
%   \meta{expression}.
%    \begin{macrocode}
\NewDocumentCommand \AssertMathStyle { m } {
  \AssertIntEqual { \luatexmathstyle } { #1 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_assert_cramped:Nx}
%   The macro \cmd{\@@_assert_cramped:Nn}\meta{predicate}\marg{name} asserts
%   that we are in math mode and that the current style fulfills the
%   \meta{predicate} (identified by the \meta{name}) which must have the
%   argument specification \texttt{n}.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_assert_cramped:Nx #1 #2 {
  \int_set:Nn \l_@@_tmpa_int { \luatexmathstyle }
  \bool_if:nTF {
    \int_compare_p:nNn { \l_@@_tmpa_int } > { \c_minus_one }
    &&
    #1 { \l_@@_tmpa_int }
  } {
    \@@_pass:x {
      \exp_not:N \luatexmathstyle
      \c_@@_equal_tl
      \int_use:N \l_@@_tmpa_int
      \c_space_tl
      is~ a~ #2~ style
    }
  } {
    \@@_fail:x {
      \exp_not:N \luatexmathstyle
      \c_@@_equal_tl
      \int_use:N \l_@@_tmpa_int
      \c_space_tl
      is~ not~ a~ #2~ style
    }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\AssertNoncrampedStyle}
%   The command \cmd{\AssertNoncrampedStyle} asserts that the current
%   mathematical style is one of the non-cramped styles.
%    \begin{macrocode}
\NewDocumentCommand \AssertNoncrampedStyle { } {
  \@@_assert_cramped:Nx \int_if_even_p:n { non-cramped }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\AssertCrampedStyle}
%   The command \cmd{\AssertCrampedStyle} asserts that the current mathematical
%   style is one of the cramped styles.
%    \begin{macrocode}
\NewDocumentCommand \AssertCrampedStyle { } {
  \@@_assert_cramped:Nx \int_if_odd_p:n { cramped }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_tmpa_box}
% \begin{macro}{\l_@@_tmpb_box}
%   Scratch registers for box constructions.
%    \begin{macrocode}
\box_new:N \l_@@_tmpa_box
\box_new:N \l_@@_tmpb_box
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{function}{contains_space}
%   The function \func{contains_space}|(head, width)| returns |true| if the
%   node list starting at |head| or any of its sublists contain a glue or kern
%   node of width |width|.  If |width| is |nil|, returns |true| if there is any
%   glue or kern node.  If |width| is the string |"nonzero"|, returns |true| if
%   there is any glue node or kern node of nonzero with.
%   \changes{v1.1}{2012/10/13}{Allow testing for nonzero kern nodes}
%    \begin{macrocode}
\begin{luacode*}
function contains_space(head, width)
  for n in node.traverse(head) do
    local id = n.id
    if id == 10 then  -- glue node
      if width then
        if width == "nonzero" or n.spec.width == width then
          return true
        end
      end
    elseif id == 11 then  -- kern node
      if width then
        if width == "nonzero" then
          if n.kern ~= 0 then
            return true
          end
        elseif n.kern == width then
          return true
        end
      end
    elseif id == 0 or id == 1 then  -- sublist
      if contains_space(n.head, width) then
        return true
      end
    end
  end
  return false
end
\end{luacode*}
%    \end{macrocode}
% \end{function}
%
% \begin{macro}{\AssertNoSpace}
%   The command \cmd{\AssertNoSpace}\marg{text} asserts that the node list that
%   is the result of typesetting \meta{text} contains no glue or kern nodes.
%   When called with a star, the command ignores zero-width kerns.
%   \changes{v0.3c}{2012/08/23}{\pkg{l3kernel} renamed \cs{lua_now:x} to
%   \cs{lua_now_x:n}}
%   \changes{v1.1}{2012/10/13}{Allow testing for nonzero kern nodes}
%    \begin{macrocode}
\NewDocumentCommand \AssertNoSpace { s m } {
  \hbox_set:Nn \l_@@_tmpa_box { #2 }
  \int_if_odd:nTF {
    \lua_now_x:n {
      local~ b = tex.getbox(\int_use:N \l_@@_tmpa_box)
      if~ contains_space(b.head,
          \IfBooleanTF { #1 } { "nonzero" } { nil }) then~
        tex.sprint("0")
      else~
        tex.sprint("1")
      end
    }
  } {
    \@@_pass:x {
      \tl_to_str:n { #2 } ~
      contains~ no~ skip~ or~ kern~ node
    }
  } {
    \@@_fail:x {
      \tl_to_str:n { #2 } ~
      contains~ a~ skip~ or~ kern~ node
    }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\AssertMuSpace}
%   The command \cmd{\AssertMuSpace}\marg{text}\marg{muskip} asserts that the
%   node list that is the result of typesetting \meta{text} contains at least
%   one glue or kern node of with \meta{muskip}.
%   \changes{v0.3c}{2012/08/23}{\pkg{l3kernel} renamed \cs{lua_now:x} to
%   \cs{lua_now_x:n}}
%    \begin{macrocode}
\makeatletter
\NewDocumentCommand \AssertMuSpace { m m } {
  \hbox_set:Nn \l_@@_tmpa_box { #1 }
  \hbox_set:Nn \l_@@_tmpb_box { $ \mskip #2 \m@th $ }
  \int_if_odd:nTF {
    \lua_now_x:n {
      local~ b = tex.getbox(\int_use:N \l_@@_tmpa_box)
      local~ s = tex.getbox(\int_use:N \l_@@_tmpb_box)
      if~ contains_space(b.head, s.width) then~
        tex.sprint("1")
      else~
        tex.sprint("0")
      end
    }
  } {
    \@@_pass:x {
      \tl_to_str:n { #1 } ~
      contains~ a~ skip~ or~ kern~ node~ of~ width~
      \tl_to_str:n { #2 }
    }
  } {
    \@@_fail:x {
      \tl_to_str:n { #1 } ~
      contains~ no~ skip~ or~ kern~ node~ of~ width~
      \tl_to_str:n { #2 }
    }
  }
}
\makeatother
\ExplSyntaxOff
%</test>
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{\Hologo{LaTeX2e} kernel, allocation of math families}
%
% \changes{v0.3}{2011/08/07}{Added test file for modified family allocation
% scheme}
% The \hologo{LaTeX2e} kernel itself allocates four families (also known as
% \enquote{math groups} in \hologo{LaTeX} parlance).  Therefore we should still
% be able to allocate 252 families.  We do this alternately with \cmd{\newfam},
% \cmd{\new@mathgroup} and \cmd{\DeclareSymbolFont}.
% \changes{v1.2}{2013/01/13}{Replace removed macro \cs{chk_if_free_cs:N}}
% \changes{v1.2}{2013/01/13}{Track renaming of \cs{int_step_inline:nnnn}}
%    \begin{macrocode}
%<*test-kernel-alloc>
\usepackage{lualatex-math}
\makeatletter
\ExplSyntaxOn
\int_step_inline:nnnn { \c_four } { \c_one } {
  \c_two_hundred_fifty_five - \c_one
} {
  \int_case:nnn { \int_mod:nn { #1 } { \c_three } } {
    { \c_zero } {
      \int_new:N \g_@@_family_int
      \newfam \g_@@_family_int
      \AssertIntEqual { \g_@@_family_int } { #1 }
      \cs_undefine:N \g_@@_family_int
    }
    { \c_one } {
      \int_new:N \g_@@_mathgroup_int
      \new@mathgroup \g_@@_mathgroup_int
      \AssertIntEqual { \g_@@_mathgroup_int } { #1 }
      \cs_undefine:N \g_@@_mathgroup_int
    }
    { \c_two } {
      \DeclareSymbolFont { Test #1 } { OT1 } { cmr } { m } { n }
      \exp_args:Nc \AssertIntEqual { sym Test #1 } { #1 }
    }
  } {
    \@@_fail:x { This~ cannot~ happen }
  }
}
\DeclareSymbolFont { Test 255 } { OT1 } { cmr } { bx } { it }
\DeclareSymbolFontAlphabet { \TestAlphabet } { Test 255 }
\exp_args:Nc \AssertIntEqual { sym Test 255 }
  { \c_two_hundred_fifty_five }
\ExplSyntaxOff
\makeatother
\begin{document}
\[
\TestAlphabet{
  abc
  \AssertIntEqual{\fam}{255}
  \AssertIntEqual{\mathgroup}{255}
}
\]
\end{document}
%</test-kernel-alloc>
%    \end{macrocode}
%
%
% \subsection{\Hologo{LaTeX2e} kernel, \cs{mathstyle} primitive}
%
% Here we only check whether different fractions and other style-changing
% commands result in the correct mathematical style.
%    \begin{macrocode}
%<*test-kernel-style>
\usepackage{lualatex-math}
\begin{document}
\begin{displaymath}
  \AssertMathStyle{0} \sqrt{\AssertMathStyle{1}}
  \frac{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  a^{\frac{\AssertMathStyle{6}}{\AssertMathStyle{7}}}
  \sqrt{\frac{\AssertMathStyle{3}}{\AssertMathStyle{3}}}
  \displaystyle
  \frac{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  \luatexcrampeddisplaystyle
  \frac{\AssertMathStyle{3}}{\AssertMathStyle{3}}
  \textstyle
  \frac{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  \luatexcrampedtextstyle
  \frac{\AssertMathStyle{5}}{\AssertMathStyle{5}}
  \scriptstyle
  \frac{\AssertMathStyle{6}}{\AssertMathStyle{7}}
  \luatexcrampedscriptstyle
  \frac{\AssertMathStyle{7}}{\AssertMathStyle{7}}
\end{displaymath}
\begin{math}
  \AssertMathStyle{2} \sqrt{\AssertMathStyle{3}}
  \frac{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  a^{\frac{\AssertMathStyle{6}}{\AssertMathStyle{7}}}
  \sqrt{\frac{\AssertMathStyle{5}}{\AssertMathStyle{5}}}
  \displaystyle
  \frac{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  \luatexcrampeddisplaystyle
  \frac{\AssertMathStyle{3}}{\AssertMathStyle{3}}
  \textstyle
  \frac{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  \luatexcrampedtextstyle
  \frac{\AssertMathStyle{5}}{\AssertMathStyle{5}}
  \scriptstyle
  \frac{\AssertMathStyle{6}}{\AssertMathStyle{7}}
  \luatexcrampedscriptstyle
  \frac{\AssertMathStyle{7}}{\AssertMathStyle{7}}
\end{math}
\end{document}
%</test-kernel-style>
%    \end{macrocode}
%
%
% \subsection{\pkg{amsmath}, \pkg{amsopn}, and \pkg{mathtools}}
%
% \changes{v1.1}{2012/10/13}{Add fix and unit test for \pkg{amsopn}}
% Since \pkg{mathtools} loads \pkg{amsmath} and \pkg{amsopn} anyway, we test
% all three in one file.
% \begin{macro}{\testbox}
%   First a scratch box register.
%    \begin{macrocode}
%<*test-amsmath>
\usepackage{lualatex-math}
\newsavebox{\testbox}
%    \end{macrocode}
% \end{macro}
% We set the mathematical code for the minus sign to some arbitrary Unicode
% value to test whether the load-time patch works.
%    \begin{macrocode}
\luatexUmathcode`\-="2 "33 "44444 \relax
\usepackage{amsmath}
\AssertIntEqual{\luatexUmathcode`\-}{"33444444}
\makeatletter
\AssertIntEqual{\std@minus}{"33444444}
\makeatother
%    \end{macrocode}
% Check that we can still declare operators.
%    \begin{macrocode}
\DeclareMathOperator{\Operator}{*-/'a-b}
\DeclareMathOperator*{\OperatorWithLimits}{01'*-/}
\DeclareMathOperator{\OperatorWithPunctuation}{a:b*/'-.}
\usepackage{mathtools}
%    \end{macrocode}
% The same for the document begin hook.
%    \begin{macrocode}
\luatexUmathcode`\="5 "66 "77777 \relax
\begin{document}
\AssertIntEqual{\luatexUmathcode`\=}{"66A77777}
\makeatletter
\AssertIntEqual{\std@equal}{"66A77777}
\makeatother
%    \end{macrocode}
% Here we test whether the strut box has the correct height and depth.
%    \begin{macrocode}
\sbox{\testbox}{$($} % )
\makeatletter
\AssertDimEqual{\ht\Mathstrutbox@}{\ht\testbox}
\AssertDimEqual{\dp\Mathstrutbox@}{\dp\testbox}
\makeatother
%    \end{macrocode}
% Here we test for the various \pkg{amsmath} features that have to be patched:
% sub-arrays and various kind of fraction-like objects.  The \cmd{\substack}
% command and \env{subarray} environment aren’t really tested since it is hard
% to check whether the outcome looks right in an automated way.  All tests are
% done in both inline and display mode.
%    \begin{macrocode}
\begin{equation*}
  \AssertMathStyle{0} \sqrt{\AssertMathStyle{1}}
  \sum_{
    \substack{\frac12 \\ \frac34 \\ \frac56}
  }
  \sum_{
    \begin{subarray}{l} \frac12 \\ \frac34 \\ \frac56 \end{subarray}
  }
  \frac{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  a^{\frac{\AssertMathStyle{6}}{\AssertMathStyle{7}}}
  \dfrac{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  \tfrac{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  \binom{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  a^{\binom{\AssertMathStyle{6}}{\AssertMathStyle{7}}}
  \dbinom{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  \tbinom{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  \genfrac{}{}{}{}{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  \genfrac{<}{/}{0pt}{0}{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  \genfrac{}{}{}{1}{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  \genfrac{|}{]}{4pt}{2}{\AssertMathStyle{6}}{\AssertMathStyle{7}}
  \genfrac{}{}{}{3}{\AssertMathStyle{6}}{\AssertMathStyle{7}}
\end{equation*}
\begin{math}
  \AssertMathStyle{2} \sqrt{\AssertMathStyle{3}}
  \sum_{
    \substack{\frac12 \\ \frac34 \\ \frac56}
  }
  \sum_{
    \begin{subarray}{l} \frac12 \\ \frac34 \\ \frac56 \end{subarray}
  }
  \frac{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  a^{\frac{\AssertMathStyle{6}}{\AssertMathStyle{7}}}
  \dfrac{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  \tfrac{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  \binom{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  a^{\binom{\AssertMathStyle{6}}{\AssertMathStyle{7}}}
  \dbinom{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  \tbinom{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  \genfrac{}{}{}{}{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  \genfrac{<}{/}{0pt}{0}{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  \genfrac{}{}{}{1}{\AssertMathStyle{4}}{\AssertMathStyle{5}}
  \genfrac{|}{]}{4pt}{2}{\AssertMathStyle{6}}{\AssertMathStyle{7}}
  \genfrac{}{}{}{3}{\AssertMathStyle{6}}{\AssertMathStyle{7}}
\end{math}
%    \end{macrocode}
% Since \pkg{mathtools}’ \cmd{\cramped} command uses \cmd{\mathchoice}, we
% cannot test for a single mathematical style since all of them are executed;
% instead, we just verify that all styles encountered are cramped.
%    \begin{macrocode}
\begin{equation*}
  \AssertMathStyle{0}
  a^{\AssertMathStyle{4} a}
  \cramped{\AssertCrampedStyle a^{\AssertCrampedStyle a}}
  a^{
    \AssertMathStyle{4}
    a^a
    \cramped{\AssertCrampedStyle a^{\AssertCrampedStyle a}}
    a^a
    \AssertMathStyle{4}
  }
  a^{
    a^{
      \AssertMathStyle{6}
      a^a
      \cramped{\AssertCrampedStyle a^{\AssertCrampedStyle a}}
      a^a
      \AssertMathStyle{6}
    }
  }
  a^{\AssertMathStyle{4} a}
  \AssertMathStyle{0}
\end{equation*}
\begin{math}
  \AssertMathStyle{2}
  a^{\AssertMathStyle{4} a}
  \cramped{\AssertCrampedStyle a^{\AssertCrampedStyle a}}
  a^{
    \AssertMathStyle{4}
    a^a
    \cramped{\AssertCrampedStyle a^{\AssertCrampedStyle a}}
    a^a
    \AssertMathStyle{4}
  }
  a^{
    a^{
      \AssertMathStyle{6}
      a^a
      \cramped{\AssertCrampedStyle a^{\AssertCrampedStyle a}}
      a^a
      \AssertMathStyle{6}
    }
  }
  a^{\AssertMathStyle{4} a}
  \AssertMathStyle{2}
\end{math}
%    \end{macrocode}
% The \pkg{amsopn} package uses |\mathcode| when executing a user-defined
% operator command.  Test that this was patched out.
%    \begin{macrocode}
\AssertNoSpace*{$\Operator$}
\AssertNoSpace*{$\OperatorWithLimits$}
\AssertMuSpace{$\OperatorWithPunctuation$}{\thinmuskip}
\mathcode`\-=45 \relax
\AssertNoSpace*{$\Operator$}
\AssertNoSpace*{$\OperatorWithLimits$}
\AssertMuSpace{$\OperatorWithPunctuation$}{\thinmuskip}
\end{document}
%</test-amsmath>
%    \end{macrocode}
%
%
% \subsection{\pkg{unicode-math}}
%
% This test file loads both \pkg{amsmath} and \pkg{unicode-math}.  The latter
% package contains fixes that somewhat overlap with ours.  We have to take care
% in all packages that no attempt is made to patch a single macro twice.
% Therefore we treat warnings (that occur when trying to patch a macro with an
% unknown meaning) as errors here.  However, the auxiliary package
% \pkg{fontspec-patches} uses \cmd{\RenewDocumentCommand} from the \pkg{xparse}
% package, which generates a warning that we don't want to turn into an error.
% Therefore we treat the offending message \msg{redefine-command} specially.
% \changes{v0.3c}{2012/08/23}{Added special treatment for
% \msg{redefine-command} warning}
%
%    \begin{macrocode}
%<*test-unicode>
\ExplSyntaxOn
\msg_redirect_class:nn { warning } { error }
\msg_redirect_name:nnn { LaTeX } { xparse / redefine-command } { info }
\ExplSyntaxOff
\usepackage{amsmath}
\usepackage{unicode-math}[2011/05/05]
\setmathfont{XITS Math}
\usepackage{lualatex-math}
\begin{document}
\begin{equation*}
  \AssertMathStyle{0} \sqrt{\AssertMathStyle{1}}
  \frac{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  a^{\frac{\AssertMathStyle{6}}{\AssertMathStyle{7}}}
  \dfrac{\AssertMathStyle{2}}{\AssertMathStyle{3}}
  \tfrac{\AssertMathStyle{4}}{\AssertMathStyle{5}}
\end{equation*}
\end{document}
%</test-unicode>
%    \end{macrocode}
%
%
% \subsection{\pkg{icomma} without \pkg{unicode-math}}
%
% \changes{v0.2}{2011/07/03}{Added test file for \pkg{icomma} without
% \pkg{unicode-math}}
% This test file loads only \pkg{icomma} to test whether our patch works for
% Computer Modern.
%
%    \begin{macrocode}
%<*test-icomma>
\usepackage{lualatex-math}
\usepackage{icomma}
\begin{document}
$1,234 \; (x, y)$
\AssertNoSpace{$1,234$}
\AssertMuSpace{$(x, y)$}{\thinmuskip}
\AssertIntEqual{\mathcomma}{"1C0003B}
\end{document}
%</test-icomma>
%    \end{macrocode}
%
%
% \subsection{\pkg{icomma} with \pkg{unicode-math}}
%
% \changes{v0.2}{2011/07/03}{Added test file for \pkg{icomma} with
% \pkg{unicode-math}}
% This test file loads both \pkg{icomma} and \pkg{unicode-math} to test whether
% they interact well.
%
%    \begin{macrocode}
%<*test-icomma-unicode>
\usepackage{unicode-math}[2011/05/05]
\setmathfont{XITS Math}
\usepackage{lualatex-math}
\usepackage{icomma}
\begin{document}
$1,234 \; (x, y)$
\AssertNoSpace{$1,234$}
\AssertMuSpace{$(x, y)$}{\thinmuskip}
\AssertIntEqual{\mathcomma}{"0C0002C}
\end{document}
%</test-icomma-unicode>
%    \end{macrocode}
%
% \Finale
\endinput

% Local Variables:
% mode: doctex
% coding: utf-8-unix
% TeX-engine: luatex
% End:
