Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 23 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
Operator | |
0.00% |
0 / 23 |
|
0.00% |
0 / 2 |
30 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
operate | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | /** |
3 | * @author Niklas Laxström, Tim Starling |
4 | * @license GPL-2.0-or-later |
5 | * @file |
6 | */ |
7 | |
8 | namespace CLDRPluralRuleParser\Converter; |
9 | |
10 | use CLDRPluralRuleParser\Converter; |
11 | |
12 | /** |
13 | * Helper for Converter. |
14 | * An operator object, representing a region of the input string (for error |
15 | * messages), and the binary operator at that location. |
16 | */ |
17 | class Operator extends Fragment { |
18 | /** @var string The name */ |
19 | public $name; |
20 | |
21 | /** |
22 | * Each op type has three characters: left operand type, right operand type and result type |
23 | * |
24 | * b = boolean |
25 | * n = number |
26 | * r = range |
27 | * |
28 | * A number is a kind of range. |
29 | * |
30 | * @var array |
31 | */ |
32 | private const OP_TYPES = [ |
33 | 'or' => 'bbb', |
34 | 'and' => 'bbb', |
35 | 'is' => 'nnb', |
36 | 'is-not' => 'nnb', |
37 | 'in' => 'nrb', |
38 | 'not-in' => 'nrb', |
39 | 'within' => 'nrb', |
40 | 'not-within' => 'nrb', |
41 | 'mod' => 'nnn', |
42 | ',' => 'rrr', |
43 | '..' => 'nnr', |
44 | ]; |
45 | |
46 | /** |
47 | * Map converting from the abbreviation to the full form. |
48 | * |
49 | * @var array |
50 | */ |
51 | private const TYPE_SPEC_MAP = [ |
52 | 'b' => 'boolean', |
53 | 'n' => 'number', |
54 | 'r' => 'range', |
55 | ]; |
56 | |
57 | /** |
58 | * Map for converting the new operators introduced in Rev 33 to the old forms |
59 | * |
60 | * @var array |
61 | */ |
62 | private const ALIAS_MAP = [ |
63 | '%' => 'mod', |
64 | '!=' => 'not-in', |
65 | '=' => 'in' |
66 | ]; |
67 | |
68 | /** |
69 | * Initialize a new instance of a CLDRPluralRuleConverterOperator object |
70 | * |
71 | * @param Converter $parser The parser |
72 | * @param string $name The operator name |
73 | * @param int $pos The length |
74 | * @param int $length |
75 | */ |
76 | public function __construct( Converter $parser, $name, $pos, $length ) { |
77 | parent::__construct( $parser, $pos, $length ); |
78 | if ( isset( self::ALIAS_MAP[$name] ) ) { |
79 | $name = self::ALIAS_MAP[$name]; |
80 | } |
81 | $this->name = $name; |
82 | } |
83 | |
84 | /** |
85 | * Compute the operation |
86 | * |
87 | * @param Expression $left The left part of the expression |
88 | * @param Expression $right The right part of the expression |
89 | * @return Expression The result of the operation |
90 | */ |
91 | public function operate( Expression $left, Expression $right ): Expression { |
92 | $typeSpec = self::OP_TYPES[$this->name]; |
93 | |
94 | $leftType = self::TYPE_SPEC_MAP[$typeSpec[0]]; |
95 | $rightType = self::TYPE_SPEC_MAP[$typeSpec[1]]; |
96 | $resultType = self::TYPE_SPEC_MAP[$typeSpec[2]]; |
97 | |
98 | $start = min( $this->pos, $left->pos, $right->pos ); |
99 | $end = max( $this->end, $left->end, $right->end ); |
100 | $length = $end - $start; |
101 | |
102 | $newExpr = new Expression( |
103 | $this->parser, |
104 | $resultType, |
105 | "{$left->rpn} {$right->rpn} {$this->name}", |
106 | $start, |
107 | $length |
108 | ); |
109 | |
110 | if ( !$left->isType( $leftType ) ) { |
111 | $newExpr->error( "invalid type for left operand: expected $leftType, got {$left->type}" ); |
112 | } |
113 | |
114 | if ( !$right->isType( $rightType ) ) { |
115 | $newExpr->error( "invalid type for right operand: expected $rightType, got {$right->type}" ); |
116 | } |
117 | |
118 | return $newExpr; |
119 | } |
120 | } |