Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
17.91% covered (danger)
17.91%
12 / 67
54.55% covered (warning)
54.55%
6 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
MMLutil
17.91% covered (danger)
17.91%
12 / 67
54.55% covered (warning)
54.55%
6 / 11
673.47
0.00% covered (danger)
0.00%
0 / 1
 initalParseLiteralExpression
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 uc2xNotation
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 number2xNotation
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 round2em
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 size2em
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 squashLitsToUnit
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 addPreOperator
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
90
 dimen2em
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
30
 createEntity
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 squashLitsToUnitIntent
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
56
 removeDollarEscaping
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2namespace MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util;
3
4use IntlChar;
5use MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ;
6use MediaWiki\Extension\Math\WikiTexVC\Nodes\Literal;
7use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexArray;
8use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexNode;
9
10/**
11 * Utility Methods for parsing Tex to MathML
12 * @author Johannes Stegmüller
13 */
14class 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 "&#x123;", 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    public static function number2xNotation( string $input ): string {
42        return "&#x" . $input . ";";
43    }
44
45    /**
46     * Rounds a floating point input to three digits precision
47     * and returns it as string with succeeding "em".
48     * @param float $size input to be processed
49     * @return string rounded digits with em
50     */
51    public static function round2em( float $size ) {
52        $rounded = round( $size, 3 );
53        return $rounded . "em";
54    }
55
56    /**
57     * In a floating point digit as string, set input to precision of three digits
58     * without rounding.
59     * @param string $size input to be checked
60     * @return string digits of precision three with em
61     */
62    public static function size2em( string $size ): string {
63        return preg_replace( "/(\.\d\d\d).+/", '$1', $size ) . "em";
64    }
65
66    /**
67     * Assumes the input curly contains an TexArray of literals, squashes the TexArray characters to a string.
68     * @param TexArray $node TexArray of literals
69     * @return ?string squashed string in example "2mu", "-3mu" etc. Null if no TexArray inside curly.
70     */
71    public static function squashLitsToUnit( TexArray $node ): ?string {
72        $unit = "";
73        foreach ( $node as $literal ) {
74            if ( !$literal instanceof Literal ) {
75                continue;
76            }
77            $unit .= $literal->getArg();
78        }
79
80        return $unit;
81    }
82
83    /**
84     * em or other dimensional unit gets multiplied by pre-operator.
85     * @param string $size input size i.e-123em
86     * @param string $operator plus (+) or minus (-)
87     * @return string ++ => + , -- => +, -+ => -
88     */
89    public static function addPreOperator( string $size, string $operator ): string {
90        $emtr = trim( $size );
91
92        $ok = preg_match( "/^([+\-])$/", $operator );
93        if ( !$ok ) {
94            return '';
95        }
96        switch ( $emtr[0] ) {
97            case "-":
98                if ( $operator == "+" ) {
99                    return $emtr;
100                } elseif ( $operator == "-" ) {
101                    $emtr[0] = "+";
102                    return $emtr;
103                }
104                break;
105            case "+":
106                if ( $operator == "+" ) {
107                    return $emtr;
108                } elseif ( $operator == "-" ) {
109                    $emtr[0] = "-";
110                    return $emtr;
111                }
112                break;
113            default:
114                return $operator . $emtr;
115        }
116        return $emtr;
117    }
118
119    /**
120     * Convert a length dimension to em format
121     * currently supports "mu: math unit and forwards em"
122     * @param string $dimen input for length dimension  like "-2mu" or "3 em"
123     * @return string|null converted string i.e. "0.333em"  or null if error
124     */
125    public static function dimen2em( string $dimen ): ?string {
126        $matches = [];
127        $matched = preg_match( '/([+-]?)(\d*\.*\d+)\s*(mu|em)/', $dimen, $matches );
128
129        if ( !$matched ) {
130            return null;
131        }
132        if ( $matches[3] == "mu" ) {
133            $ret = self::size2em( strval( intval( $matches[2] ) / 18 ) );
134        } elseif ( $matches[3] == "em" ) {
135            $ret = $matches[2] . "em";
136        } else {
137            return null;
138        }
139
140        return ( $matches[1] == "-" ? "-" : "" ) . $ret;
141    }
142
143    public static function createEntity( string $code ): ?string {
144        return IntlChar::chr( intval( $code, 16 ) );
145    }
146
147    /**
148     * Assumes the input curly contains an TexArray of literals, squashes the TexArray characters to a string.
149     * It checks for dollar escaping and removes a backslash, also renders DQ args with underscores
150     * @param TexNode $node curly containing a TexArray of literals
151     * @return ?string squashed string in example "2mu", "-3mu" etc. Null if no TexArray inside curly.
152     */
153    public static function squashLitsToUnitIntent( TexNode $node ): ?string {
154        if ( !$node->isCurly() ) {
155            return null;
156        }
157        $unit = "";
158        foreach ( $node->getArgs() as $literal ) {
159            if ( $literal instanceof DQ ) {
160                $args = $literal->getArgs();
161                if ( !$args[0] instanceof Literal || !$args[1] instanceof Literal ) {
162                    continue;
163                }
164                $arg = self::removeDollarEscaping( $args[0]->getArgs()[0] ) . "_"
165                    . self::removeDollarEscaping( $args[1]->getArgs()[0] );
166            } else {
167                if ( !$literal instanceof Literal ) {
168                    continue;
169                }
170                $arg = self::removeDollarEscaping( $literal->getArg() );
171            }
172            $unit .= $arg;
173        }
174        return $unit;
175    }
176
177    public static function removeDollarEscaping( string $input ): string {
178        if ( $input == "\\$" ) {
179            return "\$";
180        }
181        return $input;
182    }
183
184}