1<?php 2 3declare(strict_types=1); 4 5namespace Antlr\Antlr4\Runtime\PredictionContexts; 6 7use Antlr\Antlr4\Runtime\Comparison\Equality; 8use Antlr\Antlr4\Runtime\Comparison\Hasher; 9 10final class ArrayPredictionContext extends PredictionContext 11{ 12 /** 13 * Parent can be null only if full ctx mode and we make an array from 14 * {@see ArrayPredictionContext::empty()} and non-empty. We merge 15 * {@see ArrayPredictionContext::empty()} by using null parent and 16 * returnState === {@see ArrayPredictionContext::EMPTY_RETURN_STATE}. 17 * 18 * @var array<PredictionContext|null> 19 */ 20 public $parents; 21 22 /** 23 * Sorted for merge, no duplicates; if present, 24 * {@see ArrayPredictionContext::EMPTY_RETURN_STATE} is always last. 25 * 26 * @var array<int> 27 */ 28 public $returnStates; 29 30 /** 31 * @param array<PredictionContext|null> $parents 32 * @param array<int> $returnStates 33 */ 34 public function __construct(array $parents, array $returnStates) 35 { 36 parent::__construct(); 37 38 $this->parents = $parents; 39 $this->returnStates = $returnStates; 40 } 41 42 public static function fromOne(SingletonPredictionContext $ctx) : self 43 { 44 return new ArrayPredictionContext([$ctx->parent], [$ctx->returnState]); 45 } 46 47 /** 48 * @param array<PredictionContext|null> $parents 49 */ 50 public function withParents(array $parents) : self 51 { 52 $clone = clone $this; 53 $clone->parents = $parents; 54 55 return $clone; 56 } 57 58 public function isEmpty() : bool 59 { 60 // since EMPTY_RETURN_STATE can only appear in the last position, we don't need to verify that size==1 61 return $this->returnStates[0] === PredictionContext::EMPTY_RETURN_STATE; 62 } 63 64 public function getLength() : int 65 { 66 return \count($this->returnStates); 67 } 68 69 public function getParent(int $index) : ?PredictionContext 70 { 71 return $this->parents[$index]; 72 } 73 74 public function getReturnState(int $index) : int 75 { 76 return $this->returnStates[$index]; 77 } 78 79 public function equals(object $other) : bool 80 { 81 if ($this === $other) { 82 return true; 83 } 84 85 if (!$other instanceof self) { 86 return false; 87 } 88 89 if ($this->returnStates === $other->returnStates) { 90 return false; 91 } 92 93 return Equality::equals($this->parents, $other->parents); 94 } 95 96 public function __toString() : string 97 { 98 if ($this->isEmpty()) { 99 return '[]'; 100 } 101 102 $string = '['; 103 for ($i = 0, $count = \count($this->returnStates); $i < $count; $i++) { 104 if ($i > 0) { 105 $string .= ', '; 106 } 107 108 if ($this->returnStates[$i] === PredictionContext::EMPTY_RETURN_STATE) { 109 $string .= '$'; 110 continue; 111 } 112 113 $string .= $this->returnStates[$i]; 114 115 if ($this->parents[$i] !== null) { 116 $string .= ' ' . $this->parents[$i]; 117 } else { 118 $string .= 'null'; 119 } 120 } 121 122 return $string . ']'; 123 } 124 125 protected function computeHashCode() : int 126 { 127 return Hasher::hash($this->parents, $this->returnStates); 128 } 129} 130