']'`. */ class BlockMatcher extends Matcher { /** @var string One of the Token::T_* constants */ protected $blockType; /** @var Matcher */ protected $matcher; /** * @param string $blockType One of the Token::T_* constants * @param Matcher $matcher Matcher for the contents of the block */ public function __construct( $blockType, Matcher $matcher ) { if ( SimpleBlock::matchingDelimiter( $blockType ) === null ) { throw new \InvalidArgumentException( 'A block is delimited by either {}, [], or ().' ); } $this->blockType = $blockType; $this->matcher = $matcher; } protected function generateMatches( ComponentValueList $values, $start, array $options ) { $cv = isset( $values[$start] ) ? $values[$start] : null; if ( $cv instanceof SimpleBlock && $cv->getStartTokenType() === $this->blockType ) { // To successfully match, our sub-Matcher needs to match the whole // content of the block. $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 block, so yield the // token after the block. yield $this->makeMatch( $values, $start, $this->next( $values, $start, $options ), $match ); return; } } } } }