wp/wp-includes/pomo/plural-forms.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 21 48c4eec2b7e6
--- a/wp/wp-includes/pomo/plural-forms.php	Tue Dec 15 15:52:01 2020 +0100
+++ b/wp/wp-includes/pomo/plural-forms.php	Wed Sep 21 18:19:35 2022 +0200
@@ -5,340 +5,346 @@
  *
  * @since 4.9.0
  */
-class Plural_Forms {
-	/**
-	 * Operator characters.
-	 *
-	 * @since 4.9.0
-	 * @var string OP_CHARS Operator characters.
-	 */
-	const OP_CHARS = '|&><!=%?:';
-
-	/**
-	 * Valid number characters.
-	 *
-	 * @since 4.9.0
-	 * @var string NUM_CHARS Valid number characters.
-	 */
-	const NUM_CHARS = '0123456789';
+if ( ! class_exists( 'Plural_Forms', false ) ) :
+	class Plural_Forms {
+		/**
+		 * Operator characters.
+		 *
+		 * @since 4.9.0
+		 * @var string OP_CHARS Operator characters.
+		 */
+		const OP_CHARS = '|&><!=%?:';
 
-	/**
-	 * Operator precedence.
-	 *
-	 * Operator precedence from highest to lowest. Higher numbers indicate
-	 * higher precedence, and are executed first.
-	 *
-	 * @see https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
-	 *
-	 * @since 4.9.0
-	 * @var array $op_precedence Operator precedence from highest to lowest.
-	 */
-	protected static $op_precedence = array(
-		'%'  => 6,
-
-		'<'  => 5,
-		'<=' => 5,
-		'>'  => 5,
-		'>=' => 5,
+		/**
+		 * Valid number characters.
+		 *
+		 * @since 4.9.0
+		 * @var string NUM_CHARS Valid number characters.
+		 */
+		const NUM_CHARS = '0123456789';
 
-		'==' => 4,
-		'!=' => 4,
-
-		'&&' => 3,
-
-		'||' => 2,
+		/**
+		 * Operator precedence.
+		 *
+		 * Operator precedence from highest to lowest. Higher numbers indicate
+		 * higher precedence, and are executed first.
+		 *
+		 * @see https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
+		 *
+		 * @since 4.9.0
+		 * @var array $op_precedence Operator precedence from highest to lowest.
+		 */
+		protected static $op_precedence = array(
+			'%'  => 6,
 
-		'?:' => 1,
-		'?'  => 1,
-
-		'('  => 0,
-		')'  => 0,
-	);
+			'<'  => 5,
+			'<=' => 5,
+			'>'  => 5,
+			'>=' => 5,
 
-	/**
-	 * Tokens generated from the string.
-	 *
-	 * @since 4.9.0
-	 * @var array $tokens List of tokens.
-	 */
-	protected $tokens = array();
+			'==' => 4,
+			'!=' => 4,
+
+			'&&' => 3,
+
+			'||' => 2,
+
+			'?:' => 1,
+			'?'  => 1,
 
-	/**
-	 * Cache for repeated calls to the function.
-	 *
-	 * @since 4.9.0
-	 * @var array $cache Map of $n => $result
-	 */
-	protected $cache = array();
+			'('  => 0,
+			')'  => 0,
+		);
 
-	/**
-	 * Constructor.
-	 *
-	 * @since 4.9.0
-	 *
-	 * @param string $str Plural function (just the bit after `plural=` from Plural-Forms)
-	 */
-	public function __construct( $str ) {
-		$this->parse( $str );
-	}
+		/**
+		 * Tokens generated from the string.
+		 *
+		 * @since 4.9.0
+		 * @var array $tokens List of tokens.
+		 */
+		protected $tokens = array();
 
-	/**
-	 * Parse a Plural-Forms string into tokens.
-	 *
-	 * Uses the shunting-yard algorithm to convert the string to Reverse Polish
-	 * Notation tokens.
-	 *
-	 * @since 4.9.0
-	 *
-	 * @param string $str String to parse.
-	 */
-	protected function parse( $str ) {
-		$pos = 0;
-		$len = strlen( $str );
+		/**
+		 * Cache for repeated calls to the function.
+		 *
+		 * @since 4.9.0
+		 * @var array $cache Map of $n => $result
+		 */
+		protected $cache = array();
 
-		// Convert infix operators to postfix using the shunting-yard algorithm.
-		$output = array();
-		$stack  = array();
-		while ( $pos < $len ) {
-			$next = substr( $str, $pos, 1 );
+		/**
+		 * Constructor.
+		 *
+		 * @since 4.9.0
+		 *
+		 * @param string $str Plural function (just the bit after `plural=` from Plural-Forms)
+		 */
+		public function __construct( $str ) {
+			$this->parse( $str );
+		}
 
-			switch ( $next ) {
-				// Ignore whitespace.
-				case ' ':
-				case "\t":
-					$pos++;
-					break;
-
-				// Variable (n).
-				case 'n':
-					$output[] = array( 'var' );
-					$pos++;
-					break;
-
-				// Parentheses.
-				case '(':
-					$stack[] = $next;
-					$pos++;
-					break;
+		/**
+		 * Parse a Plural-Forms string into tokens.
+		 *
+		 * Uses the shunting-yard algorithm to convert the string to Reverse Polish
+		 * Notation tokens.
+		 *
+		 * @since 4.9.0
+		 *
+		 * @throws Exception If there is a syntax or parsing error with the string.
+		 *
+		 * @param string $str String to parse.
+		 */
+		protected function parse( $str ) {
+			$pos = 0;
+			$len = strlen( $str );
 
-				case ')':
-					$found = false;
-					while ( ! empty( $stack ) ) {
-						$o2 = $stack[ count( $stack ) - 1 ];
-						if ( '(' !== $o2 ) {
-							$output[] = array( 'op', array_pop( $stack ) );
-							continue;
-						}
+			// Convert infix operators to postfix using the shunting-yard algorithm.
+			$output = array();
+			$stack  = array();
+			while ( $pos < $len ) {
+				$next = substr( $str, $pos, 1 );
 
-						// Discard open paren.
-						array_pop( $stack );
-						$found = true;
+				switch ( $next ) {
+					// Ignore whitespace.
+					case ' ':
+					case "\t":
+						$pos++;
 						break;
-					}
 
-					if ( ! $found ) {
-						throw new Exception( 'Mismatched parentheses' );
-					}
-
-					$pos++;
-					break;
+					// Variable (n).
+					case 'n':
+						$output[] = array( 'var' );
+						$pos++;
+						break;
 
-				// Operators.
-				case '|':
-				case '&':
-				case '>':
-				case '<':
-				case '!':
-				case '=':
-				case '%':
-				case '?':
-					$end_operator = strspn( $str, self::OP_CHARS, $pos );
-					$operator     = substr( $str, $pos, $end_operator );
-					if ( ! array_key_exists( $operator, self::$op_precedence ) ) {
-						throw new Exception( sprintf( 'Unknown operator "%s"', $operator ) );
-					}
+					// Parentheses.
+					case '(':
+						$stack[] = $next;
+						$pos++;
+						break;
 
-					while ( ! empty( $stack ) ) {
-						$o2 = $stack[ count( $stack ) - 1 ];
+					case ')':
+						$found = false;
+						while ( ! empty( $stack ) ) {
+							$o2 = $stack[ count( $stack ) - 1 ];
+							if ( '(' !== $o2 ) {
+								$output[] = array( 'op', array_pop( $stack ) );
+								continue;
+							}
 
-						// Ternary is right-associative in C.
-						if ( '?:' === $operator || '?' === $operator ) {
-							if ( self::$op_precedence[ $operator ] >= self::$op_precedence[ $o2 ] ) {
-								break;
-							}
-						} elseif ( self::$op_precedence[ $operator ] > self::$op_precedence[ $o2 ] ) {
+							// Discard open paren.
+							array_pop( $stack );
+							$found = true;
 							break;
 						}
 
-						$output[] = array( 'op', array_pop( $stack ) );
-					}
-					$stack[] = $operator;
+						if ( ! $found ) {
+							throw new Exception( 'Mismatched parentheses' );
+						}
 
-					$pos += $end_operator;
-					break;
+						$pos++;
+						break;
 
-				// Ternary "else".
-				case ':':
-					$found = false;
-					$s_pos = count( $stack ) - 1;
-					while ( $s_pos >= 0 ) {
-						$o2 = $stack[ $s_pos ];
-						if ( '?' !== $o2 ) {
-							$output[] = array( 'op', array_pop( $stack ) );
-							$s_pos--;
-							continue;
+					// Operators.
+					case '|':
+					case '&':
+					case '>':
+					case '<':
+					case '!':
+					case '=':
+					case '%':
+					case '?':
+						$end_operator = strspn( $str, self::OP_CHARS, $pos );
+						$operator     = substr( $str, $pos, $end_operator );
+						if ( ! array_key_exists( $operator, self::$op_precedence ) ) {
+							throw new Exception( sprintf( 'Unknown operator "%s"', $operator ) );
 						}
 
-						// Replace.
-						$stack[ $s_pos ] = '?:';
-						$found           = true;
-						break;
-					}
+						while ( ! empty( $stack ) ) {
+							$o2 = $stack[ count( $stack ) - 1 ];
+
+							// Ternary is right-associative in C.
+							if ( '?:' === $operator || '?' === $operator ) {
+								if ( self::$op_precedence[ $operator ] >= self::$op_precedence[ $o2 ] ) {
+									break;
+								}
+							} elseif ( self::$op_precedence[ $operator ] > self::$op_precedence[ $o2 ] ) {
+								break;
+							}
 
-					if ( ! $found ) {
-						throw new Exception( 'Missing starting "?" ternary operator' );
-					}
-					$pos++;
-					break;
+							$output[] = array( 'op', array_pop( $stack ) );
+						}
+						$stack[] = $operator;
+
+						$pos += $end_operator;
+						break;
+
+					// Ternary "else".
+					case ':':
+						$found = false;
+						$s_pos = count( $stack ) - 1;
+						while ( $s_pos >= 0 ) {
+							$o2 = $stack[ $s_pos ];
+							if ( '?' !== $o2 ) {
+								$output[] = array( 'op', array_pop( $stack ) );
+								$s_pos--;
+								continue;
+							}
 
-				// Default - number or invalid.
-				default:
-					if ( $next >= '0' && $next <= '9' ) {
-						$span     = strspn( $str, self::NUM_CHARS, $pos );
-						$output[] = array( 'value', intval( substr( $str, $pos, $span ) ) );
-						$pos     += $span;
+							// Replace.
+							$stack[ $s_pos ] = '?:';
+							$found           = true;
+							break;
+						}
+
+						if ( ! $found ) {
+							throw new Exception( 'Missing starting "?" ternary operator' );
+						}
+						$pos++;
 						break;
-					}
+
+					// Default - number or invalid.
+					default:
+						if ( $next >= '0' && $next <= '9' ) {
+							$span     = strspn( $str, self::NUM_CHARS, $pos );
+							$output[] = array( 'value', intval( substr( $str, $pos, $span ) ) );
+							$pos     += $span;
+							break;
+						}
 
-					throw new Exception( sprintf( 'Unknown symbol "%s"', $next ) );
+						throw new Exception( sprintf( 'Unknown symbol "%s"', $next ) );
+				}
 			}
+
+			while ( ! empty( $stack ) ) {
+				$o2 = array_pop( $stack );
+				if ( '(' === $o2 || ')' === $o2 ) {
+					throw new Exception( 'Mismatched parentheses' );
+				}
+
+				$output[] = array( 'op', $o2 );
+			}
+
+			$this->tokens = $output;
 		}
 
-		while ( ! empty( $stack ) ) {
-			$o2 = array_pop( $stack );
-			if ( '(' === $o2 || ')' === $o2 ) {
-				throw new Exception( 'Mismatched parentheses' );
+		/**
+		 * Get the plural form for a number.
+		 *
+		 * Caches the value for repeated calls.
+		 *
+		 * @since 4.9.0
+		 *
+		 * @param int $num Number to get plural form for.
+		 * @return int Plural form value.
+		 */
+		public function get( $num ) {
+			if ( isset( $this->cache[ $num ] ) ) {
+				return $this->cache[ $num ];
 			}
-
-			$output[] = array( 'op', $o2 );
-		}
-
-		$this->tokens = $output;
-	}
-
-	/**
-	 * Get the plural form for a number.
-	 *
-	 * Caches the value for repeated calls.
-	 *
-	 * @since 4.9.0
-	 *
-	 * @param int $num Number to get plural form for.
-	 * @return int Plural form value.
-	 */
-	public function get( $num ) {
-		if ( isset( $this->cache[ $num ] ) ) {
+			$this->cache[ $num ] = $this->execute( $num );
 			return $this->cache[ $num ];
 		}
-		$this->cache[ $num ] = $this->execute( $num );
-		return $this->cache[ $num ];
-	}
+
+		/**
+		 * Execute the plural form function.
+		 *
+		 * @since 4.9.0
+		 *
+		 * @throws Exception If the plural form value cannot be calculated.
+		 *
+		 * @param int $n Variable "n" to substitute.
+		 * @return int Plural form value.
+		 */
+		public function execute( $n ) {
+			$stack = array();
+			$i     = 0;
+			$total = count( $this->tokens );
+			while ( $i < $total ) {
+				$next = $this->tokens[ $i ];
+				$i++;
+				if ( 'var' === $next[0] ) {
+					$stack[] = $n;
+					continue;
+				} elseif ( 'value' === $next[0] ) {
+					$stack[] = $next[1];
+					continue;
+				}
+
+				// Only operators left.
+				switch ( $next[1] ) {
+					case '%':
+						$v2      = array_pop( $stack );
+						$v1      = array_pop( $stack );
+						$stack[] = $v1 % $v2;
+						break;
+
+					case '||':
+						$v2      = array_pop( $stack );
+						$v1      = array_pop( $stack );
+						$stack[] = $v1 || $v2;
+						break;
+
+					case '&&':
+						$v2      = array_pop( $stack );
+						$v1      = array_pop( $stack );
+						$stack[] = $v1 && $v2;
+						break;
 
-	/**
-	 * Execute the plural form function.
-	 *
-	 * @since 4.9.0
-	 *
-	 * @param int $n Variable "n" to substitute.
-	 * @return int Plural form value.
-	 */
-	public function execute( $n ) {
-		$stack = array();
-		$i     = 0;
-		$total = count( $this->tokens );
-		while ( $i < $total ) {
-			$next = $this->tokens[ $i ];
-			$i++;
-			if ( 'var' === $next[0] ) {
-				$stack[] = $n;
-				continue;
-			} elseif ( 'value' === $next[0] ) {
-				$stack[] = $next[1];
-				continue;
+					case '<':
+						$v2      = array_pop( $stack );
+						$v1      = array_pop( $stack );
+						$stack[] = $v1 < $v2;
+						break;
+
+					case '<=':
+						$v2      = array_pop( $stack );
+						$v1      = array_pop( $stack );
+						$stack[] = $v1 <= $v2;
+						break;
+
+					case '>':
+						$v2      = array_pop( $stack );
+						$v1      = array_pop( $stack );
+						$stack[] = $v1 > $v2;
+						break;
+
+					case '>=':
+						$v2      = array_pop( $stack );
+						$v1      = array_pop( $stack );
+						$stack[] = $v1 >= $v2;
+						break;
+
+					case '!=':
+						$v2      = array_pop( $stack );
+						$v1      = array_pop( $stack );
+						$stack[] = $v1 != $v2;
+						break;
+
+					case '==':
+						$v2      = array_pop( $stack );
+						$v1      = array_pop( $stack );
+						$stack[] = $v1 == $v2;
+						break;
+
+					case '?:':
+						$v3      = array_pop( $stack );
+						$v2      = array_pop( $stack );
+						$v1      = array_pop( $stack );
+						$stack[] = $v1 ? $v2 : $v3;
+						break;
+
+					default:
+						throw new Exception( sprintf( 'Unknown operator "%s"', $next[1] ) );
+				}
 			}
 
-			// Only operators left.
-			switch ( $next[1] ) {
-				case '%':
-					$v2      = array_pop( $stack );
-					$v1      = array_pop( $stack );
-					$stack[] = $v1 % $v2;
-					break;
-
-				case '||':
-					$v2      = array_pop( $stack );
-					$v1      = array_pop( $stack );
-					$stack[] = $v1 || $v2;
-					break;
-
-				case '&&':
-					$v2      = array_pop( $stack );
-					$v1      = array_pop( $stack );
-					$stack[] = $v1 && $v2;
-					break;
-
-				case '<':
-					$v2      = array_pop( $stack );
-					$v1      = array_pop( $stack );
-					$stack[] = $v1 < $v2;
-					break;
-
-				case '<=':
-					$v2      = array_pop( $stack );
-					$v1      = array_pop( $stack );
-					$stack[] = $v1 <= $v2;
-					break;
-
-				case '>':
-					$v2      = array_pop( $stack );
-					$v1      = array_pop( $stack );
-					$stack[] = $v1 > $v2;
-					break;
+			if ( count( $stack ) !== 1 ) {
+				throw new Exception( 'Too many values remaining on the stack' );
+			}
 
-				case '>=':
-					$v2      = array_pop( $stack );
-					$v1      = array_pop( $stack );
-					$stack[] = $v1 >= $v2;
-					break;
-
-				case '!=':
-					$v2      = array_pop( $stack );
-					$v1      = array_pop( $stack );
-					$stack[] = $v1 != $v2;
-					break;
-
-				case '==':
-					$v2      = array_pop( $stack );
-					$v1      = array_pop( $stack );
-					$stack[] = $v1 == $v2;
-					break;
-
-				case '?:':
-					$v3      = array_pop( $stack );
-					$v2      = array_pop( $stack );
-					$v1      = array_pop( $stack );
-					$stack[] = $v1 ? $v2 : $v3;
-					break;
-
-				default:
-					throw new Exception( sprintf( 'Unknown operator "%s"', $next[1] ) );
-			}
+			return (int) $stack[0];
 		}
-
-		if ( count( $stack ) !== 1 ) {
-			throw new Exception( 'Too many values remaining on the stack' );
-		}
-
-		return (int) $stack[0];
 	}
-}
+endif;