Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 90 |
|
0.00% |
0 / 15 |
CRAP | |
0.00% |
0 / 1 |
MMLutil | |
0.00% |
0 / 90 |
|
0.00% |
0 / 15 |
2256 | |
0.00% |
0 / 1 |
initalParseLiteralExpression | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
uc2xNotation | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
x2uNotation | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
number2xNotation | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
round2em | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
size2em | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
squashLitsToUnit | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
addPreOperator | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
90 | |||
dimen2em | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
30 | |||
inputPreparation | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
30 | |||
createEntity | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getMappingByKey | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
getMappingByKeySimple | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
squashLitsToUnitIntent | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
56 | |||
removeDollarEscaping | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | namespace MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util; |
3 | |
4 | use IntlChar; |
5 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Curly; |
6 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ; |
7 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Literal; |
8 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexNode; |
9 | |
10 | /** |
11 | * Utility Methods for parsing Tex to MathML |
12 | * @author Johannes Stegmüller |
13 | */ |
14 | class MMLutil { |
15 | /** |
16 | * Splits a regular expression in the form '\operatorname {someparams} |
17 | * Also recognizes succeeding parentheses '\operatorname (' as params |
18 | * @param string $input tex expression |
19 | * @return array|null found groups or null |
20 | */ |
21 | public static function initalParseLiteralExpression( $input ): ?array { |
22 | $pattern = "/([\\a-zA-Z\s]+)\{([^}]+)\}/"; |
23 | $matches = []; |
24 | $matched = preg_match_all( $pattern, $input, $matches ); |
25 | return $matched ? $matches : null; |
26 | } |
27 | |
28 | /** |
29 | * Recognize if input is a unicode string "\\u1235" |
30 | * If yes converts it to notation "ģ", if no just returns the input. |
31 | * @param string $input input to be checked |
32 | * @return string modified input or input |
33 | */ |
34 | public static function uc2xNotation( string $input ): string { |
35 | if ( str_starts_with( $input, "\\u" ) ) { |
36 | return str_replace( "\\u", "&#x", $input ) . ";"; |
37 | } |
38 | return $input; |
39 | } |
40 | |
41 | /** |
42 | * If an input string is in "..:" notation |
43 | * then convert it to a string of notation \\u12.. |
44 | * @param string $input input to be checked |
45 | * @return string modified input or input |
46 | */ |
47 | public static function x2uNotation( string $input ): string { |
48 | if ( str_starts_with( $input, "&#x" ) ) { |
49 | return rtrim( str_replace( "&#x", "\\u", $input ), ";" ); |
50 | } |
51 | return $input; |
52 | } |
53 | |
54 | public static function number2xNotation( $input ): string { |
55 | return "&#x" . $input . ";"; |
56 | } |
57 | |
58 | /** |
59 | * Rounds a floating point input to three digits precision |
60 | * and returns it as string with succeeding "em". |
61 | * @param float $size input to be processed |
62 | * @return string rounded digits with em |
63 | */ |
64 | public static function round2em( float $size ) { |
65 | $rounded = round( $size, 3 ); |
66 | return $rounded . "em"; |
67 | } |
68 | |
69 | /** |
70 | * In a floating point digit as string, set input to precision of three digits |
71 | * without rounding. |
72 | * @param string $size input to be checked |
73 | * @return string digits of precision three with em |
74 | */ |
75 | public static function size2em( string $size ): string { |
76 | return preg_replace( "/(\.\d\d\d).+/", '$1', $size ) . "em"; |
77 | } |
78 | |
79 | /** |
80 | * Assumes the input curly contains an TexArray of literals, squashes the TexArray characters to a string. |
81 | * @param Curly $node curly containing a TexArray of literals |
82 | * @return ?string squashed string in example "2mu", "-3mu" etc. Null if no TexArray inside curly. |
83 | */ |
84 | public static function squashLitsToUnit( Curly $node ): ?string { |
85 | $unit = ""; |
86 | foreach ( $node->getArg()->getArgs() as $literal ) { |
87 | if ( !$literal instanceof Literal ) { |
88 | continue; |
89 | } |
90 | $unit .= $literal->getArg(); |
91 | } |
92 | |
93 | return $unit; |
94 | } |
95 | |
96 | /** |
97 | * em or other dimensional unit gets multiplied by pre-operator. |
98 | * @param string $size input size i.e-123em |
99 | * @param string $operator "plus (+) or minus (-) |
100 | * @return string ++ => + , -- => +, -+ => - |
101 | */ |
102 | public static function addPreOperator( string $size, string $operator ): string { |
103 | $emtr = trim( $size ); |
104 | |
105 | $ok = preg_match( "/^([+\-])$/", $operator ); |
106 | if ( !$ok ) { |
107 | return ''; |
108 | } |
109 | switch ( $emtr[0] ) { |
110 | case "-": |
111 | if ( $operator == "+" ) { |
112 | return $emtr; |
113 | } elseif ( $operator == "-" ) { |
114 | $emtr[0] = "+"; |
115 | return $emtr; |
116 | } |
117 | break; |
118 | case "+": |
119 | if ( $operator == "+" ) { |
120 | return $emtr; |
121 | } elseif ( $operator == "-" ) { |
122 | $emtr[0] = "-"; |
123 | return $emtr; |
124 | } |
125 | break; |
126 | default: |
127 | return $operator . $emtr; |
128 | } |
129 | return $emtr; |
130 | } |
131 | |
132 | /** |
133 | * Convert a length dimension to em format |
134 | * currently supports "mu: math unit and forwards em" |
135 | * @param string $dimen input for length dimension like "-2mu" or "3 em" |
136 | * @return string|null converted string i.e. "0.333em" or null if error |
137 | */ |
138 | public static function dimen2em( string $dimen ): ?string { |
139 | $matches = []; |
140 | $matched = preg_match( '/([+-]?)(\d*\.*\d+)\s*(mu|em)/', $dimen, $matches ); |
141 | |
142 | if ( !$matched ) { |
143 | return null; |
144 | } |
145 | if ( $matches[3] == "mu" ) { |
146 | $ret = self::size2em( strval( intval( $matches[2] ) / 18 ) ); |
147 | } elseif ( $matches[3] == "em" ) { |
148 | $ret = $matches[2] . "em"; |
149 | } else { |
150 | return null; |
151 | } |
152 | |
153 | return ( $matches[1] == "-" ? "-" : "" ) . $ret; |
154 | } |
155 | |
156 | /** |
157 | * Some common steps of processing an input string before passing it as a key to the mappings. |
158 | * @param string $input string to be processed |
159 | * @return string prepared input string |
160 | */ |
161 | public static function inputPreparation( $input ): string { |
162 | if ( $input === null ) { |
163 | return ""; |
164 | } |
165 | $input = trim( $input ); |
166 | if ( str_starts_with( $input, "\\" ) && strlen( $input ) >= 2 ) { |
167 | $input = substr( $input, 1 ); |
168 | // These are edge cases where input can be a Literal OR an Operator |
169 | $edgeCases = [ "S", "P", ";", ",", "!", "'", ">" ]; |
170 | if ( in_array( $input, $edgeCases, true ) ) { |
171 | $input = "\\" . $input; |
172 | } |
173 | } |
174 | return $input; |
175 | } |
176 | |
177 | public static function createEntity( $code ): ?string { |
178 | return IntlChar::chr( intval( $code, 16 ) ); |
179 | } |
180 | |
181 | /** |
182 | * From a defined mapping table get the value by key. |
183 | * Do some optional common conversion steps for the values. |
184 | * @param string $key key to find entry in table |
185 | * @param array $mappingTable table which the value is found by key |
186 | * @param bool $convertUc2X convert first value of the found entry in array to specific "ģ" notation |
187 | * @return mixed|string[]|null the found entry in the table |
188 | */ |
189 | public static function getMappingByKey( string $key, array $mappingTable, bool $convertUc2X = false ) { |
190 | if ( isset( $mappingTable[$key] ) ) { |
191 | $found = $mappingTable[$key]; |
192 | if ( is_string( $found ) ) { |
193 | $found = [ $found ]; |
194 | } |
195 | if ( $convertUc2X ) { |
196 | $found[0] = self::uc2xNotation( $found[0] ); |
197 | } |
198 | return $found; |
199 | } |
200 | return null; |
201 | } |
202 | |
203 | /** |
204 | * From a defined mapping table get the value by key. |
205 | * @param string $key key to find entry in table |
206 | * @param array $mappingTable table which the value is found by key |
207 | * @return mixed|string[]|null the found entry in the table |
208 | */ |
209 | public static function getMappingByKeySimple( string $key, array $mappingTable ) { |
210 | if ( isset( $mappingTable[$key] ) ) { |
211 | return $mappingTable[$key]; |
212 | } |
213 | return null; |
214 | } |
215 | |
216 | /** |
217 | * Assumes the input curly contains an TexArray of literals, squashes the TexArray characters to a string. |
218 | * It checks for dollar escaping and removes a backslash, also renders DQ args with underscores |
219 | * @param TexNode $node curly containing a TexArray of literals |
220 | * @return ?string squashed string in example "2mu", "-3mu" etc. Null if no TexArray inside curly. |
221 | */ |
222 | public static function squashLitsToUnitIntent( TexNode $node ): ?string { |
223 | if ( !$node instanceof Curly ) { |
224 | return null; |
225 | } |
226 | $unit = ""; |
227 | foreach ( $node->getArg()->getArgs() as $literal ) { |
228 | if ( $literal instanceof DQ ) { |
229 | $args = $literal->getArgs(); |
230 | if ( !$args[0] instanceof Literal || !$args[1] instanceof Literal ) { |
231 | continue; |
232 | } |
233 | $arg = self::removeDollarEscaping( $args[0]->getArgs()[0] ) . "_" |
234 | . self::removeDollarEscaping( $args[1]->getArgs()[0] ); |
235 | } else { |
236 | if ( !$literal instanceof Literal ) { |
237 | continue; |
238 | } |
239 | $arg = self::removeDollarEscaping( $literal->getArg() ); |
240 | } |
241 | $unit .= $arg; |
242 | } |
243 | return $unit; |
244 | } |
245 | |
246 | public static function removeDollarEscaping( $input ) { |
247 | if ( $input == "\\$" ) { |
248 | return "\$"; |
249 | } |
250 | return $input; |
251 | } |
252 | |
253 | } |