1*37748cd8SNickeau<?php 2*37748cd8SNickeau 3*37748cd8SNickeaudeclare(strict_types=1); 4*37748cd8SNickeau 5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime\Atn; 6*37748cd8SNickeau 7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\SemanticContexts\SemanticContext; 8*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\States\ATNState; 9*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Equality; 10*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Hashable; 11*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Hasher; 12*37748cd8SNickeauuse Antlr\Antlr4\Runtime\PredictionContexts\PredictionContext; 13*37748cd8SNickeau 14*37748cd8SNickeau/** 15*37748cd8SNickeau * A tuple: (ATN state, predicted alt, syntactic, semantic context). 16*37748cd8SNickeau * The syntactic context is a graph-structured stack node whose path(s) 17*37748cd8SNickeau * to the root is the rule invocation(s) chain used to arrive at the state. 18*37748cd8SNickeau * The semantic context is the tree of semantic predicates encountered 19*37748cd8SNickeau * before reaching an ATN state. 20*37748cd8SNickeau */ 21*37748cd8SNickeauclass ATNConfig implements Hashable 22*37748cd8SNickeau{ 23*37748cd8SNickeau /** 24*37748cd8SNickeau * This field stores the bit mask for implementing the 25*37748cd8SNickeau * {@see ATNConfig::isPrecedenceFilterSuppressed()} property as a bit within 26*37748cd8SNickeau * the existing {@see ATNConfig::$reachesIntoOuterContext} field. 27*37748cd8SNickeau */ 28*37748cd8SNickeau private const SUPPRESS_PRECEDENCE_FILTER = 0x40000000; 29*37748cd8SNickeau 30*37748cd8SNickeau /** 31*37748cd8SNickeau * The ATN state associated with this configuration. 32*37748cd8SNickeau * 33*37748cd8SNickeau * @var ATNState 34*37748cd8SNickeau */ 35*37748cd8SNickeau public $state; 36*37748cd8SNickeau 37*37748cd8SNickeau /** 38*37748cd8SNickeau * What alt (or lexer rule) is predicted by this configuration. 39*37748cd8SNickeau * 40*37748cd8SNickeau * @var int 41*37748cd8SNickeau */ 42*37748cd8SNickeau public $alt; 43*37748cd8SNickeau 44*37748cd8SNickeau /** 45*37748cd8SNickeau * The stack of invoking states leading to the rule/states associated 46*37748cd8SNickeau * with this config. We track only those contexts pushed during 47*37748cd8SNickeau * execution of the ATN simulator. 48*37748cd8SNickeau * 49*37748cd8SNickeau * @var PredictionContext|null 50*37748cd8SNickeau */ 51*37748cd8SNickeau public $context; 52*37748cd8SNickeau 53*37748cd8SNickeau /** 54*37748cd8SNickeau * We cannot execute predicates dependent upon local context unless 55*37748cd8SNickeau * we know for sure we are in the correct context. Because there is 56*37748cd8SNickeau * no way to do this efficiently, we simply cannot evaluate 57*37748cd8SNickeau * dependent predicates unless we are in the rule that initially 58*37748cd8SNickeau * invokes the ATN simulator. 59*37748cd8SNickeau * 60*37748cd8SNickeau * closure() tracks the depth of how far we dip into the outer context: 61*37748cd8SNickeau * `depth > 0`. Note that it may not be totally accurate depth since I 62*37748cd8SNickeau * don't ever decrement. TODO: make it a boolean then 63*37748cd8SNickeau * 64*37748cd8SNickeau * For memory efficiency, {@see ATNConfig::isPrecedenceFilterSuppressed()} 65*37748cd8SNickeau * is also backed by this field. Since the field is publicly accessible, the 66*37748cd8SNickeau * highest bit which would not cause the value to become negative is used to 67*37748cd8SNickeau * store this field. This choice minimizes the risk that code which only 68*37748cd8SNickeau * compares this value to 0 would be affected by the new purpose of the 69*37748cd8SNickeau * flag. It also ensures the performance of the existing {@see ATNConfig} 70*37748cd8SNickeau * constructors as well as certain operations like 71*37748cd8SNickeau * {@see ATNConfigSet::add()} method are completely unaffected by the change. 72*37748cd8SNickeau * 73*37748cd8SNickeau * @var int 74*37748cd8SNickeau */ 75*37748cd8SNickeau public $reachesIntoOuterContext; 76*37748cd8SNickeau 77*37748cd8SNickeau /** @var SemanticContext */ 78*37748cd8SNickeau public $semanticContext; 79*37748cd8SNickeau 80*37748cd8SNickeau public function __construct( 81*37748cd8SNickeau ?self $oldConfig, 82*37748cd8SNickeau ?ATNState $state, 83*37748cd8SNickeau ?PredictionContext $context = null, 84*37748cd8SNickeau ?SemanticContext $semanticContext = null, 85*37748cd8SNickeau ?int $alt = null 86*37748cd8SNickeau ) { 87*37748cd8SNickeau if ($oldConfig === null) { 88*37748cd8SNickeau if ($state === null) { 89*37748cd8SNickeau throw new \RuntimeException('ATN State cannot be null.'); 90*37748cd8SNickeau } 91*37748cd8SNickeau 92*37748cd8SNickeau $this->state = $state; 93*37748cd8SNickeau $this->alt = $alt ?? 0; 94*37748cd8SNickeau $this->context = $context; 95*37748cd8SNickeau $this->semanticContext = $semanticContext ?? SemanticContext::none(); 96*37748cd8SNickeau } else { 97*37748cd8SNickeau $this->state = $state ?? $oldConfig->state; 98*37748cd8SNickeau $this->alt = $alt ?? $oldConfig->alt; 99*37748cd8SNickeau $this->context = $context ?? $oldConfig->context; 100*37748cd8SNickeau $this->semanticContext = $semanticContext ?? $oldConfig->semanticContext; 101*37748cd8SNickeau $this->reachesIntoOuterContext = $oldConfig->reachesIntoOuterContext; 102*37748cd8SNickeau } 103*37748cd8SNickeau } 104*37748cd8SNickeau 105*37748cd8SNickeau /** 106*37748cd8SNickeau * This method gets the value of the {@see ATNConfig::$reachesIntoOuterContext} 107*37748cd8SNickeau * field as it existed prior to the introduction of the 108*37748cd8SNickeau * {@see ATNConfig::isPrecedenceFilterSuppressed()} method. 109*37748cd8SNickeau */ 110*37748cd8SNickeau public function getOuterContextDepth() : int 111*37748cd8SNickeau { 112*37748cd8SNickeau return $this->reachesIntoOuterContext & ~self::SUPPRESS_PRECEDENCE_FILTER; 113*37748cd8SNickeau } 114*37748cd8SNickeau 115*37748cd8SNickeau public function isPrecedenceFilterSuppressed() : bool 116*37748cd8SNickeau { 117*37748cd8SNickeau return ($this->reachesIntoOuterContext & self::SUPPRESS_PRECEDENCE_FILTER) !== 0; 118*37748cd8SNickeau } 119*37748cd8SNickeau 120*37748cd8SNickeau public function setPrecedenceFilterSuppressed(bool $value) : void 121*37748cd8SNickeau { 122*37748cd8SNickeau if ($value) { 123*37748cd8SNickeau $this->reachesIntoOuterContext |= self::SUPPRESS_PRECEDENCE_FILTER; 124*37748cd8SNickeau } else { 125*37748cd8SNickeau $this->reachesIntoOuterContext &= ~self::SUPPRESS_PRECEDENCE_FILTER; 126*37748cd8SNickeau } 127*37748cd8SNickeau } 128*37748cd8SNickeau 129*37748cd8SNickeau /** 130*37748cd8SNickeau * An ATN configuration is equal to another if both have the same state, they 131*37748cd8SNickeau * predict the same alternative, and syntactic/semantic contexts are the same. 132*37748cd8SNickeau */ 133*37748cd8SNickeau public function equals(object $other) : bool 134*37748cd8SNickeau { 135*37748cd8SNickeau if ($this === $other) { 136*37748cd8SNickeau return true; 137*37748cd8SNickeau } 138*37748cd8SNickeau 139*37748cd8SNickeau return $other instanceof self 140*37748cd8SNickeau && $this->alt === $other->alt 141*37748cd8SNickeau && $this->isPrecedenceFilterSuppressed() === $other->isPrecedenceFilterSuppressed() 142*37748cd8SNickeau && $this->semanticContext->equals($other->semanticContext) 143*37748cd8SNickeau && Equality::equals($this->state, $other->state) 144*37748cd8SNickeau && Equality::equals($this->context, $other->context); 145*37748cd8SNickeau } 146*37748cd8SNickeau 147*37748cd8SNickeau public function hashCode() : int 148*37748cd8SNickeau { 149*37748cd8SNickeau return Hasher::hash( 150*37748cd8SNickeau $this->state->stateNumber, 151*37748cd8SNickeau $this->alt, 152*37748cd8SNickeau $this->context, 153*37748cd8SNickeau $this->semanticContext 154*37748cd8SNickeau ); 155*37748cd8SNickeau } 156*37748cd8SNickeau 157*37748cd8SNickeau public function toString(bool $showAlt) : string 158*37748cd8SNickeau { 159*37748cd8SNickeau $buf = '(' . $this->state; 160*37748cd8SNickeau 161*37748cd8SNickeau if ($showAlt) { 162*37748cd8SNickeau $buf .= ',' . $this->alt; 163*37748cd8SNickeau } 164*37748cd8SNickeau 165*37748cd8SNickeau if ($this->context !== null) { 166*37748cd8SNickeau $buf .= ',[' . $this->context . ']'; 167*37748cd8SNickeau } 168*37748cd8SNickeau 169*37748cd8SNickeau if ($this->semanticContext->equals(SemanticContext::none())) { 170*37748cd8SNickeau $buf .= ',' . $this->semanticContext; 171*37748cd8SNickeau } 172*37748cd8SNickeau 173*37748cd8SNickeau if ($this->getOuterContextDepth() > 0) { 174*37748cd8SNickeau $buf .= ',up=' . $this->getOuterContextDepth(); 175*37748cd8SNickeau } 176*37748cd8SNickeau 177*37748cd8SNickeau $buf .= ')'; 178*37748cd8SNickeau 179*37748cd8SNickeau return $buf; 180*37748cd8SNickeau } 181*37748cd8SNickeau 182*37748cd8SNickeau public function __toString() : string 183*37748cd8SNickeau { 184*37748cd8SNickeau return \sprintf( 185*37748cd8SNickeau '(%s,%d%s%s%s)', 186*37748cd8SNickeau $this->state, 187*37748cd8SNickeau $this->alt, 188*37748cd8SNickeau $this->context !== null ? ',[' . $this->context . ']' : '', 189*37748cd8SNickeau $this->semanticContext !== null && $this->semanticContext->equals(SemanticContext::none()) ? 190*37748cd8SNickeau ',' . $this->semanticContext : 191*37748cd8SNickeau '', 192*37748cd8SNickeau $this->reachesIntoOuterContext > 0 ? ',up=' . $this->reachesIntoOuterContext : '' 193*37748cd8SNickeau ); 194*37748cd8SNickeau } 195*37748cd8SNickeau} 196