xtag-mmp.mkii / last modification: 2020-01-30 14:15
%D \module
%D   [       file=xtag-mmp,
%D        version=2000.12.20,
%D          title=\CONTEXT\ XML Macros,
%D       subtitle=Presentation MathML,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

% \points should become \bodyfontsize

% under reconstruction
%
% \starttext
% \usemodule[mathml] \useXMLfilter[utf]
% \unprotect
%
% \remapXMLsequence [mover]      [CPA] \MMLpOVER
% \remapXMLsequence [munder]     [CPA] \MMLpUNDER
%
% \def\MMLpUNDER#1#2%
%   {\getXMLarguments{munder}{accent="false" #1}%
%    \withnexttwoXMLRelements\doMMLpUNDER#2}
%
% \def\MMLpOVER#1#2%
%   {\getXMLarguments{mover}{accent="false" #1}%
%    \withnexttwoXMLRelements\doMMLpOVER #2}
%
% \def\doMMLpUNDER
%   {\doifelse{\XMLpar{munder}{accent}{}}{true}
%      {\secondXMLRelement\firstXMLRelement}
%      {\mathop{\vtop{\mathsurround\zeropoint\ialign{\hss##\hss\crcr
%         \disabledelimiter\doMMLfiller\firstXMLRelement
%         \crcr\noalign{\kern3\points\nointerlineskip}%
%         \disabledelimiter\doMMLfiller\secondXMLRelement
%        \crcr\noalign{\kern3\points}}}}\limits}}
%
% \def\doMMLpOVER
%   {\doifelse{\XMLpar{mover}{accent}{}}{true}
%      {\secondXMLRelement\firstXMLRelement}
%      {\mathop{\vbox{\mathsurround\zeropoint\ialign{\hss##\hss\crcr\noalign{\kern3\points}%
%         \disabledelimiter\doMMLfiller\secondXMLRelement
%         \crcr\noalign{\kern3\points\nointerlineskip}%
%         \disabledelimiter\doMMLfiller\firstXMLRelement
%         \crcr}}}\limits}}
%
% \protect
%
% Normal: \startXMLdata<math><mover              ><mi>a</mi><mo>¯</mo></mover></math>\stopXMLdata \par
% Accent: \startXMLdata<math><mover accent="true"><mi>x</mi><mo>¯</mo></mover></math>\stopXMLdata \par
%
% \stoptext

\writestatus{loading}{ConTeXt XML Macros / Presentational MathML}

\unprotect

\def\convertasciiafter#1#2%
  {\defconvertedargument\asciiafter{#2}%
   \@EA#1\@EA{\asciiafter}}

\def\checkMMLoperator#1#2% temp hack
  {\unspaceargument#1\to\ascii
   \doifXMLentityelse\ascii{\getXMLentity\ascii}{#2}}

\startXMLmapping [mml]

\remapXMLsequence [mi] [CPA] \MMLpMI
\remapXMLsequence [mn] [CPA] \MMLpMN
\remapXMLsequence [mo] [CPA] \MMLpMO

\def\MMLpmath#1#2%
  {\begingroup
   \getXMLarguments{mstyle}{#1}\setMMLpmathstyle{mstyle}#2%
   \endgroup}

\def\MMLpMI#1#2%
  {\MMLpmath{#1}{\checkMMLoperator{#2}{#2}}}

\def\MMLpMN#1#2%
  {\begingroup\rm\MMLpmath{#1}{#2}\endgroup}

\def\MMLpMO#1#2% yes or no
  {\checkMMLoperator
     {#2}
     {\ConvertConstantAfter\doifinstringelse{\xmlrent}{#2}
        {#2}{\hbox{\MMLpmath{#1}{\ignorespaces#2\unskip}}}}} % \hbox ?

\remapXMLsequence [mfenced] [CPA] \MMLpFENCED

\def\doMMLleft #1{\pushmacro\left \let\left \empty\normalleft #1\popmacro\left}
\def\doMMLright#1{\pushmacro\right\let\right\empty\normalright#1\popmacro\right}

\let\MMLpopen \empty
\let\MMLpclose\empty

\def\MMLpFENCED#1#2%
  {\getXMLarguments{mfenced}{open="(" close=")" separators="" #1}%
   \edef\MMLpopen {\XMLpar{mfenced}{open}{}}%
   \edef\MMLpclose{\XMLpar{mfenced}{close}{}}%
   \ifx\MMLpopen\empty\else\doMMLleft\MMLpopen\fi
   \pushmacro\MMLpopen
   \pushmacro\MMLpclose
   \doifXMLparelse{mfenced}{separators}
     {\resetMMLseparator
      \encapsulateXMLR
        {}%
        {\pushmacro\myspecialnormalvert % hack
         \def\myspecialnormalvert{\;\vrule\;}%
         \grabMMLseparator{\XMLpar{mfenced}{separators}{}}%
         \popmacro\myspecialnormalvert}
        {}%
        {#2\empty}}
     {#2}%
   \popmacro\MMLpclose
   \popmacro\MMLpopen
   \ifx\MMLpclose\empty
   \ifx\MMLpopen\empty\else\right.\fi
   \else\doMMLright\MMLpclose\fi}

\def\resetMMLseparator
  {\newcounter\MMLxxcounter
   \let\lastMMLseparator\empty}

\def\grabMMLseparator#1%
  {\increment\MMLxxcounter
   \newcounter\MMLyycounter
   \expanded{\dograbMMLseparator#1\noexpand\relax}}

\def\dograbMMLseparator
  {\increment\MMLyycounter
   \doifnextcharelse\relax
     {\lastMMLseparator\gobbleoneargument}
     {\doifnextcharelse\xmlrent\grabMMLseparatora\grabMMLseparatorb}}

\def\grabMMLseparatora#1\xmlrent#2%
  {\ifnum\MMLxxcounter=\MMLyycounter\space
     \def\lastMMLseparator{\xmlrent{#2}}%
   \fi
   \dograbMMLseparator}

\def\grabMMLseparatorb#1% better use \checkMMLoperator
  {\ifnum\MMLxxcounter=\MMLyycounter\space
\doifXMLentityelse{#1}
  {\def\lastMMLseparator{\xmlrent{#1}}}
  {\def\lastMMLseparator{#1}}%
   \fi
   \dograbMMLseparator}

\remapXMLsequence [menclose] [CPA] \MMLpENCLOSE

\def\MMLpENCLOSE#1#2%
  {\getXMLarguments{menclose}{notation="" #1}%
   \doifelse{\XMLpar{menclose}{notation}{}}{longdiv}
     {\overline{)#2}}
     {#2}}

\remapXMLsequence [mfrac] [CPA] \MMLpFRAC

\def\MMLpFRAC#1#2% \above is suboptimal since the spacing changes
  {\withnexttwoXMLRelements
     {\getXMLarguments{mfrac}{linethickness="" #1}%
      \doifXMLparelse{mfrac}{linethickness}
        {\edef\theXMLpar{\XMLpar{mfrac}{linethickness}{1}}%
         \processaction
           [\theXMLpar]
           [    thin=>\scratchdimen=.2pt,
              medium=>\scratchdimen=.4pt,
               thick=>\scratchdimen=.8pt,
             unknown=>\setdimensionwithunit\scratchdimen{\theXMLpar}{}]%
         {{\firstXMLRelement}\above\scratchdimen{\secondXMLRelement}}}
        {\frac{\firstXMLRelement}{\secondXMLRelement}}}%
   #2}

\remapXMLsequence [ms] [CPA] \MMLpSTRING

\def\MMLpSTRING#1#2%
  {\MMLpTEXT{#1}
     {\getXMLarguments{mstyle}{#1}%
      \getXMLarguments{ms}{lquote="\xmlrent{quot}" rquote="\xmlrent{quot}" #1}%
      \XMLpar{ms}{lquote}{}\ignorespaces#2\unskip\unskip\XMLpar{ms}{rquote}{}}}

\remapXMLsequence [mstyle] [CPA] \MMLpSTYLE

\getXMLarguments
  {mstyle}
  {fontweight="" fontstyle="" mathstyle="" mathvariant="" background="" color=""}

\def\MMLpSTYLE#1#2%
  {\getXMLarguments{mstyle}{#1}#2}

\remapXMLsequence [mtext]    [CPA] \MMLpTEXT
\remapXMLsequence [merror]   [CPA] \MMLpERROR
\remapXMLsequence [mphantom] [CPA] \MMLpPHANTOM
\remapXMLsequence [mpadded]  [CPA] \MMLpPADDED

\def\MMLpTEXT#1#2%
  {\hbox
     {\tf % else encoding problems
      \getXMLarguments{mstyle}{#1}%
      \doMMPpbackground{mstyle}
        {\doMMPpcolor{mstyle}
           {\setMMLptextstyle{mstyle}%
            \ignorespaces#2\unskip\unskip}}}}

\def\setMMLpstyle#1%
  {\doifdefined{MMLpstyle:#1}{\getvalue{MMLpstyle:#1}}}

\def\defineMMLstyle[#1]#2%
  {\setvalue{MMLpstyle:#1}{#2}}

\defineMMLstyle[normal]     {\tf} \defineMMLstyle[double-stuck] {\bf}
\defineMMLstyle[bolditalic] {\bi} \defineMMLstyle[bold-italic]  {\bi}
\defineMMLstyle[boldslanted]{\bs} \defineMMLstyle[bold-slanted] {\bs}
\defineMMLstyle[boldnormal] {\bf} \defineMMLstyle[bold]         {\bf}
\defineMMLstyle[slanted]    {\sl} \defineMMLstyle[normalslanted]{\sl}
\defineMMLstyle[italic]     {\it} \defineMMLstyle[normalitalic] {\it}
\defineMMLstyle[fraktur]    {\bf} \defineMMLstyle[bold-fraktur] {\bf}
\defineMMLstyle[script]     {\tf} \defineMMLstyle[bold-script]  {\bf}

% and all kind of other crappy names

\def\setMMLptextstyle#1%
  {\setMMLpstyle{\XMLpar{#1}{fontweight}{}\XMLpar{#1}{fontstyle}{}}}

\def\setMMLpmathstyle#1%
  {\setMMLpstyle{\XMLpar{#1}{mathvariant}{}}}

\def\doMMPpcolor#1#2%
  {\doifXMLparelse{#1}{color}{\color[\XMLpar{#1}{color}{}]{#2}}{#2}}

\def\doMMPpbackground#1#2%
  {\doifXMLparelse{#1}{background}
     {\inframed
        [\c!frame=\v!off,
         \c!background=\v!color,
         \c!backgroundcolor=\XMLpar{#1}{background}{}]
        {#2}}
     {#2}}

\def\MMLpERROR  #1#2{\hbox{$\displaystyle#2$}}
\def\MMLpPHANTOM#1#2{\phantom{\ignorespaces{}#2\unskip}} % watch spacing {} hack
\def\MMLpPADDED #1#2{#2}

\remapXMLsequence [mrow] [CPA] \MMLpROW

\def\MMLpROW#1#2{#2}

\remapXMLsequence [msqrt] [CPA] \MMLpSQRT
\remapXMLsequence [mroot] [CPA] \MMLpROOT

\def\MMLpSQRT#1#2%
  {\sqrt{#2}}

\def\MMLpROOT#1#2%
  {\withnexttwoXMLRelements{\root{\secondXMLRelement}\of{\firstXMLRelement}}#2}

\remapXMLsequence [msup] [CPA] \MMLpSUP
\remapXMLsequence [msub] [CPA] \MMLpSUB

\setupMMLappearance[scripts][\c!alternative=\v!a]

\def\MMLpSUBP#1#2%
  {\withnexttwoXMLRelements
     {\doifelse\@@MMLscriptsalternative\v!a
        {{\firstXMLRelement}#1{\secondXMLRelement}} % both {} essential
        {\firstXMLRelement#1{\secondXMLRelement}}}%
   #2}

\def\MMLpSUP#1{\MMLpSUBP ^}
\def\MMLpSUB#1{\MMLpSUBP _}

\remapXMLsequence [msubsup] [CPA] \MMLpSUBSUP

\def\MMLpSUBSUP#1#2%
  {\withnextthreeXMLRelements
     {\firstXMLRelement _{\secondXMLRelement}^{\thirdXMLRelement}}%
   #2}

\remapXMLsequence [mover]      [CPA] \MMLpOVER
\remapXMLsequence [munder]     [CPA] \MMLpUNDER
\remapXMLsequence [munderover] [CPA] \MMLpUNDEROVER

% hack, cannot be nested

\def\MMLpUNDER#1#2{\withnexttwoXMLRelements\doMMLpUNDER#2}
\def\MMLpOVER #1#2{\withnexttwoXMLRelements\doMMLpOVER #2}

\def\doMMLfiller#1%
   {\pushmacro\doMMLfiller
    \let\doMMLfiller\gobbleoneargument
    \gdef\dodoMMLfiller{\disablefiller\mathematics{#1}}%
    \setbox\scratchbox=\hbox
      {\def\normalorfiller##1##2%
         {\gdef\dodoMMLfiller{\enablefiller#1}%
          \let\normalorfiller\gobbletwoarguments}%
       $#1$}%
    \popmacro\doMMLfiller
    \dodoMMLfiller}

\def\doMMLpUNDER
  {\mathop{\vtop{\mathsurround\zeropoint\ialign{\hss##\hss\crcr
     \disabledelimiter\doMMLfiller\firstXMLRelement
     \crcr\noalign{\kern3\points\nointerlineskip}%
     \disabledelimiter\doMMLfiller\secondXMLRelement
     \crcr\noalign{\kern3\points}}}}\limits}

\def\doMMLpOVER
  {\mathop{\vbox{\mathsurround\zeropoint\ialign{\hss##\hss\crcr\noalign{\kern3\points}%
     \disabledelimiter\doMMLfiller\secondXMLRelement
     \crcr\noalign{\kern3\points\nointerlineskip}%
     \disabledelimiter\doMMLfiller\firstXMLRelement
     \crcr}}}\limits}

\def\MMLpUNDEROVER#1#2%
  {\withnextthreeXMLRelements
     {\firstXMLRelement
        _{\disablefiller\disabledelimiter\secondXMLRelement}%
        ^{\disablefiller\disabledelimiter\thirdXMLRelement}}#2}

\remapXMLsequence [mtable]     [CPA] \MMLpTABLE
\remapXMLsequence [mtr]        [CPA] \MMLpTR
\remapXMLsequence [mtd]        [CPA] \MMLpTD
\remapXMLsequence [mlabeledtr] [CPA] \MMLpLABELEDTR

\unexpanded\def\@col@amp@{&}

\def\MMLpTR#1#2{\collectbetweenXMLR{\@col@amp@}{#2}\the\XMLRtoks\crcr}
\def\MMLpTD#1#2{#2}

\def\MMLpLABELEDTR{\MMLpTR}

\def\MMLpTABLEmapper#1#2#3%
  {\doifXMLparelse{mtable}{#1}
     {\newcounter\MMLcounter
      \def\docommand##1%
        {\increment\MMLcounter
         \let\MMLpREMAP\doMMLpREMAP
         \def\MMLsetting{##1}#3% remap list
         \expanded{\setupTABLE[column][\MMLcounter][#2=\MMLsetting]}}%
       \expanded{\processseparatedlist[\XMLpar{mtable}{#1}{}][ ]\noexpand\docommand}}
     {}}

\def\MMLpTABLEmap#1#2#3%
  {\doifXMLparelse{mtbl}{#1}
     {\edef\MMLsetting{\XMLpar{mtbl}{#1}{}}#3% remap list
      \edef\theMMLpTABLEmap{#2=\MMLsetting,\theMMLpTABLEmap}}
     {}}

\def\doMMLpREMAP#1#2%
  {\doif{\MMLsetting}{#1}
     {\def\MMLsetting{#2}%
      \let\MMLpREMAP\gobbletwoarguments}}

\let\MMLpREMAP\doMMLpREMAP

\def\doMMLpTABLE#1#2%
  {\begingroup
   \getXMLarguments{mtable}
     {columnalign="" columnspacing=".25ex" rowspacing=".25ex"
      frame="" color="" background="" #1}%
   \setupTABLE[\c!frame=\v!off]%
   \MMLpTABLEmapper{background}{\c!backgroundcolor}{}%
   \MMLpTABLEmapper{color}{\c!color}{}%
   \MMLpTABLEmapper{frame}{\c!frame}
     {\MMLpREMAP{none}{off}\MMLpREMAP{solid}{on}}%
   \MMLpTABLEmapper{columnalign}{\c!align}
     {\MMLpREMAP{left}{right}%
      \MMLpREMAP{right}{left}%
      \MMLpREMAP{center}{middle}}%
   \setMMLpunit{\XMLpar{mtable}{rowspacing}{}}{.25ex}%
   \let\MMLpTABLEoffset\MMLpunit
   \let\MMLpTR\doMMLpTR
   \let\MMLpTD\doMMLpTD
   \bTABLE[\c!background=\v!color,\c!offset=\MMLpTABLEoffset]#2\eTABLE
   \endgroup}

\def\doMMLpTR#1#2%
  {\doifXMLRchildelse{mtd}{#2}
     {\bTR\ignorespaces#2\unskip\eTR}
     {\bTR\doMMLpTD{#1}{#2}\eTR}}

\def\doMMLpTD#1#2%
  {\getXMLarguments{mtbl}
     {columnalign="" columnspacing="" rowspacing=""
      frame="" color="" background="" #1}%
   \let\theMMLpTABLEmap\empty
   \MMLpTABLEmap{background}{\c!backgroundcolor}{}%
   \MMLpTABLEmap{color}{\c!color}{}%
   \MMLpTABLEmap{frame}{\c!frame}
     {\MMLpREMAP{none}{off}\MMLpREMAP{solid}{on}}%
   \MMLpTABLEmap{columnalign}{\c!align}
     {\MMLpREMAP{left}{right}\MMLpREMAP{right}{left}}%
   \@EA\bTD\@EA[\theMMLpTABLEmap]$\ignorespaces#2\unskip$\eTD}

\setupMMLappearance[mtable][\c!alternative=\v!a]

\def\MMLpTABLE
  {\doifelse\@@MMLmtablealternative\v!a
     {\expandafter\MMLpTABLEa}
     {\expandafter\MMLpTABLEb}}

\def\MMLpTABLEa#1#2%
  {\begingroup
   \doifelsenothing{#1}
     {\global\setfalse\mmlTABLEargs}
     {\global\settrue\mmlTABLEargs}%
   \ifconditional\mmlTABLEargs \else
     \setbox\scratchbox=\hbox
       {$\displaystyle
        \def\MMLpTABLE##1##2%
          {\ifconditional\mmlTABLEargs \else
             \doifelsenothing{##1}{##2}{\global\settrue\mmlTABLEargs}%
           \fi}%
        \let\MMLpTR\MMLpTABLE
        \let\MMLpTD\MMLpTABLE
        #2$}%
   \fi
   \ifconditional\mmlTABLEargs
     \let\MMLpTABLE\doMMLpTABLE
     \def\next{\MMLpTABLE{#1}}%
   \else
     \let\next\matrix
   \fi
   \next{#2}%
   \endgroup}

\let\MMLpTABLEb\doMMLpTABLE

\remapXMLsingular [mspace] [CPA] \MMLpSPACE

\def\setMMLpunit#1#2%
  {\setbox\scratchbox=\hbox
     {\edef\ascii{#1}%
      \@EA\aftersplitstring\ascii\at.\to\ascii
      \scratchcounter=\ifx\ascii\empty#1\else\ascii\fi
      \unskip\unskip}%
   \ifdim\wd\scratchbox=\zeropoint
     \edef\MMLpunit{#1em}%
   \else
     \edefconvertedargument\ascii{#1}%
     \convertasciiafter\doifinstringelse{em}{\ascii}{\edef\MMLpunit{#1}}{%
     \convertasciiafter\doifinstringelse{ex}{\ascii}{\edef\MMLpunit{#1}}{%
     \convertasciiafter\doifinstringelse{pt}{\ascii}{\edef\MMLpunit{#1}}{%
                                                     \edef\MMLpunit{#2}}}}%
  \fi}

\def\MMLpSPACE#1#2%
  {\getXMLarguments{mspace}{width=".5em" #1}%
   \setMMLpunit{\XMLpar{mspace}{width}{}}{.5em}%
   \hskip\MMLpunit\relax}


\remapXMLsingular [mglyph] [CPA] \MMLpGLYPH

\def\MMLpGLYPH#1#2% we assume \definefont usage
  {\getXMLarguments{mglyph}{fontfamily="" index="1" alt="" #1}%
   \def\MMLpglyph{\XMLpar{mglyph}{fontfamily}{}}%
   \doifelsenothing{\MMLpglyph}
     {\hbox{\tttf[fontfamily unspecified]}}
     {\doifdefinedelse{\MMLpglyph}
        {\hbox{\getvalue{\MMLpglyph}\char0\XMLpar{mglyph}{index}{1}}}
        {\doifelsenothing{\XMLpar{mglyph}{alt}{}}
           {\hbox{\tttf[unknown fontfamily \XMLpar{mglyph}{fontfamily}{}]}}
           {\hbox{\tttf\XMLpar{mglyph}{alt}{}}}}}}

\remapXMLsingular [malignmark] [CPA] \MMLpALIGNMARK

\def\MMLpALIGNMARK#1#2%
  {}

\remapXMLsingular [none]          [CPA] \MMLpNONE
\remapXMLsingular [mprescripts]   [CPA] \MMLpMPRESCRIPTS
\remapXMLsequence [mmultiscripts] [CPA] \MMLpMULTISCRIPTS

\def\MMLpNONE       #1#2{}
\def\MMLpMPRESCRIPTS#1#2{}

\def\MMLpMULTISCRIPTS#1#2%
  {\pushmacro\xmlr
   \let\xmlr\pMULTISCRIPTmmlPRE
   \donefalse \scratchcounter=0 #2\empty
   \let\xmlr\pMULTISCRIPTmmlPOST
   \donetrue  \scratchcounter=0 #2\empty
   \popmacro\xmlr}

\def\pMULTISCRIPTmmlPRE#1#2#3#4%
  {\ifdone
     \ifodd\scratchcounter
       _{\naturalxmlr{#1}{#2}{#3}{#4}}%
     \else
       ^{\naturalxmlr{#1}{#2}{#3}{#4}}{}%
     \fi
   \else
     \doif{mprescripts/}{#1}{\donetrue{}}% weak, the / here
   \fi
   \ifdone \advance\scratchcounter \plusone \fi}

\let\pMULTISCRIPTmmlPOST\pMULTISCRIPTmmlPRE

\stopXMLmapping

\protect \endinput

% extra samples

\startXMLdata
<formula>
    <dmath>
        <mfrac>
            <mrow>
                <mfrac>
                    <mrow>
                        <mtext>Q</mtext>
                    </mrow>
                    <mrow>
                        <mtext>P</mtext>
                    </mrow>
                </mfrac>
            </mrow>
            <mrow>
                <mtext>R</mtext>
            </mrow>
        </mfrac>
    </dmath>
</formula>
\stopXMLdata

\startXMLdata
<formula>
    <dmath>
        <mfrac>
            <mrow>
                <mfrac>
                    <mrow>
                        <mi mathvariant='normal'>R</mi>
                    </mrow>
                    <mrow>
                        <mi mathvariant='normal'>P</mi>
                    </mrow>
                </mfrac>
            </mrow>
            <mrow>
                <mi mathvariant='normal'>R</mi>
            </mrow>
        </mfrac>
    </dmath>
</formula>
\stopXMLdata