Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
57.67% |
466 / 808 |
|
29.17% |
14 / 48 |
CRAP | |
0.00% |
0 / 1 |
BaseParsing | |
57.67% |
466 / 808 |
|
29.17% |
14 / 48 |
5549.09 | |
0.00% |
0 / 1 |
accent | |
95.00% |
19 / 20 |
|
0.00% |
0 / 1 |
5 | |||
array | |
77.78% |
14 / 18 |
|
0.00% |
0 / 1 |
13.58 | |||
alignAt | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
3 | |||
amsEqnArray | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
3 | |||
boldsymbol | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
cancel | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
cancelTo | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
chemCustom | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
customLetters | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
cFrac | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
1 | |||
crLaTeX | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
dots | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
genFrac | |
76.47% |
39 / 51 |
|
0.00% |
0 / 1 |
16.55 | |||
frac | |
46.15% |
6 / 13 |
|
0.00% |
0 / 1 |
8.90 | |||
hline | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
hskip | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
42 | |||
handleOperatorName | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
lap | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
20 | |||
macro | |
43.86% |
50 / 114 |
|
0.00% |
0 / 1 |
107.64 | |||
matrix | |
96.43% |
54 / 56 |
|
0.00% |
0 / 1 |
21 | |||
namedOp | |
44.44% |
4 / 9 |
|
0.00% |
0 / 1 |
2.69 | |||
over | |
57.69% |
15 / 26 |
|
0.00% |
0 / 1 |
12.85 | |||
oint | |
50.00% |
10 / 20 |
|
0.00% |
0 / 1 |
16.00 | |||
overset | |
75.00% |
6 / 8 |
|
0.00% |
0 / 1 |
2.06 | |||
phantom | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
raiseLower | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
72 | |||
underset | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
underOver | |
94.44% |
17 / 18 |
|
0.00% |
0 / 1 |
6.01 | |||
mathFont | |
90.48% |
19 / 21 |
|
0.00% |
0 / 1 |
7.04 | |||
mathChoice | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
132 | |||
makeBig | |
94.12% |
32 / 34 |
|
0.00% |
0 / 1 |
14.04 | |||
machine | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
namedFn | |
44.44% |
4 / 9 |
|
0.00% |
0 / 1 |
2.69 | |||
limits | |
94.74% |
18 / 19 |
|
0.00% |
0 / 1 |
8.01 | |||
setFont | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
sideset | |
68.29% |
28 / 41 |
|
0.00% |
0 / 1 |
13.19 | |||
spacer | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
smash | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
72 | |||
texAtom | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
42 | |||
intent | |
0.00% |
0 / 32 |
|
0.00% |
0 / 1 |
240 | |||
hBox | |
28.21% |
11 / 39 |
|
0.00% |
0 / 1 |
86.53 | |||
setStyle | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
not | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
vbox | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
sqrt | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
3 | |||
tilde | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
xArrow | |
100.00% |
31 / 31 |
|
100.00% |
1 / 1 |
2 | |||
getApplyFct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 |
1 | <?php |
2 | namespace MediaWiki\Extension\Math\WikiTexVC\MMLmappings; |
3 | |
4 | use IntlChar; |
5 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Misc; |
6 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Sizes; |
7 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Tag; |
8 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\TexClass; |
9 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Variants; |
10 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLParsingUtil; |
11 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLutil; |
12 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmenclose; |
13 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmerror; |
14 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmfrac; |
15 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmi; |
16 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmmultiscripts; |
17 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmo; |
18 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmover; |
19 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmpadded; |
20 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmphantom; |
21 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmroot; |
22 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmrow; |
23 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmspace; |
24 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsqrt; |
25 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmstyle; |
26 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsub; |
27 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsup; |
28 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtable; |
29 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtd; |
30 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtext; |
31 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtr; |
32 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmunder; |
33 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmunderover; |
34 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ; |
35 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\FQ; |
36 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun1; |
37 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun1nb; |
38 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun2; |
39 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun2sq; |
40 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun4; |
41 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Literal; |
42 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Matrix; |
43 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexArray; |
44 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexNode; |
45 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\UQ; |
46 | use MediaWiki\Extension\Math\WikiTexVC\TexUtil; |
47 | use MediaWiki\Extension\Math\WikiTexVC\TexVC; |
48 | |
49 | /** |
50 | * Parsing functions for specific recognized mappings. |
51 | * Usually the parsing functions are invoked from the BaseMethods classes. |
52 | */ |
53 | class BaseParsing { |
54 | |
55 | public static function accent( $node, $passedArgs, $name, $operatorContent, $accent, $stretchy = null ) { |
56 | // Currently this is own implementation from Fun1.php |
57 | // TODO The first if-clause is mathjax specific (and not necessary by generic parsers) |
58 | // and will most probably removed (just for running all tc atm) |
59 | if ( $accent == "00B4" || $accent == "0060" ) { |
60 | $attrs = [ Tag::SCRIPTTAG => "true" ]; |
61 | } else { |
62 | if ( $stretchy == null ) { |
63 | // $attrs = [ "stretchy" => "false" ]; // not mention explicit stretchy |
64 | $attrs = []; |
65 | } else { |
66 | $attrs = [ "stretchy" => "true" ]; |
67 | } |
68 | } |
69 | // Fetching entity from $accent key tbd |
70 | $entity = MMLutil::createEntity( $accent ); |
71 | if ( !$entity ) { |
72 | $entity = $accent; |
73 | } |
74 | |
75 | $mrow = new MMLmrow(); |
76 | $mo = new MMLmo( "", $attrs ); // $passedArgs |
77 | $mover = new MMLmover(); |
78 | $ret = $mrow->encapsulateRaw( |
79 | $mrow->encapsulateRaw( |
80 | $mover->encapsulateRaw( |
81 | $node->getArg()->renderMML( $passedArgs ) . |
82 | $mo->encapsulateRaw( $entity ) |
83 | ) |
84 | ) |
85 | ); |
86 | return $ret; |
87 | } |
88 | |
89 | public static function array( $node, $passedArgs, $operatorContent, $name, $begin = null, $open = null, |
90 | $close = null, $align = null, $spacing = null, |
91 | $vspacing = null, $style = null, $raggedHeight = null ) { |
92 | $output = ""; |
93 | $mrow = new MMLmrow(); |
94 | if ( $open != null ) { |
95 | $resDelimiter = TexUtil::getInstance()->delimiter( trim( $open ) ) ?? false; |
96 | if ( $resDelimiter ) { |
97 | // $retDelim = $bm->checkAndParseDelimiter($open, $node,$passedArgs,true); |
98 | $moOpen = new MMLmo( TexClass::OPEN ); |
99 | $output .= $moOpen->encapsulateRaw( $resDelimiter[0] ); |
100 | } |
101 | } |
102 | if ( $name == "Bmatrix" || $name == "bmatrix" || $name == "Vmatrix" |
103 | || $name == "vmatrix" || $name == "smallmatrix" || $name == "pmatrix" || $name == "matrix" ) { |
104 | // This is a workaround and might be improved mapping BMatrix to Matrix directly instead of array |
105 | return self::matrix( $node, $passedArgs, $operatorContent, $name, |
106 | $open, $close, null, null, null, null, true ); |
107 | |
108 | } else { |
109 | $output .= $mrow->encapsulateRaw( $node->getMainarg()->renderMML() ); |
110 | } |
111 | |
112 | if ( $close != null ) { |
113 | $resDelimiter = TexUtil::getInstance()->delimiter( trim( $close ) ) ?? false; |
114 | if ( $resDelimiter ) { |
115 | $moClose = new MMLmo( TexClass::CLOSE ); |
116 | $output .= $moClose->encapsulateRaw( $resDelimiter[0] ); |
117 | } |
118 | } |
119 | return $output; |
120 | } |
121 | |
122 | public static function alignAt( Matrix $node, $passedArgs, $operatorContent, $name, $smth, |
123 | $smth2 = null ) { |
124 | // Parsing is very similar to AmsEQArray, maybe extract function ... tcs: 178 |
125 | $mrow = new MMLmrow(); |
126 | $mtable = new MMLmtable( "" ); |
127 | $mtr = new MMLmtr(); |
128 | $mtd = new MMLmtd(); |
129 | $renderedInner = ""; |
130 | |
131 | foreach ( $node as $tableRow ) { |
132 | $renderedInner .= $mtr->getStart(); |
133 | foreach ( $tableRow->getArgs() as $tableCell ) { |
134 | $renderedInner .= $mtd->getStart() . $tableCell->renderMML() . $mtd->getEnd(); |
135 | } |
136 | $renderedInner .= $mtr->getEnd(); |
137 | } |
138 | return $mrow->encapsulateRaw( $mtable->encapsulateRaw( $renderedInner ) ); |
139 | } |
140 | |
141 | public static function amsEqnArray( $node, $passedArgs, $operatorContent, $name, $smth, $smth2 = null ) { |
142 | $mrow = new MMLmrow(); |
143 | $mtable = new MMLmtable( '' ); |
144 | $mtr = new MMLmtr(); |
145 | $mtd = new MMLmtd(); |
146 | $renderedInner = ""; |
147 | foreach ( $node as $tableRow ) { |
148 | $renderedInner .= $mtr->getStart(); |
149 | foreach ( $tableRow->getArgs() as $tableCell ) { |
150 | $renderedInner .= $mtd->encapsulateRaw( $tableCell->renderMML() ); // pass args here ? |
151 | } |
152 | $renderedInner .= $mtr->getEnd(); |
153 | } |
154 | return $mrow->encapsulateRaw( $mtable->encapsulateRaw( $renderedInner ) ); |
155 | } |
156 | |
157 | public static function boldsymbol( $node, $passedArgs, $operatorContent, $name, $smth = null, $smth2 = null ) { |
158 | $mrow = new MMLmrow(); |
159 | $passedArgs = array_merge( [ "mathvariant" => Variants::BOLDITALIC ] ); |
160 | return $mrow->encapsulateRaw( $node->getArg()->renderMML( $passedArgs ) ); |
161 | } |
162 | |
163 | public static function cancel( Fun1 $node, $passedArgs, $operatorContent, $name, $notation = '' ): string { |
164 | $outer = new MMLmenclose( '', [ 'notation' => $notation, 'class' => 'menclose' ] ); |
165 | $bars = ''; |
166 | foreach ( explode( ' ', $notation ) as $element ) { |
167 | $bars .= ( new MMLmrow( '', [ 'class' => 'menclose-' . $element ] ) )->getEmpty(); |
168 | } |
169 | |
170 | return $outer->encapsulateRaw( $node->getArg()->renderMML() . $bars ); |
171 | } |
172 | |
173 | public static function cancelTo( $node, $passedArgs, $operatorContent, $name, $notation = null ) { |
174 | $mrow = new MMLmrow(); |
175 | $msup = new MMLmsup(); |
176 | $mpAdded = new MMLmpadded( "", [ "depth" => "-.1em", "height" => "+.1em", "voffset" => ".1em" ] ); |
177 | |
178 | $menclose = new MMLmenclose( "", [ "notation" => $notation ] ); |
179 | $inner = $menclose->encapsulateRaw( |
180 | $node->getArg2()->renderMML() ) . $mpAdded->encapsulateRaw( $node->getArg1()->renderMML() ); |
181 | return $mrow->encapsulateRaw( $msup->encapsulateRaw( $inner ) ); |
182 | } |
183 | |
184 | public static function chemCustom( $node, $passedArgs, $operatorContent, $name, $translation = null ) { |
185 | return $translation ?: 'tbd chemCustom'; |
186 | } |
187 | |
188 | public static function customLetters( $node, $passedArgs, $operatorContent, $name, $char, $isOperator = false ) { |
189 | $mrow = new MMLmrow(); |
190 | |
191 | if ( $isOperator ) { |
192 | $mo = new MMLmo(); |
193 | return $mrow->encapsulateRaw( $mo->encapsulateRaw( $char ) ); |
194 | } |
195 | |
196 | $mi = new MMLmi( "", [ "mathvariant" => "normal" ] ); |
197 | return $mrow->encapsulateRaw( $mi->encapsulateRaw( $char ) ); |
198 | } |
199 | |
200 | public static function cFrac( $node, $passedArgs, $operatorContent, $name ) { |
201 | $mrow = new MMLmrow(); |
202 | $mfrac = new MMLmfrac(); |
203 | $mstyle = new MMLmstyle( "", [ "displaystyle" => "false", "scriptlevel" => "0" ] ); |
204 | $mpAdded = new MMLmpadded( "", [ "depth" => "3pt", "height" => "8.6pt", "width" => "0" ] ); |
205 | // See TexUtilMMLTest testcase 81 |
206 | // (mml3 might be erronous here, but this element seems to be rendered correctly) |
207 | $whatIsThis = $mrow->getStart() . $mpAdded->getStart() . $mpAdded->getEnd() . $mrow->getEnd(); |
208 | $inner = $mrow->encapsulateRaw( $whatIsThis . |
209 | $mstyle->encapsulateRaw( $mrow->encapsulateRaw( $node->getArg1()->renderMML() ) ) ) . |
210 | $mrow->encapsulateRaw( $whatIsThis . $mstyle->encapsulateRaw( |
211 | $mrow->encapsulateRaw( $node->getArg2()->renderMML() ) ) ); |
212 | |
213 | return $mrow->encapsulateRaw( $mfrac->encapsulateRaw( $inner ) ); |
214 | } |
215 | |
216 | public static function crLaTeX( $node, $passedArgs, $operatorContent, $name ) { |
217 | $mspace = new MMLmspace( "", [ "linebreak" => "newline" ] ); |
218 | return $mspace->getEmpty(); |
219 | } |
220 | |
221 | public static function dots( $node, $passedArgs, $operatorContent, $name, $smth = null, $smth2 = null ) { |
222 | // lowerdots || centerdots seems aesthetical, just using lowerdots atm s |
223 | $mo = new MMLmo( "", $passedArgs ); |
224 | return $mo->encapsulateRaw( "…" ); |
225 | } |
226 | |
227 | public static function genFrac( $node, $passedArgs, $operatorContent, $name, |
228 | $left = null, $right = null, $thick = null, $style = null ) { |
229 | // Actually this is in AMSMethods, consider refactoring left, right, thick, style |
230 | $bm = new BaseMethods(); |
231 | $ret = $bm->checkAndParseDelimiter( $name, $node, $passedArgs, $operatorContent, true ); |
232 | if ( $ret ) { |
233 | // TBD |
234 | if ( $left == null ) { |
235 | $left = $ret; |
236 | } |
237 | if ( $right == null ) { |
238 | $right = $ret; |
239 | } |
240 | if ( $thick == null ) { |
241 | $thick = $ret; |
242 | } |
243 | if ( $style == null ) { |
244 | $style = trim( $ret ); |
245 | } |
246 | } |
247 | $attrs = []; |
248 | $fract = null; |
249 | $styleAttr = []; |
250 | $displayStyle = "false"; |
251 | if ( in_array( $thick, [ 'thin', 'medium', 'thick', '0' ], true ) ) { |
252 | $attrs = array_merge( $attrs, [ "linethickness" => $thick ] ); |
253 | } |
254 | if ( $style !== '' ) { |
255 | $styleDigit = intval( $style, 10 ); |
256 | $styleAlpha = [ 'D', 'T', 'S', 'SS' ][$styleDigit]; |
257 | if ( $styleAlpha == null ) { |
258 | $mrow = new MMLmrow(); |
259 | return $mrow->encapsulateRaw( "Bad math style" ); |
260 | } |
261 | |
262 | if ( $styleAlpha === 'D' ) { |
263 | // NodeUtil_js_1.default.setProperties(frac, { displaystyle: true, scriptlevel: 0 }); |
264 | |
265 | // tbd add props |
266 | $displayStyle = "true"; |
267 | $styleAttr = [ "minsize" => "2.047em" ]; |
268 | |
269 | } else { |
270 | $styleAttr = [ "minsize" => "1.2em" ]; |
271 | } |
272 | |
273 | /* @phan-suppress-next-line SecurityCheck-DoubleEscaped */ |
274 | $frac = new MMLmfrac( '', $attrs ); |
275 | } else { |
276 | // NodeUtil_js_1.default.setProperties(frac, { displaystyle: false, |
277 | // scriptlevel: styleDigit - 1 }); |
278 | // tbd add props |
279 | /* @phan-suppress-next-line SecurityCheck-DoubleEscaped */ |
280 | $frac = new MMLmfrac( '', $attrs ); |
281 | $styleAttr = [ "maxsize" => "1.2em", "minsize" => "1.2em" ]; |
282 | |
283 | } |
284 | $mrow = new MMLmrow(); |
285 | $mstyle = new MMLmstyle( "", [ "displaystyle" => $displayStyle, "scriptlevel" => "0" ] ); |
286 | $output = $mrow->getStart(); |
287 | if ( $style !== '' ) { |
288 | $output .= $mstyle->getStart(); |
289 | } |
290 | $output .= $mrow->getStart(); |
291 | if ( $left ) { |
292 | $mrowOpen = new MMLmrow( TexClass::OPEN ); |
293 | $moL = new MMLmo( "", $styleAttr ); |
294 | $output .= $mrowOpen->encapsulateRaw( $moL->encapsulateRaw( $left ) ); |
295 | } |
296 | $output .= $frac->encapsulateRaw( $mrow->encapsulateRaw( $node->getArg1()->renderMML() ) . |
297 | $mrow->encapsulateRaw( $node->getArg2()->renderMML() ) ); |
298 | if ( $right ) { |
299 | $mrowClose = new MMLmrow( TexClass::CLOSE ); |
300 | $moR = new MMLmo( "", $styleAttr ); |
301 | $output .= $mrowClose->encapsulateRaw( $moR->encapsulateRaw( $right ) ); |
302 | |
303 | } |
304 | $output .= $mrow->getEnd(); |
305 | if ( $style !== '' ) { |
306 | $output .= $mstyle->getEnd(); |
307 | } |
308 | $output .= $mrow->getEnd(); |
309 | |
310 | return $output; |
311 | } |
312 | |
313 | public static function frac( $node, $passedArgs, $operatorContent, $name ) { |
314 | $mrow = new MMLmrow(); |
315 | $mfrac = new MMLmfrac(); |
316 | if ( $node instanceof Fun2 ) { |
317 | $inner = $mrow->encapsulateRaw( $node->getArg1()->renderMML() ) . |
318 | $mrow->encapsulateRaw( $node->getArg2()->renderMML() ); |
319 | } elseif ( $node instanceof DQ ) { |
320 | $inner = $mrow->encapsulateRaw( $node->getBase()->renderMML() ) . |
321 | $mrow->encapsulateRaw( $node->getDown()->renderMML() ); |
322 | } else { |
323 | $inner = ""; |
324 | foreach ( $node->getArgs() as $arg ) { |
325 | $rendered = is_string( $arg ) ? $arg : $arg->renderMML(); |
326 | $inner .= $mrow->encapsulateRaw( $rendered ); |
327 | } |
328 | } |
329 | return $mrow->encapsulateRaw( $mfrac->encapsulateRaw( $inner ) ); |
330 | } |
331 | |
332 | public static function hline( $node, $passedArgs, $operatorContent, $name, |
333 | $smth1 = null, $smth2 = null, $smth3 = null, $smth4 = null ) { |
334 | // HLine is most probably not parsed this way, since only parsed in Matrix context |
335 | $mmlRow = new MMLmrow( "tbd" ); |
336 | return $mmlRow->encapsulateRaw( "HLINE TBD" ); |
337 | } |
338 | |
339 | public static function hskip( $node, $passedArgs, $operatorContent, $name ) { |
340 | if ( $node->getArg()->isCurly() ) { |
341 | $unit = MMLutil::squashLitsToUnit( $node->getArg() ); |
342 | if ( !$unit ) { |
343 | return null; |
344 | } |
345 | $em = MMLutil::dimen2em( $unit ); |
346 | } else { |
347 | // Prevent parsing in unmapped cases |
348 | return null; |
349 | } |
350 | // Added kern j4t |
351 | if ( $name == "mskip" || $name == "mkern" || "kern" ) { |
352 | $args = [ "width" => $em ]; |
353 | } else { |
354 | return null; |
355 | } |
356 | |
357 | $mspace = new MMLmspace( "", $args ); |
358 | return $mspace->encapsulateRaw( "" ); |
359 | } |
360 | |
361 | public static function handleOperatorName( $node, $passedArgs, $operatorContent, $name ) { |
362 | // In example "\\operatorname{a}" |
363 | $applyFct = self::getApplyFct( $operatorContent ); |
364 | $mmlNot = ""; |
365 | if ( isset( $operatorContent['not'] ) && $operatorContent['not'] ) { |
366 | $mmlNot = MMLParsingUtil::createNot(); |
367 | } |
368 | $passedArgs = array_merge( $passedArgs, [ Tag::CLASSTAG => TexClass::OP, "mathvariant" => Variants::NORMAL ] ); |
369 | $state = [ 'squashLiterals' => true ]; |
370 | return $mmlNot . $node->getArg()->renderMML( $passedArgs, $state ) . $applyFct; |
371 | } |
372 | |
373 | public static function lap( $node, $passedArgs, $operatorContent, $name ) { |
374 | if ( !$node instanceof Fun1 ) { |
375 | return null; |
376 | } |
377 | if ( trim( $name ) === "\\rlap" ) { |
378 | $args = [ "width" => "0" ]; |
379 | } elseif ( trim( $name ) === "\\llap" ) { |
380 | $args = [ "width" => "0", "lspace" => "-1width" ]; |
381 | } else { |
382 | return null; |
383 | } |
384 | $mrow = new MMLmrow(); |
385 | $mpAdded = new MMLmpadded( "", $args ); |
386 | return $mrow->encapsulateRaw( $mpAdded->encapsulateRaw( $node->getArg()->renderMML() ) ); |
387 | } |
388 | |
389 | public static function macro( $node, $passedArgs, $operatorContent, $name, |
390 | $macro = '', $argcount = null, $def = null ) { |
391 | // Parse the Macro |
392 | if ( $macro == "\\text{ }" ) { |
393 | $mtext = new MMLmtext(); |
394 | return $mtext->encapsulateRaw( ' ' ); |
395 | } |
396 | switch ( trim( $name ) ) { |
397 | case "\\mod": |
398 | $mmlRow = new MMLmrow(); |
399 | $mo = new MMLmo( "", [ "lspace" => "2.5pt", "rspace" => "2.5pt" ] ); |
400 | // @phan-suppress-next-line PhanUndeclaredMethod |
401 | $inner = $node->getArg() instanceof TexNode ? $node->getArg()->renderMML() : ""; |
402 | return $mmlRow->encapsulateRaw( $mo->encapsulate( "mod" ) . $inner ); |
403 | case "\\pmod": |
404 | // tbd indicate in mapping that this is composed within php |
405 | $mmlRow = new MMLmrow(); |
406 | $mspace = new MMLmspace( "", [ "width" => "0.444em" ] ); |
407 | $mspace2 = new MMLmspace( "", [ "width" => "0.333em" ] ); |
408 | $mo = new MMLmo( "", [ "stretchy" => "false" ] ); |
409 | $mi = new MMLmi(); |
410 | // @phan-suppress-next-line PhanUndeclaredMethod |
411 | $inner = $node->getArg() instanceof TexNode ? $node->getArg()->renderMML() : ""; |
412 | |
413 | return $mmlRow->encapsulateRaw( $mspace->encapsulate() . |
414 | $mo->encapsulate( "(" ) . $mi->encapsulate( "mod" ) . |
415 | $mspace2->encapsulate() . $inner . $mo->encapsulate( ")" ) ); |
416 | case "\\varlimsup": |
417 | case "\\varliminf": |
418 | // hardcoded macro in php (there is also a dynamic mapping which is not completely resolved atm) |
419 | $mmlRow = new MMLmrow( TexClass::OP ); |
420 | if ( trim( $name ) === "\\varlimsup" ) { |
421 | $movu = new MMLmover(); |
422 | |
423 | } else { |
424 | $movu = new MMLmunder(); |
425 | } |
426 | $mmlMi = new MMLmi(); |
427 | $mo = new MMLmo( "", [ "accent" => "true" ] ); |
428 | return $mmlRow->encapsulateRaw( $movu->encapsulateRaw( |
429 | $mmlMi->encapsulateRaw( "lim" ) . $mo->encapsulateRaw( "―" ) ) ); |
430 | |
431 | case "\\varinjlim": |
432 | $mmlRow = new MMLmrow( TexClass::OP ); |
433 | $mmlMunder = new MMLmunder(); |
434 | $mi = new MMLmi(); |
435 | $mo = new MMLmo(); |
436 | return $mmlRow->encapsulateRaw( $mmlMunder->encapsulateRaw( |
437 | $mi->encapsulateRaw( "lim" ) . |
438 | $mo->encapsulateRaw( "→" ) ) |
439 | ); |
440 | case "\\varprojlim": |
441 | $mmlRow = new MMLmrow( TexClass::OP ); |
442 | $mmlMunder = new MMLmunder(); |
443 | $mi = new MMLmi(); |
444 | $mo = new MMLmo(); |
445 | return $mmlRow->encapsulateRaw( $mmlMunder->encapsulateRaw( |
446 | $mi->encapsulate( "lim" ) . |
447 | $mo->encapsulateRaw( "←" ) |
448 | ) ); |
449 | case "\\stackrel": |
450 | // hardcoded macro in php (there is also a dynamic mapping which is not not completely resolved atm) |
451 | $mmlRow = new MMLmrow(); |
452 | $mmlRowInner = new MMLmrow( TexClass::REL ); |
453 | $mover = new MMLmover(); |
454 | $mmlRowArg2 = new MMLmrow( TexClass::OP ); |
455 | if ( $node instanceof DQ ) { |
456 | $inner = $mover->encapsulateRaw( $mmlRowArg2->encapsulateRaw( |
457 | $node->getBase()->renderMML() ) . |
458 | $mmlRow->encapsulateRaw( $node->getDown()->renderMML() ) |
459 | ); |
460 | } else { |
461 | $inner = $mover->encapsulateRaw( $mmlRowArg2->encapsulateRaw( |
462 | // @phan-suppress-next-line PhanUndeclaredMethod |
463 | $node->getArg2()->renderMML() ) . |
464 | // @phan-suppress-next-line PhanUndeclaredMethod |
465 | $mmlRow->encapsulateRaw( $node->getArg1()->renderMML() ) |
466 | ); |
467 | } |
468 | return $mmlRow->encapsulateRaw( $mmlRowInner->encapsulateRaw( $inner ) ); |
469 | case "\\bmod": |
470 | $mo = new MMLmo( "", [ "lspace" => Sizes::THICKMATHSPACE, "rspace" => Sizes::THICKMATHSPACE ] ); |
471 | $mmlRow = new MMLmrow( TexClass::ORD ); |
472 | $mspace = new MMLmspace( "", [ "width" => "0.167em" ] ); |
473 | // @phan-suppress-next-line PhanUndeclaredMethod |
474 | $inner = $node->getArg() instanceof TexNode ? |
475 | // @phan-suppress-next-line PhanUndeclaredMethod |
476 | $mmlRow->encapsulateRaw( $node->getArg()->renderMML() ) : ""; |
477 | return $mmlRow->encapsulateRaw( $mo->encapsulate( "mod" ) . |
478 | $inner . $mmlRow->encapsulateRaw( $mspace->getEmpty() ) ); |
479 | case "\\implies": |
480 | $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); |
481 | $mspace = new MMLmspace( "", [ "width" => "0.278em" ] ); |
482 | $mo = new MMLmo(); |
483 | return $mstyle->encapsulateRaw( $mspace->getEmpty() ) . $mo->encapsulateRaw( "⟹" ) . |
484 | $mstyle->encapsulateRaw( $mspace->getEmpty() ); |
485 | case "\\iff": |
486 | $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); |
487 | $mspace = new MMLmspace( "", [ "width" => "0.278em" ] ); |
488 | $mo = new MMLmo(); |
489 | return $mstyle->encapsulateRaw( $mspace->getEmpty() ) . $mo->encapsulateRaw( "⟺" ) . |
490 | $mstyle->encapsulateRaw( $mspace->getEmpty() ); |
491 | case "\\tripledash": |
492 | // Using emdash for rendering here. |
493 | $mo = new MMLmo(); |
494 | return $mo->encapsulateRaw( "—" ); |
495 | case "\\longrightleftharpoons": |
496 | case "\\longLeftrightharpoons": |
497 | case "\\longRightleftharpoons": |
498 | $texvc = new TexVC(); |
499 | $warnings = []; |
500 | $checkRes = $texvc->check( $macro, [ "usemhchem" => true, "usemhchemtexified" => true ], |
501 | $warnings, true ); |
502 | return $checkRes["input"]->renderMML(); |
503 | case "\\longleftrightarrows": |
504 | // The tex-cmds used in makro are not supported, just use a hardcoded mml macro here. |
505 | $mtext = new MMLmtext(); |
506 | $mrowRel = new MMLmrow( TexClass::REL ); |
507 | $mrowOrd = new MMLmrow( TexClass::ORD ); |
508 | $mrowOp = new MMLmrow( TexClass::OP ); |
509 | $mover = new MMLmover(); |
510 | $mpadded = new MMLmpadded( "", [ "height" => "0", "depth" => "0" ] ); |
511 | $mo = new MMLmo( "", [ "stretchy" => "false" ] ); |
512 | $mspace = new MMLmspace( "", [ "width" => "0px", "height" => ".25em", |
513 | "depth" => "0px", "mathbackground" => "black" ] ); |
514 | return $mtext->encapsulateRaw( " " ) . |
515 | $mrowRel->encapsulateRaw( $mover->encapsulateRaw( |
516 | $mrowOp->encapsulateRaw( |
517 | $mrowOrd->encapsulateRaw( $mpadded->encapsulateRaw( |
518 | $mo->encapsulateRaw( "⟵" ) ) ) . |
519 | $mspace->getEmpty() ) . |
520 | $mrowOrd->encapsulateRaw( |
521 | $mo->encapsulateRaw( "⟶" ) |
522 | ) ) ); |
523 | |
524 | } |
525 | |
526 | // Removed all token based parsing, since macro resolution for the supported macros can be hardcoded in php |
527 | $mmlMrow = new MMLmrow(); |
528 | return $mmlMrow->encapsulate( "macro not resolved: " . $macro ); |
529 | } |
530 | |
531 | public static function matrix( Matrix $node, $passedArgs, $operatorContent, |
532 | $name, $open = null, $close = null, $align = null, $spacing = null, |
533 | $vspacing = null, $style = null, $cases = null, $numbered = null ) { |
534 | $resInner = ''; |
535 | $mtr = new MMLmtr(); |
536 | $tableArgs = [ "columnspacing" => "1em", "rowspacing" => "4pt" ]; |
537 | $boarder = $node->getBoarder(); |
538 | if ( $align ) { |
539 | $tableArgs['columnalign'] = $align; |
540 | } elseif ( $node->hasColumnInfo() ) { |
541 | $tableArgs['columnalign'] = $node->getAlignInfo(); |
542 | } |
543 | $rowNo = 0; |
544 | $lines = $node->getLines(); |
545 | foreach ( $node as $row ) { |
546 | $resInner .= $mtr->getStart(); |
547 | $colNo = 0; |
548 | foreach ( $row as $cell ) { |
549 | $usedArg = clone $cell; |
550 | if ( $usedArg instanceof TexArray && |
551 | $usedArg->getLength() >= 1 && |
552 | $usedArg[0] instanceof Literal && |
553 | $usedArg[0]->getArg() === '\\hline ' |
554 | ) { |
555 | $usedArg->pop(); |
556 | if ( $rowNo === $node->getLength() - 1 && |
557 | $usedArg->getLength() === 0 |
558 | ) { |
559 | // remove the started row |
560 | $resInner = substr( $resInner, 0, -1 * strlen( $mtr->getStart() ) ); |
561 | continue 2; |
562 | } |
563 | } |
564 | $mtdAttributes = []; |
565 | $texclass = $lines[$rowNo] ? TexClass::TOP : ''; |
566 | $texclass .= $lines[$rowNo + 1] ?? false ? ' ' . TexClass::BOTTOM : ''; |
567 | $texclass .= $boarder[$colNo] ?? false ? ' ' . TexClass::LEFT : ''; |
568 | $texclass .= $boarder[$colNo + 1 ] ?? false ? ' ' . TexClass::RIGHT : ''; |
569 | $texclass = trim( $texclass ); |
570 | if ( $texclass ) { |
571 | $mtdAttributes['class'] = $texclass; |
572 | } |
573 | $mtd = new MMLmtd( '', $mtdAttributes ); |
574 | |
575 | $state = [ 'inMatrix' => true ]; |
576 | $resInner .= $mtd->encapsulateRaw( $usedArg->renderMML( $passedArgs, $state ) ); |
577 | $colNo++; |
578 | } |
579 | $resInner .= $mtr->getEnd(); |
580 | $rowNo++; |
581 | } |
582 | $mrow = new MMLmrow(); |
583 | $mtable = new MMLmtable( "", $tableArgs ); |
584 | if ( $cases || ( $open != null && $close != null ) ) { |
585 | $bm = new BaseMethods(); |
586 | $mmlMoOpen = $bm->checkAndParseDelimiter( $open, $node, [], [], |
587 | true, TexClass::OPEN ); |
588 | if ( $mmlMoOpen == null ) { |
589 | $mmlMoOpen = new MMLmo( TexClass::OPEN, [] ); |
590 | $mmlMoOpen = $mmlMoOpen->encapsulateRaw( $open ?? '' ); |
591 | } |
592 | |
593 | $closeAtts = [ "fence" => "true", "stretchy" => "true", "symmetric" => "true" ]; |
594 | $mmlMoClose = $bm->checkAndParseDelimiter( $close, $node, $closeAtts, |
595 | null, true, TexClass::CLOSE ); |
596 | if ( $mmlMoOpen == null ) { |
597 | $mmlMoClose = new MMLmo( TexClass::CLOSE, $closeAtts ); |
598 | $mmlMoClose = $mmlMoClose->encapsulateRaw( $close ); |
599 | } |
600 | $resInner = $mmlMoOpen . $mtable->encapsulateRaw( $resInner ) . $mmlMoClose; |
601 | return $mrow->encapsulateRaw( $resInner ); |
602 | } |
603 | return $mtable->encapsulateRaw( $resInner ); |
604 | } |
605 | |
606 | public static function namedOp( $node, $passedArgs, $operatorContent, $name, $id = null ) { |
607 | /* Determine whether the named function should have an added apply function. The operatorContent is defined |
608 | as state in parsing of TexArray */ |
609 | $applyFct = self::getApplyFct( $operatorContent ); |
610 | |
611 | if ( $node instanceof Literal ) { |
612 | $mi = new MMLmi( "", $passedArgs ); |
613 | return $mi->encapsulateRaw( $id ?? ltrim( $name, '\\' ) ) . $applyFct; |
614 | } |
615 | $mrow = new MMLmrow( TexClass::ORD, [] ); |
616 | $msub = new MMLmsub( "", $passedArgs ); |
617 | return $msub->encapsulateRaw( $node->getBase()->renderMML() . |
618 | $applyFct . |
619 | $mrow->encapsulateRaw( $node->getDown()->renderMML() ) ); |
620 | } |
621 | |
622 | public static function over( $node, $passedArgs, $operatorContent, $name, $id = null ) { |
623 | $attributes = []; |
624 | $start = ""; |
625 | $tail = ""; |
626 | if ( trim( $name ) === "\\atop" ) { |
627 | $attributes = [ "linethickness" => "0" ]; |
628 | } elseif ( trim( $name ) == "\\choose" ) { |
629 | $mrowAll = new MMLmrow( TexClass::ORD ); |
630 | $mrowOpen = new MMLmrow( TexClass::OPEN ); |
631 | $mrowClose = new MMLmrow( TexClass::CLOSE ); |
632 | $mo = new MMLmo( "", [ "maxsize" => "1.2em", "minsize" => "1.2em" ] ); |
633 | $start = $mrowAll->getStart() . $mrowOpen->encapsulateRaw( $mo->encapsulate( "(" ) ); |
634 | $tail = $mrowClose->encapsulateRaw( $mo->encapsulate( ")" ) ) . $mrowAll->getEnd(); |
635 | $attributes = [ "linethickness" => "0" ]; |
636 | |
637 | } |
638 | $mfrac = new MMLmfrac( "", $attributes ); |
639 | |
640 | $mrow = new MMLmrow( "", [] ); |
641 | if ( $node instanceof Fun2 ) { |
642 | return $start . $mfrac->encapsulateRaw( $mrow->encapsulateRaw( |
643 | $node->getArg1()->renderMML() ) . $mrow->encapsulateRaw( $node->getArg2()->renderMML() ) ) |
644 | . $tail; |
645 | } |
646 | $inner = ""; |
647 | foreach ( $node->getArgs() as $arg ) { |
648 | if ( is_string( $arg ) && str_contains( $arg, $name ) ) { |
649 | continue; |
650 | } |
651 | $rendered = $arg instanceof TexNode ? $arg->renderMML() : $arg; |
652 | $inner .= $mrow->encapsulateRaw( $rendered ); |
653 | } |
654 | |
655 | return $start . $mfrac->encapsulateRaw( $inner ) . $tail; |
656 | } |
657 | |
658 | public static function oint( $node, $passedArgs, $operatorContent, |
659 | $name, $uc = null, $attributes = null, $smth2 = null ) { |
660 | // This is a custom mapping not in js. |
661 | $mmlText = new MMLmtext( "", $attributes ); |
662 | $mrow = new MMLmrow(); |
663 | switch ( trim( $name ) ) { |
664 | case "\\oint": |
665 | $mStyle = new MMLmstyle( "", [ "displaystyle" => "true" ] ); |
666 | $mo = new MMLmo(); |
667 | return $mStyle->encapsulateRaw( $mo->encapsulateRaw( MMLutil::uc2xNotation( $uc ) ) ); |
668 | case "\\P": |
669 | $mo = new MMLmo(); |
670 | return $mo->encapsulateRaw( MMLutil::uc2xNotation( $uc ) ); |
671 | case "\\oiint": |
672 | case "\\oiiint": |
673 | case "\\ointctrclockwise": |
674 | case "\\varointclockwise": |
675 | $mStyle = new MMLmstyle( "", [ "mathsize" => "2.07em" ] ); |
676 | $mSpace = new MMLmspace( "", [ "width" => Sizes::THINMATHSPACE ] ); |
677 | return $mrow->encapsulateRaw( $mStyle->encapsulateRaw( |
678 | $mmlText->encapsulateRaw( MMLutil::uc2xNotation( $uc ) ) |
679 | . $mSpace->getEmpty() ) ); |
680 | default: |
681 | return ( new MMLmerror() )->encapsulate( "not found in OintMethod" ); |
682 | |
683 | } |
684 | } |
685 | |
686 | public static function overset( $node, $passedArgs, $operatorContent, $name, $id = null ) { |
687 | $mrow = new MMLmrow( TexClass::ORD, [] ); // tbd remove mathjax specifics |
688 | $mrow2 = new MMLmrow( "", [] ); |
689 | $mover = new MMLmover(); |
690 | |
691 | if ( $node instanceof DQ ) { |
692 | return $mrow->encapsulateRaw( $mover->encapsulateRaw( $mrow2->encapsulateRaw( |
693 | $node->getDown()->renderMML() . $node->getDown()->renderMML() ) ) ); |
694 | } else { |
695 | $inrow = $mrow2->encapsulateRaw( $node->getArg2()->renderMML() ); |
696 | } |
697 | return $mrow->encapsulateRaw( $mover->encapsulateRaw( $inrow . $node->getArg1()->renderMML() ) ); |
698 | } |
699 | |
700 | public static function phantom( $node, $passedArgs, $operatorContent, |
701 | $name, $vertical = null, $horizontal = null, $smh3 = null ) { |
702 | $mrow = new MMLmrow( TexClass::ORD, [] ); |
703 | |
704 | $attrs = []; |
705 | if ( $vertical ) { |
706 | $attrs = array_merge( $attrs, [ "width" => "0" ] ); |
707 | } |
708 | if ( $horizontal ) { |
709 | $attrs = array_merge( $attrs, [ "depth" => "0", "height" => "0" ] ); |
710 | } |
711 | $mpadded = new MMLmpadded( "", $attrs ); |
712 | $mphantom = new MMLmphantom(); |
713 | return $mrow->encapsulateRaw( $mrow->encapsulateRaw( |
714 | $mpadded->encapsulateRaw( $mphantom->encapsulateRaw( $node->getArg()->renderMML() ) ) ) ); |
715 | } |
716 | |
717 | public static function raiseLower( $node, $passedArgs, $operatorContent, $name ) { |
718 | if ( !$node instanceof Fun2 ) { |
719 | return null; |
720 | } |
721 | |
722 | $arg1 = $node->getArg1(); |
723 | // the second check is to avoid a false positive for PhanTypeMismatchArgumentSuperType |
724 | if ( $arg1->isCurly() && $arg1 instanceof TexArray ) { |
725 | $unit = MMLutil::squashLitsToUnit( $arg1 ); |
726 | if ( !$unit ) { |
727 | return null; |
728 | } |
729 | $em = MMLutil::dimen2em( $unit ); |
730 | if ( !$em ) { |
731 | return null; |
732 | } |
733 | } else { |
734 | return null; |
735 | } |
736 | |
737 | if ( trim( $name ) === "\\raise" ) { |
738 | $args = [ "height" => MMLutil::addPreOperator( $em, "+" ), |
739 | "depth" => MMLutil::addPreOperator( $em, "-" ), |
740 | "voffset" => MMLutil::addPreOperator( $em, "+" ) ]; |
741 | } elseif ( trim( $name ) === "\\lower" ) { |
742 | $args = [ "height" => MMLutil::addPreOperator( $em, "-" ), |
743 | "depth" => MMLutil::addPreOperator( $em, "+" ), |
744 | "voffset" => MMLutil::addPreOperator( $em, "-" ) ]; |
745 | } else { |
746 | // incorrect name, should not happen, prevent erroneous mappings from getting rendered. |
747 | return null; |
748 | } |
749 | $mrow = new MMLmrow(); |
750 | $mpAdded = new MMLmpadded( "", $args ); |
751 | return $mrow->encapsulateRaw( $mpAdded->encapsulateRaw( $node->getArg2()->renderMML() ) ); |
752 | } |
753 | |
754 | public static function underset( $node, $passedArgs, $operatorContent, $name, $smh = null ) { |
755 | $mrow = new MMLmrow( TexClass::ORD, [] ); |
756 | $inrow = $node->getArg2()->renderMML(); |
757 | $arg1 = $node->getArg1()->renderMML(); |
758 | if ( $inrow && $arg1 ) { |
759 | $munder = new MMLmunder(); |
760 | return $mrow->encapsulateRaw( $munder->encapsulateRaw( $inrow . $arg1 ) ); |
761 | } |
762 | |
763 | // If there are no two elements in munder, not render munder |
764 | return $mrow->encapsulateRaw( $inrow . $arg1 ); |
765 | } |
766 | |
767 | public static function underOver( Fun1 $node, $passedArgs, $operatorContent, |
768 | $name, $operatorId = null, $stack = null, $nonHex = false ) { |
769 | // tbd verify if stack interpreted correctly ? |
770 | $texClass = $stack ? TexClass::OP : TexClass::ORD; // ORD or "" |
771 | |
772 | $mrow = new MMLmrow( $texClass ); |
773 | $fname = $node->getFname(); |
774 | if ( str_starts_with( $fname, '\\over' ) ) { |
775 | $movun = new MMLmover(); |
776 | } elseif ( str_starts_with( $fname, '\\under' ) ) { |
777 | $movun = new MMLmunder(); |
778 | } else { |
779 | // incorrect name, should not happen, prevent erroneous mappings from getting rendered. |
780 | $merror = new MMLmerror(); |
781 | return $merror->encapsulateRaw( |
782 | 'underOver rendering requires macro to start with either \\under or \\over.' ); |
783 | } |
784 | |
785 | if ( $operatorId == 2015 ) { // eventually move such cases to mapping |
786 | $mo = new MMLmo( "", [ "accent" => "true" ] ); |
787 | } else { |
788 | $mo = new MMLmo(); |
789 | } |
790 | |
791 | $inner = $nonHex ? $operatorId : MMLutil::number2xNotation( $operatorId ); |
792 | return $mrow->encapsulateRaw( $movun->encapsulateRaw( |
793 | $node->getArg()->renderMML( $passedArgs ) . |
794 | $mo->encapsulateRaw( $inner ) |
795 | ) ); |
796 | } |
797 | |
798 | public static function mathFont( $node, $passedArgs, $operatorContent, $name, $mathvariant = null ) { |
799 | $mrow = new MMLmrow( TexClass::ORD, [] ); |
800 | $args = MMLParsingUtil::getFontArgs( $name, $mathvariant, $passedArgs ); |
801 | $state = []; |
802 | |
803 | // Unicode fixes for the operators |
804 | switch ( $mathvariant ) { |
805 | case Variants::DOUBLESTRUCK: |
806 | $state = [ "double-struck-literals" => true ]; |
807 | break; |
808 | case Variants::CALLIGRAPHIC: |
809 | $state = [ "calligraphic" => true ]; |
810 | break; |
811 | case Variants::BOLDCALLIGRAPHIC: |
812 | $state = [ "bold-calligraphic" => true ]; |
813 | break; |
814 | case Variants::FRAKTUR: |
815 | $state = [ "fraktur" => true ]; |
816 | break; |
817 | case Variants::BOLD: |
818 | $state = [ "bold" => true ]; |
819 | break; |
820 | } |
821 | |
822 | if ( $node instanceof Fun1nb ) { |
823 | // Only one mrow from Fun1nb !? |
824 | return $mrow->encapsulateRaw( $node->getArg()->renderMML( $args, $state ) ); |
825 | } |
826 | return $mrow->encapsulateRaw( $mrow->encapsulateRaw( $node->getArg()->renderMML( $args, $state ) ) ); |
827 | } |
828 | |
829 | public static function mathChoice( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
830 | if ( !$node instanceof Fun4 ) { |
831 | $merror = new MMLmerror(); |
832 | return $merror->encapsulateRaw( "Wrong node type in mathChoice" ); |
833 | } |
834 | |
835 | /** |
836 | * Parametrization for mathchoice: |
837 | * \mathchoice |
838 | * {<material for display style>} |
839 | * {<material for text style>} |
840 | * {<material for script style>} |
841 | * {<material for scriptscript style>} |
842 | */ |
843 | |
844 | if ( isset( $operatorContent["styleargs"] ) ) { |
845 | $styleArgs = $operatorContent["styleargs"]; |
846 | $displayStyle = $styleArgs["displaystyle"] ?? "true"; |
847 | $scriptLevel = $styleArgs["scriptlevel"] ?? "0"; |
848 | |
849 | if ( $displayStyle == "true" && $scriptLevel == "0" ) { |
850 | // This is displaystyle |
851 | return $node->getArg1()->renderMML( $passedArgs, $operatorContent ); |
852 | } elseif ( $displayStyle == "false" && $scriptLevel == "0" ) { |
853 | // This is textstyle |
854 | return $node->getArg2()->renderMML( $passedArgs, $operatorContent ); |
855 | } elseif ( $displayStyle == "false" && $scriptLevel == "1" ) { |
856 | // This is scriptstyle |
857 | return $node->getArg3()->renderMML( $passedArgs, $operatorContent ); |
858 | } elseif ( $displayStyle == "false" && $scriptLevel == "2" ) { |
859 | // This is scriptscriptstyle |
860 | return $node->getArg4()->renderMML( $passedArgs, $operatorContent ); |
861 | } |
862 | } |
863 | // By default render displaystyle |
864 | return $node->getArg1()->renderMML( $passedArgs, $operatorContent ); |
865 | } |
866 | |
867 | public static function makeBig( $node, $passedArgs, $operatorContent, $name, $texClass = null, $size = null ) { |
868 | // Create the em format and shorten commas |
869 | $size *= Misc::P_HEIGHT; |
870 | $sizeShortened = MMLutil::size2em( strval( $size ) ); |
871 | $mrowOuter = new MMLmrow( TexClass::ORD, [] ); |
872 | $mrow = new MMLmrow( $texClass, [] ); |
873 | $passedArgs = array_merge( $passedArgs, [ "maxsize" => $sizeShortened, "minsize" => $sizeShortened ] ); |
874 | $mo = new MMLmo( "", $passedArgs ); |
875 | // Sieve arg if it is a delimiter (it seems args are not applied here |
876 | $bm = new BaseMethods(); |
877 | $argcurrent = trim( $node->getArg() ); |
878 | switch ( $argcurrent ) { |
879 | case "\\|": |
880 | case "|": |
881 | $passedArgs = array_merge( $passedArgs, [ "stretchy" => "true", "symmetric" => "true" ] ); |
882 | break; |
883 | case "\\uparrow": |
884 | case "\\downarrow": |
885 | case "\\Uparrow": |
886 | case "\\Downarrow": |
887 | case "\\updownarrow": |
888 | case "/": |
889 | case "\\backslash": |
890 | case "\\Updownarrow": |
891 | $passedArgs = array_merge( |
892 | [ "fence" => "true" ], |
893 | $passedArgs, |
894 | [ "stretchy" => "true", "symmetric" => "true" ] ); |
895 | break; |
896 | } |
897 | |
898 | if ( in_array( $name, [ "\\bigl", "\\Bigl", "\\biggl", "\\Biggl" ] ) ) { |
899 | $passedArgs = array_merge( $passedArgs, [ Tag::CLASSTAG => TexClass::OPEN ] ); |
900 | } |
901 | |
902 | if ( in_array( $name, [ "\\bigr", "\\Bigr", "\\biggr", "\\Biggr" ] ) ) { |
903 | $passedArgs = array_merge( $passedArgs, [ Tag::CLASSTAG => TexClass::CLOSE ] ); |
904 | } |
905 | |
906 | $ret = $bm->checkAndParseDelimiter( $node->getArg(), $node, $passedArgs, $operatorContent, true ); |
907 | if ( $ret ) { |
908 | return $ret; |
909 | } |
910 | |
911 | $argPrep = $node->getArg(); |
912 | return $mrowOuter->encapsulateRaw( $mrow->encapsulateRaw( $mo->encapsulateRaw( $argPrep ) ) ); |
913 | } |
914 | |
915 | public static function machine( $node, $passedArgs, $operatorContent, $name, $type = null ) { |
916 | // this could also be shifted to MhChem.php renderMML for ce |
917 | // For parsing chem (ce) or ??? (pu) |
918 | $mmlMrow = new MMLmrow(); |
919 | return $mmlMrow->encapsulateRaw( $node->getArg()->renderMML() ); |
920 | } |
921 | |
922 | public static function namedFn( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
923 | // Determine wether the named function should have an added apply function. The state is defined in |
924 | // parsing of TexArray |
925 | $applyFct = self::getApplyFct( $operatorContent ); |
926 | if ( $node instanceof Literal ) { |
927 | $mi = new MMLmi(); |
928 | return $mi->encapsulateRaw( ltrim( $name, '\\' ) ) . $applyFct; |
929 | } |
930 | $mrow = new MMLmrow( TexClass::ORD, [] ); // tbd remove mathjax specifics |
931 | $msub = new MMLmsub(); |
932 | return $msub->encapsulateRaw( $node->getBase()->renderMML() . |
933 | $applyFct . |
934 | $mrow->encapsulateRaw( $node->getDown()->renderMML() ) ); |
935 | } |
936 | |
937 | public static function limits( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
938 | $argsOp = [ 'form' => 'prefix' ]; |
939 | if ( isset( $operatorContent['styleargs'] ) ) { |
940 | $displaystyle = $operatorContent['styleargs']['displaystyle'] ?? 'true'; |
941 | if ( $displaystyle === 'false' ) { |
942 | $argsOp['movablelimits'] = 'true'; |
943 | } |
944 | if ( $node->containsFunc( '\\nolimits' ) ) { |
945 | $argsOp['movablelimits'] = 'false'; |
946 | } |
947 | } |
948 | $mrow = new MMLmrow( TexClass::ORD, [] ); |
949 | $opParsed = ( $operatorContent["limits"] ?? false ) |
950 | ? $operatorContent["limits"]->renderMML( $argsOp ) : ""; |
951 | |
952 | if ( $node instanceof DQ ) { |
953 | $munder = new MMLmunder(); |
954 | return $munder->encapsulateRaw( $opParsed . $mrow->encapsulateRaw( $node->getDown()->renderMML() ) ); |
955 | } elseif ( $node instanceof FQ ) { |
956 | $munderOver = new MMLmunderover(); |
957 | return $munderOver->encapsulateRaw( $opParsed . $mrow->encapsulateRaw( $node->getDown()->renderMML() ) |
958 | . $mrow->encapsulateRaw( $node->getUp()->renderMML() ) ); |
959 | } elseif ( preg_match( '/\s*\\\\?(no)?limits\s*/', $name ) ) { |
960 | // Don't render limits |
961 | return ''; |
962 | } |
963 | } |
964 | |
965 | public static function setFont( $node, $passedArgs, $operatorContent, $name, $variant = null ) { |
966 | return self::mathFont( $node, $passedArgs, $operatorContent, $name, $variant ); |
967 | } |
968 | |
969 | public static function sideset( $node, $passedArgs, $operatorContent, $name ) { |
970 | if ( !array_key_exists( "sideset", $operatorContent ) ) { |
971 | $merror = new MMLmerror(); |
972 | return $merror->encapsulateRaw( "Error parsing sideset expression, no succeeding operator found" ); |
973 | } |
974 | |
975 | $mmlMrow = new MMLmrow( TexClass::OP ); |
976 | if ( $operatorContent["sideset"] instanceof Literal ) { |
977 | $mmlMultiscripts = new MMLmmultiscripts( "", [ Tag::ALIGN => "left" ] ); |
978 | |
979 | $bm = new BaseMethods(); |
980 | $opParsed = $bm->checkAndParseOperator( $operatorContent["sideset"]->getArg(), null, [], [], null ); |
981 | $in1 = $node->getArg1()->renderMML(); |
982 | $in2 = $node->getArg2()->renderMML(); |
983 | return $mmlMrow->encapsulateRaw( $mmlMultiscripts->encapsulateRaw( $opParsed . |
984 | $in2 . "<mprescripts/>" . $in1 ) ); |
985 | } |
986 | |
987 | if ( $operatorContent["sideset"] instanceof FQ || |
988 | $operatorContent["sideset"] instanceof DQ || |
989 | $operatorContent["sideset"] instanceof UQ ) { |
990 | $mmlMultiscripts = new MMLmmultiscripts( "", [] ); |
991 | $mmlMunderOver = new MMLmunderover(); |
992 | $mstyle = new MMLmstyle( "", [ "displaystyle" => "true" ] ); |
993 | $bm = new BaseMethods(); |
994 | if ( count( $operatorContent["sideset"]->getBase()->getArgs() ) == 1 ) { |
995 | $baseOperator = $operatorContent["sideset"]->getBase()->getArgs()[0]; |
996 | $opParsed = $bm->checkAndParseOperator( $baseOperator, |
997 | null, [ "largeop" => "true", "movablelimits" => "false", "symmetric" => "true" ], [], null ); |
998 | if ( $opParsed == null ) { |
999 | $opParsed = $operatorContent["sideset"]->getBase()->renderMML(); |
1000 | } |
1001 | } else { |
1002 | $merror = new MMLmerror(); |
1003 | $opParsed = $merror->encapsulateRaw( "Sideset operator parsing not implemented yet" ); |
1004 | } |
1005 | |
1006 | $in1 = $node->getArg1()->renderMML(); |
1007 | $in2 = $node->getArg2()->renderMML(); |
1008 | |
1009 | $mrowEnd = new MMLmrow( "", [] ); |
1010 | $down = $operatorContent["sideset"] instanceof UQ ? '<mrow />' : |
1011 | $operatorContent["sideset"]->getDown()->renderMML(); |
1012 | $end1 = $mrowEnd->encapsulateRaw( $down ); |
1013 | $up = $operatorContent["sideset"] instanceof DQ ? '<mrow />' : |
1014 | $operatorContent["sideset"]->getUp()->renderMML(); |
1015 | $end2 = $mrowEnd->encapsulateRaw( $up ); |
1016 | |
1017 | return $mmlMrow->encapsulateRaw( $mmlMunderOver->encapsulateRaw( $mstyle->encapsulateRaw( |
1018 | $mmlMultiscripts->encapsulateRaw( $opParsed . $in2 . "<mprescripts/>" . $in1 ) ) |
1019 | . $end1 . $end2 ) ); |
1020 | } |
1021 | |
1022 | $merror = new MMLmerror(); |
1023 | return $merror->encapsulateRaw( "Error parsing sideset expression, no valid succeeding operator found" ); |
1024 | } |
1025 | |
1026 | public static function spacer( $node, $passedArgs, $operatorContent, $name, $withIn = null, $smth2 = null ) { |
1027 | $width = MMLutil::round2em( $withIn ); |
1028 | $mspace = new MMLmspace( "", [ "width" => $width ] ); |
1029 | return $mspace->encapsulate(); |
1030 | } |
1031 | |
1032 | public static function smash( $node, $passedArgs, $operatorContent, $name ) { |
1033 | $mpArgs = []; |
1034 | $inner = ""; |
1035 | if ( $node instanceof Fun2sq ) { |
1036 | $arg1 = $node->getArg1(); |
1037 | $arg1i = ""; |
1038 | if ( $arg1->isCurly() ) { |
1039 | $arg1i = $arg1->render(); |
1040 | } |
1041 | |
1042 | if ( str_contains( $arg1i, "{b}" ) ) { |
1043 | $mpArgs = [ "depth" => "0" ]; |
1044 | } |
1045 | if ( str_contains( $arg1i, "{t}" ) ) { |
1046 | $mpArgs = [ "height" => "0" ]; |
1047 | } |
1048 | if ( str_contains( $arg1i, "{tb}" ) || str_contains( $arg1i, "{bt}" ) ) { |
1049 | $mpArgs = [ "height" => "0", "depth" => "0" ]; |
1050 | } |
1051 | |
1052 | $inner = $node->getArg2()->renderMML() ?? ""; |
1053 | } elseif ( $node instanceof Fun1 ) { |
1054 | // Implicitly assume "tb" as default mode |
1055 | $mpArgs = [ "height" => "0", "depth" => "0" ]; |
1056 | $inner = $node->getArg()->renderMML() ?? ""; |
1057 | } |
1058 | $mrow = new MMLmrow(); |
1059 | $mpAdded = new MMLmpadded( "", $mpArgs ); |
1060 | return $mrow->encapsulateRaw( $mpAdded->encapsulateRaw( $inner ) ); |
1061 | } |
1062 | |
1063 | public static function texAtom( $node, $passedArgs, $operatorContent, $name, $texClass = null ) { |
1064 | switch ( $name ) { |
1065 | case "mathclose": |
1066 | $mrow = new MMLmrow(); |
1067 | $mrow2 = new MMLmrow( $texClass, [] ); |
1068 | $inner = $node->getArg()->renderMML(); |
1069 | return $mrow->encapsulateRaw( $mrow2->encapsulateRaw( $inner ) ); |
1070 | case "mathbin": |
1071 | // no break |
1072 | case "mathop": |
1073 | // no break |
1074 | case "mathrel": |
1075 | $mrow2 = new MMLmrow( $texClass, [] ); |
1076 | $inner = $node->getArg()->renderMML(); |
1077 | return $mrow2->encapsulateRaw( $inner ); |
1078 | default: |
1079 | $mrow = new MMLmrow( TexClass::ORD ); |
1080 | $mrow2 = new MMLmrow( $texClass, [] ); |
1081 | $inner = $node->getArg()->renderMML(); |
1082 | return $mrow->encapsulateRaw( $mrow2->encapsulateRaw( $inner ) ); |
1083 | } |
1084 | } |
1085 | |
1086 | public static function intent( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
1087 | if ( !$node instanceof Fun2 ) { |
1088 | return null; |
1089 | } |
1090 | // if there is intent annotation add intent to root element |
1091 | // match args in row of subargs, unless an element has explicit annotations |
1092 | // nested annotations ? |
1093 | $arg1 = $node->getArg1(); |
1094 | $arg2 = $node->getArg2(); |
1095 | if ( !$arg2->isCurly() ) { |
1096 | return null; |
1097 | } |
1098 | // tbd refactor intent form and fiddle in mml or tree |
1099 | $intentStr = MMLutil::squashLitsToUnitIntent( $arg2 ); |
1100 | $intentContent = MMLParsingUtil::getIntentContent( $intentStr ); |
1101 | $intentParams = MMLParsingUtil::getIntentParams( $intentContent ); |
1102 | // Sometimes the intent has additioargs = {array[3]} nal args in the same string |
1103 | $intentArg = MMLParsingUtil::getIntentArgs( $intentStr ); |
1104 | if ( !$intentContent && !$intentParams && $intentArg !== null ) { |
1105 | // explicit args annotation parsing in literal |
1106 | // return $arg1->renderMML([],["intent-params-expl"=>$intentArg]); |
1107 | // alternative just add the arg here |
1108 | return $arg1->renderMML( [ "arg" => $intentArg ] ); |
1109 | } |
1110 | $intentContentAtr = [ "intent" => $intentContent ]; |
1111 | if ( $intentArg !== null ) { |
1112 | $intentContentAtr["arg"] = $intentArg; |
1113 | } |
1114 | // tbd refine intent params and operator content merging (does it overwrite ??) |
1115 | $intentParamsState = $intentParams ? [ "intent-params" => $intentParams ] : $operatorContent; |
1116 | // Here are some edge cases, they might go into renderMML in the related element |
1117 | if ( str_contains( $intentContent ?? '', "matrix" ) || |
1118 | ( $arg1->isCurly() && $arg1->getArgs()[0] instanceof Matrix ) ) { |
1119 | $element = $arg1->getArgs()[0]; |
1120 | $rendered = $element->renderMML( [], $intentParamsState ); |
1121 | $hackyXML = MMLParsingUtil::forgeIntentToSpecificElement( $rendered, |
1122 | $intentContentAtr, "mtable" ); |
1123 | return $hackyXML; |
1124 | } elseif ( $arg1->isCurly() && count( $arg1->getArgs() ) >= 2 ) { |
1125 | // Create a surrounding element which holds the intents |
1126 | $mrow = new MMLmrow( "", $intentContentAtr ); |
1127 | return $mrow->encapsulateRaw( $arg1->renderMML( [], $intentParamsState ) ); |
1128 | } elseif ( $arg1->isCurly() && count( $arg1->getArgs() ) >= 1 ) { |
1129 | // Forge the intent attribute to the top-level element after MML rendering |
1130 | $element = $arg1->getArgs()[0]; |
1131 | $rendered = $element->renderMML( [], $intentParamsState ); |
1132 | $hackyXML = MMLParsingUtil::forgeIntentToTopElement( $rendered, $intentContentAtr ); |
1133 | return $hackyXML; |
1134 | } else { |
1135 | // This is the default case |
1136 | return $arg1->renderMML( $intentContentAtr, $intentParamsState ); |
1137 | } |
1138 | } |
1139 | |
1140 | public static function hBox( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
1141 | switch ( trim( $name ) ) { |
1142 | case "\\mbox": |
1143 | $mo = new MMLmo(); |
1144 | $mmlMrow = new MMLmrow(); |
1145 | if ( isset( $operatorContent['foundOC'] ) ) { |
1146 | $op = $operatorContent['foundOC']; |
1147 | $macro = TexUtil::getInstance()->nullary_macro_in_mbox( $op ) ? |
1148 | /* tested in \MediaWiki\Extension\Math\Tests\WikiTexVC\TexUtilTest::testUnicodeDefined */ |
1149 | [ '&#x' . TexUtil::getInstance()->unicode_char( $op ) . ';' ] : |
1150 | TexUtil::getInstance()->identifier( $op ); |
1151 | $input = $macro[0] ?? $op; |
1152 | // @phan-suppress-next-line PhanTypeMismatchArgumentNullable - false positive see above |
1153 | return $mmlMrow->encapsulateRaw( $mo->encapsulateRaw( MMLutil::uc2xNotation( $input ) ) ); |
1154 | } else { |
1155 | $mmlMrow = new MMLmrow(); |
1156 | $mtext = new MMLmtext(); |
1157 | return $mmlMrow->encapsulateRaw( $mtext->encapsulateRaw( "\mbox" ) ); |
1158 | } |
1159 | case "\\hbox": |
1160 | $mmlMrow = new MMLmrow(); |
1161 | $mstyle = new MMLmstyle( "", [ "displaystyle" => "false", "scriptlevel" => "0" ] ); |
1162 | $mtext = new MMLmtext(); |
1163 | $inner = $node->getArg() instanceof TexNode ? $node->getArg()->renderMML() : $node->getArg(); |
1164 | return $mmlMrow->encapsulateRaw( $mstyle->encapsulateRaw( $mtext->encapsulateRaw( $inner ) ) ); |
1165 | case "\\text": |
1166 | $mmlMrow = new MMLmrow(); |
1167 | $mtext = new MMLmtext(); |
1168 | $inner = $node->getArg() instanceof TexNode ? $node->getArg()->renderMML() : $node->getArg(); |
1169 | return $mmlMrow->encapsulateRaw( $mtext->encapsulateRaw( $inner ) ); |
1170 | case "\\textbf": |
1171 | // no break |
1172 | case "\\textit": |
1173 | // no break |
1174 | case "\\textrm": |
1175 | // no break |
1176 | case "\\textsf": |
1177 | // no break |
1178 | case "\\texttt": |
1179 | $mmlMrow = new MMLmrow(); |
1180 | $mtext = new MMLmtext( "", MMLParsingUtil::getFontArgs( $name, null, null ) ); |
1181 | |
1182 | $state = [ "inHBox" => true ]; |
1183 | $inner = $node->getArg()->isCurly() ? $node->getArg()->renderMML( |
1184 | [], $state ) |
1185 | : $node->getArg()->renderMML( [ "fromHBox" => true ] ); |
1186 | return $mmlMrow->encapsulateRaw( $mtext->encapsulateRaw( $inner ) ); |
1187 | } |
1188 | |
1189 | $merror = new MMLmerror(); |
1190 | // $node->getArg1()->renderMML() . $node->getArg2()->renderMML() |
1191 | return $merror->encapsulateRaw( "undefined hbox" ); |
1192 | } |
1193 | |
1194 | public static function setStyle( $node, $passedArgs, $operatorContent, $name, |
1195 | $smth = null, $smth1 = null, $smth2 = null ) { |
1196 | // Just discard setstyle since they are captured in TexArray now} |
1197 | return " "; |
1198 | } |
1199 | |
1200 | public static function not( $node, $passedArgs, $operatorContent, $name, $smth = null, |
1201 | $smth1 = null, $smth2 = null ) { |
1202 | // This is only tested for \not statement without follow-up parameters |
1203 | if ( $node instanceof Literal ) { |
1204 | return MMLParsingUtil::createNot(); |
1205 | } else { |
1206 | $mError = new MMLmerror(); |
1207 | return $mError->encapsulateRaw( "TBD implement not" ); |
1208 | } |
1209 | } |
1210 | |
1211 | public static function vbox( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
1212 | // This is only example functionality for vbox("ab"). |
1213 | // TBD: it should be discussed if vbox is supported since it |
1214 | // does not seem to be supported by mathjax |
1215 | if ( is_string( $node->getArg() ) ) { |
1216 | $mmlMover = new MMLmover(); |
1217 | $mmlmrow = new MMLmrow(); |
1218 | $arr1 = str_split( $node->getArg() ); |
1219 | $inner = ""; |
1220 | foreach ( $arr1 as $char ) { |
1221 | $inner .= $mmlmrow->encapsulateRaw( $char ); |
1222 | } |
1223 | return $mmlMover->encapsulateRaw( $inner ); |
1224 | } |
1225 | $mError = new MMLmerror(); |
1226 | return $mError->encapsulateRaw( "no implemented vbox" ); |
1227 | } |
1228 | |
1229 | public static function sqrt( $node, $passedArgs, $operatorContent, $name ) { |
1230 | $mrow = new MMLmrow(); |
1231 | |
1232 | // There is an additional argument for the root |
1233 | if ( $node instanceof Fun2sq ) { |
1234 | $mroot = new MMLmroot(); |
1235 | |
1236 | // In case of an empty curly add an mrow |
1237 | $arg2Rendered = $node->getArg2()->renderMML( $passedArgs ); |
1238 | if ( trim( $arg2Rendered ) === "" ) { |
1239 | $arg2Rendered = $mrow->getEmpty(); |
1240 | } |
1241 | return $mrow->encapsulateRaw( |
1242 | $mroot->encapsulateRaw( |
1243 | $arg2Rendered . |
1244 | $mrow->encapsulateRaw( |
1245 | $node->getArg1()->renderMML( $passedArgs ) |
1246 | ) |
1247 | ) |
1248 | ); |
1249 | } |
1250 | $msqrt = new MMLmsqrt(); |
1251 | // Currently this is own implementation from Fun1.php |
1252 | return $mrow->encapsulateRaw( // assuming that this is always encapsulated in mrow |
1253 | $msqrt->encapsulateRaw( |
1254 | $node->getArg()->renderMML( $passedArgs ) |
1255 | ) |
1256 | ); |
1257 | } |
1258 | |
1259 | public static function tilde( $node, $passedArgs, $operatorContent, $name ) { |
1260 | $mspace = new MMLmspace( "", [ "width" => "0.5em" ] ); |
1261 | return $mspace->getEmpty(); |
1262 | } |
1263 | |
1264 | public static function xArrow( $node, $passedArgs, $operatorContent, $name, $chr = null, $l = null, $r = null ) { |
1265 | $defWidth = "+" . MMLutil::round2em( ( $l + $r ) / 18 ); |
1266 | $defLspace = MMLutil::round2em( $l / 18 ); |
1267 | |
1268 | $mover = new MMLmover(); |
1269 | $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); |
1270 | $moArrow = new MMLmo( Texclass::REL, [] ); |
1271 | $char = IntlChar::chr( $chr ); |
1272 | |
1273 | $mpaddedArgs = [ "height" => "-.2em", "lspace" => $defLspace, "voffset" => "-.2em", "width" => $defWidth ]; |
1274 | $mpadded = new MMLmpadded( "", $mpaddedArgs ); |
1275 | $mspace = new MMLmspace( "", [ "depth" => ".25em" ] ); |
1276 | if ( $node instanceof Fun2sq ) { |
1277 | $mmlMrow = new MMLmrow(); |
1278 | $mmlUnderOver = new MMLmunderover(); |
1279 | return $mmlMrow->encapsulateRaw( $mmlUnderOver->encapsulateRaw( |
1280 | $mstyle->encapsulateRaw( $moArrow->encapsulateRaw( $char ) ) . |
1281 | $mpadded->encapsulateRaw( |
1282 | $mmlMrow->encapsulateRaw( |
1283 | $node->getArg1()->renderMML() |
1284 | ) . |
1285 | $mspace->encapsulate() |
1286 | ) . |
1287 | $mpadded->encapsulateRaw( |
1288 | $node->getArg2()->renderMML() |
1289 | ) |
1290 | ) ); |
1291 | |
1292 | } |
1293 | return $mover->encapsulateRaw( |
1294 | $mstyle->encapsulateRaw( $moArrow->encapsulateRaw( $char ) ) . |
1295 | $mpadded->encapsulateRaw( |
1296 | $node->getArg()->renderMML() . |
1297 | $mspace->encapsulate() |
1298 | ) |
1299 | ); |
1300 | } |
1301 | |
1302 | private static function getApplyFct( array $operatorContent ): string { |
1303 | $applyFct = ""; |
1304 | if ( array_key_exists( "foundNamedFct", $operatorContent ) ) { |
1305 | $hasNamedFct = $operatorContent['foundNamedFct'][0]; |
1306 | $hasValidParameters = $operatorContent["foundNamedFct"][1]; |
1307 | if ( $hasNamedFct && $hasValidParameters ) { |
1308 | $applyFct = MMLParsingUtil::renderApplyFunction(); |
1309 | } |
1310 | } |
1311 | return $applyFct; |
1312 | } |
1313 | } |