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