Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
74.70% |
62 / 83 |
|
58.33% |
7 / 12 |
CRAP | |
0.00% |
0 / 1 |
Literal | |
74.70% |
62 / 83 |
|
58.33% |
7 / 12 |
56.99 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
changeUnicodeFontInput | |
55.56% |
5 / 9 |
|
0.00% |
0 / 1 |
7.19 | |||
renderMML | |
70.83% |
34 / 48 |
|
0.00% |
0 / 1 |
26.04 | |||
getArg | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setArg | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getLiterals | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getExtendedLiterals | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
extractIdentifiers | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
extractSubscripts | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getModIdent | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
getLiteral | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
3.04 | |||
createVlineElement | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | declare( strict_types = 1 ); |
4 | |
5 | namespace MediaWiki\Extension\Math\WikiTexVC\Nodes; |
6 | |
7 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\BaseMethods; |
8 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLParsingUtil; |
9 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLutil; |
10 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmi; |
11 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmn; |
12 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmo; |
13 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmpadded; |
14 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmrow; |
15 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmstyle; |
16 | use MediaWiki\Extension\Math\WikiTexVC\TexUtil; |
17 | |
18 | class Literal extends TexNode { |
19 | |
20 | /** @var string */ |
21 | private $arg; |
22 | /** @var string[] */ |
23 | private $literals; |
24 | /** @var string[] */ |
25 | private $extendedLiterals; |
26 | |
27 | public function __construct( string $arg ) { |
28 | parent::__construct( $arg ); |
29 | $this->arg = $arg; |
30 | $this->literals = array_keys( TexUtil::getInstance()->getBaseElements()['is_literal'] ); |
31 | $this->extendedLiterals = $this->literals; |
32 | array_push( $this->extendedLiterals, '\\infty', '\\emptyset' ); |
33 | } |
34 | |
35 | public function changeUnicodeFontInput( string $input, array &$state ): string { |
36 | /** |
37 | * In some font modifications, it is required to explicitly use Unicode |
38 | * characters instead of (only) attributes in MathML to indicate the font. |
39 | * This is mostly because of Chrome behaviour. See: https://phabricator.wikimedia.org/T352196 |
40 | */ |
41 | if ( isset( $state["double-struck-literals"] ) ) { |
42 | return MMLParsingUtil::mapToDoubleStruckUnicode( $input ); |
43 | } elseif ( isset( $state["calligraphic"] ) ) { |
44 | return MMLParsingUtil::mapToCaligraphicUnicode( $input ); |
45 | } elseif ( isset( $state["fraktur"] ) ) { |
46 | return MMLParsingUtil::mapToFrakturUnicode( $input ); |
47 | } elseif ( isset( $state["bold"] ) ) { |
48 | return MMLParsingUtil::mapToBoldUnicode( $input ); |
49 | } |
50 | return $input; |
51 | } |
52 | |
53 | /** @inheritDoc */ |
54 | public function renderMML( $arguments = [], &$state = [] ) { |
55 | if ( isset( $state["intent-params"] ) ) { |
56 | foreach ( $state["intent-params"] as $intparam ) { |
57 | if ( $intparam == $this->arg ) { |
58 | $arguments["arg"] = $intparam; |
59 | } |
60 | } |
61 | } |
62 | |
63 | if ( isset( $state["intent-params-expl"] ) ) { |
64 | $arguments["arg"] = $state["intent-params-expl"]; |
65 | } |
66 | |
67 | if ( $this->arg === " " ) { |
68 | // Fixes https://gerrit.wikimedia.org/r/c/mediawiki/extensions/Math/+/961711 |
69 | // And they creation of empty mo elements. |
70 | return ""; |
71 | } |
72 | |
73 | if ( is_numeric( $this->arg ) ) { |
74 | $mn = new MMLmn( "", $arguments ); |
75 | return $mn->encapsulateRaw( $this->changeUnicodeFontInput( $this->arg, $state ) ); |
76 | } |
77 | // is important to split and find chars within curly and differentiate, see tc 459 |
78 | $foundOperatorContent = MMLutil::initalParseLiteralExpression( $this->arg ); |
79 | if ( !$foundOperatorContent ) { |
80 | $input = $this->arg; |
81 | $operatorContent = null; |
82 | } else { |
83 | $input = $foundOperatorContent[1][0]; |
84 | $operatorContent = [ "foundOC" => $foundOperatorContent[2][0] ]; |
85 | } |
86 | |
87 | // This is rather a workaround: |
88 | // Sometimes literals from WikiTexVC contain complete \\operatorname {asd} hinted as bug tex-2-mml.json |
89 | if ( str_contains( $input, "\\operatorname" ) ) { |
90 | $mi = new MMLmi(); |
91 | return $mi->encapsulateRaw( $operatorContent["foundOC"] ); |
92 | } |
93 | |
94 | $inputP = $input; |
95 | |
96 | // Sieve for Operators |
97 | $bm = new BaseMethods(); |
98 | $noStretchArgs = $arguments; |
99 | // Delimiters and operators should not be stretchy by default when used as literals |
100 | $noStretchArgs['stretchy'] ??= 'false'; |
101 | $ret = $bm->checkAndParseOperator( $inputP, $this, $noStretchArgs, $operatorContent, $state, false ); |
102 | if ( $ret ) { |
103 | return $ret; |
104 | } |
105 | // Sieve for mathchar07 chars |
106 | $bm = new BaseMethods(); |
107 | $ret = $bm->checkAndParseMathCharacter( $inputP, $this, $arguments, $operatorContent, false ); |
108 | if ( $ret ) { |
109 | return $ret; |
110 | } |
111 | |
112 | // Sieve for Identifiers |
113 | $ret = $bm->checkAndParseIdentifier( $inputP, $this, $arguments, $operatorContent, false ); |
114 | if ( $ret ) { |
115 | return $ret; |
116 | } |
117 | // Sieve for Delimiters |
118 | $ret = $bm->checkAndParseDelimiter( $input, $this, $noStretchArgs, $operatorContent ); |
119 | if ( $ret ) { |
120 | return $ret; |
121 | } |
122 | |
123 | // Sieve for Makros |
124 | $ret = BaseMethods::checkAndParse( $inputP, $arguments, |
125 | array_merge( $operatorContent ?? [], $state ?? [] ), |
126 | $this, false ); |
127 | if ( $ret || $ret === '' ) { |
128 | return $ret; |
129 | } |
130 | |
131 | // Specific |
132 | if ( !( empty( $state['inMatrix'] ) ) && trim( $this->arg ) === '\vline' ) { |
133 | return $this->createVlineElement(); |
134 | } |
135 | |
136 | if ( !( empty( $state['inHBox'] ) ) ) { |
137 | // No mi, if literal is from HBox |
138 | return $input; |
139 | } |
140 | |
141 | // If falling through all sieves just create an MI element |
142 | $mi = new MMLmi( "", $arguments ); |
143 | return $mi->encapsulateRaw( $this->changeUnicodeFontInput( $input, $state ) ); // $this->arg |
144 | } |
145 | |
146 | /** |
147 | * @return string |
148 | */ |
149 | public function getArg(): string { |
150 | return $this->arg; |
151 | } |
152 | |
153 | public function setArg( string $arg ) { |
154 | $this->arg = $arg; |
155 | } |
156 | |
157 | /** |
158 | * @return int[]|string[] |
159 | */ |
160 | public function getLiterals(): array { |
161 | return $this->literals; |
162 | } |
163 | |
164 | /** |
165 | * @return int[]|string[] |
166 | */ |
167 | public function getExtendedLiterals(): array { |
168 | return $this->extendedLiterals; |
169 | } |
170 | |
171 | /** @inheritDoc */ |
172 | public function extractIdentifiers( $args = null ) { |
173 | return $this->getLiteral( $this->literals, '/^([a-zA-Z\']|\\\\int)$/' ); |
174 | } |
175 | |
176 | /** @inheritDoc */ |
177 | public function extractSubscripts() { |
178 | return $this->getLiteral( $this->extendedLiterals, '/^([0-9a-zA-Z+\',-])$/' ); |
179 | } |
180 | |
181 | /** @inheritDoc */ |
182 | public function getModIdent() { |
183 | if ( $this->arg === '\\ ' ) { |
184 | return [ '\\ ' ]; |
185 | } |
186 | return $this->getLiteral( $this->literals, '/^([0-9a-zA-Z\'])$/' ); |
187 | } |
188 | |
189 | private function getLiteral( array $lit, string $regexp ): array { |
190 | $s = trim( $this->arg ); |
191 | if ( preg_match( $regexp, $s ) == 1 ) { |
192 | return [ $s ]; |
193 | } elseif ( in_array( $s, $lit, true ) ) { |
194 | return [ $s ]; |
195 | } else { |
196 | return []; |
197 | } |
198 | } |
199 | |
200 | /** |
201 | * @return string |
202 | */ |
203 | public function createVlineElement(): string { |
204 | $mrow = new MMLmrow(); |
205 | $mpAdded = new MMLmpadded( "", [ "depth" => "0", "height" => "0" ] ); |
206 | $mStyle = new MMLmstyle( "", [ "mathsize" => "1.2em" ] ); |
207 | $mo = new MMLmo( "", [ "fence" => "false", "stretchy" => "false" ] ); |
208 | return $mrow->encapsulateRaw( $mpAdded->encapsulateRaw( |
209 | $mStyle->encapsulateRaw( $mo->encapsulateRaw( "|" ) ) ) ); |
210 | } |
211 | |
212 | } |