1<?php 2 3declare(strict_types=1); 4 5namespace Antlr\Antlr4\Runtime\Atn; 6 7use Antlr\Antlr4\Runtime\Atn\Actions\LexerAction; 8use Antlr\Antlr4\Runtime\Atn\Actions\LexerActionType; 9use Antlr\Antlr4\Runtime\Atn\Actions\LexerChannelAction; 10use Antlr\Antlr4\Runtime\Atn\Actions\LexerCustomAction; 11use Antlr\Antlr4\Runtime\Atn\Actions\LexerModeAction; 12use Antlr\Antlr4\Runtime\Atn\Actions\LexerMoreAction; 13use Antlr\Antlr4\Runtime\Atn\Actions\LexerPopModeAction; 14use Antlr\Antlr4\Runtime\Atn\Actions\LexerPushModeAction; 15use Antlr\Antlr4\Runtime\Atn\Actions\LexerSkipAction; 16use Antlr\Antlr4\Runtime\Atn\Actions\LexerTypeAction; 17use Antlr\Antlr4\Runtime\Atn\States\ATNState; 18use Antlr\Antlr4\Runtime\Atn\States\BasicBlockStartState; 19use Antlr\Antlr4\Runtime\Atn\States\BasicState; 20use Antlr\Antlr4\Runtime\Atn\States\BlockEndState; 21use Antlr\Antlr4\Runtime\Atn\States\BlockStartState; 22use Antlr\Antlr4\Runtime\Atn\States\DecisionState; 23use Antlr\Antlr4\Runtime\Atn\States\LoopEndState; 24use Antlr\Antlr4\Runtime\Atn\States\PlusBlockStartState; 25use Antlr\Antlr4\Runtime\Atn\States\PlusLoopbackState; 26use Antlr\Antlr4\Runtime\Atn\States\RuleStartState; 27use Antlr\Antlr4\Runtime\Atn\States\RuleStopState; 28use Antlr\Antlr4\Runtime\Atn\States\StarBlockStartState; 29use Antlr\Antlr4\Runtime\Atn\States\StarLoopbackState; 30use Antlr\Antlr4\Runtime\Atn\States\StarLoopEntryState; 31use Antlr\Antlr4\Runtime\Atn\States\TokensStartState; 32use Antlr\Antlr4\Runtime\Atn\Transitions\ActionTransition; 33use Antlr\Antlr4\Runtime\Atn\Transitions\AtomTransition; 34use Antlr\Antlr4\Runtime\Atn\Transitions\EpsilonTransition; 35use Antlr\Antlr4\Runtime\Atn\Transitions\NotSetTransition; 36use Antlr\Antlr4\Runtime\Atn\Transitions\PrecedencePredicateTransition; 37use Antlr\Antlr4\Runtime\Atn\Transitions\PredicateTransition; 38use Antlr\Antlr4\Runtime\Atn\Transitions\RangeTransition; 39use Antlr\Antlr4\Runtime\Atn\Transitions\RuleTransition; 40use Antlr\Antlr4\Runtime\Atn\Transitions\SetTransition; 41use Antlr\Antlr4\Runtime\Atn\Transitions\Transition; 42use Antlr\Antlr4\Runtime\Atn\Transitions\WildcardTransition; 43use Antlr\Antlr4\Runtime\IntervalSet; 44use Antlr\Antlr4\Runtime\Token; 45use Antlr\Antlr4\Runtime\Utils\StringUtils; 46 47final class ATNDeserializer 48{ 49 /** 50 * This value should never change. Updates following this version are 51 * reflected as change in the unique ID SERIALIZED_UUID. 52 */ 53 public const SERIALIZED_VERSION = 3; 54 55 /** 56 * This is the earliest supported serialized UUID. 57 * Stick to serialized version for now, we don't need a UUID instance. 58 */ 59 private const BASE_SERIALIZED_UUID = 'AADB8D7E-AEEF-4415-AD2B-8204D6CF042E'; 60 61 /** 62 * This UUID indicates the serialized ATN contains two sets of IntervalSets, 63 * where the second set's values are encoded as 32-bit integers to support 64 * the full Unicode SMP range up to U+10FFFF. 65 */ 66 private const ADDED_UNICODE_SMP = '59627784-3BE5-417A-B9EB-8131A7286089'; 67 68 /** 69 * This list contains all of the currently supported UUIDs, ordered by when 70 * the feature first appeared in this branch. 71 */ 72 private const SUPPORTED_UUIDS = [ 73 self::BASE_SERIALIZED_UUID, 74 self::ADDED_UNICODE_SMP, 75 ]; 76 77 /** 78 * This is the current serialized UUID. 79 */ 80 private const SERIALIZED_UUID = self::ADDED_UNICODE_SMP; 81 82 /** @var ATNDeserializationOptions */ 83 private $deserializationOptions; 84 85 /** @var array<int> */ 86 private $data = []; 87 88 /** @var int */ 89 private $pos = 0; 90 91 /** @var string */ 92 private $uuid = ''; 93 94 /** @var array<int, callable|null>|null */ 95 private $stateFactories; 96 97 /** @var array<int, callable|null>|null */ 98 private $actionFactories; 99 100 public function __construct(?ATNDeserializationOptions $options = null) 101 { 102 $this->deserializationOptions = $options ?? ATNDeserializationOptions::defaultOptions(); 103 } 104 105 /** 106 * Determines if a particular serialized representation of an ATN supports 107 * a particular feature, identified by the {@see UUID} used for serializing 108 * the ATN at the time the feature was first introduced. 109 * 110 * @param string $feature The {@see UUID} marking the first time the 111 * feature was supported in the serialized ATN. 112 * @param string $actualUuid The {@see UUID} of the actual serialized ATN 113 * which is currently being deserialized. 114 * 115 * @return bool `true` if the `actualUuid` value represents a serialized 116 * ATN at or after the feature identified by `feature` was 117 * introduced; otherwise, `false`. 118 */ 119 protected function isFeatureSupported(string $feature, string $actualUuid) : bool 120 { 121 $featureIndex = \array_search($feature, self::SUPPORTED_UUIDS, true); 122 123 if ($featureIndex === false) { 124 return false; 125 } 126 127 $actualUuidIndex = \array_search($actualUuid, self::SUPPORTED_UUIDS, true); 128 129 return $actualUuidIndex >= $featureIndex; 130 } 131 132 public function deserialize(string $data) : ATN 133 { 134 $this->reset($data); 135 $this->checkVersion(); 136 $this->checkUUID(); 137 $atn = $this->readATN(); 138 $this->readStates($atn); 139 $this->readRules($atn); 140 $this->readModes($atn); 141 $sets = []; 142 143 // First, deserialize sets with 16-bit arguments <= U+FFFF. 144 $this->readSets($sets, function () { 145 return $this->readInt(); 146 }); 147 148 // Next, if the ATN was serialized with the Unicode SMP feature, 149 // deserialize sets with 32-bit arguments <= U+10FFFF. 150 151 if ($this->isFeatureSupported(self::ADDED_UNICODE_SMP, $this->uuid)) { 152 $this->readSets($sets, function () { 153 return $this->readInt32(); 154 }); 155 } 156 157 $this->readEdges($atn, $sets); 158 $this->readDecisions($atn); 159 $this->readLexerActions($atn); 160 $this->markPrecedenceDecisions($atn); 161 $this->verifyATN($atn); 162 163 if ($atn->grammarType === ATN::ATN_TYPE_PARSER 164 && $this->deserializationOptions->isGenerateRuleBypassTransitions()) { 165 $this->generateRuleBypassTransitions($atn); 166 // re-verify after modification 167 $this->verifyATN($atn); 168 } 169 170 return $atn; 171 } 172 173 private function reset(string $data) : void 174 { 175 $characters = \preg_split('//u', $data, -1, \PREG_SPLIT_NO_EMPTY); 176 177 if ($characters === false) { 178 return; 179 } 180 181 $this->data = [StringUtils::codePoint($characters[0])]; 182 for ($i = 1, $length = \count($characters); $i < $length; $i++) { 183 $code = StringUtils::codePoint($characters[$i]); 184 $this->data[] = $code > 1 ? $code - 2 : $code + 65533; 185 } 186 187 $this->pos = 0; 188 } 189 190 191 private function checkVersion() : void 192 { 193 $version = $this->readInt(); 194 195 if ($version !== self::SERIALIZED_VERSION) { 196 throw new \InvalidArgumentException(\sprintf( 197 'Could not deserialize ATN with version %d (expected %d).', 198 $version, 199 self::SERIALIZED_VERSION 200 )); 201 } 202 } 203 204 private function checkUUID() : void 205 { 206 $uuid = $this->readUUID(); 207 208 if (!\in_array($uuid, self::SUPPORTED_UUIDS, true)) { 209 throw new \InvalidArgumentException(\sprintf( 210 'Could not deserialize ATN with UUID: %s (expected %s or a legacy UUID).', 211 $uuid, 212 self::SERIALIZED_UUID 213 )); 214 } 215 216 $this->uuid = $uuid; 217 } 218 219 private function readATN() : ATN 220 { 221 $grammarType = $this->readInt(); 222 $maxTokenType = $this->readInt(); 223 224 return new ATN($grammarType, $maxTokenType); 225 } 226 227 private function readStates(ATN $atn) : void 228 { 229 $loopBackStateNumbers = []; 230 $endStateNumbers = []; 231 $nstates = $this->readInt(); 232 233 for ($i=0; $i < $nstates; $i++) { 234 $stype = $this->readInt(); 235 236 // ignore bad type of states 237 if ($stype === ATNState::INVALID_TYPE) { 238 $atn->addState(null); 239 240 continue; 241 } 242 243 $ruleIndex = $this->readInt(); 244 245 if ($ruleIndex === 0xFFFF) { 246 $ruleIndex = -1; 247 } 248 249 $s = $this->stateFactory($stype, $ruleIndex); 250 251 if ($stype === ATNState::LOOP_END) { 252 // special case 253 $loopBackStateNumber = $this->readInt(); 254 255 if (!$s instanceof LoopEndState) { 256 throw new \RuntimeException('Unexpected ATN State'); 257 } 258 259 $loopBackStateNumbers[] = [$s, $loopBackStateNumber]; 260 } elseif ($s instanceof BlockStartState) { 261 $endStateNumber = $this->readInt(); 262 263 $endStateNumbers[] = [$s, $endStateNumber]; 264 } 265 266 $atn->addState($s); 267 } 268 269 // delay the assignment of loop back and end states until we know all the 270 // state instances have been initialized 271 foreach ($loopBackStateNumbers as $pair) { 272 $pair[0]->loopBackState = $atn->states[$pair[1]]; 273 } 274 275 foreach ($endStateNumbers as $pair) { 276 $endState = $atn->states[$pair[1]]; 277 278 if (!$endState instanceof BlockEndState) { 279 throw new \RuntimeException('Unexpected ATN State'); 280 } 281 282 $pair[0]->endState = $endState; 283 } 284 285 $numNonGreedyStates = $this->readInt(); 286 287 for ($j=0; $j < $numNonGreedyStates; $j++) { 288 $decisionState = $atn->states[$this->readInt()]; 289 290 if (!$decisionState instanceof DecisionState) { 291 throw new \RuntimeException('Unexpected ATN State'); 292 } 293 294 $decisionState->nonGreedy = true; 295 } 296 297 $numPrecedenceStates = $this->readInt(); 298 299 for ($j=0; $j < $numPrecedenceStates; $j++) { 300 $ruleStartState = $atn->states[$this->readInt()]; 301 302 if (!$ruleStartState instanceof RuleStartState) { 303 throw new \RuntimeException('Unexpected ATN State'); 304 } 305 306 $ruleStartState->isLeftRecursiveRule = true; 307 } 308 } 309 310 private function readRules(ATN $atn) : void 311 { 312 $nRules = $this->readInt(); 313 314 $atn->ruleToTokenType = []; 315 $atn->ruleToStartState = []; 316 for ($i=0; $i < $nRules; $i++) { 317 $s = $this->readInt(); 318 $startState = $atn->states[$s]; 319 320 if (!$startState instanceof RuleStartState) { 321 throw new \RuntimeException('Unexpected ATN State'); 322 } 323 324 $atn->ruleToStartState[$i] = $startState; 325 326 if ($atn->grammarType === ATN::ATN_TYPE_LEXER) { 327 $tokenType = $this->readInt(); 328 329 if ($tokenType === 0xFFFF) { 330 $tokenType = Token::EOF; 331 } 332 333 $atn->ruleToTokenType[$i] = $tokenType; 334 } 335 } 336 337 $atn->ruleToStopState = []; 338 foreach ($atn->states as $state) { 339 if (!$state instanceof RuleStopState) { 340 continue; 341 } 342 343 $atn->ruleToStopState[$state->ruleIndex] = $state; 344 $atn->ruleToStartState[$state->ruleIndex]->stopState = $state; 345 } 346 } 347 348 private function readModes(ATN $atn) : void 349 { 350 $nmodes = $this->readInt(); 351 352 for ($i=0; $i < $nmodes; $i++) { 353 $tokensStartState = $atn->states[$this->readInt()]; 354 355 if (!$tokensStartState instanceof TokensStartState) { 356 throw new \RuntimeException('Unexpected ATN State'); 357 } 358 359 $atn->modeToStartState[] = $tokensStartState; 360 } 361 } 362 363 /** 364 * @param array<IntervalSet> $sets 365 */ 366 private function readSets(array &$sets, callable $readUnicode) : void 367 { 368 $m = $this->readInt(); 369 370 for ($i=0; $i < $m; $i++) { 371 $iset = new IntervalSet(); 372 373 $sets[] = $iset; 374 $n = $this->readInt(); 375 $containsEof = $this->readInt(); 376 377 if ($containsEof !== 0) { 378 $iset->addOne(-1); 379 } 380 381 for ($j=0; $j < $n; $j++) { 382 $i1 = $readUnicode(); 383 $i2 = $readUnicode(); 384 $iset->addRange($i1, $i2); 385 } 386 } 387 } 388 389 /** 390 * @param array<IntervalSet> $sets 391 */ 392 private function readEdges(ATN $atn, array &$sets) : void 393 { 394 $nEdges = $this->readInt(); 395 396 for ($i=0; $i < $nEdges; $i++) { 397 $src = $this->readInt(); 398 $trg = $this->readInt(); 399 $ttype = $this->readInt(); 400 $arg1 = $this->readInt(); 401 $arg2 = $this->readInt(); 402 $arg3 = $this->readInt(); 403 $trans = $this->edgeFactory($atn, $ttype, $src, $trg, $arg1, $arg2, $arg3, $sets); 404 $srcState = $atn->states[$src]; 405 $srcState->addTransition($trans); 406 } 407 408 // edges for rule stop states can be derived, so they aren't serialized 409 foreach ($atn->states as $state) { 410 foreach ($state->getTransitions() as $t) { 411 if (!$t instanceof RuleTransition) { 412 continue; 413 } 414 415 $outermostPrecedenceReturn = -1; 416 if ($atn->ruleToStartState[$t->target->ruleIndex]->isLeftRecursiveRule) { 417 if ($t->precedence === 0) { 418 $outermostPrecedenceReturn = $t->target->ruleIndex; 419 } 420 } 421 422 $trans = new EpsilonTransition($t->followState, $outermostPrecedenceReturn); 423 $atn->ruleToStopState[$t->target->ruleIndex]->addTransition($trans); 424 } 425 } 426 427 foreach ($atn->states as $state) { 428 if ($state instanceof BlockStartState) { 429 // we need to know the end state to set its start state 430 if ($state->endState === null) { 431 throw new \RuntimeException('Unexpected null EndState.'); 432 } 433 434 // block end states can only be associated to a single block start state 435 if ($state->endState->startState !== null) { 436 throw new \RuntimeException('Unexpected null StartState.'); 437 } 438 439 $state->endState->startState = $state; 440 } 441 442 if ($state instanceof PlusLoopbackState) { 443 foreach ($state->getTransitions() as $t) { 444 $target = $t->target; 445 446 if ($target instanceof PlusBlockStartState) { 447 $target->loopBackState = $state; 448 } 449 } 450 } elseif ($state instanceof StarLoopbackState) { 451 foreach ($state->getTransitions() as $t) { 452 $target = $t->target; 453 454 if ($target instanceof StarLoopEntryState) { 455 $target->loopBackState = $state; 456 } 457 } 458 } 459 } 460 } 461 462 private function readDecisions(ATN $atn) : void 463 { 464 $decisions = $this->readInt(); 465 466 for ($i = 0; $i < $decisions; $i++) { 467 $s = $this->readInt(); 468 /** @var DecisionState $decState */ 469 $decState = $atn->states[$s]; 470 471 $atn->decisionToState[] = $decState; 472 473 $decState->decision = $i; 474 } 475 } 476 477 private function readLexerActions(ATN $atn) : void 478 { 479 if ($atn->grammarType === ATN::ATN_TYPE_LEXER) { 480 $count = $this->readInt(); 481 482 $atn->lexerActions = []; 483 for ($i = 0; $i < $count; $i++) { 484 $actionType = $this->readInt(); 485 $data1 = $this->readInt(); 486 487 if ($data1 === 0xFFFF) { 488 $data1 = -1; 489 } 490 491 $data2 = $this->readInt(); 492 493 if ($data2 === 0xFFFF) { 494 $data2 = -1; 495 } 496 497 $lexerAction = $this->lexerActionFactory($actionType, $data1, $data2); 498 $atn->lexerActions[$i] = $lexerAction; 499 } 500 } 501 } 502 503 private function generateRuleBypassTransitions(ATN $atn) : void 504 { 505 $count = \count($atn->ruleToStartState); 506 507 for ($i = 0; $i < $count; $i++) { 508 $atn->ruleToTokenType[$i] = $atn->maxTokenType + $i + 1; 509 } 510 511 for ($i = 0; $i < $count; $i++) { 512 $this->generateRuleBypassTransition($atn, $i); 513 } 514 } 515 516 private function generateRuleBypassTransition(ATN $atn, int $idx) : void 517 { 518 $bypassStart = new BasicBlockStartState(); 519 $bypassStart->ruleIndex = $idx; 520 $atn->addState($bypassStart); 521 522 $bypassStop = new BlockEndState(); 523 $bypassStop->ruleIndex = $idx; 524 $atn->addState($bypassStop); 525 526 $bypassStart->endState = $bypassStop; 527 $atn->defineDecisionState($bypassStart); 528 529 $bypassStop->startState = $bypassStart; 530 531 $excludeTransition = null; 532 if ($atn->ruleToStartState[$idx]->isLeftRecursiveRule) { 533 // wrap from the beginning of the rule to the StarLoopEntryState 534 $endState = null; 535 536 foreach ($atn->states as $state) { 537 if ($this->stateIsEndStateFor($state, $idx)) { 538 $endState = $state; 539 540 if (!$state instanceof LoopEndState) { 541 throw new \RuntimeException('Unexpected state type.'); 542 } 543 544 if ($state->loopBackState === null) { 545 throw new \RuntimeException('Unexpected null loop back state.'); 546 } 547 548 $excludeTransition = $state->loopBackState->getTransition(0); 549 550 break; 551 } 552 } 553 554 if ($excludeTransition === null) { 555 throw new \RuntimeException('Couldn\'t identify final state of the precedence rule prefix section.'); 556 } 557 } else { 558 $endState = $atn->ruleToStopState[$idx]; 559 } 560 561 // all non-excluded transitions that currently target end state need to target blockEnd instead 562 // TODO:looks like a bug 563 foreach ($atn->states as $state) { 564 foreach ($state->getTransitions() as $transition) { 565 if ($excludeTransition !== null && $transition->equals($excludeTransition)) { 566 continue; 567 } 568 569 if ($endState !== null && $transition->target->equals($endState)) { 570 $transition->target = $bypassStop; 571 } 572 } 573 } 574 575 // all transitions leaving the rule start state need to leave blockStart instead 576 $ruleToStartState = $atn->ruleToStartState[$idx]; 577 $count = $ruleToStartState->getNumberOfTransitions(); 578 579 while ($count > 0) { 580 $bypassStart->addTransition($ruleToStartState->getTransition($count-1)); 581 $ruleToStartState->setTransitions(\array_slice($ruleToStartState->getTransitions(), -1)); 582 } 583 584 // link the new states 585 $atn->ruleToStartState[$idx]->addTransition(new EpsilonTransition($bypassStart)); 586 587 if ($endState === null) { 588 throw new \RuntimeException('Unexpected null end state.'); 589 } 590 591 $bypassStop->addTransition(new EpsilonTransition($endState)); 592 593 $matchState = new BasicState(); 594 $atn->addState($matchState); 595 $matchState->addTransition(new AtomTransition($bypassStop, $atn->ruleToTokenType[$idx] ?? 0)); 596 $bypassStart->addTransition(new EpsilonTransition($matchState)); 597 } 598 599 private function stateIsEndStateFor(ATNState $state, int $idx) : ?ATNState 600 { 601 if ($state->ruleIndex !== $idx) { 602 return null; 603 } 604 605 if (!$state instanceof StarLoopEntryState) { 606 return null; 607 } 608 609 $maybeLoopEndState = $state->getTransition($state->getNumberOfTransitions() - 1)->target; 610 611 if (!$maybeLoopEndState instanceof LoopEndState) { 612 return null; 613 } 614 615 if ($maybeLoopEndState->epsilonOnlyTransitions 616 && $maybeLoopEndState->getTransition(0)->target instanceof RuleStopState) { 617 return $state; 618 } 619 620 return null; 621 } 622 623 /** 624 * Analyze the {@see StarLoopEntryState} states in the specified ATN to set 625 * the {@see StarLoopEntryState::$isPrecedenceDecision} field to the correct 626 * value. 627 * 628 * @param ATN $atn The ATN. 629 */ 630 private function markPrecedenceDecisions(ATN $atn) : void 631 { 632 foreach ($atn->states as $state) { 633 if (!$state instanceof StarLoopEntryState) { 634 continue; 635 } 636 637 // We analyze the ATN to determine if this ATN decision state is the 638 // decision for the closure block that determines whether a 639 // precedence rule should continue or complete. 640 if ($atn->ruleToStartState[$state->ruleIndex]->isLeftRecursiveRule) { 641 $maybeLoopEndState = $state->getTransition($state->getNumberOfTransitions() - 1)->target; 642 643 if ($maybeLoopEndState instanceof LoopEndState) { 644 if ($maybeLoopEndState->epsilonOnlyTransitions 645 && $maybeLoopEndState->getTransition(0)->target instanceof RuleStopState) { 646 $state->isPrecedenceDecision = true; 647 } 648 } 649 } 650 } 651 } 652 653 private function verifyATN(ATN $atn) : void 654 { 655 if (!$this->deserializationOptions->isVerifyATN()) { 656 return; 657 } 658 659 // verify assumptions 660 foreach ($atn->states as $state) { 661 $this->checkCondition($state->epsilonOnlyTransitions || $state->getNumberOfTransitions() <= 1); 662 663 switch (true) { 664 case $state instanceof PlusBlockStartState: 665 $this->checkCondition($state->loopBackState !== null); 666 667 break; 668 669 case $state instanceof StarLoopEntryState: 670 $this->checkCondition($state->loopBackState !== null); 671 $this->checkCondition($state->getNumberOfTransitions() === 2); 672 673 if ($state->getTransition(0)->target instanceof StarBlockStartState) { 674 $this->checkCondition($state->getTransition(1)->target instanceof LoopEndState); 675 $this->checkCondition(!$state->nonGreedy); 676 } elseif ($state->getTransition(0)->target instanceof LoopEndState) { 677 $this->checkCondition($state->getTransition(1)->target instanceof StarBlockStartState); 678 $this->checkCondition($state->nonGreedy); 679 } else { 680 throw new \InvalidArgumentException('IllegalState'); 681 } 682 683 break; 684 685 case $state instanceof StarLoopbackState: 686 $this->checkCondition($state->getNumberOfTransitions() === 1); 687 $this->checkCondition($state->getTransition(0)->target instanceof StarLoopEntryState); 688 689 break; 690 691 case $state instanceof LoopEndState: 692 $this->checkCondition($state->loopBackState !== null); 693 694 break; 695 696 case $state instanceof RuleStartState: 697 $this->checkCondition($state->stopState !== null); 698 699 break; 700 701 case $state instanceof BlockStartState: 702 $this->checkCondition($state->endState !== null); 703 704 break; 705 706 case $state instanceof BlockEndState: 707 $this->checkCondition($state->startState !== null); 708 709 break; 710 711 case $state instanceof DecisionState: 712 $this->checkCondition($state->getNumberOfTransitions() <= 1 || $state->decision >= 0); 713 714 break; 715 716 default: 717 $this->checkCondition($state->getNumberOfTransitions() <= 1 || $state instanceof RuleStopState); 718 } 719 } 720 } 721 722 private function checkCondition(?bool $condition, $message = 'IllegalState') : void 723 { 724 if ($condition === null) { 725 throw new \InvalidArgumentException($message); 726 } 727 } 728 729 private function readInt() : int 730 { 731 return $this->data[$this->pos++]; 732 } 733 734 private function readInt32() : int 735 { 736 $low = $this->readInt(); 737 $high = $this->readInt(); 738 739 return $low | ($high << 16); 740 } 741 742 private function readUUID() : string 743 { 744 $bb = []; 745 for ($i=0; $i < 8; $i++) { 746 $int = $this->readInt(); 747 $bb[] = $int & 0xFF; 748 $bb[] = ($int >> 8) & 0xFF; 749 } 750 751 $bb = \array_reverse($bb); 752 $hex = \strtoupper(\bin2hex(\implode(\array_map('chr', $bb)))); 753 754 return \vsprintf('%s%s-%s-%s-%s-%s%s%s', \str_split($hex, 4)); 755 } 756 757 /** 758 * @param array<IntervalSet> $sets 759 */ 760 private function edgeFactory( 761 ATN $atn, 762 int $type, 763 int $src, 764 int $trg, 765 int $arg1, 766 int $arg2, 767 int $arg3, 768 array $sets 769 ) : Transition { 770 $target = $atn->states[$trg]; 771 772 switch ($type) { 773 case Transition::EPSILON: 774 return new EpsilonTransition($target); 775 776 case Transition::RANGE: 777 return $arg3 !== 0 ? 778 new RangeTransition($target, Token::EOF, $arg2) : 779 new RangeTransition($target, $arg1, $arg2); 780 781 case Transition::RULE: 782 $ruleStart = $atn->states[$arg1]; 783 784 if (!$ruleStart instanceof RuleStartState) { 785 throw new \RuntimeException('Unexpected transition type.'); 786 } 787 788 return new RuleTransition($ruleStart, $arg2, $arg3, $target); 789 790 case Transition::PREDICATE: 791 return new PredicateTransition($target, $arg1, $arg2, $arg3 !== 0); 792 793 case Transition::PRECEDENCE: 794 return new PrecedencePredicateTransition($target, $arg1); 795 796 case Transition::ATOM: 797 return $arg3 !== 0 ? new AtomTransition($target, Token::EOF) : new AtomTransition($target, $arg1); 798 799 case Transition::ACTION: 800 return new ActionTransition($target, $arg1, $arg2, $arg3 !== 0); 801 802 case Transition::SET: 803 return new SetTransition($target, $sets[$arg1]); 804 805 case Transition::NOT_SET: 806 return new NotSetTransition($target, $sets[$arg1]); 807 808 case Transition::WILDCARD: 809 return new WildcardTransition($target); 810 811 default: 812 throw new \InvalidArgumentException(\sprintf( 813 'The specified transition type: %d is not valid.', 814 $type 815 )); 816 } 817 } 818 819 private function stateFactory(int $type, int $ruleIndex) : ?ATNState 820 { 821 switch ($type) { 822 case ATNState::INVALID_TYPE: 823 return null; 824 825 case ATNState::BASIC: 826 $s = new BasicState(); 827 828 break; 829 830 case ATNState::RULE_START: 831 $s = new RuleStartState(); 832 833 break; 834 835 case ATNState::BLOCK_START: 836 $s = new BasicBlockStartState(); 837 838 break; 839 840 case ATNState::PLUS_BLOCK_START: 841 $s = new PlusBlockStartState(); 842 843 break; 844 845 case ATNState::STAR_BLOCK_START: 846 $s = new StarBlockStartState(); 847 848 break; 849 850 case ATNState::TOKEN_START: 851 $s = new TokensStartState(); 852 853 break; 854 855 case ATNState::RULE_STOP: 856 $s = new RuleStopState(); 857 858 break; 859 860 case ATNState::BLOCK_END: 861 $s = new BlockEndState(); 862 863 break; 864 865 case ATNState::STAR_LOOP_BACK: 866 $s = new StarLoopbackState(); 867 868 break; 869 870 case ATNState::STAR_LOOP_ENTRY: 871 $s = new StarLoopEntryState(); 872 873 break; 874 875 case ATNState::PLUS_LOOP_BACK: 876 $s = new PlusLoopbackState(); 877 878 break; 879 880 case ATNState::LOOP_END: 881 $s = new LoopEndState(); 882 883 break; 884 885 default: 886 throw new \InvalidArgumentException(\sprintf( 887 'The specified state type %d is not valid.', 888 $type 889 )); 890 } 891 892 $s->ruleIndex = $ruleIndex; 893 894 return $s; 895 } 896 897 private function lexerActionFactory(int $type, int $data1, int $data2) : LexerAction 898 { 899 switch ($type) { 900 case LexerActionType::CHANNEL: 901 return new LexerChannelAction($data1); 902 903 case LexerActionType::CUSTOM: 904 return new LexerCustomAction($data1, $data2); 905 906 case LexerActionType::MODE: 907 return new LexerModeAction($data1); 908 909 case LexerActionType::MORE: 910 return LexerMoreAction::instance(); 911 912 case LexerActionType::POP_MODE: 913 return LexerPopModeAction::instance(); 914 915 case LexerActionType::PUSH_MODE: 916 return new LexerPushModeAction($data1); 917 918 case LexerActionType::SKIP: 919 return LexerSkipAction::instance(); 920 921 case LexerActionType::TYPE: 922 return new LexerTypeAction($data1); 923 924 default: 925 throw new \InvalidArgumentException(\sprintf( 926 'The specified lexer action type %d is not valid.', 927 $type 928 )); 929 } 930 } 931} 932