Diff: STRATO-apps/wordpress_03/app/wp-includes/pomo/plural-forms.php
Keine Baseline-Datei – Diff nur gegen leer.
1
-
1
+
<?php
2
+
3
+
/**
4
+
* A gettext Plural-Forms parser.
5
+
*
6
+
* @since 4.9.0
7
+
*/
8
+
if ( ! class_exists( 'Plural_Forms', false ) ) :
9
+
#[AllowDynamicProperties]
10
+
class Plural_Forms {
11
+
/**
12
+
* Operator characters.
13
+
*
14
+
* @since 4.9.0
15
+
* @var string OP_CHARS Operator characters.
16
+
*/
17
+
const OP_CHARS = '|&><!=%?:';
18
+
19
+
/**
20
+
* Valid number characters.
21
+
*
22
+
* @since 4.9.0
23
+
* @var string NUM_CHARS Valid number characters.
24
+
*/
25
+
const NUM_CHARS = '0123456789';
26
+
27
+
/**
28
+
* Operator precedence.
29
+
*
30
+
* Operator precedence from highest to lowest. Higher numbers indicate
31
+
* higher precedence, and are executed first.
32
+
*
33
+
* @see https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
34
+
*
35
+
* @since 4.9.0
36
+
* @var array $op_precedence Operator precedence from highest to lowest.
37
+
*/
38
+
protected static $op_precedence = array(
39
+
'%' => 6,
40
+
41
+
'<' => 5,
42
+
'<=' => 5,
43
+
'>' => 5,
44
+
'>=' => 5,
45
+
46
+
'==' => 4,
47
+
'!=' => 4,
48
+
49
+
'&&' => 3,
50
+
51
+
'||' => 2,
52
+
53
+
'?:' => 1,
54
+
'?' => 1,
55
+
56
+
'(' => 0,
57
+
')' => 0,
58
+
);
59
+
60
+
/**
61
+
* Tokens generated from the string.
62
+
*
63
+
* @since 4.9.0
64
+
* @var array $tokens List of tokens.
65
+
*/
66
+
protected $tokens = array();
67
+
68
+
/**
69
+
* Cache for repeated calls to the function.
70
+
*
71
+
* @since 4.9.0
72
+
* @var array $cache Map of $n => $result
73
+
*/
74
+
protected $cache = array();
75
+
76
+
/**
77
+
* Constructor.
78
+
*
79
+
* @since 4.9.0
80
+
*
81
+
* @param string $str Plural function (just the bit after `plural=` from Plural-Forms)
82
+
*/
83
+
public function __construct( $str ) {
84
+
$this->parse( $str );
85
+
}
86
+
87
+
/**
88
+
* Parse a Plural-Forms string into tokens.
89
+
*
90
+
* Uses the shunting-yard algorithm to convert the string to Reverse Polish
91
+
* Notation tokens.
92
+
*
93
+
* @since 4.9.0
94
+
*
95
+
* @throws Exception If there is a syntax or parsing error with the string.
96
+
*
97
+
* @param string $str String to parse.
98
+
*/
99
+
protected function parse( $str ) {
100
+
$pos = 0;
101
+
$len = strlen( $str );
102
+
103
+
// Convert infix operators to postfix using the shunting-yard algorithm.
104
+
$output = array();
105
+
$stack = array();
106
+
while ( $pos < $len ) {
107
+
$next = substr( $str, $pos, 1 );
108
+
109
+
switch ( $next ) {
110
+
// Ignore whitespace.
111
+
case ' ':
112
+
case "\t":
113
+
++$pos;
114
+
break;
115
+
116
+
// Variable (n).
117
+
case 'n':
118
+
$output[] = array( 'var' );
119
+
++$pos;
120
+
break;
121
+
122
+
// Parentheses.
123
+
case '(':
124
+
$stack[] = $next;
125
+
++$pos;
126
+
break;
127
+
128
+
case ')':
129
+
$found = false;
130
+
while ( ! empty( $stack ) ) {
131
+
$o2 = $stack[ count( $stack ) - 1 ];
132
+
if ( '(' !== $o2 ) {
133
+
$output[] = array( 'op', array_pop( $stack ) );
134
+
continue;
135
+
}
136
+
137
+
// Discard open paren.
138
+
array_pop( $stack );
139
+
$found = true;
140
+
break;
141
+
}
142
+
143
+
if ( ! $found ) {
144
+
throw new Exception( 'Mismatched parentheses' );
145
+
}
146
+
147
+
++$pos;
148
+
break;
149
+
150
+
// Operators.
151
+
case '|':
152
+
case '&':
153
+
case '>':
154
+
case '<':
155
+
case '!':
156
+
case '=':
157
+
case '%':
158
+
case '?':
159
+
$end_operator = strspn( $str, self::OP_CHARS, $pos );
160
+
$operator = substr( $str, $pos, $end_operator );
161
+
if ( ! array_key_exists( $operator, self::$op_precedence ) ) {
162
+
throw new Exception( sprintf( 'Unknown operator "%s"', $operator ) );
163
+
}
164
+
165
+
while ( ! empty( $stack ) ) {
166
+
$o2 = $stack[ count( $stack ) - 1 ];
167
+
168
+
// Ternary is right-associative in C.
169
+
if ( '?:' === $operator || '?' === $operator ) {
170
+
if ( self::$op_precedence[ $operator ] >= self::$op_precedence[ $o2 ] ) {
171
+
break;
172
+
}
173
+
} elseif ( self::$op_precedence[ $operator ] > self::$op_precedence[ $o2 ] ) {
174
+
break;
175
+
}
176
+
177
+
$output[] = array( 'op', array_pop( $stack ) );
178
+
}
179
+
$stack[] = $operator;
180
+
181
+
$pos += $end_operator;
182
+
break;
183
+
184
+
// Ternary "else".
185
+
case ':':
186
+
$found = false;
187
+
$s_pos = count( $stack ) - 1;
188
+
while ( $s_pos >= 0 ) {
189
+
$o2 = $stack[ $s_pos ];
190
+
if ( '?' !== $o2 ) {
191
+
$output[] = array( 'op', array_pop( $stack ) );
192
+
--$s_pos;
193
+
continue;
194
+
}
195
+
196
+
// Replace.
197
+
$stack[ $s_pos ] = '?:';
198
+
$found = true;
199
+
break;
200
+
}
201
+
202
+
if ( ! $found ) {
203
+
throw new Exception( 'Missing starting "?" ternary operator' );
204
+
}
205
+
++$pos;
206
+
break;
207
+
208
+
// Default - number or invalid.
209
+
default:
210
+
if ( $next >= '0' && $next <= '9' ) {
211
+
$span = strspn( $str, self::NUM_CHARS, $pos );
212
+
$output[] = array( 'value', intval( substr( $str, $pos, $span ) ) );
213
+
$pos += $span;
214
+
break;
215
+
}
216
+
217
+
throw new Exception( sprintf( 'Unknown symbol "%s"', $next ) );
218
+
}
219
+
}
220
+
221
+
while ( ! empty( $stack ) ) {
222
+
$o2 = array_pop( $stack );
223
+
if ( '(' === $o2 || ')' === $o2 ) {
224
+
throw new Exception( 'Mismatched parentheses' );
225
+
}
226
+
227
+
$output[] = array( 'op', $o2 );
228
+
}
229
+
230
+
$this->tokens = $output;
231
+
}
232
+
233
+
/**
234
+
* Get the plural form for a number.
235
+
*
236
+
* Caches the value for repeated calls.
237
+
*
238
+
* @since 4.9.0
239
+
*
240
+
* @param int $num Number to get plural form for.
241
+
* @return int Plural form value.
242
+
*/
243
+
public function get( $num ) {
244
+
if ( isset( $this->cache[ $num ] ) ) {
245
+
return $this->cache[ $num ];
246
+
}
247
+
$this->cache[ $num ] = $this->execute( $num );
248
+
return $this->cache[ $num ];
249
+
}
250
+
251
+
/**
252
+
* Execute the plural form function.
253
+
*
254
+
* @since 4.9.0
255
+
*
256
+
* @throws Exception If the plural form value cannot be calculated.
257
+
*
258
+
* @param int $n Variable "n" to substitute.
259
+
* @return int Plural form value.
260
+
*/
261
+
public function execute( $n ) {
262
+
$stack = array();
263
+
$i = 0;
264
+
$total = count( $this->tokens );
265
+
while ( $i < $total ) {
266
+
$next = $this->tokens[ $i ];
267
+
++$i;
268
+
if ( 'var' === $next[0] ) {
269
+
$stack[] = $n;
270
+
continue;
271
+
} elseif ( 'value' === $next[0] ) {
272
+
$stack[] = $next[1];
273
+
continue;
274
+
}
275
+
276
+
// Only operators left.
277
+
switch ( $next[1] ) {
278
+
case '%':
279
+
$v2 = array_pop( $stack );
280
+
$v1 = array_pop( $stack );
281
+
$stack[] = $v1 % $v2;
282
+
break;
283
+
284
+
case '||':
285
+
$v2 = array_pop( $stack );
286
+
$v1 = array_pop( $stack );
287
+
$stack[] = $v1 || $v2;
288
+
break;
289
+
290
+
case '&&':
291
+
$v2 = array_pop( $stack );
292
+
$v1 = array_pop( $stack );
293
+
$stack[] = $v1 && $v2;
294
+
break;
295
+
296
+
case '<':
297
+
$v2 = array_pop( $stack );
298
+
$v1 = array_pop( $stack );
299
+
$stack[] = $v1 < $v2;
300
+
break;
301
+
302
+
case '<=':
303
+
$v2 = array_pop( $stack );
304
+
$v1 = array_pop( $stack );
305
+
$stack[] = $v1 <= $v2;
306
+
break;
307
+
308
+
case '>':
309
+
$v2 = array_pop( $stack );
310
+
$v1 = array_pop( $stack );
311
+
$stack[] = $v1 > $v2;
312
+
break;
313
+
314
+
case '>=':
315
+
$v2 = array_pop( $stack );
316
+
$v1 = array_pop( $stack );
317
+
$stack[] = $v1 >= $v2;
318
+
break;
319
+
320
+
case '!=':
321
+
$v2 = array_pop( $stack );
322
+
$v1 = array_pop( $stack );
323
+
$stack[] = $v1 !== $v2;
324
+
break;
325
+
326
+
case '==':
327
+
$v2 = array_pop( $stack );
328
+
$v1 = array_pop( $stack );
329
+
$stack[] = $v1 === $v2;
330
+
break;
331
+
332
+
case '?:':
333
+
$v3 = array_pop( $stack );
334
+
$v2 = array_pop( $stack );
335
+
$v1 = array_pop( $stack );
336
+
$stack[] = $v1 ? $v2 : $v3;
337
+
break;
338
+
339
+
default:
340
+
throw new Exception( sprintf( 'Unknown operator "%s"', $next[1] ) );
341
+
}
342
+
}
343
+
344
+
if ( count( $stack ) !== 1 ) {
345
+
throw new Exception( 'Too many values remaining on the stack' );
346
+
}
347
+
348
+
return (int) $stack[0];
349
+
}
350
+
}
351
+
endif;
352
+