/** * 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,
'==' => 4, '!=' => 4,
'&&' => 3,
'||' => 2,
'?:' => 1, '?' => 1,
'(' => 0, ')' => 0, );
/** * Tokens generated from the string. * * @since 4.9.0 * @var array $tokens List of tokens. */ protected $tokens = array();
/** * Cache for repeated calls to the function. * * @since 4.9.0 * @var array $cache Map of $n => $result */ protected $cache = array();
/** * 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 ); }
/** * 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 );
// Convert infix operators to postfix using the shunting-yard algorithm. $output = array(); $stack = array(); while ( $pos < $len ) { $next = substr( $str, $pos, 1 );
switch ( $next ) { // Ignore whitespace. case ' ': case "\t": ++$pos; break;
/** * 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 ]; } $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; }