Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 142 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
BaseMethods | |
0.00% |
0 / 142 |
|
0.00% |
0 / 10 |
4290 | |
0.00% |
0 / 1 |
checkAndParse | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
182 | |||
checkAndParseOperator | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
90 | |||
parseOperatorDict | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
42 | |||
parseOperator | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
20 | |||
checkAndParseIdentifier | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
42 | |||
parseIdentifier | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
20 | |||
checkAndParseDelimiter | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
90 | |||
checkAndParseMathCharacter | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
checkAndParseColor | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
110 | |||
generateMMLError | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | namespace MediaWiki\Extension\Math\WikiTexVC\MMLmappings; |
3 | |
4 | use ArgumentCountError; |
5 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Variants; |
6 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLutil; |
7 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmerror; |
8 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmi; |
9 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmo; |
10 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmrow; |
11 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmspace; |
12 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmstyle; |
13 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtext; |
14 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexNode; |
15 | |
16 | /** |
17 | * This contains the basic parsing methods for tex elements, which get invoked |
18 | * to check if there is a specific parsing function defined in the mappings |
19 | * and then forward to the parsing function. |
20 | * |
21 | * Much of this is WIP since there are many cases. |
22 | * @author Johannes Stegmüller |
23 | */ |
24 | class BaseMethods { |
25 | |
26 | public static function checkAndParse( $input, $passedArgs, $operatorContent, TexNode $node, $prepareInput = true ) { |
27 | if ( !is_string( $input ) ) { |
28 | // just discard these elements, sometimes empty TexArray |
29 | return null; |
30 | } |
31 | if ( $prepareInput ) { |
32 | $input = MMLutil::inputPreparation( $input ); |
33 | } |
34 | |
35 | // Checking for a named parsing function |
36 | $resFct = BaseMappings::getMacroByKey( $input ); |
37 | if ( $resFct == null ) { |
38 | $resFct = AMSMappings::getMacroByKey( $input ); |
39 | if ( $resFct == null ) { |
40 | // Also check for mathtools environment, this is currently done to find some form of matrices, |
41 | // probably refactored later |
42 | $resFct = AMSMappings::getEnvironmentByKey( $input ); |
43 | if ( $resFct == null ) { |
44 | $resFct = BaseMappings::getCustomByKey( $input ); |
45 | if ( $resFct == null ) { |
46 | $resFct = BaseMappings::getSpecialByKey( $input ); |
47 | if ( $resFct == null ) { |
48 | $resFct = BaseMappings::getCancelByKey( $input ); |
49 | if ( $resFct == null ) { |
50 | $resFct = BaseMappings::getMhChemByKey( $input ); |
51 | } |
52 | } |
53 | } |
54 | } |
55 | } |
56 | } |
57 | if ( $resFct == null ) { |
58 | return null; |
59 | } |
60 | // If the function has been found, dynamically call the associated parsing function. |
61 | if ( is_string( $resFct ) ) { |
62 | $resFct = [ $resFct ]; |
63 | } |
64 | try { |
65 | // Passing resolved function as param without first id |
66 | if ( count( $resFct ) > 1 ) { |
67 | $shifted = array_shift( $resFct ); |
68 | return BaseParsing::{$shifted}( $node, $passedArgs, $operatorContent, $input, ...$resFct ); |
69 | } else { |
70 | return BaseParsing::{$resFct[0]}( $node, $passedArgs, $operatorContent, $input ); |
71 | } |
72 | } catch ( \Exception $exception ) { |
73 | return null; |
74 | } |
75 | } |
76 | |
77 | public function checkAndParseOperator( $input, $node, $passedArgs, $operatorContent, |
78 | $state, $prepareInput = true ) { |
79 | if ( $prepareInput ) { |
80 | $input = MMLutil::inputPreparation( $input ); |
81 | } |
82 | $resOperator = BaseMappings::getOperatorByKey( $input ); |
83 | if ( $resOperator == null ) { |
84 | |
85 | $resOperator = AMSMappings::getOperatorByKey( $input ); |
86 | if ( $resOperator == null ) { |
87 | $resOperator = OperatorDictionary::getOperatorByKey( $input ); |
88 | if ( $resOperator ) { |
89 | if ( isset( $resOperator[1] ) ) { |
90 | // custom parsing here |
91 | return $this->parseOperatorDict( $node, $passedArgs, $operatorContent, $input, false ); |
92 | } |
93 | // Atm just do simple parsing for elements in operator dictionary |
94 | $mmlMo = new MMLmo(); |
95 | return $mmlMo->encapsulateRaw( $input ); |
96 | } |
97 | } |
98 | } |
99 | // If the macro has been found, dynamically call the associated parsing function. |
100 | if ( is_string( $resOperator ) ) { |
101 | $resOperator = [ $resOperator ]; |
102 | } |
103 | |
104 | if ( $resOperator == null ) { |
105 | return null; |
106 | } |
107 | try { |
108 | return $this->parseOperator( $node, $passedArgs, $operatorContent, $input, $state, ...$resOperator ); |
109 | |
110 | } catch ( ArgumentCountError $errArgcount ) { |
111 | return null; |
112 | } |
113 | } |
114 | |
115 | public function parseOperatorDict( $node, $passedArgs, $operatorContent, $input, $uc = null, $attrs = [] ) { |
116 | // Some custom parsing from operatorDict |
117 | switch ( $input ) { |
118 | case ";": |
119 | case ",": |
120 | // this maybe just a default case, this is not rendered when it is the last in row |
121 | $mmlMo = new MMLmo(); |
122 | return $mmlMo->encapsulate( $input ); |
123 | case "<": |
124 | $mmlMo = new MMLmo(); |
125 | return $mmlMo->encapsulateRaw( "<" ); |
126 | case ">": |
127 | $mmlMo = new MMLmo(); |
128 | return $mmlMo->encapsulateRaw( ">" ); |
129 | case "\\": |
130 | // instead of carriage return, force whitespace here: |
131 | // see: https://gerrit.wikimedia.org/r/c/mediawiki/extensions/Math/+/961213 |
132 | $mspace = new MMLmspace( "", [ "width" => "0.5em" ] ); |
133 | return $mspace->getEmpty(); |
134 | } |
135 | return $input; |
136 | } |
137 | |
138 | public function parseOperator( $node, $passedArgs, $operatorContent, $name, $state, $uc = null, $attrs = [] ) { |
139 | // if($name == "equiv" || $name == "dotplus" || $name == "mp" || $name == "pm"){ |
140 | $attrs = array_merge( $passedArgs, $attrs ); // this is rather a workaround |
141 | $mo = new MMLmo( "", $attrs ); |
142 | |
143 | if ( $state != null && array_key_exists( "not", $state ) && $state["not"] ) { |
144 | $text = $mo->encapsulateRaw( $uc . "̸" ); |
145 | } else { |
146 | $text = $mo->encapsulateRaw( $uc ); |
147 | } |
148 | |
149 | // Some attributes are nnot used which come from the mapping, tbd refactor this |
150 | $text = str_replace( " largeop=\"\"", "", $text ); |
151 | $text = str_replace( "variantForm=\"True\"", "data-mjx-alternate=\"1\"", $text ); |
152 | $text = str_replace( "variantForm=\"1\"", "data-mjx-alternate=\"1\"", $text ); |
153 | $text = str_replace( " movesupsub=\"1\"", "", $text ); |
154 | return str_replace( "texClass", "data-mjx-texclass", $text ); |
155 | } |
156 | |
157 | public function checkAndParseIdentifier( $input, $node, $passedArgs, $operatorContent, $prepareInput = true ) { |
158 | if ( $prepareInput ) { |
159 | $input = MMLutil::inputPreparation( $input ); |
160 | } |
161 | $resIdentifier = BaseMappings::getIdentifierByKey( $input ); |
162 | if ( $resIdentifier == null ) { |
163 | $resIdentifier = AMSMappings::getIdentifierByKey( $input ); |
164 | } |
165 | // If the macro has been found, dynamically call the associated parsing function. |
166 | if ( is_string( $resIdentifier ) ) { |
167 | $resIdentifier = [ $resIdentifier ]; |
168 | } |
169 | |
170 | if ( $resIdentifier == null ) { |
171 | return null; |
172 | } |
173 | try { |
174 | return $this->parseIdentifier( $node, $passedArgs, $operatorContent, $input, ...$resIdentifier ); |
175 | } catch ( ArgumentCountError $errArgcount ) { |
176 | return null; |
177 | } |
178 | } |
179 | |
180 | public function parseIdentifier( $node, $passedArgs, $operatorContent, $name, $uc = null, $attrs = [] ) { |
181 | // tbd verify rule: Lowercase name ("operator" instead "Operator") seems to |
182 | // indicate additional italic mathvariant when bold already |
183 | if ( !ctype_upper( $name ) ) { |
184 | if ( isset( $passedArgs["mathvariant"] ) && $passedArgs["mathvariant"] ) { |
185 | $passedArgs["mathvariant"] = $passedArgs["mathvariant"] . "-" . Variants::ITALIC; |
186 | } |
187 | } |
188 | |
189 | $args = array_merge( $passedArgs, $attrs ); |
190 | $mi = new MMLmi( "", $args ); |
191 | $text = $mi->encapsulateRaw( $uc ); |
192 | // TODO refactor just for test |
193 | $text = str_replace( "variantForm=\"True\"", "data-mjx-alternate=\"1\"", $text ); |
194 | $text = str_replace( "variantForm=\"1\"", "data-mjx-alternate=\"1\"", $text ); |
195 | return str_replace( "texClass", "data-mjx-texclass", $text ); |
196 | } |
197 | |
198 | public function checkAndParseDelimiter( $input, $node, $passedArgs, |
199 | $operatorContent, $noargs = false, $texClass = "" ) { |
200 | if ( $input === null ) { |
201 | return null; |
202 | } |
203 | $resDelimiter = BaseMappings::getDelimiterByKey( trim( $input ) ); |
204 | |
205 | if ( $resDelimiter == null ) { |
206 | $input = MMLutil::inputPreparation( $input ); |
207 | $resDelimiter = AMSMappings::getSymbolDelimiterByKey( $input ); |
208 | if ( $resDelimiter == null ) { |
209 | $resDelimiter = AMSMappings::getMathDelimiterByKey( $input ); |
210 | if ( $resDelimiter == null ) { |
211 | return null; |
212 | } |
213 | } |
214 | } |
215 | if ( is_string( $resDelimiter ) ) { |
216 | $resDelimiter = [ $resDelimiter ]; |
217 | } else { |
218 | if ( isset( $resDelimiter[1] ) && is_array( $resDelimiter[1] ) && !$noargs ) { |
219 | $passedArgs = array_merge( $resDelimiter[1], $passedArgs ); |
220 | } |
221 | } |
222 | |
223 | $mo = new MMLmo( $texClass, $passedArgs ); |
224 | return $mo->encapsulateRaw( $resDelimiter[0] ); |
225 | } |
226 | |
227 | public function checkAndParseMathCharacter( $input, $node, $passedArgs, $operatorContent, $prepareInput = true ) { |
228 | if ( $prepareInput ) { |
229 | $input = MMLutil::inputPreparation( $input ); |
230 | } |
231 | $resChar = BaseMappings::getCharacterByKey( $input ); |
232 | if ( $resChar == null ) { |
233 | return null; |
234 | } |
235 | |
236 | // Maybe move this to the mapping |
237 | $args = [ "mathvariant" => "normal" ]; |
238 | |
239 | $mi = new MMLmi( "", $args ); |
240 | $enc = MMLutil::uc2xNotation( $resChar ); |
241 | return $mi->encapsulateRaw( $enc ); |
242 | } |
243 | |
244 | public function checkAndParseColor( $input, $node, $passedArgs, $operatorContent, $prepareInput = true ) { |
245 | // tbd usually this encapsulates the succeeding box element |
246 | if ( $operatorContent == null ) { |
247 | return null; |
248 | } |
249 | |
250 | if ( $prepareInput ) { |
251 | $input = MMLutil::inputPreparation( $input ); |
252 | } |
253 | if ( !( $input === 'color' || $input === 'pagecolor' ) ) { |
254 | return null; |
255 | } |
256 | |
257 | $resColor = BaseMappings::getColorByKey( $operatorContent ); |
258 | if ( $resColor == null ) { |
259 | return null; |
260 | } |
261 | if ( is_array( $resColor ) ) { |
262 | $resColor = $resColor[0]; // tbd refactor or correct mappings |
263 | } |
264 | |
265 | if ( $input === 'color' ) { |
266 | $mstyle = new MMLmstyle( "", [ "mathcolor" => $resColor ] ); |
267 | return $mstyle->encapsulate(); |
268 | } else { |
269 | // Input is 'pagecolor' |
270 | $mtext = new MMLmtext( "", [ "mathcolor" => $resColor ] ); |
271 | $mrow = new MMLmrow(); |
272 | $mi = new MMLmi(); |
273 | // Mj3 does this, probably not necessary |
274 | $innerRow = ""; |
275 | foreach ( str_split( $operatorContent ) as $char ) { |
276 | $innerRow .= $mi->encapsulateRaw( $char ); |
277 | } |
278 | if ( $innerRow !== "" ) { |
279 | return $mtext->encapsulate( "\\pagecolor" ) . $mrow->encapsulateRaw( $innerRow ); |
280 | } else { |
281 | return $mtext->encapsulate( "\\pagecolor" ); |
282 | } |
283 | } |
284 | } |
285 | |
286 | public static function generateMMLError( $msg ): string { |
287 | return ( new MMLmerror() )->encapsulateRaw( |
288 | ( new MMLmtext() )->encapsulate( $msg ) |
289 | ); |
290 | } |
291 | } |