Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
14 / 14 |
|
100.00% |
2 / 2 |
CRAP | |
100.00% |
1 / 1 |
BlockMatcher | |
100.00% |
14 / 14 |
|
100.00% |
2 / 2 |
7 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
generateMatches | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
5 |
1 | <?php |
2 | /** |
3 | * @file |
4 | * @license https://opensource.org/licenses/Apache-2.0 Apache-2.0 |
5 | */ |
6 | |
7 | namespace Wikimedia\CSS\Grammar; |
8 | |
9 | use InvalidArgumentException; |
10 | use Wikimedia\CSS\Objects\ComponentValueList; |
11 | use Wikimedia\CSS\Objects\SimpleBlock; |
12 | |
13 | /** |
14 | * Matcher that matches a SimpleBlock |
15 | * |
16 | * The grammar definitions in the standards seem to be written assuming they're |
17 | * being passed a sequence of Tokens only, even though they're defined over a |
18 | * sequence of ComponentValues (which includes SimpleBlocks and CSSFunctions) |
19 | * instead. |
20 | * |
21 | * Thus, to be safe you'll want to use this when a grammar specifies something |
22 | * like `'[' <stuff> ']'`. |
23 | */ |
24 | class BlockMatcher extends Matcher { |
25 | /** @var string One of the Token::T_* constants */ |
26 | protected $blockType; |
27 | |
28 | /** @var Matcher */ |
29 | protected $matcher; |
30 | |
31 | /** |
32 | * @param string $blockType One of the Token::T_* constants |
33 | * @param Matcher $matcher Matcher for the contents of the block |
34 | */ |
35 | public function __construct( $blockType, Matcher $matcher ) { |
36 | if ( SimpleBlock::matchingDelimiter( $blockType ) === null ) { |
37 | throw new InvalidArgumentException( |
38 | 'A block is delimited by either {}, [], or ().' |
39 | ); |
40 | } |
41 | $this->blockType = $blockType; |
42 | $this->matcher = $matcher; |
43 | } |
44 | |
45 | /** @inheritDoc */ |
46 | protected function generateMatches( ComponentValueList $values, $start, array $options ) { |
47 | $cv = $values[$start] ?? null; |
48 | if ( $cv instanceof SimpleBlock && $cv->getStartTokenType() === $this->blockType ) { |
49 | // To successfully match, our sub-Matcher needs to match the whole |
50 | // content of the block. |
51 | $l = $cv->getValue()->count(); |
52 | $s = $this->next( $cv->getValue(), -1, $options ); |
53 | foreach ( $this->matcher->generateMatches( $cv->getValue(), $s, $options ) as $match ) { |
54 | if ( $match->getNext() === $l ) { |
55 | // Matched the whole content of the block, so yield the |
56 | // token after the block. |
57 | yield $this->makeMatch( $values, $start, $this->next( $values, $start, $options ), $match ); |
58 | return; |
59 | } |
60 | } |
61 | } |
62 | } |
63 | } |