')'`. */ class FunctionMatcher extends Matcher { /** @var callable|null Function name */ protected $nameCheck; /** @var Matcher */ protected $matcher; /** * @param string|Closure|null $name Function name, case-insensitive, or a * function to check the name. * @param Matcher $matcher Matcher for the contents of the function */ public function __construct( $name, Matcher $matcher ) { if ( is_string( $name ) ) { $this->nameCheck = static function ( $s ) use ( $name ) { return !strcasecmp( $s, $name ); }; } elseif ( is_callable( $name ) || $name === null ) { $this->nameCheck = $name; } else { throw new InvalidArgumentException( '$name must be a string, callable, or null' ); } $this->matcher = $matcher; } /** @inheritDoc */ protected function generateMatches( ComponentValueList $values, $start, array $options ) { $cv = $values[$start] ?? null; if ( $cv instanceof CSSFunction && ( !$this->nameCheck || call_user_func( $this->nameCheck, $cv->getName() ) ) ) { // To successfully match, our sub-Matcher needs to match the whole // content of the function. $l = $cv->getValue()->count(); $s = $this->next( $cv->getValue(), -1, $options ); foreach ( $this->matcher->generateMatches( $cv->getValue(), $s, $options ) as $match ) { if ( $match->getNext() === $l ) { // Matched the whole content of the function, so yield the // token after the function. yield $this->makeMatch( $values, $start, $this->next( $values, $start, $options ), $match ); return; } } } } }