Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
83.33% |
15 / 18 |
|
57.14% |
4 / 7 |
CRAP | |
0.00% |
0 / 1 |
LeafVisitor | |
83.33% |
15 / 18 |
|
57.14% |
4 / 7 |
10.46 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
visitParsedBooleanNode | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
visitNegatedNode | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
visitNamespaceHeader | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
visitBooleanClause | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
3 | |||
negated | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCurrentBooleanClause | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php declare( strict_types=1 ); |
2 | |
3 | namespace CirrusSearch\Parser\AST\Visitor; |
4 | |
5 | use CirrusSearch\Parser\AST\BooleanClause; |
6 | use CirrusSearch\Parser\AST\NamespaceHeaderNode; |
7 | use CirrusSearch\Parser\AST\NegatedNode; |
8 | use CirrusSearch\Parser\AST\ParsedBooleanNode; |
9 | use Wikimedia\Assert\Assert; |
10 | |
11 | /** |
12 | * Visit leaves only |
13 | */ |
14 | abstract class LeafVisitor implements Visitor { |
15 | /** |
16 | * @var string[] |
17 | */ |
18 | private array $excludeOccurs; |
19 | |
20 | /** |
21 | * @var bool true when this branch is "negated". |
22 | */ |
23 | private bool $inNegation = false; |
24 | private ?BooleanClause $currentClause = null; |
25 | |
26 | /** |
27 | * @param string[] $excludeOccurs |
28 | */ |
29 | public function __construct( array $excludeOccurs = [] ) { |
30 | array_walk( $excludeOccurs, static fn ( $x ) => BooleanClause::validateOccur( $x ) ); |
31 | $this->excludeOccurs = $excludeOccurs; |
32 | } |
33 | |
34 | final public function visitParsedBooleanNode( ParsedBooleanNode $node ): void { |
35 | foreach ( $node->getClauses() as $clause ) { |
36 | $clause->accept( $this ); |
37 | } |
38 | } |
39 | |
40 | final public function visitNegatedNode( NegatedNode $node ): void { |
41 | /** @phan-suppress-next-line PhanImpossibleCondition I agree, this is impossible. */ |
42 | Assert::invariant( false, 'NegatedNode should be optimized at parse time' ); |
43 | } |
44 | |
45 | final public function visitNamespaceHeader( NamespaceHeaderNode $node ): void { |
46 | /** @phan-suppress-next-line PhanImpossibleCondition I agree, this is impossible. */ |
47 | Assert::invariant( false, 'Not yet part of the AST, should not be visited.' ); |
48 | } |
49 | |
50 | final public function visitBooleanClause( BooleanClause $clause ): void { |
51 | if ( in_array( $clause->getOccur(), $this->excludeOccurs ) ) { |
52 | return; |
53 | } |
54 | |
55 | $oldNegated = $this->inNegation; |
56 | $oldClause = $this->currentClause; |
57 | if ( $clause->getOccur() === BooleanClause::MUST_NOT ) { |
58 | $this->inNegation = !$this->inNegation; |
59 | } |
60 | $this->currentClause = $clause; |
61 | |
62 | $clause->getNode()->accept( $this ); |
63 | $this->inNegation = $oldNegated; |
64 | $this->currentClause = $oldClause; |
65 | } |
66 | |
67 | /** |
68 | * @return bool true if this node is in a negation |
69 | */ |
70 | final public function negated(): bool { |
71 | return $this->inNegation; |
72 | } |
73 | |
74 | /** |
75 | * @return BooleanClause|null the boolean clause the visited node is in or null if top-level |
76 | */ |
77 | final public function getCurrentBooleanClause(): ?BooleanClause { |
78 | return $this->currentClause; |
79 | } |
80 | } |