1*37748cd8SNickeau<?php 2*37748cd8SNickeau 3*37748cd8SNickeaudeclare(strict_types=1); 4*37748cd8SNickeau 5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime; 6*37748cd8SNickeau 7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\ATN; 8*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\ATNConfig; 9*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\States\ATNState; 10*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\States\RuleStopState; 11*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\Transitions\AbstractPredicateTransition; 12*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\Transitions\NotSetTransition; 13*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\Transitions\RuleTransition; 14*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\Transitions\Transition; 15*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\Transitions\WildcardTransition; 16*37748cd8SNickeauuse Antlr\Antlr4\Runtime\PredictionContexts\PredictionContext; 17*37748cd8SNickeauuse Antlr\Antlr4\Runtime\PredictionContexts\SingletonPredictionContext; 18*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Utils\BitSet; 19*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Utils\Set; 20*37748cd8SNickeau 21*37748cd8SNickeauclass LL1Analyzer 22*37748cd8SNickeau{ 23*37748cd8SNickeau /** 24*37748cd8SNickeau * Special value added to the lookahead sets to indicate that we hit 25*37748cd8SNickeau * a predicate during analysis if `seeThruPreds === false`. 26*37748cd8SNickeau */ 27*37748cd8SNickeau public const HIT_PRED = Token::INVALID_TYPE; 28*37748cd8SNickeau 29*37748cd8SNickeau /** @var ATN */ 30*37748cd8SNickeau public $atn; 31*37748cd8SNickeau 32*37748cd8SNickeau public function __construct(ATN $atn) 33*37748cd8SNickeau { 34*37748cd8SNickeau $this->atn = $atn; 35*37748cd8SNickeau } 36*37748cd8SNickeau 37*37748cd8SNickeau /** 38*37748cd8SNickeau * Calculates the SLL(1) expected lookahead set for each outgoing transition 39*37748cd8SNickeau * of an {@see ATNState}. The returned array has one element for each 40*37748cd8SNickeau * outgoing transition in `s`. If the closure from transition 41*37748cd8SNickeau * `i` leads to a semantic predicate before matching a symbol, the 42*37748cd8SNickeau * element at index `i` of the result will be `null`. 43*37748cd8SNickeau * 44*37748cd8SNickeau * @param ATNState|null $s The ATN state 45*37748cd8SNickeau * 46*37748cd8SNickeau * @return array<IntervalSet|null>|null The expected symbols for 47*37748cd8SNickeau * each outgoing transition of `s`. 48*37748cd8SNickeau */ 49*37748cd8SNickeau public function getDecisionLookahead(?ATNState $s) : ?array 50*37748cd8SNickeau { 51*37748cd8SNickeau if ($s === null) { 52*37748cd8SNickeau return null; 53*37748cd8SNickeau } 54*37748cd8SNickeau 55*37748cd8SNickeau $look = []; 56*37748cd8SNickeau for ($alt = 0; $alt < $s->getNumberOfTransitions(); $alt++) { 57*37748cd8SNickeau $interval = new IntervalSet(); 58*37748cd8SNickeau $lookBusy = new Set(); 59*37748cd8SNickeau $seeThruPreds = false; // fail to get lookahead upon pred 60*37748cd8SNickeau 61*37748cd8SNickeau $this->lookRecursively( 62*37748cd8SNickeau $s->getTransition($alt)->target, 63*37748cd8SNickeau null, 64*37748cd8SNickeau PredictionContext::empty(), 65*37748cd8SNickeau $interval, 66*37748cd8SNickeau $lookBusy, 67*37748cd8SNickeau new BitSet(), 68*37748cd8SNickeau $seeThruPreds, 69*37748cd8SNickeau false 70*37748cd8SNickeau ); 71*37748cd8SNickeau 72*37748cd8SNickeau // Wipe out lookahead for this alternative if we found nothing 73*37748cd8SNickeau // or we had a predicate when we !seeThruPreds 74*37748cd8SNickeau if ($interval->length() === 0 || $interval->contains(self::HIT_PRED)) { 75*37748cd8SNickeau $look[$alt] = null; 76*37748cd8SNickeau } else { 77*37748cd8SNickeau $look[$alt] = $interval; 78*37748cd8SNickeau } 79*37748cd8SNickeau } 80*37748cd8SNickeau 81*37748cd8SNickeau return $look; 82*37748cd8SNickeau } 83*37748cd8SNickeau 84*37748cd8SNickeau /** 85*37748cd8SNickeau * Compute set of tokens that can follow `s` in the ATN in the 86*37748cd8SNickeau * specified `context`. 87*37748cd8SNickeau * 88*37748cd8SNickeau * If `context` is `null` and the end of the rule containing 89*37748cd8SNickeau * `s` is reached, {@see Token::EPSILON} is added to the result set. 90*37748cd8SNickeau * If `context` is not `null` and the end of the outermost rule is 91*37748cd8SNickeau * reached, {@see Token::EOF} is added to the result set. 92*37748cd8SNickeau * 93*37748cd8SNickeau * @param ATNState $s The ATN state. 94*37748cd8SNickeau * @param ATNState|null $stopState The ATN state to stop at. This can be 95*37748cd8SNickeau * a {@see BlockEndState} to detect 96*37748cd8SNickeau * epsilon paths through a closure. 97*37748cd8SNickeau * @param RuleContext|null $context The complete parser context, or `null` 98*37748cd8SNickeau * if the context should be ignored. 99*37748cd8SNickeau * 100*37748cd8SNickeau * @return IntervalSet The set of tokens that can follow `s` in the ATN 101*37748cd8SNickeau * in the specified `context`. 102*37748cd8SNickeau */ 103*37748cd8SNickeau public function look(ATNState $s, ?ATNState $stopState, ?RuleContext $context) : IntervalSet 104*37748cd8SNickeau { 105*37748cd8SNickeau $r = new IntervalSet(); 106*37748cd8SNickeau $seeThruPreds = true;// ignore preds; get all lookahead 107*37748cd8SNickeau 108*37748cd8SNickeau $lookContext = $context !== null && $s->atn !== null ? 109*37748cd8SNickeau PredictionContext::fromRuleContext($s->atn, $context) : 110*37748cd8SNickeau null; 111*37748cd8SNickeau 112*37748cd8SNickeau $this->lookRecursively( 113*37748cd8SNickeau $s, 114*37748cd8SNickeau $stopState, 115*37748cd8SNickeau $lookContext, 116*37748cd8SNickeau $r, 117*37748cd8SNickeau new Set(), 118*37748cd8SNickeau new BitSet(), 119*37748cd8SNickeau $seeThruPreds, 120*37748cd8SNickeau true 121*37748cd8SNickeau ); 122*37748cd8SNickeau 123*37748cd8SNickeau return $r; 124*37748cd8SNickeau } 125*37748cd8SNickeau 126*37748cd8SNickeau /** 127*37748cd8SNickeau * Compute set of tokens that can follow `s` in the ATN in the 128*37748cd8SNickeau * specified `context`. 129*37748cd8SNickeau * 130*37748cd8SNickeau * If `context` is `null` and `stopState` or the end of the 131*37748cd8SNickeau * rule containing `s` is reached, {@see Token::EPSILON} is added to 132*37748cd8SNickeau * the result set. If `context` is not `null` and `addEOF` is 133*37748cd8SNickeau * `true` and `stopState` or the end of the outermost rule is 134*37748cd8SNickeau * reached, {@see Token::EOF} is added to the result set. 135*37748cd8SNickeau * 136*37748cd8SNickeau * @param ATNState $s The ATN state. 137*37748cd8SNickeau * @param ATNState|null $stopState The ATN state to stop at. 138*37748cd8SNickeau * This can be a 139*37748cd8SNickeau * {@see BlockEndState} to 140*37748cd8SNickeau * detect epsilon paths 141*37748cd8SNickeau * through a closure. 142*37748cd8SNickeau * @param PredictionContext|null $context The outer context, or `null` 143*37748cd8SNickeau * if the outer context should 144*37748cd8SNickeau * not be used. 145*37748cd8SNickeau * @param IntervalSet $look The result lookahead set. 146*37748cd8SNickeau * @param Set $lookBusy A set used for preventing 147*37748cd8SNickeau * epsilon closures in the ATN 148*37748cd8SNickeau * from causing a stack overflow. 149*37748cd8SNickeau * Outside code should pass 150*37748cd8SNickeau * `new Set<ATNConfig>}` for 151*37748cd8SNickeau * this argument. 152*37748cd8SNickeau * @param BitSet $calledRuleStack A set used for preventing 153*37748cd8SNickeau * left recursion in the ATN 154*37748cd8SNickeau * from causing a stack overflow. 155*37748cd8SNickeau * Outside code should pass 156*37748cd8SNickeau * `new BitSet()` for 157*37748cd8SNickeau * this argument. 158*37748cd8SNickeau * @param bool $seeThruPreds `true` to true semantic 159*37748cd8SNickeau * predicates as implicitly 160*37748cd8SNickeau * `true` and "see through them", 161*37748cd8SNickeau * otherwise `false` to treat 162*37748cd8SNickeau * semantic predicates as 163*37748cd8SNickeau * opaque and add 164*37748cd8SNickeau * {@see self::HIT_PRED} to 165*37748cd8SNickeau * the result if one is 166*37748cd8SNickeau * encountered. 167*37748cd8SNickeau * @param bool $addEOF Add {@see Token::EOF} to 168*37748cd8SNickeau * the result if the end of 169*37748cd8SNickeau * the outermost context is 170*37748cd8SNickeau * reached. This parameter 171*37748cd8SNickeau * has no effect if `context` 172*37748cd8SNickeau * is `null`. 173*37748cd8SNickeau */ 174*37748cd8SNickeau protected function lookRecursively( 175*37748cd8SNickeau ATNState $s, 176*37748cd8SNickeau ?ATNState $stopState, 177*37748cd8SNickeau ?PredictionContext $context, 178*37748cd8SNickeau IntervalSet $look, 179*37748cd8SNickeau Set $lookBusy, 180*37748cd8SNickeau BitSet $calledRuleStack, 181*37748cd8SNickeau bool $seeThruPreds, 182*37748cd8SNickeau bool $addEOF 183*37748cd8SNickeau ) : void { 184*37748cd8SNickeau $c = new ATNConfig(null, $s, $context, null, 0); 185*37748cd8SNickeau 186*37748cd8SNickeau if (!$lookBusy->add($c)) { 187*37748cd8SNickeau return; 188*37748cd8SNickeau } 189*37748cd8SNickeau 190*37748cd8SNickeau if ($stopState !== null && $s->equals($stopState)) { 191*37748cd8SNickeau if ($context === null) { 192*37748cd8SNickeau $look->addOne(Token::EPSILON); 193*37748cd8SNickeau 194*37748cd8SNickeau return; 195*37748cd8SNickeau } 196*37748cd8SNickeau 197*37748cd8SNickeau if ($context->isEmpty() && $addEOF) { 198*37748cd8SNickeau $look->addOne(Token::EOF); 199*37748cd8SNickeau 200*37748cd8SNickeau return; 201*37748cd8SNickeau } 202*37748cd8SNickeau } 203*37748cd8SNickeau 204*37748cd8SNickeau if ($s instanceof RuleStopState) { 205*37748cd8SNickeau if ($context === null) { 206*37748cd8SNickeau $look->addOne(Token::EPSILON); 207*37748cd8SNickeau 208*37748cd8SNickeau return; 209*37748cd8SNickeau } 210*37748cd8SNickeau 211*37748cd8SNickeau if ($context->isEmpty() && $addEOF) { 212*37748cd8SNickeau $look->addOne(Token::EOF); 213*37748cd8SNickeau 214*37748cd8SNickeau return; 215*37748cd8SNickeau } 216*37748cd8SNickeau 217*37748cd8SNickeau if ($context !== PredictionContext::empty()) { 218*37748cd8SNickeau // run thru all possible stack tops in ctx 219*37748cd8SNickeau $removed = $calledRuleStack->contains($s->ruleIndex); 220*37748cd8SNickeau 221*37748cd8SNickeau try { 222*37748cd8SNickeau $calledRuleStack->remove($s->ruleIndex); 223*37748cd8SNickeau for ($i = 0; $i < $context->getLength(); $i++) { 224*37748cd8SNickeau $returnState = $this->atn->states[$context->getReturnState($i)]; 225*37748cd8SNickeau $this->lookRecursively( 226*37748cd8SNickeau $returnState, 227*37748cd8SNickeau $stopState, 228*37748cd8SNickeau $context->getParent($i), 229*37748cd8SNickeau $look, 230*37748cd8SNickeau $lookBusy, 231*37748cd8SNickeau $calledRuleStack, 232*37748cd8SNickeau $seeThruPreds, 233*37748cd8SNickeau $addEOF 234*37748cd8SNickeau ); 235*37748cd8SNickeau } 236*37748cd8SNickeau } finally { 237*37748cd8SNickeau if ($removed) { 238*37748cd8SNickeau $calledRuleStack->add($s->ruleIndex); 239*37748cd8SNickeau } 240*37748cd8SNickeau } 241*37748cd8SNickeau 242*37748cd8SNickeau return; 243*37748cd8SNickeau } 244*37748cd8SNickeau } 245*37748cd8SNickeau 246*37748cd8SNickeau /** @var Transition $t */ 247*37748cd8SNickeau foreach ($s->getTransitions() as $t) { 248*37748cd8SNickeau if ($t instanceof RuleTransition) { 249*37748cd8SNickeau if ($calledRuleStack->contains($t->target->ruleIndex)) { 250*37748cd8SNickeau continue; 251*37748cd8SNickeau } 252*37748cd8SNickeau 253*37748cd8SNickeau $newContext = SingletonPredictionContext::create($context, $t->followState->stateNumber); 254*37748cd8SNickeau 255*37748cd8SNickeau try { 256*37748cd8SNickeau $calledRuleStack->add($t->target->ruleIndex); 257*37748cd8SNickeau $this->lookRecursively( 258*37748cd8SNickeau $t->target, 259*37748cd8SNickeau $stopState, 260*37748cd8SNickeau $newContext, 261*37748cd8SNickeau $look, 262*37748cd8SNickeau $lookBusy, 263*37748cd8SNickeau $calledRuleStack, 264*37748cd8SNickeau $seeThruPreds, 265*37748cd8SNickeau $addEOF 266*37748cd8SNickeau ); 267*37748cd8SNickeau } finally { 268*37748cd8SNickeau $calledRuleStack->remove($t->target->ruleIndex); 269*37748cd8SNickeau } 270*37748cd8SNickeau } elseif ($t instanceof AbstractPredicateTransition) { 271*37748cd8SNickeau if ($seeThruPreds) { 272*37748cd8SNickeau $this->lookRecursively( 273*37748cd8SNickeau $t->target, 274*37748cd8SNickeau $stopState, 275*37748cd8SNickeau $context, 276*37748cd8SNickeau $look, 277*37748cd8SNickeau $lookBusy, 278*37748cd8SNickeau $calledRuleStack, 279*37748cd8SNickeau $seeThruPreds, 280*37748cd8SNickeau $addEOF 281*37748cd8SNickeau ); 282*37748cd8SNickeau } else { 283*37748cd8SNickeau $look->addOne(self::HIT_PRED); 284*37748cd8SNickeau } 285*37748cd8SNickeau } elseif ($t->isEpsilon()) { 286*37748cd8SNickeau $this->lookRecursively( 287*37748cd8SNickeau $t->target, 288*37748cd8SNickeau $stopState, 289*37748cd8SNickeau $context, 290*37748cd8SNickeau $look, 291*37748cd8SNickeau $lookBusy, 292*37748cd8SNickeau $calledRuleStack, 293*37748cd8SNickeau $seeThruPreds, 294*37748cd8SNickeau $addEOF 295*37748cd8SNickeau ); 296*37748cd8SNickeau } elseif ($t instanceof WildcardTransition) { 297*37748cd8SNickeau $look->addRange(Token::MIN_USER_TOKEN_TYPE, $this->atn->maxTokenType); 298*37748cd8SNickeau } else { 299*37748cd8SNickeau $set = $t->label(); 300*37748cd8SNickeau 301*37748cd8SNickeau if ($set !== null) { 302*37748cd8SNickeau if ($t instanceof NotSetTransition) { 303*37748cd8SNickeau $set = $set->complement(IntervalSet::fromRange( 304*37748cd8SNickeau Token::MIN_USER_TOKEN_TYPE, 305*37748cd8SNickeau $this->atn->maxTokenType 306*37748cd8SNickeau )); 307*37748cd8SNickeau } 308*37748cd8SNickeau 309*37748cd8SNickeau if ($set !== null) { 310*37748cd8SNickeau $look->addSet($set); 311*37748cd8SNickeau } 312*37748cd8SNickeau } 313*37748cd8SNickeau } 314*37748cd8SNickeau } 315*37748cd8SNickeau } 316*37748cd8SNickeau} 317