1*37748cd8SNickeau<?php 2*37748cd8SNickeau 3*37748cd8SNickeaudeclare(strict_types=1); 4*37748cd8SNickeau 5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime\Atn\SemanticContexts; 6*37748cd8SNickeau 7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Equality; 8*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Hasher; 9*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Recognizer; 10*37748cd8SNickeauuse Antlr\Antlr4\Runtime\RuleContext; 11*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Utils\Set; 12*37748cd8SNickeau 13*37748cd8SNickeau/** 14*37748cd8SNickeau * A semantic context which is true whenever at least one of the contained 15*37748cd8SNickeau * contexts is true. 16*37748cd8SNickeau */ 17*37748cd8SNickeaufinal class OrOperator extends Operator 18*37748cd8SNickeau{ 19*37748cd8SNickeau /** @var array<SemanticContext> */ 20*37748cd8SNickeau public $operand; 21*37748cd8SNickeau 22*37748cd8SNickeau public function __construct(SemanticContext $a, SemanticContext $b) 23*37748cd8SNickeau { 24*37748cd8SNickeau $operands = new Set(); 25*37748cd8SNickeau 26*37748cd8SNickeau if ($a instanceof self) { 27*37748cd8SNickeau foreach ($a->operand as $o) { 28*37748cd8SNickeau $operands->add($o); 29*37748cd8SNickeau } 30*37748cd8SNickeau } else { 31*37748cd8SNickeau $operands->add($a); 32*37748cd8SNickeau } 33*37748cd8SNickeau 34*37748cd8SNickeau if ($b instanceof self) { 35*37748cd8SNickeau foreach ($b->operand as $o) { 36*37748cd8SNickeau $operands->add($o); 37*37748cd8SNickeau } 38*37748cd8SNickeau } else { 39*37748cd8SNickeau $operands->add($b); 40*37748cd8SNickeau } 41*37748cd8SNickeau 42*37748cd8SNickeau $precedencePredicates = self::filterPrecedencePredicates($operands); 43*37748cd8SNickeau 44*37748cd8SNickeau if (\count($precedencePredicates) !== 0) { 45*37748cd8SNickeau // interested in the transition with the highest precedence 46*37748cd8SNickeau \usort($precedencePredicates, static function (PrecedencePredicate $a, PrecedencePredicate $b) { 47*37748cd8SNickeau return $a->precedence - $b->precedence; 48*37748cd8SNickeau }); 49*37748cd8SNickeau $reduced = $precedencePredicates[\count($precedencePredicates) - 1]; 50*37748cd8SNickeau $operands->add($reduced); 51*37748cd8SNickeau } 52*37748cd8SNickeau 53*37748cd8SNickeau $this->operand = $operands->getValues(); 54*37748cd8SNickeau } 55*37748cd8SNickeau 56*37748cd8SNickeau /** 57*37748cd8SNickeau * @return array<SemanticContext> 58*37748cd8SNickeau */ 59*37748cd8SNickeau public function getOperands() : array 60*37748cd8SNickeau { 61*37748cd8SNickeau return $this->operand; 62*37748cd8SNickeau } 63*37748cd8SNickeau 64*37748cd8SNickeau /** 65*37748cd8SNickeau * {@inheritdoc} 66*37748cd8SNickeau * 67*37748cd8SNickeau * The evaluation of predicates by this context is short-circuiting, but 68*37748cd8SNickeau * unordered. 69*37748cd8SNickeau */ 70*37748cd8SNickeau public function eval(Recognizer $parser, RuleContext $parserCallStack) : bool 71*37748cd8SNickeau { 72*37748cd8SNickeau foreach ($this->operand as $operand) { 73*37748cd8SNickeau if ($operand->eval($parser, $parserCallStack)) { 74*37748cd8SNickeau return true; 75*37748cd8SNickeau } 76*37748cd8SNickeau } 77*37748cd8SNickeau 78*37748cd8SNickeau return false; 79*37748cd8SNickeau } 80*37748cd8SNickeau 81*37748cd8SNickeau public function evalPrecedence(Recognizer $parser, RuleContext $parserCallStack) : ?SemanticContext 82*37748cd8SNickeau { 83*37748cd8SNickeau $differs = false; 84*37748cd8SNickeau 85*37748cd8SNickeau $operands = []; 86*37748cd8SNickeau foreach ($this->operand as $context) { 87*37748cd8SNickeau $evaluated = $context->evalPrecedence($parser, $parserCallStack); 88*37748cd8SNickeau $differs |= ($evaluated !== $context); 89*37748cd8SNickeau 90*37748cd8SNickeau if ($evaluated === SemanticContext::none()) { 91*37748cd8SNickeau // The OR context is true if any element is true 92*37748cd8SNickeau return SemanticContext::none(); 93*37748cd8SNickeau } 94*37748cd8SNickeau 95*37748cd8SNickeau if ($evaluated !== null) { 96*37748cd8SNickeau // Reduce the result by skipping false elements 97*37748cd8SNickeau $operands[] = $evaluated; 98*37748cd8SNickeau } 99*37748cd8SNickeau } 100*37748cd8SNickeau 101*37748cd8SNickeau if (!$differs) { 102*37748cd8SNickeau return $this; 103*37748cd8SNickeau } 104*37748cd8SNickeau 105*37748cd8SNickeau // all elements were false, so the OR context is false 106*37748cd8SNickeau if (\count($operands) === 0) { 107*37748cd8SNickeau return null; 108*37748cd8SNickeau } 109*37748cd8SNickeau 110*37748cd8SNickeau $result = null; 111*37748cd8SNickeau foreach ($operands as $operand) { 112*37748cd8SNickeau $result = $result === null ? $operand : SemanticContext::orContext($result, $operand); 113*37748cd8SNickeau } 114*37748cd8SNickeau 115*37748cd8SNickeau return $result; 116*37748cd8SNickeau } 117*37748cd8SNickeau 118*37748cd8SNickeau public function equals(object $other) : bool 119*37748cd8SNickeau { 120*37748cd8SNickeau if ($this === $other) { 121*37748cd8SNickeau return true; 122*37748cd8SNickeau } 123*37748cd8SNickeau 124*37748cd8SNickeau if (!$other instanceof self) { 125*37748cd8SNickeau return false; 126*37748cd8SNickeau } 127*37748cd8SNickeau 128*37748cd8SNickeau return Equality::equals($this->operand, $other->operand); 129*37748cd8SNickeau } 130*37748cd8SNickeau 131*37748cd8SNickeau public function hashCode() : int 132*37748cd8SNickeau { 133*37748cd8SNickeau return Hasher::hash(37, $this->operand); 134*37748cd8SNickeau } 135*37748cd8SNickeau 136*37748cd8SNickeau 137*37748cd8SNickeau public function __toString() : string 138*37748cd8SNickeau { 139*37748cd8SNickeau $s = ''; 140*37748cd8SNickeau foreach ($this->operand as $o) { 141*37748cd8SNickeau $s .= '|| ' . $o; 142*37748cd8SNickeau } 143*37748cd8SNickeau 144*37748cd8SNickeau return \strlen($s) > 3 ? (string) \substr($s, 3) : $s; 145*37748cd8SNickeau } 146*37748cd8SNickeau} 147