xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/Atn/SemanticContexts/OrOperator.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
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