From f8e25f5dceea641684f55c35af1074fa3af7f3e6 Mon Sep 17 00:00:00 2001 From: Stegmujo Date: Fri, 23 Dec 2022 11:34:16 +0000 Subject: [PATCH] Update visitor functions and add parsing methods (MMLGen) Bug: T302628 Change-Id: I5374a831cf74a6eb3bf3165abe3ad0661ec07f5f --- src/TexVC/MMLmappings/AMSMappings.php | 76 +- src/TexVC/MMLmappings/BaseMappings.php | 442 ++++++------ src/TexVC/MMLmappings/BaseMethods.php | 256 +++++++ src/TexVC/MMLmappings/BaseParsing.php | 929 +++++++++++++++++++++++++ src/TexVC/Nodes/Big.php | 12 + src/TexVC/Nodes/Box.php | 26 + src/TexVC/Nodes/ChemWord.php | 13 + src/TexVC/Nodes/Curly.php | 7 + src/TexVC/Nodes/DQ.php | 18 + src/TexVC/Nodes/Declh.php | 12 + src/TexVC/Nodes/FQ.php | 39 ++ src/TexVC/Nodes/Fun1.php | 30 + src/TexVC/Nodes/Fun1nb.php | 36 + src/TexVC/Nodes/Fun2.php | 12 + src/TexVC/Nodes/Infix.php | 12 + src/TexVC/Nodes/Literal.php | 69 ++ src/TexVC/Nodes/Lr.php | 43 ++ src/TexVC/Nodes/Matrix.php | 11 + src/TexVC/Nodes/TexArray.php | 55 ++ src/TexVC/Nodes/TexNode.php | 13 + src/TexVC/Nodes/UQ.php | 19 + 21 files changed, 1871 insertions(+), 259 deletions(-) create mode 100644 src/TexVC/MMLmappings/BaseMethods.php create mode 100644 src/TexVC/MMLmappings/BaseParsing.php diff --git a/src/TexVC/MMLmappings/AMSMappings.php b/src/TexVC/MMLmappings/AMSMappings.php index c327c68d2..20e8f04cd 100644 --- a/src/TexVC/MMLmappings/AMSMappings.php +++ b/src/TexVC/MMLmappings/AMSMappings.php @@ -17,37 +17,37 @@ class AMSMappings { private static $instance = null; private const AMSMACROS = [ - "mathring" => [ 'Accent', '02DA' ], + "mathring" => [ 'accent', '02DA' ], "nobreakspace" => 'Tilde', - "negmedspace" => [ 'Spacer', MathSpace::NEGATIVEMEDIUMMATHSPACE ], - "negthickspace" => [ 'Spacer', MathSpace::NEGATIVETHICKMATHSPACE ], + "negmedspace" => [ 'spacer', MathSpace::NEGATIVEMEDIUMMATHSPACE ], + "negthickspace" => [ 'spacer', MathSpace::NEGATIVETHICKMATHSPACE ], "idotsint" => [ 'MultiIntegral', '\\int\\cdots\\int' ], - "dddot" => [ 'Accent', '20DB' ], - "ddddot" => [ 'Accent', '20DC' ], + "dddot" => [ 'accent', '20DB' ], + "ddddot" => [ 'accent', '20DC' ], "sideset" => 'SideSet', - "boxed" => [ 'Macro', '\\fbox{$\\displaystyle{#1}$}', 1 ], + "boxed" => [ 'macro', '\\fbox{$\\displaystyle{#1}$}', 1 ], "tag" => 'HandleTag', "notag" => 'HandleNoTag', "eqref" => [ 'HandleRef', true ], - "substack" => [ 'Macro', '\\begin{subarray}{c}#1\\end{subarray}', 1 ], - "injlim" => [ 'NamedOp', 'inj lim' ], - "projlim" => [ 'NamedOp', 'proj lim' ], - "varliminf" => [ 'Macro', '\\mathop{\\underline{\\mmlToken{mi}{lim}}}' ], - "varlimsup" => [ 'Macro', '\\mathop{\\overline{\\mmlToken{mi}{lim}}}' ], + "substack" => [ 'macro', '\\begin{subarray}{c}#1\\end{subarray}', 1 ], + "injlim" => [ 'namedOp', 'inj lim' ], + "projlim" => [ 'namedOp', 'proj lim' ], + "varliminf" => [ 'macro', '\\mathop{\\underline{\\mmlToken{mi}{lim}}}' ], + "varlimsup" => [ 'macro', '\\mathop{\\overline{\\mmlToken{mi}{lim}}}' ], // replaced underrightarrow here not supported - "varinjlim" => [ 'Macro', '\\mathop{\\xrightarrow{\\mmlToken{mi}{lim}}}' ], + "varinjlim" => [ 'macro', '\\mathop{\\xrightarrow{\\mmlToken{mi}{lim}}}' ], // replaced underleftarrow here not supported - "varprojlim" => [ 'Macro', '\\mathop{\\xleftarrow{\\mmlToken{mi}{lim}}}' ], + "varprojlim" => [ 'macro', '\\mathop{\\xleftarrow{\\mmlToken{mi}{lim}}}' ], "DeclareMathOperator" => 'HandleDeclareOp', - "operatorname" => 'HandleOperatorName', - "genfrac" => 'Genfrac', - "frac" => [ 'Genfrac', '', '', '', '' ], - "tfrac" => [ 'Genfrac', '', '', '', '1' ], - "dfrac" => [ 'Genfrac', '', '', '', '0' ], - "binom" => [ 'Genfrac', '(', ')', '0', '' ], - "tbinom" => [ 'Genfrac', '(', ')', '0', '1' ], - "dbinom" => [ 'Genfrac', '(', ')', '0', '0' ], - "cfrac" => 'CFrac', + "operatorname" => 'handleOperatorName', + "genfrac" => 'genFrac', + "frac" => [ 'genFrac', '', '', '', '' ], + "tfrac" => [ 'genFrac', '', '', '', '1' ], + "dfrac" => [ 'genFrac', '', '', '', '0' ], + "binom" => [ 'genFrac', '(', ')', '0', '' ], + "tbinom" => [ 'genFrac', '(', ')', '0', '1' ], + "dbinom" => [ 'genFrac', '(', ')', '0', '0' ], + "cfrac" => 'cFrac', "shoveleft" => [ 'HandleShove', Align::LEFT ], "shoveright" => [ 'HandleShove', Align::RIGHT ], "xrightarrow" => [ 'xArrow', 0x2192, 5, 10 ], @@ -309,26 +309,26 @@ class AMSMappings { "split" => [ 'EqnArray', null, false, false, 'rl', "ParseUtil_js_1.default.cols(0)" ], "gather" => [ 'EqnArray', null, true, true, 'c' ], 'gather*' => [ 'EqnArray', null, false, true, 'c' ], - "alignat" => [ 'AlignAt', null, true, true ], - 'alignat*' => [ 'AlignAt', null, false, true ], - "alignedat" => [ 'AlignAt', null, false, false ], - "aligned" => [ 'AmsEqnArray', null, null, null, 'rl', "ParseUtil_js_1.default.cols(0, 2)", '.5em', 'D' ], - "gathered" => [ 'AmsEqnArray', null, null, null, 'c', null, '.5em', 'D' ], + "alignat" => [ 'alignAt', null, true, true ], + 'alignat*' => [ 'alignAt', null, false, true ], + "alignedat" => [ 'alignAt', null, false, false ], + "aligned" => [ 'amsEqnArray', null, null, null, 'rl', "ParseUtil_js_1.default.cols(0, 2)", '.5em', 'D' ], + "gathered" => [ 'amsEqnArray', null, null, null, 'c', null, '.5em', 'D' ], "xalignat" => [ 'XalignAt', null, true, true ], 'xalignat*' => [ 'XalignAt', null, false, true ], "xxalignat" => [ 'XalignAt', null, false, false ], "flalign" => [ 'FlalignArray', null, true, false, true, 'rlc', 'auto auto fit' ], 'flalign*' => [ 'FlalignArray', null, false, false, true, 'rlc', 'auto auto fit' ], - "subarray" => [ 'Array', null, null, null, null, "ParseUtil_js_1.default.cols(0)", '0.1em', 'S', 1 ], - "smallmatrix" => [ 'Array', null, null, null, 'c', "ParseUtil_js_1.default.cols(1 / 3)", + "subarray" => [ 'array', null, null, null, null, "ParseUtil_js_1.default.cols(0)", '0.1em', 'S', 1 ], + "smallmatrix" => [ 'array', null, null, null, 'c', "ParseUtil_js_1.default.cols(1 / 3)", '.2em', 'S', 1 ], - "matrix" => [ 'Array', null, null, null, 'c' ], - "pmatrix" => [ 'Array', null, '(', ')', 'c' ], - "bmatrix" => [ 'Array', null, '[', ']', 'c' ], - "Bmatrix" => [ 'Array', null, '\\{', '\\}', 'c' ], - "vmatrix" => [ 'Array', null, '\\vert', '\\vert', 'c' ], - "Vmatrix" => [ 'Array', null, '\\Vert', '\\Vert', 'c' ], - "cases" => [ 'Array', null, '\\{', '.', 'll', null, '.2em', 'T' ] + "matrix" => [ 'array', null, null, null, 'c' ], + "pmatrix" => [ 'array', null, '(', ')', 'c' ], + "bmatrix" => [ 'array', null, '[', ']', 'c' ], + "Bmatrix" => [ 'array', null, '\\{', '\\}', 'c' ], + "vmatrix" => [ 'array', null, '\\vert', '\\vert', 'c' ], + "Vmatrix" => [ 'array', null, '\\Vert', '\\Vert', 'c' ], + "cases" => [ 'array', null, '\\{', '.', 'll', null, '.2em', 'T' ] ]; private const AMSSYMBOLDELIMITERS = [ 'ulcorner' => '\u231C', @@ -338,8 +338,8 @@ class AMSMappings { ]; private const AMSSYMBOLMACROS = [ - "implies" => [ 'Macro', '\\;\\Longrightarrow\\;' ], - "impliedby" => [ 'Macro', '\\;\\Longleftarrow\\;' ] + "implies" => [ 'macro', '\\;\\Longrightarrow\\;' ], + "impliedby" => [ 'macro', '\\;\\Longleftarrow\\;' ] ]; private const AMSMATHDELIMITERS = [ diff --git a/src/TexVC/MMLmappings/BaseMappings.php b/src/TexVC/MMLmappings/BaseMappings.php index ce07d7fa5..a500dd716 100644 --- a/src/TexVC/MMLmappings/BaseMappings.php +++ b/src/TexVC/MMLmappings/BaseMappings.php @@ -323,72 +323,72 @@ class BaseMappings { ]; private const MACROS = [ - "displaystyle" => [ 'SetStyle', 'D', true, 0 ], - "textstyle" => [ 'SetStyle', 'T', false, 0 ], - "scriptstyle" => [ 'SetStyle', 'S', false, 1 ], - "scriptscriptstyle" => [ 'SetStyle', 'SS', false, 2 ], - "rm" => [ 'SetFont', Variants::NORMAL ], - "mit" => [ 'SetFont', Variants::ITALIC ], - "oldstyle" => [ 'SetFont', Variants::OLDSTYLE ], - "cal" => [ 'SetFont', Variants::CALLIGRAPHIC ], - "it" => [ 'SetFont', Variants::MATHITALIC ], - "bf" => [ 'SetFont', Variants::BOLD ], - "bbFont" => [ 'SetFont', Variants::DOUBLESTRUCK ], - "scr" => [ 'SetFont', Variants::SCRIPT ], - "frak" => [ 'SetFont', Variants::FRAKTUR ], - "sf" => [ 'SetFont', Variants::SANSSERIF ], - "tt" => [ 'SetFont', Variants::MONOSPACE ], - "mathrm" => [ 'MathFont', Variants::NORMAL ], - "mathup" => [ 'MathFont', Variants::NORMAL ], - "mathnormal" => [ 'MathFont', '' ], - "mathbf" => [ 'MathFont', Variants::BOLD ], - "mathbfup" => [ 'MathFont', Variants::BOLD ], - "mathit" => [ 'MathFont', Variants::MATHITALIC ], - "mathbfit" => [ 'MathFont', Variants::BOLDITALIC ], - "mathbb" => [ 'MathFont', Variants::DOUBLESTRUCK ], - "Bbb" => [ 'MathFont', Variants::DOUBLESTRUCK ], - "mathfrak" => [ 'MathFont', Variants::FRAKTUR ], - "mathbffrak" => [ 'MathFont', Variants::BOLDFRAKTUR ], - "mathscr" => [ 'MathFont', Variants::SCRIPT ], - "mathbfscr" => [ 'MathFont', Variants::BOLDSCRIPT ], - "mathsf" => [ 'MathFont', Variants::SANSSERIF ], - "mathsfup" => [ 'MathFont', Variants::SANSSERIF ], - "mathbfsf" => [ 'MathFont', Variants::BOLDSANSSERIF ], - "mathbfsfup" => [ 'MathFont', Variants::BOLDSANSSERIF ], - "mathsfit" => [ 'MathFont', Variants::SANSSERIFITALIC ], - "mathbfsfit" => [ 'MathFont', Variants::SANSSERIFBOLDITALIC ], - "mathtt" => [ 'MathFont', Variants::MONOSPACE ], - "mathcal" => [ 'MathFont', Variants::CALLIGRAPHIC ], - "mathbfcal" => [ 'MathFont', Variants::BOLDCALLIGRAPHIC ], - "emph" => [ 'MathFont', Variants::ITALIC ], // added this specific case, toggles roman/italic fonts - "symrm" => [ 'MathFont', Variants::NORMAL ], - "symup" => [ 'MathFont', Variants::NORMAL ], - "symnormal" => [ 'MathFont', '' ], - "symbf" => [ 'MathFont', Variants::BOLD ], - "symbfup" => [ 'MathFont', Variants::BOLD ], - "symit" => [ 'MathFont', Variants::ITALIC ], - "symbfit" => [ 'MathFont', Variants::BOLDITALIC ], - "symbb" => [ 'MathFont', Variants::DOUBLESTRUCK ], - "symfrak" => [ 'MathFont', Variants::FRAKTUR ], - "symbffrak" => [ 'MathFont', Variants::BOLDFRAKTUR ], - "symscr" => [ 'MathFont', Variants::SCRIPT ], - "symbfscr" => [ 'MathFont', Variants::BOLDSCRIPT ], - "symsf" => [ 'MathFont', Variants::SANSSERIF ], - "symsfup" => [ 'MathFont', Variants::SANSSERIF ], - "symbfsf" => [ 'MathFont', Variants::BOLDSANSSERIF ], - "symbfsfup" => [ 'MathFont', Variants::BOLDSANSSERIF ], - "symsfit" => [ 'MathFont', Variants::SANSSERIFITALIC ], - "symbfsfit" => [ 'MathFont', Variants::SANSSERIFBOLDITALIC ], - "symtt" => [ 'MathFont', Variants::MONOSPACE ], - "symcal" => [ 'MathFont', Variants::CALLIGRAPHIC ], - "symbfcal" => [ 'MathFont', Variants::BOLDCALLIGRAPHIC ], - "textrm" => [ 'HBox', null, Variants::NORMAL ], - "textup" => [ 'HBox', null, Variants::NORMAL ], - "textnormal" => [ 'HBox' ], - "textit" => [ 'HBox', null, Variants::ITALIC ], - "textbf" => [ 'HBox', null, Variants::BOLD ], - "textsf" => [ 'HBox', null, Variants::SANSSERIF ], - "texttt" => [ 'HBox', null, Variants::MONOSPACE ], + "displaystyle" => [ 'setStyle', 'D', true, 0 ], + "textstyle" => [ 'setStyle', 'T', false, 0 ], + "scriptstyle" => [ 'setStyle', 'S', false, 1 ], + "scriptscriptstyle" => [ 'setStyle', 'SS', false, 2 ], + "rm" => [ 'setFont', Variants::NORMAL ], + "mit" => [ 'setFont', Variants::ITALIC ], + "oldstyle" => [ 'setFont', Variants::OLDSTYLE ], + "cal" => [ 'setFont', Variants::CALLIGRAPHIC ], + "it" => [ 'setFont', Variants::MATHITALIC ], + "bf" => [ 'setFont', Variants::BOLD ], + "bbFont" => [ 'setFont', Variants::DOUBLESTRUCK ], + "scr" => [ 'setFont', Variants::SCRIPT ], + "frak" => [ 'setFont', Variants::FRAKTUR ], + "sf" => [ 'setFont', Variants::SANSSERIF ], + "tt" => [ 'setFont', Variants::MONOSPACE ], + "mathrm" => [ 'mathFont', Variants::NORMAL ], + "mathup" => [ 'mathFont', Variants::NORMAL ], + "mathnormal" => [ 'mathFont', '' ], + "mathbf" => [ 'mathFont', Variants::BOLD ], + "mathbfup" => [ 'mathFont', Variants::BOLD ], + "mathit" => [ 'mathFont', Variants::MATHITALIC ], + "mathbfit" => [ 'mathFont', Variants::BOLDITALIC ], + "mathbb" => [ 'mathFont', Variants::DOUBLESTRUCK ], + "Bbb" => [ 'mathFont', Variants::DOUBLESTRUCK ], + "mathfrak" => [ 'mathFont', Variants::FRAKTUR ], + "mathbffrak" => [ 'mathFont', Variants::BOLDFRAKTUR ], + "mathscr" => [ 'mathFont', Variants::SCRIPT ], + "mathbfscr" => [ 'mathFont', Variants::BOLDSCRIPT ], + "mathsf" => [ 'mathFont', Variants::SANSSERIF ], + "mathsfup" => [ 'mathFont', Variants::SANSSERIF ], + "mathbfsf" => [ 'mathFont', Variants::BOLDSANSSERIF ], + "mathbfsfup" => [ 'mathFont', Variants::BOLDSANSSERIF ], + "mathsfit" => [ 'mathFont', Variants::SANSSERIFITALIC ], + "mathbfsfit" => [ 'mathFont', Variants::SANSSERIFBOLDITALIC ], + "mathtt" => [ 'mathFont', Variants::MONOSPACE ], + "mathcal" => [ 'mathFont', Variants::CALLIGRAPHIC ], + "mathbfcal" => [ 'mathFont', Variants::BOLDCALLIGRAPHIC ], + "emph" => [ 'mathFont', Variants::ITALIC ], // added this specific case, toggles roman/italic fonts + "symrm" => [ 'mathFont', Variants::NORMAL ], + "symup" => [ 'mathFont', Variants::NORMAL ], + "symnormal" => [ 'mathFont', '' ], + "symbf" => [ 'mathFont', Variants::BOLD ], + "symbfup" => [ 'mathFont', Variants::BOLD ], + "symit" => [ 'mathFont', Variants::ITALIC ], + "symbfit" => [ 'mathFont', Variants::BOLDITALIC ], + "symbb" => [ 'mathFont', Variants::DOUBLESTRUCK ], + "symfrak" => [ 'mathFont', Variants::FRAKTUR ], + "symbffrak" => [ 'mathFont', Variants::BOLDFRAKTUR ], + "symscr" => [ 'mathFont', Variants::SCRIPT ], + "symbfscr" => [ 'mathFont', Variants::BOLDSCRIPT ], + "symsf" => [ 'mathFont', Variants::SANSSERIF ], + "symsfup" => [ 'mathFont', Variants::SANSSERIF ], + "symbfsf" => [ 'mathFont', Variants::BOLDSANSSERIF ], + "symbfsfup" => [ 'mathFont', Variants::BOLDSANSSERIF ], + "symsfit" => [ 'mathFont', Variants::SANSSERIFITALIC ], + "symbfsfit" => [ 'mathFont', Variants::SANSSERIFBOLDITALIC ], + "symtt" => [ 'mathFont', Variants::MONOSPACE ], + "symcal" => [ 'mathFont', Variants::CALLIGRAPHIC ], + "symbfcal" => [ 'mathFont', Variants::BOLDCALLIGRAPHIC ], + "textrm" => [ 'hBox', null, Variants::NORMAL ], + "textup" => [ 'hBox', null, Variants::NORMAL ], + "textnormal" => [ 'hBox' ], + "textit" => [ 'hBox', null, Variants::ITALIC ], + "textbf" => [ 'hBox', null, Variants::BOLD ], + "textsf" => [ 'hBox', null, Variants::SANSSERIF ], + "texttt" => [ 'hBox', null, Variants::MONOSPACE ], "tiny" => [ 'SetSize', 0.5 ], "Tiny" => [ 'SetSize', 0.6 ], "scriptsize" => [ 'SetSize', 0.7 ], @@ -399,68 +399,68 @@ class BaseMappings { "LARGE" => [ 'SetSize', 1.73 ], "huge" => [ 'SetSize', 2.07 ], "Huge" => [ 'SetSize', 2.49 ], - "arcsin" => 'NamedFn', - "arccos" => 'NamedFn', - "arctan" => 'NamedFn', - "arg" => 'NamedFn', - "cos" => 'NamedFn', - "cosh" => 'NamedFn', - "cot" => 'NamedFn', - "coth" => 'NamedFn', - "csc" => 'NamedFn', - "deg" => 'NamedFn', - "det" => 'NamedOp', - "dim" => 'NamedFn', - "exp" => 'NamedFn', - "gcd" => 'NamedOp', - "hom" => 'NamedFn', - "inf" => 'NamedOp', - "ker" => 'NamedFn', - "lg" => 'NamedFn', - "lim" => 'NamedOp', - "liminf" => [ 'NamedOp', 'lim inf' ], - "limsup" => [ 'NamedOp', 'lim sup' ], - "ln" => 'NamedFn', - "log" => 'NamedFn', - "max" => 'NamedOp', - "min" => 'NamedOp', - "Pr" => 'NamedOp', - "sec" => 'NamedFn', - "sin" => 'NamedFn', - "sinh" => 'NamedFn', - "sup" => 'NamedOp', - "tan" => 'NamedFn', - "tanh" => 'NamedFn', - "limits" => [ 'Limits', 1 ], - "nolimits" => [ 'Limits', 0 ], - "overline" => [ 'UnderOver', '2015' ], - "underline" => [ 'UnderOver', '2015' ], - "overbrace" => [ 'UnderOver', '23DE', 1 ], - "underbrace" => [ 'UnderOver', '23DF', 1 ], - "overparen" => [ 'UnderOver', '23DC' ], - "underparen" => [ 'UnderOver', '23DD' ], - "overrightarrow" => [ 'UnderOver', '2192' ], - "underrightarrow" => [ 'UnderOver', '2192' ], - "overleftarrow" => [ 'UnderOver', '2190' ], - "underleftarrow" => [ 'UnderOver', '2190' ], - "overleftrightarrow" => [ 'UnderOver', '2194' ], - "underleftrightarrow" => [ 'UnderOver', '2194' ], - "overset" => 'Overset', - "underset" => 'Underset', + "arcsin" => 'namedFn', + "arccos" => 'namedFn', + "arctan" => 'namedFn', + "arg" => 'namedFn', + "cos" => 'namedFn', + "cosh" => 'namedFn', + "cot" => 'namedFn', + "coth" => 'namedFn', + "csc" => 'namedFn', + "deg" => 'namedFn', + "det" => 'namedOp', + "dim" => 'namedFn', + "exp" => 'namedFn', + "gcd" => 'namedOp', + "hom" => 'namedFn', + "inf" => 'namedOp', + "ker" => 'namedFn', + "lg" => 'namedFn', + "lim" => 'namedOp', + "liminf" => [ 'namedOp', 'lim inf' ], + "limsup" => [ 'namedOp', 'lim sup' ], + "ln" => 'namedFn', + "log" => 'namedFn', + "max" => 'namedOp', + "min" => 'namedOp', + "Pr" => 'namedOp', + "sec" => 'namedFn', + "sin" => 'namedFn', + "sinh" => 'namedFn', + "sup" => 'namedOp', + "tan" => 'namedFn', + "tanh" => 'namedFn', + "limits" => [ 'limits', 1 ], + "nolimits" => [ 'limits', 0 ], + "overline" => [ 'underOver', '2015' ], + "underline" => [ 'underOver', '2015' ], + "overbrace" => [ 'underOver', '23DE', 1 ], + "underbrace" => [ 'underOver', '23DF', 1 ], + "overparen" => [ 'underOver', '23DC' ], + "underparen" => [ 'underOver', '23DD' ], + "overrightarrow" => [ 'underOver', '2192' ], + "underrightarrow" => [ 'underOver', '2192' ], + "overleftarrow" => [ 'underOver', '2190' ], + "underleftarrow" => [ 'underOver', '2190' ], + "overleftrightarrow" => [ 'underOver', '2194' ], + "underleftrightarrow" => [ 'underOver', '2194' ], + "overset" => 'overset', + "underset" => 'underset', "overunderset" => 'Overunderset', - "stackrel" => [ 'Macro', '\\mathrel{\\mathop{#2}\\limits^{#1}}', 2 ], - "stackbin" => [ 'Macro', '\\mathbin{\\mathop{#2}\\limits^{#1}}', 2 ], - "over" => 'Over', - "overwithdelims" => 'Over', - "atop" => 'Over', - "atopwithdelims" => 'Over', - "above" => 'Over', - "abovewithdelims" => 'Over', - "brace" => [ 'Over', '{', '}' ], - "brack" => [ 'Over', '[', ']' ], - "choose" => [ 'Over', '(', ')' ], - "frac" => 'Frac', - "sqrt" => 'Sqrt', + "stackrel" => [ 'macro', '\\mathrel{\\mathop{#2}\\limits^{#1}}', 2 ], + "stackbin" => [ 'macro', '\\mathbin{\\mathop{#2}\\limits^{#1}}', 2 ], + "over" => 'over', + "overwithdelims" => 'over', + "atop" => 'over', + "atopwithdelims" => 'over', + "above" => 'over', + "abovewithdelims" => 'over', + "brace" => [ 'over', '{', '}' ], + "brack" => [ 'over', '[', ']' ], + "choose" => [ 'over', '(', ')' ], + "frac" => 'frac', + "sqrt" => 'sqrt', "root" => 'Root', "uproot" => [ 'MoveRoot', 'upRoot' ], "leftroot" => [ 'MoveRoot', 'leftRoot' ], @@ -473,16 +473,16 @@ class BaseMappings { "lower" => 'RaiseLower', "moveleft" => 'MoveLeftRight', "moveright" => 'MoveLeftRight', - ',' => [ 'Spacer', MathSpace::THINMATHSPACE ], - "'" => [ 'Spacer', MathSpace::MEDIUMMATHSPACE ], - '>' => [ 'Spacer', MathSpace::MEDIUMMATHSPACE ], - ';' => [ 'Spacer', MathSpace::THICKMATHSPACE ], - '!' => [ 'Spacer', MathSpace::NEGATIVETHINMATHSPACE ], - "enspace" => [ 'Spacer', 0.5 ], - "quad" => [ 'Spacer', 1 ], - "qquad" => [ 'Spacer', 2 ], - "thinspace" => [ 'Spacer', MathSpace::THINMATHSPACE ], - "negthinspace" => [ 'Spacer', MathSpace::NEGATIVETHINMATHSPACE ], + ',' => [ 'spacer', MathSpace::THINMATHSPACE ], + "'" => [ 'spacer', MathSpace::MEDIUMMATHSPACE ], + '>' => [ 'spacer', MathSpace::MEDIUMMATHSPACE ], + ';' => [ 'spacer', MathSpace::THICKMATHSPACE ], + '!' => [ 'spacer', MathSpace::NEGATIVETHINMATHSPACE ], + "enspace" => [ 'spacer', 0.5 ], + "quad" => [ 'spacer', 1 ], + "qquad" => [ 'spacer', 2 ], + "thinspace" => [ 'spacer', MathSpace::THINMATHSPACE ], + "negthinspace" => [ 'spacer', MathSpace::NEGATIVETHINMATHSPACE ], "hskip" => 'Hskip', "hspace" => 'Hskip', "kern" => 'Hskip', @@ -493,22 +493,22 @@ class BaseMappings { "Rule" => [ 'Rule' ], "Space" => [ 'Rule', 'blank' ], "nonscript" => 'Nonscript', - "big" => [ 'MakeBig', TexClass::ORD, 0.85 ], - "Big" => [ 'MakeBig', TexClass::ORD, 1.15 ], - "bigg" => [ 'MakeBig', TexClass::ORD, 1.45 ], - "Bigg" => [ 'MakeBig', TexClass::ORD, 1.75 ], - "bigl" => [ 'MakeBig', TexClass::OPEN, 0.85 ], - "Bigl" => [ 'MakeBig', TexClass::OPEN, 1.15 ], - "biggl" => [ 'MakeBig', TexClass::OPEN, 1.45 ], - "Biggl" => [ 'MakeBig', TexClass::OPEN, 1.75 ], - "bigr" => [ 'MakeBig', TexClass::CLOSE, 0.85 ], - "Bigr" => [ 'MakeBig', TexClass::CLOSE, 1.15 ], - "biggr" => [ 'MakeBig', TexClass::CLOSE, 1.45 ], - "Biggr" => [ 'MakeBig', TexClass::CLOSE, 1.75 ], - "bigm" => [ 'MakeBig', TexClass::REL, 0.85 ], - "Bigm" => [ 'MakeBig', TexClass::REL, 1.15 ], - "biggm" => [ 'MakeBig', TexClass::REL, 1.45 ], - "Biggm" => [ 'MakeBig', TexClass::REL, 1.75 ], + "big" => [ 'makeBig', TexClass::ORD, 0.85 ], + "Big" => [ 'makeBig', TexClass::ORD, 1.15 ], + "bigg" => [ 'makeBig', TexClass::ORD, 1.45 ], + "Bigg" => [ 'makeBig', TexClass::ORD, 1.75 ], + "bigl" => [ 'makeBig', TexClass::OPEN, 0.85 ], + "Bigl" => [ 'makeBig', TexClass::OPEN, 1.15 ], + "biggl" => [ 'makeBig', TexClass::OPEN, 1.45 ], + "Biggl" => [ 'makeBig', TexClass::OPEN, 1.75 ], + "bigr" => [ 'makeBig', TexClass::CLOSE, 0.85 ], + "Bigr" => [ 'makeBig', TexClass::CLOSE, 1.15 ], + "biggr" => [ 'makeBig', TexClass::CLOSE, 1.45 ], + "Biggr" => [ 'makeBig', TexClass::CLOSE, 1.75 ], + "bigm" => [ 'makeBig', TexClass::REL, 0.85 ], + "Bigm" => [ 'makeBig', TexClass::REL, 1.15 ], + "biggm" => [ 'makeBig', TexClass::REL, 1.45 ], + "Biggm" => [ 'makeBig', TexClass::REL, 1.75 ], "mathord" => [ 'TeXAtom', TexClass::ORD ], "mathop" => [ 'TeXAtom', TexClass::OP ], "mathopen" => [ 'TeXAtom', TexClass::OPEN ], @@ -519,70 +519,70 @@ class BaseMappings { "mathinner" => [ 'TeXAtom', TexClass::INNER ], "vcenter" => [ 'TeXAtom', TexClass::VCENTER ], "buildrel" => 'BuildRel', - "hbox" => [ 'HBox', 0 ], - "text" => 'HBox', - "mbox" => [ 'HBox', 0 ], - "vbox" => [ 'VBox', 0 ], // added this here in addition + "hbox" => [ 'hBox', 0 ], + "text" => 'hBox', + "mbox" => [ 'hBox', 0 ], + "vbox" => [ 'vbox', 0 ], // added this here in addition "fbox" => 'FBox', - "boxed" => [ 'Macro', '\\fbox{$\\displaystyle{#1}$}', 1 ], + "boxed" => [ 'macro', '\\fbox{$\\displaystyle{#1}$}', 1 ], "framebox" => 'FrameBox', "strut" => 'Strut', - "mathstrut" => [ 'Macro', '\\vphantom{(}' ], - "phantom" => 'Phantom', - "vphantom" => [ 'Phantom', 1, 0 ], - "hphantom" => [ 'Phantom', 0, 1 ], + "mathstrut" => [ 'macro', '\\vphantom{(}' ], + "phantom" => 'phantom', + "vphantom" => [ 'phantom', 1, 0 ], + "hphantom" => [ 'phantom', 0, 1 ], "smash" => 'Smash', - "acute" => [ 'Accent', '00B4' ], - "grave" => [ 'Accent', '0060' ], - "ddot" => [ 'Accent', '00A8' ], - "tilde" => [ 'Accent', '007E' ], - "bar" => [ 'Accent', '00AF' ], - "breve" => [ 'Accent', '02D8' ], - "check" => [ 'Accent', '02C7' ], - "hat" => [ 'Accent', '005E' ], - "vec" => [ 'Accent', '2192' ], - "dot" => [ 'Accent', '02D9' ], - "widetilde" => [ 'Accent', '007E', 1 ], - "widehat" => [ 'Accent', '005E', 1 ], - "matrix" => 'Matrix', - "array" => 'Matrix', - "pmatrix" => [ 'Matrix', '(', ')' ], - "cases" => [ 'Matrix', '{', '', 'left left', null, '.1em', null, + "acute" => [ 'accent', '00B4' ], + "grave" => [ 'accent', '0060' ], + "ddot" => [ 'accent', '00A8' ], + "tilde" => [ 'accent', '007E' ], + "bar" => [ 'accent', '00AF' ], + "breve" => [ 'accent', '02D8' ], + "check" => [ 'accent', '02C7' ], + "hat" => [ 'accent', '005E' ], + "vec" => [ 'accent', '2192' ], + "dot" => [ 'accent', '02D9' ], + "widetilde" => [ 'accent', '007E', 1 ], + "widehat" => [ 'accent', '005E', 1 ], + "matrix" => 'matrix', + "array" => 'matrix', + "pmatrix" => [ 'matrix', '(', ')' ], + "cases" => [ 'matrix', '{', '', 'left left', null, '.1em', null, true ], - "eqalign" => [ 'Matrix', null, null, 'right left', + "eqalign" => [ 'matrix', null, null, 'right left', "(0, lengths_js_1.em)(MathSpace::thickmathspace)", '.5em', 'D' ], - "displaylines" => [ 'Matrix', null, null, 'center', null, '.5em', 'D' ], + "displaylines" => [ 'matrix', null, null, 'center', null, '.5em', 'D' ], "cr" => 'Cr', '\\' => 'CrLaTeX', "newline" => [ 'CrLaTeX', true ], - "hline" => [ 'HLine', 'solid' ], - "hdashline" => [ 'HLine', 'dashed' ], - "eqalignno" => [ 'Matrix', null, null, 'right left', + "hline" => [ 'hline', 'solid' ], + "hdashline" => [ 'hline', 'dashed' ], + "eqalignno" => [ 'matrix', null, null, 'right left', "(0, lengths_js_1.em)(MathSpace::thickmathspace)", '.5em', 'D', null, 'right' ], - "leqalignno" => [ 'Matrix', null, null, 'right left', + "leqalignno" => [ 'matrix', null, null, 'right left', "(0, lengths_js_1.em)(MathSpace::thickmathspace)", '.5em', 'D', null, 'left' ], "hfill" => 'HFill', "hfil" => 'HFill', "hfilll" => 'HFill', - "bmod" => [ 'Macro', '\\mmlToken{mo}[lspace="thickmathspace"' . + "bmod" => [ 'macro', '\\mmlToken{mo}[lspace="thickmathspace"' . ' rspace="thickmathspace"]{mod}' ], - "pmod" => [ 'Macro', '\\pod{\\mmlToken{mi}{mod}\\kern 6mu #1}', 1 ], - "mod" => [ 'Macro', '\\mathchoice{\\kern18mu}{\\kern12mu}' . + "pmod" => [ 'macro', '\\pod{\\mmlToken{mi}{mod}\\kern 6mu #1}', 1 ], + "mod" => [ 'macro', '\\mathchoice{\\kern18mu}{\\kern12mu}' . '{\\kern12mu}{\\kern12mu}\\mmlToken{mi}{mod}\\,\\,#1', 1 ], - "pod" => [ 'Macro', '\\mathchoice{\\kern18mu}{\\kern8mu}' . + "pod" => [ 'macro', '\\mathchoice{\\kern18mu}{\\kern8mu}' . '{\\kern8mu}{\\kern8mu}(#1)', 1 ], - "iff" => [ 'Macro', '\\;\\Longleftrightarrow\\;' ], - "skew" => [ 'Macro', '{{#2{#3\\mkern#1mu}\\mkern-#1mu}{}}', 3 ], - "pmb" => [ 'Macro', '\\rlap{#1}\\kern1px{#1}', 1 ], - "TeX" => [ 'Macro', 'T\\kern-.14em\\lower.5ex{E}\\kern-.115em X' ], - "LaTeX" => [ 'Macro', 'L\\kern-.325em\\raise.21em' . + "iff" => [ 'macro', '\\;\\Longleftrightarrow\\;' ], + "skew" => [ 'macro', '{{#2{#3\\mkern#1mu}\\mkern-#1mu}{}}', 3 ], + "pmb" => [ 'macro', '\\rlap{#1}\\kern1px{#1}', 1 ], + "TeX" => [ 'macro', 'T\\kern-.14em\\lower.5ex{E}\\kern-.115em X' ], + "LaTeX" => [ 'macro', 'L\\kern-.325em\\raise.21em' . '{\\scriptstyle{A}}\\kern-.17em\\TeX' ], - ' ' => [ 'Macro', '\\text{ }' ], - "not" => 'Not', - "dots" => 'Dots', + ' ' => [ 'macro', '\\text{ }' ], + "not" => 'not', + "dots" => 'dots', "space" => 'Tilde', '\u00A0' => 'Tilde', "begin" => 'BeginEnd', @@ -603,9 +603,9 @@ class BaseMappings { // Mathtools environment actually from Mathtools mappings tbd refactor private const ENVIRONMNENTMT = [ - 'dcases' => [ 'Array', null, '\\{', '', 'll', null, '.2em', 'D' ], - 'rcases' => [ 'Array', null, '', '\\}', 'll', null, '.2em' ], - 'drcases' => [ 'Array', null, '', '\\}', 'll', null, '.2em', 'D' ], + 'dcases' => [ 'array', null, '\\{', '', 'll', null, '.2em', 'D' ], + 'rcases' => [ 'array', null, '', '\\}', 'll', null, '.2em' ], + 'drcases' => [ 'array', null, '', '\\}', 'll', null, '.2em', 'D' ], 'dcases*' => [ 'Cases', null, '{', '', 'D' ], 'rcases*' => [ 'Cases', null, '', '}' ], 'drcases*' => [ 'Cases', null, '', '}', 'D' ], @@ -627,11 +627,11 @@ class BaseMappings { 'vsmallmatrix*' => [ 'MtSmallMatrix', null, '\\vert', '\\vert' ], 'Vsmallmatrix' => [ 'MtSmallMatrix', null, '\\Vert', '\\Vert', 'c' ], 'Vsmallmatrix*' => [ 'MtSmallMatrix', null, '\\Vert', '\\Vert' ], - 'crampedsubarray' => [ 'Array', null, null, null, null, '0em', '0.1em', 'S\'', 1 ], + 'crampedsubarray' => [ 'array', null, null, null, null, '0em', '0.1em', 'S\'', 1 ], 'multlined' => 'MtMultlined', 'spreadlines' => [ 'SpreadLines', true ], - 'lgathered' => [ 'AmsEqnArray', null, null, null, 'l', null, '.5em', 'D' ], - 'rgathered' => [ 'AmsEqnArray', null, null, null, 'r', null, '.5em', 'D' ], + 'lgathered' => [ 'amsEqnArray', null, null, null, 'l', null, '.5em', 'D' ], + 'rgathered' => [ 'amsEqnArray', null, null, null, 'r', null, '.5em', 'D' ], ]; private const COLORS = [ @@ -705,37 +705,37 @@ class BaseMappings { 'YellowOrange' => '#FAA21A', ]; - // This is from CancelConfiguration.js + // This is from cancelConfiguration.js private const CANCEL = [ - "cancel" => [ 'Cancel', Notation::UPDIAGONALSTRIKE ], - "bcancel" => [ 'Cancel', Notation::DOWNDIAGONALSTRIKE ], - "xcancel" => [ 'Cancel', Notation::UPDIAGONALSTRIKE . ' ' . + "cancel" => [ 'cancel', Notation::UPDIAGONALSTRIKE ], + "bcancel" => [ 'cancel', Notation::DOWNDIAGONALSTRIKE ], + "xcancel" => [ 'cancel', Notation::UPDIAGONALSTRIKE . ' ' . Notation::DOWNDIAGONALSTRIKE ], - "cancelto" => [ 'CancelTo', Notation::UPDIAGONALSTRIKE . " " . Notation::UPDIAGONALARROW . + "cancelto" => [ 'cancelTo', Notation::UPDIAGONALSTRIKE . " " . Notation::UPDIAGONALARROW . " " . Notation::NORTHEASTARROW ] ]; // They are currently from mhchemConfiguration.js private const MHCHEM = [ - "ce" => [ 'Machine', 'ce' ], - "pu" => [ 'Machine', 'pu' ], + "ce" => [ 'machine', 'ce' ], + "pu" => [ 'machine', 'pu' ], "longrightleftharpoons" => [ - 'Macro', + 'macro', '\\stackrel{\\textstyle{-}\\!\\!{\\rightharpoonup}}{\\smash{{\\leftharpoondown}\\!\\!{-}}}' ], "longRightleftharpoons" => [ - 'Macro', + 'macro', '\\stackrel{\\textstyle{-}\\!\\!{\\rightharpoonup}}{\\smash{\\leftharpoondown}}' ], "longLeftrightharpoons" => [ - 'Macro', + 'macro', '\\stackrel{\\textstyle\\vphantom{{-}}{\\rightharpoonup}}{\\smash{{\\leftharpoondown}\\!\\!{-}}}' ], "longleftrightarrows" => [ - 'Macro', + 'macro', '\\stackrel{\\longrightarrow}{\\smash{\\longleftarrow}\\Rule{0px}{.25em}{0px}}' ], "tripledash" => [ - 'Macro', + 'macro', '\\vphantom{-}\\raise2mu{\\kern2mu\\tiny\\text{-}\\kern1mu\\text{-}\\kern1mu\\text{-}\\kern2mu}' ], "xleftrightarrow" => [ 'xArrow', 0x2194, 6, 6 ], @@ -743,17 +743,17 @@ class BaseMappings { "xRightleftharpoons" => [ 'xArrow', 0x21CC, 5, 7 ], "xLeftrightharpoons" => [ 'xArrow', 0x21CC, 5, 7 ], - "bond" => [ "ChemCustom", "\\bond" ], + "bond" => [ "chemCustom", "\\bond" ], ]; // These are some mappings which are created customly for this private const CUSTOM = [ - "boldsymbol" => [ 'Boldsymbol','' ], // see BoldsymbolConfiguration.js - "oiint" => [ 'Oint', '\u222F', [ "texClass" => TexClass::OP ] ], - "oiiint" => [ 'Oint', '\u2230', [ "texClass" => TexClass::OP ] ], - "ointctrclockwise" => [ 'Oint', '?', [ "texClass" => TexClass::OP ] ], + "boldsymbol" => [ 'boldsymbol','' ], // see boldsymbolConfiguration.js + "oiint" => [ 'oint', '\u222F', [ "texClass" => TexClass::OP ] ], + "oiiint" => [ 'oint', '\u2230', [ "texClass" => TexClass::OP ] ], + "ointctrclockwise" => [ 'oint', '?', [ "texClass" => TexClass::OP ] ], // \varointclockwise - "varointclockwise" => [ 'Oint', '?', [ "texClass" => TexClass::OP ] ], - "P" => [ 'Oint', '?', [ "texClass" => TexClass::OP ] ], // not correct but same mapping + "varointclockwise" => [ 'oint', '?', [ "texClass" => TexClass::OP ] ], + "P" => [ 'oint', '?', [ "texClass" => TexClass::OP ] ], // not correct but same mapping 'textvisiblespace' => [ 'Insert', '\u2423' ], // From TextCompMappings.js (only makro it seems) ]; diff --git a/src/TexVC/MMLmappings/BaseMethods.php b/src/TexVC/MMLmappings/BaseMethods.php new file mode 100644 index 000000000..d3a709b3e --- /dev/null +++ b/src/TexVC/MMLmappings/BaseMethods.php @@ -0,0 +1,256 @@ + 1 ) { + $shifted = array_shift( $resFct ); + return BaseParsing::{$shifted}( $node, $passedArgs, $operatorContent, $input, ...$resFct ); + } else { + return BaseParsing::{$resFct[0]}( $node, $passedArgs, $operatorContent, $input ); + } + } catch ( \Exception $exception ) { + return null; + } + } + + public function checkAndParseOperator( $input, $node, $passedArgs, $operatorContent ) { + $input = MMLutil::inputPreparation( $input ); + $resOperator = BaseMappings::getOperatorByKey( $input ); + if ( $resOperator == null ) { + + $resOperator = AMSMappings::getOperatorByKey( $input ); + if ( $resOperator == null ) { + $resOperator = OperatorDictionary::getOperatorByKey( $input ); + if ( $resOperator ) { + if ( isset( $resOperator[1] ) ) { + // custom parsing here + return $this->parseOperatorDict( $node, $passedArgs, $operatorContent, $input, false ); + } + // Atm just do simple parsing for elements in operator dictionary + $mmlMo = new MMLmo(); + return $mmlMo->encapsulate( $input ); + } + } + } + // If the macro has been found, dynamically call the associated parsing function. + if ( is_string( $resOperator ) ) { + $resOperator = [ $resOperator ]; + } + + if ( $resOperator == null ) { + return null; + } + try { + return $this->parseOperator( $node, $passedArgs, $operatorContent, $input, ...$resOperator ); + + } catch ( ArgumentCountError $errArgcount ) { + return null; + } + } + + public function parseOperatorDict( $node, $passedArgs, $operatorContent, $input, $uc = null, $attrs = [] ) { + // Some custom parsing from operatorDict + switch ( $input ) { + case ";": + $mmlMStyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); + $mSpace = new MMLmspace( "", [ "width" => "0.278em" ] ); + return $mmlMStyle->encapsulate( $mSpace->encapsulate( "" ) ); + case ",": + // this maybe just a default case, this is not rendered when it is the last in row + $mmlMo = new MMLmo(); + return $mmlMo->encapsulate( "," ); + } + return $input; + } + + public function parseOperator( $node, $passedArgs, $operatorContent, $name, $uc = null, $attrs = [] ) { + // if($name == "equiv" || $name == "dotplus" || $name == "mp" || $name == "pm"){ + $attrs = array_merge( $passedArgs, $attrs ); // this is rather a workaround + $mo = new MMLmo( "", $attrs ); + $text = $mo->encapsulate( $uc ); + + // Some attributes are nnot used which come from the mapping, tbd refactor this + $text = str_replace( " largeop=\"\"", "", $text ); + $text = str_replace( "variantForm=\"True\"", "data-mjx-alternate=\"1\"", $text ); + $text = str_replace( "variantForm=\"1\"", "data-mjx-alternate=\"1\"", $text ); + + $text = str_replace( " movesupsub=\"1\"", "", $text ); + return str_replace( "texClass", "data-mjx-texclass", $text ); + } + + public function checkAndParseIdentifier( $input, $node, $passedArgs, $operatorContent ) { + $input = MMLutil::inputPreparation( $input ); + $resIdentifier = BaseMappings::getIdentifierByKey( $input ); + if ( $resIdentifier == null ) { + $resIdentifier = AMSMappings::getIdentifierByKey( $input ); + } + // If the macro has been found, dynamically call the associated parsing function. + if ( is_string( $resIdentifier ) ) { + $resIdentifier = [ $resIdentifier ]; + } + + if ( $resIdentifier == null ) { + return null; + } + try { + return $this->parseIdentifier( $node, $passedArgs, $operatorContent, $input, ...$resIdentifier ); + } catch ( ArgumentCountError $errArgcount ) { + return null; + } + } + + public function parseIdentifier( $node, $passedArgs, $operatorContent, $name, $uc = null, $attrs = [] ) { + // tbd verify rule: Lowercase name ("operator" instead "Operator") seems to + // indicate additional italic mathvariant when bold already + if ( !ctype_upper( $name ) ) { + if ( isset( $passedArgs["mathvariant"] ) && $passedArgs["mathvariant"] ) { + $passedArgs["mathvariant"] = $passedArgs["mathvariant"] . "-" . Variants::ITALIC; + } + } + + $args = array_merge( $passedArgs, $attrs ); + $mi = new MMLmi( "", $args ); + $text = $mi->encapsulate( $uc ); + // TODO refactor just for test + $text = str_replace( "variantForm=\"True\"", "data-mjx-alternate=\"1\"", $text ); + $text = str_replace( "variantForm=\"1\"", "data-mjx-alternate=\"1\"", $text ); + return str_replace( "texClass", "data-mjx-texclass", $text ); + } + + public function checkAndParseDelimiter( $input, $node, $passedArgs, + $operatorContent, $noargs = false, $texClass = "" ) { + $resDelimiter = BaseMappings::getDelimiterByKey( trim( $input ) ); + if ( $resDelimiter == null ) { + $input = MMLutil::inputPreparation( $input ); + $resDelimiter = AMSMappings::getSymbolDelimiterByKey( $input ); + if ( $resDelimiter == null ) { + $resDelimiter = AMSMappings::getMathDelimiterByKey( $input ); + if ( $resDelimiter == null ) { + return null; + } + } + } + if ( is_string( $resDelimiter ) ) { + $resDelimiter = [ $resDelimiter ]; + } else { + if ( isset( $resDelimiter[1] ) && is_array( $resDelimiter[1] ) && !$noargs ) { + $passedArgs = array_merge( $resDelimiter[1], $passedArgs ); + } + } + + $mo = new MMLmo( $texClass, $passedArgs ); + return $mo->encapsulate( $resDelimiter[0] ); + } + + public function checkAndParseMathCharacter( $input, $node, $passedArgs, $operatorContent ) { + $inputP = MMLutil::inputPreparation( $input ); + $resChar = BaseMappings::getCharacterByKey( $inputP ); + if ( $resChar == null ) { + return null; + } + + // Maybe move this to the mapping + $args = [ "mathvariant" => "normal" ]; + + $mi = new MMLmi( "", $args ); + $enc = MMLutil::uc2xNotation( $resChar ); + return $mi->encapsulate( $enc ); + } + + public function checkAndParseColor( $input, $node, $passedArgs, $operatorContent ) { + // tbd usually this encapsulates the succeeding box element + if ( $operatorContent == null ) { + return null; + } + + $input = MMLutil::inputPreparation( $input ); + if ( !( $input === 'color' || $input === 'pagecolor' ) ) { + return null; + } + + $resColor = BaseMappings::getColorByKey( $operatorContent ); + if ( $resColor == null ) { + return null; + } + if ( is_array( $resColor ) ) { + $resColor = $resColor[0]; // tbd refactor or correct mappings + } + + if ( $input === 'color' ) { + $mstyle = new MMLmstyle( "", [ "mathcolor" => $resColor ] ); + return $mstyle->encapsulate( "" ); + } else { + // Input is 'pagecolor' + $mtext = new MMLmtext( "", [ "mathcolor" => $resColor ] ); + $mrow = new MMLmrow(); + $mi = new MMLmi(); + // Mj3 does this, probably not necessary + $innerRow = ""; + foreach ( str_split( $operatorContent ) as $char ) { + $innerRow .= $mi->encapsulate( $char ); + } + if ( $innerRow !== "" ) { + return $mtext->encapsulate( "\\pagecolor" ) . $mrow->encapsulate( $innerRow ); + } else { + return $mtext->encapsulate( "\\pagecolor" ); + } + } + } +} diff --git a/src/TexVC/MMLmappings/BaseParsing.php b/src/TexVC/MMLmappings/BaseParsing.php new file mode 100644 index 000000000..72baef109 --- /dev/null +++ b/src/TexVC/MMLmappings/BaseParsing.php @@ -0,0 +1,929 @@ + "true" ]; + } else { + if ( $stretchy == null ) { + // $attrs = [ "stretchy" => "false" ]; // not mention explicit stretchy + $attrs = []; + } else { + $attrs = [ "stretchy" => "true" ]; + } + } + // Fetching entity from $accent key tbd + $entity = MMLutil::createEntity( $accent ); + if ( !$entity ) { + $entity = $accent; + } + + if ( $node->getArg() instanceof Curly && $node->getArg()->getArg() instanceof TexArray + && count( $node->getArg()->getArg()->getArgs() ) > 1 ) { + $mrow = new MMLmrow(); + $renderedArg = $mrow->encapsulate( $node->getArg()->renderMML() ); + } else { + $renderedArg = $node->getArg()->renderMML(); + } + + $mrow = new MMLmrow(); + $mo = new MMLmo( "", $attrs ); // $passedArgs + $mover = new MMLmover(); + $ret = $mrow->encapsulate( + $mrow->encapsulate( + $mover->encapsulate( + $renderedArg . + $mo->encapsulate( $entity ) + ) + ) + ); + return $ret; + } + + public static function array( $node, $passedArgs, $operatorContent, $name, $begin = null, $open = null, + $close = null, $align = null, $spacing = null, + $vspacing = null, $style = null, $raggedHeight = null ) { + $output = ""; + $mrow = new MMLmrow(); + if ( $open != null ) { + $resDelimiter = BaseMappings::getDelimiterByKey( trim( $open ) ); + if ( $resDelimiter ) { + // $retDelim = $bm->checkAndParseDelimiter($open, $node,$passedArgs,true); + $moOpen = new MMLmo( TexClass::OPEN ); + $output .= $moOpen->encapsulate( $resDelimiter[0] ); + } + } + if ( $name == "Bmatrix" || $name == "bmatrix" || $name == "Vmatrix" + || $name == "vmatrix" || $name == "smallmatrix" || $name == "pmatrix" || $name == "matrix" ) { + // This is a workaround and might be improved mapping BMatrix to Matrix directly instead of array + return self::matrix( $node, $passedArgs, $operatorContent, $name, + $open, $close, null, null, null, null, true ); + + } else { + $output .= $mrow->encapsulate( $node->getMainarg()->renderMML() ); + } + + if ( $close != null ) { + $resDelimiter = BaseMappings::getDelimiterByKey( trim( $close ) ); + if ( $resDelimiter ) { + // $retDelim = $bm->checkAndParseDelimiter($open, $node,$passedArgs,true); + $moClose = new MMLmo( TexClass::CLOSE ); + $output .= $moClose->encapsulate( $resDelimiter[0] ); + } + } + return $output; + } + + public static function alignAt( $node, $passedArgs, $operatorContent, $name, $smth, $smth2 = null ) { + // Parsing is very similar to AmsEQArray, maybe extract function ... tcs: 178 + $mrow = new MMLmrow(); + // tbd how are the table args composed ? + $tableArgs = [ "columnalign" => "right", + "columnspacing" => "", "displaystyle" => "true", "rowspacing" => "3pt" ]; + $mtable = new MMLmtable( "", $tableArgs ); + $mtr = new MMLmtr(); + $mtd = new MMLmtd(); + $renderedInner = ""; + + $tableElements = array_slice( $node->getArgs(), 1 )[0]; + $discarded = false; + foreach ( $tableElements->getArgs() as $tableRow ) { + $renderedInner .= $mtr->getStart(); + foreach ( $tableRow->getArgs() as $tableCell ) { + $renderedInner .= $mtd->getStart(); + foreach ( $tableCell->getArgs() as $cellItem ) { + if ( !$discarded && $cellItem instanceof Curly ) { + $discarded = true; + // Just discard the number of rows atm, it is in the first Curly + } else { + $renderedInner .= $cellItem->renderMML(); // pass args here ? + } + } + + $renderedInner .= $mtd->getEnd(); + + } + $renderedInner .= $mtr->getEnd(); + } + return $mrow->encapsulate( $mtable->encapsulate( $renderedInner ) ); + } + + public static function amsEqnArray( $node, $passedArgs, $operatorContent, $name, $smth, $smth2 = null ) { + // this goes for name =="aligned" ... tcs: 358 420 421 + $mrow = new MMLmrow(); + // tbd how are the table args composed ? + $tableArgs = [ "columnalign" => "right", + "columnspacing" => "", "displaystyle" => "true", "rowspacing" => "3pt" ]; + $mtable = new MMLmtable( "", $tableArgs ); + $mtr = new MMLmtr(); + $mtd = new MMLmtd(); + $renderedInner = ""; + $tableElements = array_slice( $node->getArgs(), 1 )[0]; + foreach ( $tableElements->getArgs() as $tableRow ) { + $renderedInner .= $mtr->getStart(); + foreach ( $tableRow->getArgs() as $tableCell ) { + $renderedInner .= $mtd->encapsulate( $tableCell->renderMML() ); // pass args here ? + } + $renderedInner .= $mtr->getEnd(); + } + return $mrow->encapsulate( $mtable->encapsulate( $renderedInner ) ); + } + + public static function boldsymbol( $node, $passedArgs, $operatorContent, $name, $smth = null, $smth2 = null ) { + $mrow = new MMLmrow(); + $passedArgs = array_merge( [ "mathvariant" => Variants::BOLDITALIC ] ); + return $mrow->encapsulate( $node->getArg()->renderMML( $passedArgs ) ); + } + + public static function cancel( $node, $passedArgs, $operatorContent, $name, $notation = null, $smth2 = null ) { + $mrow = new MMLmrow(); + $menclose = new MMLmenclose( "", [ "notation" => $notation ] ); + return $mrow->encapsulate( $menclose->encapsulate( $node->getArg()->renderMML() ) ); + } + + public static function cancelTo( $node, $passedArgs, $operatorContent, $name, $notation = null ) { + $mrow = new MMLmrow(); + $msup = new MMLmsup(); + $mpAdded = new MMLmpadded( "", [ "depth" => "-.1em" ,"height" => "+.1em" ,"voffset" => ".1em" ] ); + + $menclose = new MMLmenclose( "", [ "notation" => $notation ] ); + $inner = $menclose->encapsulate( + $node->getArg2()->renderMML() ) . $mpAdded->encapsulate( $node->getArg1()->renderMML() ); + return $mrow->encapsulate( $msup->encapsulate( $inner ) ); + } + + public static function chemCustom( $node, $passedArgs, $operatorContent, $name, $translation = null ) { + if ( $translation ) { + return $translation; + } + return "tbd chemCustom"; + } + + public static function cFrac( $node, $passedArgs, $operatorContent, $name ) { + $mrow = new MMLmrow(); + $mfrac = new MMLmfrac(); + $mstyle = new MMLmstyle( "", [ "displaystyle" => "false", "scriptlevel" => "0" ] ); + $mpAdded = new MMLmpadded( "", [ "depth" => "3pt","height" => "8.6pt","width" => "0" ] ); + // See TexUtilMMLTest testcase 81 + // (mml3 might be erronous here, but this element seems to be rendered correctly) + $whatIsThis = $mrow->getStart() . $mpAdded->getStart() . $mpAdded->getEnd() . $mrow->getEnd(); + $inner = $mrow->encapsulate( $whatIsThis . + $mstyle->encapsulate( $mrow->encapsulate( $node->getArg1()->renderMML() ) ) ) . + $mrow->encapsulate( $whatIsThis . $mstyle->encapsulate( + $mrow->encapsulate( $node->getArg2()->renderMML() ) ) ); + + return $mrow->encapsulate( $mfrac->encapsulate( $inner ) ); + } + + public static function dots( $node, $passedArgs, $operatorContent, $name, $smth = null, $smth2 = null ) { + // lowerdots || centerdots seems aesthetical, just using lowerdots atm s + $mo = new MMLmo( "", $passedArgs ); + return $mo->encapsulate( "…" ); + } + + public function genFrac( $node, $passedArgs, $name, $operatorContent, + $left = null, $right = null, $thick = null, $style = null ) { + // Actually this is in AMSMethods, consider refactoring left, right, thick, style + $bm = new BaseMethods(); + $ret = $bm->checkAndParseDelimiter( $name, $node, $passedArgs, $operatorContent, true ); + if ( $ret ) { + // TBD + if ( $left == null ) { + $left = $ret; + } + if ( $right == null ) { + $right = $ret; + } + if ( $thick == null ) { + $thick = $ret; + } + if ( $style == null ) { + $style = trim( $ret ); + } + } + $attrs = []; + $fract = null; + $styleAttr = []; + $displayStyle = "false"; + if ( $thick !== "" ) { + $attrs = array_merge( $attrs, [ "linethickness" => $thick ] ); + } + if ( $style !== '' ) { + $styleDigit = intval( $style, 10 ); + $styleAlpha = [ 'D', 'T', 'S', 'SS' ][$styleDigit]; + if ( $styleAlpha == null ) { + $mrow = new MMLmrow(); + return $mrow->encapsulate( "Bad math style" ); + } + + if ( $styleAlpha === 'D' ) { + // NodeUtil_js_1.default.setProperties(frac, { displaystyle: true, scriptlevel: 0 }); + + // tbd add props + $displayStyle = "true"; + $styleAttr = [ "maxsize" => "2.047em", "minsize" => "2.047em" ]; + + } else { + $styleAttr = [ "maxsize" => "1.2em", "minsize" => "1.2em" ]; + } + + $frac = new MMLmfrac( "", $attrs ); + } else { + // NodeUtil_js_1.default.setProperties(frac, { displaystyle: false, + // scriptlevel: styleDigit - 1 }); + // tbd add props + $frac = new MMLmfrac( "", $attrs ); + $styleAttr = [ "maxsize" => "1.2em", "minsize" => "1.2em" ]; + + } + $mrow = new MMLmrow(); + $mstyle = new MMLmstyle( "", [ "displaystyle" => $displayStyle, "scriptlevel" => "0" ] ); + $output = $mrow->getStart(); + if ( $style !== '' ) { + $output .= $mstyle->getStart(); + } + $output .= $mrow->getStart(); + if ( $left ) { + $mrowOpen = new MMLmrow( TexClass::OPEN ); + $moL = new MMLmo( "", $styleAttr ); + $output .= $mrowOpen->encapsulate( $moL->encapsulate( $left ) ); + } + // when is mrow encapsulating and when not ? + //$output .= $frac->encapsulate( + // $mrow->encapsulate($node->getArg1()->renderMML()) .$mrow->encapsulate( $node->getArg2()->renderMML() )); + $output .= $frac->encapsulate( $node->getArg1()->renderMML() . $node->getArg2()->renderMML() ); + + if ( $right ) { + $mrowClose = new MMLmrow( TexClass::CLOSE ); + $moR = new MMLmo( "", $styleAttr ); + $output .= $mrowClose->encapsulate( $moR->encapsulate( $right ) ); + + } + $output .= $mrow->getEnd(); + if ( $style !== '' ) { + $output .= $mstyle->getEnd(); + } + $output .= $mrow->getEnd(); + + return $output; + } + + public static function frac( $node, $passedArgs, $operatorContent, $name ) { + $mrow = new MMLmrow(); + $mfrac = new MMLmfrac(); + // if node is Fun1 + $inner = $mrow->encapsulate( $node->getArg1()->renderMML() ) . + $mrow->encapsulate( $node->getArg2()->renderMML() ); + return $mrow->encapsulate( $mfrac->encapsulate( $inner ) ); + } + + public static function hline( $node, $passedArgs, $operatorContent, $name, + $smth1 = null, $smth2 = null, $smth3 = null, $smth4 = null ) { + // HLine is most probably not parsed this way, since only parsed in Matrix context + $mmlRow = new MMLmrow( "tbd" ); + return $mmlRow->encapsulate( "HLINE TBD" ); + } + + public static function handleOperatorName( $node, $passedArgs, $operatorContent, $name, + $smth1 = null, $smth2 = null, $smth3 = null, $smth4 = null ) { + // \\operatorname{a} + $passedArgs = array_merge( $passedArgs, [ Tag::CLASSTAG => TexClass::OP, "mathvariant" => Variants::NORMAL ] ); + return $node->getArg()->renderMML( $passedArgs ); + } + + public static function macro( $node, $passedArgs, $operatorContent, $name, $macro, $argcount = null, $def = null ) { + // Parse the Macro + switch ( $name ) { + case "mod": + $mmlRow = new MMLmrow(); + $mspace = new MMLmspace( "", [ "width" => "0.444em" ] ); + $mspace2 = new MMLmspace( "", [ "width" => "0.333em" ] ); + $mo = new MMLmo( "", [ "stretchy" => "false" ] ); + $mi = new MMLmi(); + return $mmlRow->encapsulate( + $mspace->encapsulate( "" ) . $mo->encapsulate( "(" ) . + $mi->encapsulate( "mod" ) . $mspace2->encapsulate( "" ) . + $mo->encapsulate( ")" ) ); + case "pmod": + // tbd indicate in mapping that this is composed within php + $mmlRow = new MMLmrow(); + $mspace = new MMLmspace( "", [ "width" => "0.444em" ] ); + $mspace2 = new MMLmspace( "", [ "width" => "0.333em" ] ); + $mo = new MMLmo( "", [ "stretchy" => "false" ] ); + $mi = new MMLmi(); + return $mmlRow->encapsulate( $mspace->encapsulate( "" ) . + $mo->encapsulate( "(" ) . $mi->encapsulate( "mod" ) . + $mspace2->encapsulate( "" ) . $node->getArg()->renderMML() . $mo->encapsulate( ")" ) ); + case "varlimsup": + case "varliminf": + // hardcoded macro in php (there is also a dynamic mapping which is not completely resolved atm) + $mmlRow = new MMLmrow( TexClass::OP ); + if ( $name === "varlimsup" ) { + $movu = new MMLmover(); + + } else { + $movu = new MMLmunder(); + } + $mmlMi = new MMLmi(); + $mo = new MMLmo( "", [ "accent" => "true" ] ); + return $mmlRow->encapsulate( $movu->encapsulate( + $mmlMi->encapsulate( "lim" ) . $mo->encapsulate( "―" ) ) ); + + case "varinjlim": + $mmlRow = new MMLmrow( TexClass::OP ); + $mmlMunder = new MMLmunder(); + $mi = new MMLmi(); + $mo = new MMLmo(); + return $mmlRow->encapsulate( $mmlMunder->encapsulate( + $mi->encapsulate( "lim" ) . + $mo->encapsulate( "→" ) ) + ); + case "varprojlim": + $mmlRow = new MMLmrow( TexClass::OP ); + $mmlMunder = new MMLmunder(); + $mi = new MMLmi(); + $mo = new MMLmo(); + return $mmlRow->encapsulate( $mmlMunder->encapsulate( + $mi->encapsulate( "lim" ) . + $mo->encapsulate( "←" ) + ) ); + case "stackrel": + // hardcoded macro in php (there is also a dynamic mapping which is not not completely resolved atm) + $mmlRow = new MMLmrow(); + $mmlRowInner = new MMLmrow( TexClass::REL ); + $mover = new MMLmover(); + $mmlRowArg2 = new MMLmrow( TexClass::OP ); + $inner = $mover->encapsulate( $mmlRowArg2->encapsulate( + $node->getArg2()->renderMML() ) . + $mmlRow->encapsulate( $node->getArg1()->renderMML() ) + ); + return $mmlRow->encapsulate( $mmlRowInner->encapsulate( $inner ) ); + case "bmod": + $mo = new MMLmo( "", [ "lspace" => "thickmathspace", "rspace" => "thickmathspace" ] ); + $mmlRow = new MMLmrow( TexClass::ORD ); + $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); + $mspace = new MMLmspace( "", [ "width" => "0.167em" ] ); + return $mmlRow->encapsulate( $mo->encapsulate( "mod" ) . + $mmlRow->encapsulate( $mstyle->encapsulate( $mspace->getEmpty() ) ) ); + case "implies": + $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); + $mspace = new MMLmspace( "", [ "width" => "0.278em" ] ); + $mo = new MMLmo(); + return $mstyle->encapsulate( $mspace->getEmpty() ) . $mo->encapsulate( "⟹" ) . + $mstyle->encapsulate( $mspace->getEmpty() ); + case "iff": + $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); + $mspace = new MMLmspace( "", [ "width" => "0.278em" ] ); + $mo = new MMLmo(); + return $mstyle->encapsulate( $mspace->getEmpty() ) . $mo->encapsulate( "⟺" ) . + $mstyle->encapsulate( $mspace->getEmpty() ); + } + + // Removed all token based parsing, since macro resolution for the supported macros can be hardcoded in php + $mmlMrow = new MMLmrow(); + return $mmlMrow->encapsulate( "macro not resolved: " . $macro ); + } + + public static function matrix( $node, $passedArgs, $operatorContent, + $name, $open = null, $close = null, $align = null, $spacing = null, + $vspacing = null, $style = null, $cases = null, $numbered = null ) { + $resInner = ""; + $mtr = new MMLmtr(); + $mtd = new MMLmtd(); + $addHlines = false; + $columnInfo = []; + // tbd hline element is the first literal element within second texarray -> resolve + foreach ( $node->getMainarg()->getArgs() as $mainarg ) { + $resInner .= $mtr->getStart(); + foreach ( $mainarg->getArgs() as $arg ) { + $usedArg = clone $arg; + if ( count( $arg->getArgs() ) >= 1 && $arg->getArgs()[0] instanceof Literal ) { + // Discarding the column information Curly at the moment + if ( $arg->getArgs()[0]->getArg() == "\\hline " ) { + // discarding the hline + // $usedArg->args[0] = null; // this does no work tbd + $usedArg->pop(); + $addHlines = true; + } + } + if ( count( $arg->getArgs() ) >= 1 && $arg->getArgs()[0] instanceof Curly ) { + // Discarding the column information Curly at the moment + // $usedArg->getArgs()[0] = null; + $columnInfo = $usedArg->getArgs()[0]->render(); + $usedArg->pop(); + + } + $resInner .= $mtd->encapsulate( $usedArg->renderMML( $passedArgs ) ); + } + $resInner .= $mtr->getEnd(); + } + $mrow = new MMLmrow(); + $tableArgs = [ "columnspacing" => "1em", "rowspacing" => "4pt" ]; + $mencloseArgs = null; + if ( $addHlines ) { + // TBD this is just simple check, create a parsing function for hlines when there are more cases + // solid as first val: hline for header row + // none as second val: no hlines for follow up rows + $tableArgs = array_merge( $tableArgs, [ "rowlines" => "solid none" ] ); + } + if ( $columnInfo ) { + // TBD this is just simple check, create a parsing function for hlines when there are more cases + if ( str_contains( $columnInfo, "|" ) ) { + $mencloseArgs = [ "data-padding" => "0","notation" => "left right" ]; + // it seems this is creted when left and right is solely coming from columninfo + $tableArgs = array_merge( $tableArgs, [ "columnlines" => "solid" ] ); + } + } + $mtable = new MMLmtable( "", $tableArgs ); + if ( $cases || ( $open != null && $close != null ) ) { + $bm = new BaseMethods(); + $mmlMoOpen = $bm->checkAndParseDelimiter( $open, $node, [], [], + true, TexClass::OPEN ); + if ( $mmlMoOpen == null ) { + $open = MMLutil::inputPreparation( $open ); + $mmlMoOpen = new MMLmo( TexClass::OPEN, [] ); + $mmlMoOpen = $mmlMoOpen->encapsulate( $open ); + } + + $closeAtts = [ "fence" => "true","stretchy" => "true","symmetric" => "true" ]; + $mmlMoClose = $bm->checkAndParseDelimiter( $close, $node, $closeAtts, + null, true, TexClass::CLOSE ); + if ( $mmlMoOpen == null ) { + $close = MMLutil::inputPreparation( $close ); + $mmlMoClose = new MMLmo( TexClass::CLOSE, $closeAtts ); + $mmlMoClose = $mmlMoClose->encapsulate( $close ); + } + $resInner = $mmlMoOpen . $mtable->encapsulate( $resInner ) . $mmlMoClose; + } else { + $resInner = $mtable->encapsulate( $resInner ); + } + if ( $mencloseArgs ) { + $menclose = new MMLmenclose( "", $mencloseArgs ); + $matrix = $mrow->encapsulate( $menclose->encapsulate( $resInner ) ); + + } else { + $matrix = $mrow->encapsulate( $resInner ); + } + return $matrix; + } + + public static function namedOp( $node, $passedArgs, $operatorContent, $name, $id = null ) { + if ( !$id ) { + // $id = substr($name,1); eventually change how name is passed + $id = $name; + } + // This id statement probably wont work atm: + + // lim inf + $id = str_replace( " ", ' ', $id ); + $mo = new MMLmo( TexClass::OP, [ "movablelimits" => "true" ] ); + // "movesupsub"=>"true" activate this also as attribute ? + return $mo->encapsulate( $id ); + } + + public static function over( $node, $passedArgs, $operatorContent, $name, $id = null ) { + $attributes = []; + $start = ""; + $tail = ""; + if ( $name === "atop" ) { + $attributes = [ "linethickness" => "0" ]; + } elseif ( $name == "choose" ) { + $mrowAll = new MMLmrow( TexClass::ORD ); + $mrowOpen = new MMLmrow( TexClass::OPEN ); + $mrowClose = new MMLmrow( TexClass::CLOSE ); + $mo = new MMLmo( "", [ "maxsize" => "1.2em","minsize" => "1.2em" ] ); + $start = $mrowAll->getStart() . $mrowOpen->encapsulate( $mo->encapsulate( "(" ) ); + $tail = $mrowClose->encapsulate( $mo->encapsulate( ")" ) ) . $mrowAll->getEnd(); + $attributes = [ "linethickness" => "0" ]; + + } + $mfrac = new MMLmfrac( "", $attributes ); // "movesupsub"=>"true" activate this also as attribute ? + + $mrow = new MMLmrow( "", [] ); // tbd remove mathjax specifics, + // tbd added a getArg2 mrow which seems correct, consider removiing in some cases ? + return $start . $mfrac->encapsulate( $mrow->encapsulate( + $node->getArg1()->renderMML() ) . $mrow->encapsulate( $node->getArg2()->renderMML() ) ) . $tail; + } + + public static function oint( $node, $passedArgs, $operatorContent, + $name, $uc = null, $smth1 = null, $smth2 = null ) { + // This is a custom mapping not in js. + $mmlText = new MMLmtext( "", [ "mathcolor" => "red" ] ); + switch ( $name ) { + case "oiiint": + case "oiint": + case "ointctrclockwise": + case "varointclockwise": + case "P": + return $mmlText->encapsulate( "\\" . $name ); + default: + return $mmlText->encapsulate( "not found in OintMethod" ); + + } + } + + public static function overset( $node, $passedArgs, $operatorContent, $name, $id = null ) { + $mrow = new MMLmrow( TexClass::ORD, [] ); // tbd remove mathjax specifics + $mrow2 = new MMLmrow( "", [] ); + $inrow = $mrow2->encapsulate( $node->getArg2()->renderMML() ); + $mover = new MMLmover(); + return $mrow->encapsulate( $mover->encapsulate( $inrow . $node->getArg1()->renderMML() ) ); + } + + public static function phantom( $node, $passedArgs, $operatorContent, + $name, $vertical = null, $horizontal = null, $smh3 = null ) { + $mrow = new MMLmrow( TexClass::ORD, [] ); + + $attrs = []; + if ( $vertical ) { + $attrs = array_merge( $attrs, [ "width" => "0" ] ); + } + if ( $horizontal ) { + $attrs = array_merge( $attrs, [ "depth" => "0", "height" => "0" ] ); + } + $mpadded = new MMLmpadded( "", $attrs ); + $mphantom = new MMLmphantom(); + return $mrow->encapsulate( $mrow->encapsulate( + $mpadded->encapsulate( $mphantom->encapsulate( $node->getArg()->renderMML() ) ) ) ); + } + + public static function underset( $node, $passedArgs, $operatorContent, $name, $smh = null ) { + $mrow = new MMLmrow( TexClass::ORD, [] ); // tbd remove mathjax specifics + $mrow2 = new MMLmrow( "", [] ); + $inrow = $node->getArg2()->renderMML(); + $munder = new MMLmunder(); + + // Some cases encapsulate getArg1 in Mrow ?? + return $mrow->encapsulate( $munder->encapsulate( $inrow . $node->getArg1()->renderMML() ) ); + } + + public static function underOver( $node, $passedArgs, $operatorContent, + $name, $operatorId = null, $stack = null ) { + // tbd verify if stack interpreted correctly ? + $texClass = $stack ? TexClass::OP : TexClass::ORD; // ORD or "" + + $mrow = new MMLmrow( $texClass ); + + if ( $name[0] === 'o' ) { + $movun = new MMLmover(); + } else { + $movun = new MMLmunder(); + } + + if ( $operatorId == 2015 ) { // eventually move such cases to mapping + $mo = new MMLmo( "", [ "accent" => "true" ] ); + } else { + $mo = new MMLmo(); + } + if ( $node instanceof DQ ) { + $mrowI = new MMLmrow(); + return $movun->encapsulate( + $node->getBase()->renderMML() . + $mrowI->encapsulate( $node->getDown()->renderMML() ) + ); + } + + // TBD: Export this check to utility function it seems to be used multiple times + $renderedArg = ""; + $check = method_exists( $node, "getArg" ); // this was to prevent crash if DQ, might be refactored + if ( $check ) { + if ( $node->getArg() instanceof Curly && $node->getArg()->getArg() instanceof TexArray + && count( $node->getArg()->getArg()->getArgs() ) > 1 ) { + $mrowI = new MMLmrow(); + $renderedArg = $mrowI->encapsulate( $node->getArg()->renderMML() ); + } else { + $renderedArg = $node->getArg()->renderMML(); + } + } + + return $mrow->encapsulate( $movun->encapsulate( + $renderedArg . $mo->encapsulate( MMLutil::number2xNotation( $operatorId ) ) + ) ); + } + + public static function mathFont( $node, $passedArgs, $operatorContent, $name, $mathvariant = null ) { + $mrow = new MMLmrow( TexClass::ORD, [] ); + $mi = new MMLmi(); + $args = MMLParsingUtil::getFontArgs( $name, $mathvariant, $passedArgs ); + + if ( $node instanceof Fun1nb ) { + // Only one mrow from Fun1nb !? + return $mrow->encapsulate( $node->getArg()->renderMML( $args ) ); + } + return $mrow->encapsulate( $mrow->encapsulate( $node->getArg()->renderMML( $args ) ) ); + } + + public static function makeBig( $node, $passedArgs, $operatorContent, $name, $texClass = null, $size = null ) { + // Create the em format and shorten commas + $size *= Misc::P_HEIGHT; + $sizeShortened = MMLutil::size2em( strval( $size ) ); + $mrowOuter = new MMLmrow( TexClass::ORD, [] ); + $mrow = new MMLmrow( $texClass, [] ); + $passedArgs = array_merge( $passedArgs, [ "maxsize" => $sizeShortened, "minsize" => $sizeShortened ] ); + + $mo = new MMLmo( "", $passedArgs ); + + // Sieve arg if it is a delimiter (it seems args are not applied here + $bm = new BaseMethods(); + $argcurrent = trim( $node->getArg() ); + switch ( $argcurrent ) { + case "\\|": + $passedArgs = array_merge( $passedArgs, [ "symmetric" => "true" ] ); + break; + case "\\uparrow": + case "\\downarrow": + case "\\Uparrow": + case "\\Downarrow": + case "\\updownarrow": + case "\\Updownarrow": + $passedArgs = array_merge( [ "fence" => "true" ], $passedArgs, [ "symmetric" => "true" ] ); + break; + case "\\backslash": + case "/": + $passedArgs = array_merge( [ "fence" => "true" ], + $passedArgs, [ "stretchy" => "true", "symmetric" => "true" ] ); + break; + } + $ret = $bm->checkAndParseDelimiter( $node->getArg(), $node, $passedArgs, $operatorContent, true ); + if ( $ret ) { + return $mrowOuter->encapsulate( $mrow->encapsulate( $ret ) ); + } + + $argPrep = MMLutil::inputPreparation( $node->getArg() ); + return $mrowOuter->encapsulate( $mrow->encapsulate( $mo->encapsulate( $argPrep ) ) ); + } + + public static function machine( $node, $passedArgs, $operatorContent, $name, $type = null ) { + // this could also be shifted to MhChem.php renderMML for ce + // For parsing chem (ce) or ??? (pu) + $mmlMrow = new MMLmrow(); + return $mmlMrow->encapsulate( $node->getArg()->renderMML() ); + } + + public static function namedFn( $node, $passedArgs, $operatorContent, $name, $smth = null ) { + if ( $node instanceof Literal ) { + $mi = new MMLmi(); + return $mi->encapsulate( $name ); + } + $mrow = new MMLmrow( TexClass::ORD, [] ); // tbd remove mathjax specifics + $msub = new MMLmsub(); + return $msub->encapsulate( $node->getBase()->renderMML() . + $mrow->encapsulate( $node->getDown()->renderMML() ) ); + } + + public static function limits( $node, $passedArgs, $operatorContent, $name, $smth = null ) { + // not completely done, has preceding lits + $mrow = new MMLmrow( TexClass::ORD, [] ); // tbd remove mathjax specifics + $munder = new MMLmunder(); + + if ( $node instanceof Literal ) { + // Workaround currently + return $munder->encapsulate( $mrow->encapsulate( $node->getArg() ) ); + + } + return $munder->encapsulate( $mrow->encapsulate( $node->getDown()->renderMML() ) ); + } + + public static function setFont( $node, $passedArgs, $operatorContent, $name, $variant = null ) { + $mrow = new MMLmrow(); + $args = MMLParsingUtil::getFontArgs( $name, $variant, $passedArgs ); + return $mrow->encapsulate( $mrow->encapsulate( $node->getArg()->renderMML( $args ) ) ); + } + + public static function sideset( $node, $passedArgs, $operatorContent, $name, + $smth1 = null, $smth2 = null, $smth3 = null ) { + // Sideset parsing is not completed yet (Waiting for MML) + $mmlMrow = new MMLmrow( TexClass::OP ); + $mmlMultiscripts = new MMLmmultiscripts( "", [ Tag::ALIGN => "left" ] ); + $in1 = $node->getArg1()->renderMML(); + $in2 = $node->getArg2()->renderMML(); + return $mmlMrow->encapsulate( $mmlMultiscripts->encapsulate( $in2 . "" . $in1 ) ); + } + + public static function spacer( $node, $passedArgs, $operatorContent, $name, $withIn = null, $smth2 = null ) { + // var node = parser.create('node', 'mspace', [], { width: (0, lengths_js_1.em)(space) }); + $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); + $width = MMLutil::round2em( $withIn ); + $mspace = new MMLmspace( "", [ "width" => $width ] ); + return $mstyle->encapsulate( $mspace->encapsulate( "" ) ); + } + + public static function texAtom( $node, $passedArgs, $operatorContent, $name, $texClass = null ) { + switch ( $name ) { + case "mathclose": + $mrow = new MMLmrow(); + $mrow2 = new MMLmrow( $texClass, [] ); + $inner = $node->getArg()->renderMML(); + return $mrow->encapsulate( $mrow2->encapsulate( $inner ) ); + case "mathbin": + // no break + case "mathop": + // no break + case "mathrel": + $mrow2 = new MMLmrow( $texClass, [] ); + $inner = $node->getArg()->renderMML(); + return $mrow2->encapsulate( $inner ); + default: + $mrow = new MMLmrow( TexClass::ORD ); + $mrow2 = new MMLmrow( $texClass, [] ); + $inner = $node->getArg()->renderMML(); + return $mrow->encapsulate( $mrow2->encapsulate( $inner ) ); + } + } + + public static function hBox( $node, $passedArgs, $operatorContent, $name, $smth = null ) { + switch ( $name ) { + case "mbox": + // These seem special case for mbox, otherwise mbox parsed like hbox + if ( $operatorContent == "\\textvisiblespace" ) { + // there is also custom mapping for now to that, + // for TexUtilMMLTest this seems to only occur here though + $mmlMrow = new MMLmrow(); + $mtext = new MMLmtext(); + return $mmlMrow->encapsulate( $mtext->encapsulate( "␣" ) ); + + } elseif ( $operatorContent != null ) { // ok ?? \\AA \\Coppa .... + $mmlMrow = new MMLmrow(); + $mtext = new MMLmtext( "", [ "mathcolor" => "red" ] ); + return $mmlMrow->encapsulate( $mtext->encapsulate( $operatorContent ) ); + } + // no break + case "hbox": + $mmlMrow = new MMLmrow(); + $mstyle = new MMLmstyle( "", [ "displaystyle" => "false", "scriptlevel" => "0" ] ); + $mtext = new MMLmtext(); + return $mmlMrow->encapsulate( $mstyle->encapsulate( + $mtext->encapsulate( $node->getArg() ) ) ); // renderMML for arg ? + case "text": + $mmlMrow = new MMLmrow(); + $mtext = new MMLmtext(); + return $mmlMrow->encapsulate( $mtext->encapsulate( $node->getArg() ) ); // renderMML for arg ? + case "textbf": + // no break + case "textit": + // no break + case "textrm": + // no break + case "textsf": + // no break + case "texttt": + $mmlMrow = new MMLmrow(); + $mtext = new MMLmtext( "", MMLParsingUtil::getFontArgs( $name, null, null ) ); + return $mmlMrow->encapsulate( $mtext->encapsulate( $node->getArg()->renderMML() ) ); + } + + $msubsup = new MMLmsubsup( "tbd HBox" ); + // $node->getArg1()->renderMML() . $node->getArg2()->renderMML() + return $msubsup->encapsulate( "undefined hbox" ); + } + + public static function setStyle( $node, $passedArgs, $operatorContent, $name, + $smth = null, $smth1 = null, $smth2 = null ) { + // Just discard setstyle since they are captured in TexArray now} + return " "; + } + + public static function not( $node, $passedArgs, $operatorContent, $name, $smth = null, + $smth1 = null, $smth2 = null ) { + // This is only tested for \not statement without follow-up parameters + $mmlMrow = new MMLmrow( TexClass::REL ); + if ( $node instanceof Literal ) { + $mpadded = new MMLmpadded( "", [ "width" => "0" ] ); + $mtext = new MMLmtext(); + return $mmlMrow->encapsulate( $mpadded->encapsulate( $mtext->encapsulate( "⧸" ) ) ); + } else { + $mmlMrow->encapsulate( "TBD Not" ); + } + } + + public static function vbox( $node, $passedArgs, $operatorContent, $name, $smth = null ) { + // This is only example functionality for vbox("ab"). + // TBD: it should be discussed if vbox is supported since it + // does not seem to be supported by mathjax + if ( is_string( $node->getArg() ) ) { + $mmlMover = new MMLmover(); + $mmlmrow = new MMLmrow(); + $arr1 = str_split( $node->getArg() ); + $inner = ""; + foreach ( $arr1 as $char ) { + $inner .= $mmlmrow->encapsulate( $char ); + } + return $mmlMover->encapsulate( $inner ); + } + $mmr = new MMLmrow(); + return $mmr->encapsulate( "no implemented vbox" ); + } + + public static function sqrt( $node, $passedArgs, $operatorContent, $name ) { + $mrow = new MMLmrow(); + + // There is an additional argument for the root + if ( $node instanceof Fun2sq ) { + $mroot = new MMLmroot(); + + // In case of an empty curly add an mrow + $arg2Rendered = $node->getArg2()->renderMML( $passedArgs ); + if ( trim( $arg2Rendered ) === "" ) { + $arg2Rendered = $mrow->getEmpty(); + } + return $mrow->encapsulate( + $mroot->encapsulate( + $arg2Rendered . + $mrow->encapsulate( + $node->getArg1()->renderMML( $passedArgs ) + ) + ) + ); + } + $msqrt = new MMLmsqrt(); + // Currently this is own implementation from Fun1.php + return $mrow->encapsulate( // assuming that this is always encapsulated in mrow + $msqrt->encapsulate( + $node->getArg()->renderMML( $passedArgs ) + ) + ); + } + + public static function xArrow( $node, $passedArgs, $operatorContent, $name, $chr = null, $l = null, $r = null ) { + $defWidth = "+" . MMLutil::round2em( ( $l + $r ) / 18 ); + $defLspace = MMLutil::round2em( $l / 18 ); + + $mover = new MMLmover(); + $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); + $moArrow = new MMLmo( Texclass::REL, [] ); + $char = IntlChar::chr( $chr ); + + $mpaddedArgs = [ "height" => "-.2em", "lspace" => $defLspace, "voffset" => "-.2em", "width" => $defWidth ]; + $mpadded = new MMLmpadded( "", $mpaddedArgs ); + $mspace = new MMLmspace( "", [ "depth" => ".25em" ] ); + if ( $node instanceof Fun2sq ) { + $mmlMrow = new MMLmrow(); + $mmlUnderOver = new MMLmunderover(); + return $mmlMrow->encapsulate( $mmlUnderOver->encapsulate( + $mstyle->encapsulate( $moArrow->encapsulate( $char ) ) . + $mpadded->encapsulate( + $mmlMrow->encapsulate( + $node->getArg1()->renderMML() + ) . + $mspace->encapsulate( "" ) + ) . + $mpadded->encapsulate( + $node->getArg2()->renderMML() + ) + ) ); + + } + return $mover->encapsulate( + $mstyle->encapsulate( $moArrow->encapsulate( $char ) ) . + $mpadded->encapsulate( + $node->getArg()->renderMML() . + $mspace->encapsulate( "" ) + ) + ); + } +} diff --git a/src/TexVC/Nodes/Big.php b/src/TexVC/Nodes/Big.php index 843f5db41..3b3f8778b 100644 --- a/src/TexVC/Nodes/Big.php +++ b/src/TexVC/Nodes/Big.php @@ -4,6 +4,8 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; + class Big extends TexNode { /** @var string */ @@ -39,6 +41,16 @@ class Big extends TexNode { return '{' . $this->fname . ' ' . $this->arg . '}'; } + public function renderMML( $arguments = [] ) { + $bm = new BaseMethods(); + $res = $bm->checkAndParse( $this->fname, $this, $arguments, null ); + if ( $res ) { + return $res; + } else { + return "Not Implemented Big for: " . $this->getArgs()[0]; + } + } + public function extractIdentifiers( $args = null ) { return []; } diff --git a/src/TexVC/Nodes/Box.php b/src/TexVC/Nodes/Box.php index 6a8ee5177..e61b438ce 100644 --- a/src/TexVC/Nodes/Box.php +++ b/src/TexVC/Nodes/Box.php @@ -4,6 +4,8 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; + class Box extends TexNode { /** @var string */ @@ -39,6 +41,30 @@ class Box extends TexNode { return '{' . $this->fname . '{' . $this->arg . '}}'; } + public function renderMML( $arguments = [] ) { + $bm = new BaseMethods(); + $res = $bm->checkAndParse( $this->getArgs()[0], $this, $arguments, null ); + if ( $res ) { + return $res; + } else { + return "Not Implemented Box for: " . $this->getArgs()[0]; + } + /** + * $mrow = new MMLmrow(); + * $mtext = new MMLmtext(); + * + * $renderedMML = $mrow->encapsulate( + * $mtext->encapsulate( $this->arg ) + * ); + * $color = BaseMappings::getColorByKey($this->arg); + * if($color){ + * $mstyle = new MMLmstyle(); + * $renderedMML = $renderedMML . $mstyle->getEnd(); + * } + * return $renderedMML; + */ + } + public function extractIdentifiers( $args = null ) { return []; } diff --git a/src/TexVC/Nodes/ChemWord.php b/src/TexVC/Nodes/ChemWord.php index a3c0d422f..e7c262bc1 100644 --- a/src/TexVC/Nodes/ChemWord.php +++ b/src/TexVC/Nodes/ChemWord.php @@ -4,6 +4,9 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmrow; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmtext; + class ChemWord extends TexNode { /** @var TexNode */ @@ -39,6 +42,16 @@ class ChemWord extends TexNode { return $this->left->render() . $this->right->render(); } + public function renderMML( $arguments = [] ) { + $mmlMrow = new MMLmrow(); + $mtextLeft = new MMLmtext( "", [ "mathcolor" => "red" ] ); + $mtextRight = new MMLmtext(); + // If right has empty literal content is resolved as dash + $right = $this->getRight()->getArgs()[0] == "" ? "-" : $this->getRight()->renderMML(); + return $mmlMrow->encapsulate( $mmlMrow->encapsulate( + $mtextLeft->encapsulate( $this->getLeft()->renderMML() ) . $mtextRight->encapsulate( $right ) ) ); + } + public function extractIdentifiers( $args = null ) { return []; } diff --git a/src/TexVC/Nodes/Curly.php b/src/TexVC/Nodes/Curly.php index 0a7c2cbf8..8b44f525a 100644 --- a/src/TexVC/Nodes/Curly.php +++ b/src/TexVC/Nodes/Curly.php @@ -25,6 +25,13 @@ class Curly extends TexNode { return $this->arg->inCurlies(); } + public function renderMML( $arguments = [] ) { + // J4T set17 + //$mmlRow = new MMLmrow(); + //return $mmlRow->encapsulate(parent::renderMML($arguments)); + return parent::renderMML( $arguments ); + } + public function inCurlies() { return $this->render(); } diff --git a/src/TexVC/Nodes/DQ.php b/src/TexVC/Nodes/DQ.php index 8fd55d4ac..1700ddf1c 100644 --- a/src/TexVC/Nodes/DQ.php +++ b/src/TexVC/Nodes/DQ.php @@ -4,6 +4,10 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmrow; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmsub; + class DQ extends TexNode { /** @var TexNode */ private $base; @@ -34,6 +38,20 @@ class DQ extends TexNode { return $this->base->render() . '_' . $this->down->inCurlies(); } + public function renderMML( $arguments = [] ) { + // Check if there is a specific parsing in BaseMethods + $bm = new BaseMethods(); + $res = $bm->checkAndParse( $this->base->getArgs()[0], $this, $arguments, null ); + if ( $res ) { + return $res; + } else { + // Otherwise use default fallback + $mmlMrow = new MMLmrow(); + $msub = new MMLmsub(); + return $msub->encapsulate( $this->base->renderMML() . $mmlMrow->encapsulate( $this->down->renderMML() ) ); + } + } + public function extractIdentifiers( $args = null ) { $d = $this->down->extractSubscripts(); $b = $this->base->extractIdentifiers(); diff --git a/src/TexVC/Nodes/Declh.php b/src/TexVC/Nodes/Declh.php index da14067e2..a4c4002b7 100644 --- a/src/TexVC/Nodes/Declh.php +++ b/src/TexVC/Nodes/Declh.php @@ -4,6 +4,8 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; + class Declh extends TexNode { /** @var string */ @@ -39,6 +41,16 @@ class Declh extends TexNode { return '{' . $this->fname . ' ' . $this->arg->inCurlies() . '}'; } + public function renderMML( $arguments = [] ) { + $bm = new BaseMethods(); + $res = $bm->checkAndParse( $this->fname, $this, $arguments, null ); + if ( $res ) { + return $res; + } else { + return "not implemented yet Declh parsing"; + } + } + public function extractIdentifiers( $args = null ) { if ( $args == null ) { $args = [ $this->arg ]; diff --git a/src/TexVC/Nodes/FQ.php b/src/TexVC/Nodes/FQ.php index ee7aaef44..e4a7a6363 100644 --- a/src/TexVC/Nodes/FQ.php +++ b/src/TexVC/Nodes/FQ.php @@ -4,6 +4,11 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmrow; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmsubsup; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmunderover; + class FQ extends TexNode { /** @var TexNode */ @@ -45,6 +50,40 @@ class FQ extends TexNode { return $this->base->render() . '_' . $this->down->inCurlies() . '^' . $this->up->inCurlies(); } + public function renderMML( $arguments = [] ) { + $bm = new BaseMethods(); + if ( $this->getArgs()[0]->getLength() == 0 ) { + // this happens when FQ is located in Sideset (is this a common parsing way?) + $mrow = new MMLmrow(); + return $mrow->encapsulate( $this->getDown()->renderMML() ) . + $mrow->encapsulate( $this->getUp()->renderMML() ); + } + + // Not sure if this case is necessary .. + if ( is_string( $this->getArgs()[0] ) ) { + $res = $bm->checkAndParse( $this->getArgs()[0], $this, $arguments, null ); + if ( $res ) { + return $res; + } else { + return "Not Implemented FQ for: " . $this->getArgs()[0]; + } + } + + $melement = new MMLmsubsup(); + // tbd check for more such cases like TexUtilTest 317 + $base = $this->getBase(); + if ( $base instanceof Literal ) { + if ( trim( $this->getBase()->getArgs()[0] ) === "\\sum" ) { + $melement = new MMLmunderover(); + } + } + + // This seems to be the common case + $mrow = new MMLmrow(); + return $melement->encapsulate( $this->getBase()->renderMML() . + $mrow->encapsulate( $this->getDown()->renderMML() ) . $mrow->encapsulate( $this->getUp()->renderMML() ) ); + } + public function name() { return 'FQ'; } diff --git a/src/TexVC/Nodes/Fun1.php b/src/TexVC/Nodes/Fun1.php index 234dc5cdb..e61e1d352 100644 --- a/src/TexVC/Nodes/Fun1.php +++ b/src/TexVC/Nodes/Fun1.php @@ -4,6 +4,10 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmo; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmover; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmrow; use MediaWiki\Extension\Math\TexVC\TexUtil; class Fun1 extends TexNode { @@ -44,6 +48,31 @@ class Fun1 extends TexNode { return '{' . $this->fname . ' ' . $this->arg->inCurlies() . '}'; } + public function renderMML( $arguments = [] ) { + $bm = new BaseMethods(); + $res = $bm->checkAndParse( $this->fname, $this, $arguments, null ); + if ( $res ) { + return $res; + } else { + return "Not Implemented Fun1 for: " . $this->fname; + } + } + + public function createMover( $inner, $moArgs = [] ): string { + $mrow = new MMLmrow(); + $mo = new MMLmo( "", $moArgs ); + $mover = new MMLmover(); + $ret = $mrow->encapsulate( + $mrow->encapsulate( + $mover->encapsulate( + $this->args[1]->renderMML() . + $mo->encapsulate( $inner ) + ) + ) + ); + return $ret; + } + public function extractIdentifiers( $args = null ) { if ( $args == null ) { $args = [ $this->arg ]; @@ -85,4 +114,5 @@ class Fun1 extends TexNode { public function name() { return 'FUN1'; } + } diff --git a/src/TexVC/Nodes/Fun1nb.php b/src/TexVC/Nodes/Fun1nb.php index e6976b112..0ce06cb4d 100644 --- a/src/TexVC/Nodes/Fun1nb.php +++ b/src/TexVC/Nodes/Fun1nb.php @@ -4,6 +4,8 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; + class Fun1nb extends Fun1 { public function name() { @@ -17,4 +19,38 @@ class Fun1nb extends Fun1 { public function render() { return $this->fname . ' ' . $this->arg->inCurlies() . ' '; } + + public function renderMML( $arguments = [] ) { + $bm = new BaseMethods(); + $res = $bm->checkAndParse( $this->fname, $this, $arguments, null ); + if ( $res ) { + return $res; + } else { + return "Not Implemented Fun1nb for: " . $this->fname; + } + // This is very preliminary and should most probably be synced with the mappings from time to time + // this might move to Fun1.php + /** + * $mrow = new MMLmrow(); + * $mo = new MMLmo(); + * switch($this->fname) { + * case "\\mathrm": + * + * $diff = $this->arg->getArg()->mmlSquash(true, false); + * if($diff<=0){ + * $arguments = array_merge([ "mathvariant"=>"normal"], $arguments); + * } + * return $mrow->encapsulate($this->arg->renderMML($arguments)); + * + * case "\\operatorname": + * // Very experimental rule here, squashed elements with 'd' are without args, others with 'd' have + * $diff = $this->arg->getArg()->mmlSquash(true, false); + * if($diff<=0){ + * $arguments = array_merge(["data-mjx-texclass"=>"OP", "mathvariant"=>"normal"], $arguments); + * } + * return $this->arg->renderMML($arguments); + * }; + * return parent::renderMML($arguments); // TODO: Change the autogenerated stub + */ + } } diff --git a/src/TexVC/Nodes/Fun2.php b/src/TexVC/Nodes/Fun2.php index 7b40dbc4f..fd7c352e5 100644 --- a/src/TexVC/Nodes/Fun2.php +++ b/src/TexVC/Nodes/Fun2.php @@ -4,6 +4,8 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; + class Fun2 extends TexNode { /** @var string */ @@ -49,6 +51,16 @@ class Fun2 extends TexNode { return '{' . $this->fname . ' ' . $this->arg1->inCurlies() . $this->arg2->inCurlies() . '}'; } + public function renderMML( $arguments = [] ) { + $bm = new BaseMethods(); + $res = $bm->checkAndParse( $this->fname, $this, $arguments, null ); + if ( $res ) { + return $res; + } else { + return "NotImplemented Fun2 for: " . $this->fname; + } + } + public function extractIdentifiers( $args = null ) { if ( $args == null ) { $args = [ $this->arg1, $this->arg2 ]; diff --git a/src/TexVC/Nodes/Infix.php b/src/TexVC/Nodes/Infix.php index 2772eae9e..79c40bcba 100644 --- a/src/TexVC/Nodes/Infix.php +++ b/src/TexVC/Nodes/Infix.php @@ -4,6 +4,8 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; + class Infix extends TexNode { /** @var string */ @@ -51,6 +53,16 @@ class Infix extends TexNode { $this->arg2->render() . '}'; } + public function renderMML( $arguments = [] ) { + $bm = new BaseMethods(); + $res = $bm->checkAndParse( $this->op, $this, $arguments, null ); + if ( $res ) { + return $res; + } else { + return "Not Implemented Infix for: " . $this->getArgs()[0]; + } + } + public function extractIdentifiers( $args = null ) { if ( $args == null ) { $args = [ $this->arg1, $this->arg2 ]; diff --git a/src/TexVC/Nodes/Literal.php b/src/TexVC/Nodes/Literal.php index 22338e0d7..8f3800626 100644 --- a/src/TexVC/Nodes/Literal.php +++ b/src/TexVC/Nodes/Literal.php @@ -4,6 +4,10 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; +use MediaWiki\Extension\Math\TexVC\MMLmappings\Util\MMLutil; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmi; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmn; use MediaWiki\Extension\Math\TexVC\TexUtil; class Literal extends TexNode { @@ -21,6 +25,67 @@ class Literal extends TexNode { array_push( $this->extendedLiterals, '\\infty', '\\emptyset' ); } + public function renderMML( $arguments = [] ) { + if ( is_numeric( $this->arg ) ) { + $mn = new MMLmn( "", $arguments ); + return $mn->encapsulate( $this->arg ); + } + // is important to split and find chars within curly and differentiate, see tc 459 + $foundOperatorContent = MMLutil::initalParseLiteralExpression( $this->arg ); + if ( !$foundOperatorContent ) { + $input = $this->arg; + $operatorContent = null; + } else { + $input = $foundOperatorContent[1][0]; + $operatorContent = $foundOperatorContent[2][0]; + } + + // This is rather a workaround: + // Sometimes literals from TexVC contain complete \\operatorname {asd} hinted as bug tex-2-mml.json + if ( str_contains( $input, "\\operatorname" ) ) { + $mi = new MMLmi(); + return $mi->encapsulate( $operatorContent ); + } + // Sieve for Operators + $bm = new BaseMethods(); + $ret = $bm->checkAndParseOperator( $input, $this, $arguments, $operatorContent ); + if ( $ret ) { + return $ret; + } + // Sieve for mathchar07 chars + $bm = new BaseMethods(); + $ret = $bm->checkAndParseMathCharacter( $input, $this, $arguments, $operatorContent ); + if ( $ret ) { + return $ret; + } + + // Sieve for Identifiers + $ret = $bm->checkAndParseIdentifier( $input, $this, $arguments, $operatorContent ); + if ( $ret ) { + return $ret; + } + // Sieve for Delimiters + $ret = $bm->checkAndParseDelimiter( $input, $this, $arguments, $operatorContent ); + if ( $ret ) { + return $ret; + } + // Sieve for Colors + $ret = $bm->checkAndParseColor( $input, $this, $arguments, $operatorContent ); + if ( $ret ) { + return $ret; + } + + // Sieve for Makros + $ret = $bm->checkAndParse( $input, $this, $arguments, $operatorContent ); + if ( $ret ) { + return $ret; + } + + // If falling through all sieves just create an MI element + $mi = new MMLmi( "", $arguments ); + return $mi->encapsulate( $input ); // $this->arg + } + /** * @return string */ @@ -28,6 +93,10 @@ class Literal extends TexNode { return $this->arg; } + public function setArg( $arg ) { + $this->arg = $arg; + } + /** * @return int[]|string[] */ diff --git a/src/TexVC/Nodes/Lr.php b/src/TexVC/Nodes/Lr.php index 588f26d2b..4e670cde6 100644 --- a/src/TexVC/Nodes/Lr.php +++ b/src/TexVC/Nodes/Lr.php @@ -4,6 +4,11 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; +use MediaWiki\Extension\Math\TexVC\MMLmappings\TexConstants\TexClass; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmo; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmrow; + class Lr extends TexNode { /** @var string */ @@ -49,6 +54,44 @@ class Lr extends TexNode { return '\\left' . $this->left . $this->arg->render() . '\\right' . $this->right; } + public function renderMML( $arguments = [] ) { + // TBD set attributes for right AND left correctly + $rightAttrs = []; + if ( $this->right == "." ) { + $rightAttrs = [ "fence" => "true", "stretchy" => "true", "symmetric" => "true" ]; + } + + $bm = new BaseMethods(); + $left = $bm->checkAndParseDelimiter( $this->left, $this, [], null, false, + TexClass::OPEN ); + if ( !$left ) { + $moLeft = new MMLmo( TexClass::OPEN, [] ); + $left = $moLeft->encapsulate( $this->right ); + } + $right = $bm->checkAndParseDelimiter( $this->right, $this, $rightAttrs, null, false, + TexClass::CLOSE ); + if ( !$right ) { + $moRight = new MMLmo( TexClass::CLOSE, $rightAttrs ); + $right = $moRight->encapsulate( $this->right ); + } + + $inner = $this->getArg()->renderMML(); + $mrow = new MMLmrow( TexClass::INNER ); + return $mrow->encapsulate( + $left . $inner . + $right + ); + } + + private function mmlTranslate( $input ) { + switch ( trim( $input ) ) { + case "\\vert": + return "|"; + default: + return $input; + } + } + public function containsFunc( $target, $args = null ) { if ( $args == null ) { $args = [ '\\left','\\right', $this->arg ]; diff --git a/src/TexVC/Nodes/Matrix.php b/src/TexVC/Nodes/Matrix.php index 529ec005b..c8731b0d1 100644 --- a/src/TexVC/Nodes/Matrix.php +++ b/src/TexVC/Nodes/Matrix.php @@ -5,6 +5,7 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; use InvalidArgumentException; +use MediaWiki\Extension\Math\TexVC\MMLmappings\BaseMethods; class Matrix extends TexNode { @@ -62,6 +63,16 @@ class Matrix extends TexNode { return '{\\begin{' . $this->top . '}' . $this->renderMatrix( $this->mainarg ) . '\\end{' . $this->top . '}}'; } + public function renderMML( $arguments = [] ) { + $bm = new BaseMethods(); + $res = $bm->checkAndParse( $this->getTop(), $this, $arguments, null ); + if ( $res ) { + return $res; + } else { + return "Not Implemented Matrix for: " . $this->getArgs()[0]; + } + } + private function renderMatrix( $matrix ) { $mapped = array_map( [ self::class, 'renderLine' ], $matrix->args ); return implode( '\\\\', $mapped ); diff --git a/src/TexVC/Nodes/TexArray.php b/src/TexVC/Nodes/TexArray.php index 5282c02d2..f4de3cafb 100644 --- a/src/TexVC/Nodes/TexArray.php +++ b/src/TexVC/Nodes/TexArray.php @@ -5,6 +5,7 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; use InvalidArgumentException; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmstyle; class TexArray extends TexNode { @@ -21,6 +22,56 @@ class TexArray extends TexNode { parent::__construct( ...$nargs ); } + public function checkForStyleArgs( $node ) { + if ( $node instanceof Literal ) { + $name = trim( $node->getArg() ); + switch ( $name ) { + case "\\displaystyle": + return [ "displaystyle" => "true", "scriptlevel" => "0" ]; + case "\\scriptstyle": + return [ "displaystyle" => "false", "scriptlevel" => "1" ]; + case "\\scriptscriptstyle": + return [ "displaystyle" => "false", "scriptlevel" => "2" ]; + case "\\textstyle": + return [ "displaystyle" => "false", "scriptlevel" => "0" ]; + } + } + return null; + } + + public function renderMML( $arguments = [] ) { + // Everything here is for parsing displaystyle, probably refactored to TexVC grammar later + $fullRenderedArray = ""; + $mmlStyle = null; + for ( $i = 0, $count = count( $this->args ); $i < $count; $i++ ) { + $current = $this->args[$i]; + if ( isset( $this->args[$i + 1] ) ) { + $next = $this->args[$i + 1]; + } else { + $next = null; + } + $styleArguments = $this->checkForStyleArgs( $current ); + + // For cases with "displaystyle{someargs} otherargs" + if ( $styleArguments ) { + $mmlStyle = new MMLmstyle( "", $styleArguments ); + $fullRenderedArray .= $mmlStyle->getStart(); + if ( $next instanceof Curly ) { + $fullRenderedArray .= $next->renderMML( $arguments ); + $fullRenderedArray .= $mmlStyle->getEnd(); + $mmlStyle = null; + $i++; + } + } else { + $fullRenderedArray .= $current->renderMML( $arguments ); + } + } + if ( $mmlStyle ) { + $fullRenderedArray .= $mmlStyle->getEnd(); + } + return $fullRenderedArray; + } + public function inCurlies() { if ( isset( $this->args[0] ) && count( $this->args ) == 1 ) { return $this->args[0]->inCurlies(); @@ -97,6 +148,10 @@ class TexArray extends TexNode { array_push( $this->args, ...$elements ); } + public function pop() { + array_splice( $this->args, 0, 1 ); + } + /** * @return TexNode|string|null first value */ diff --git a/src/TexVC/Nodes/TexNode.php b/src/TexVC/Nodes/TexNode.php index 937004a57..0d17ed30f 100644 --- a/src/TexVC/Nodes/TexNode.php +++ b/src/TexVC/Nodes/TexNode.php @@ -39,6 +39,19 @@ class TexNode { return $out; } + public function renderMML( $arguments = [] ) { + return array_reduce( $this->args, function ( $out, $child ) use ( $arguments ) { + return $out . $this->renderChildMML( $child, $arguments ); + }, '' ); + } + + public function renderChildMML( $child, $arguments ) { + if ( $child instanceof TexNode ) { + return $child->renderMML( $arguments ); + } + return $child; + } + public function getLength(): ?int { if ( isset( $this->args[0] ) ) { return count( $this->args ); diff --git a/src/TexVC/Nodes/UQ.php b/src/TexVC/Nodes/UQ.php index 2f56e0d54..172d0bac6 100644 --- a/src/TexVC/Nodes/UQ.php +++ b/src/TexVC/Nodes/UQ.php @@ -4,6 +4,10 @@ declare( strict_types = 1 ); namespace MediaWiki\Extension\Math\TexVC\Nodes; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmover; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmrow; +use MediaWiki\Extension\Math\TexVC\MMLnodes\MMLmsup; + class UQ extends TexNode { /** @var TexNode */ @@ -35,6 +39,21 @@ class UQ extends TexNode { return $this->base->render() . '^' . $this->up->inCurlies(); } + public function renderMML( $arguments = [] ) { + $mrow = new MMLmrow(); + $mmlBase = new MMLmsup(); + // Sometimes 'overbrace' or similar seems to determine the wrapping element here. + if ( $this->getBase() instanceof Fun1nb && str_starts_with( $this->getBase()->getArgs()[0], "\\o" ) ) { + $mmlBase = new MMLmover(); + } + return $mmlBase->encapsulate( + $this->base->renderMML( $arguments ) . + $mrow->getStart() . // up is inferring a new mrow + $this->up->renderMML( $arguments ) . + $mrow->getEnd() + ); + } + public function name() { return 'UQ'; }