1*37748cd8SNickeau<?php 2*37748cd8SNickeau 3*37748cd8SNickeaudeclare(strict_types=1); 4*37748cd8SNickeau 5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime; 6*37748cd8SNickeau 7*37748cd8SNickeau/** 8*37748cd8SNickeau * This class provides a default implementation of the {@see Vocabulary} 9*37748cd8SNickeau * interface. 10*37748cd8SNickeau * 11*37748cd8SNickeau * @author Sam Harwell 12*37748cd8SNickeau */ 13*37748cd8SNickeaufinal class VocabularyImpl implements Vocabulary 14*37748cd8SNickeau{ 15*37748cd8SNickeau /** @var array<string|null> */ 16*37748cd8SNickeau private $literalNames; 17*37748cd8SNickeau 18*37748cd8SNickeau /** @var array<string|null> */ 19*37748cd8SNickeau private $symbolicNames; 20*37748cd8SNickeau 21*37748cd8SNickeau /** @var array<string|null> */ 22*37748cd8SNickeau private $displayNames; 23*37748cd8SNickeau 24*37748cd8SNickeau /** @var int */ 25*37748cd8SNickeau private $maxTokenType; 26*37748cd8SNickeau 27*37748cd8SNickeau /** 28*37748cd8SNickeau * Constructs a new instance from the specified literal, symbolic 29*37748cd8SNickeau * and display token names. 30*37748cd8SNickeau * 31*37748cd8SNickeau * @param array<string|null> $literalNames The literal names assigned 32*37748cd8SNickeau * to tokens, or `null` if no 33*37748cd8SNickeau * literal names are assigned. 34*37748cd8SNickeau * @param array<string|null> $symbolicNames The symbolic names assigned 35*37748cd8SNickeau * to tokens, or `null` if 36*37748cd8SNickeau * no symbolic names are assigned. 37*37748cd8SNickeau * @param array<string|null> $displayNames The display names assigned 38*37748cd8SNickeau * to tokens, or `null` to use 39*37748cd8SNickeau * the values in literalNames` and 40*37748cd8SNickeau * `symbolicNames` as the source 41*37748cd8SNickeau * of display names, as described 42*37748cd8SNickeau * in {@see VocabularyImpl::getDisplayName()}. 43*37748cd8SNickeau */ 44*37748cd8SNickeau public function __construct(array $literalNames = [], array $symbolicNames = [], array $displayNames = []) 45*37748cd8SNickeau { 46*37748cd8SNickeau $this->literalNames = $literalNames; 47*37748cd8SNickeau $this->symbolicNames = $symbolicNames; 48*37748cd8SNickeau $this->displayNames = $displayNames; 49*37748cd8SNickeau 50*37748cd8SNickeau // See note here on -1 part: https://github.com/antlr/antlr4/pull/1146 51*37748cd8SNickeau $this->maxTokenType = \max( 52*37748cd8SNickeau \count($this->displayNames), 53*37748cd8SNickeau \count($this->literalNames), 54*37748cd8SNickeau \count($this->symbolicNames) 55*37748cd8SNickeau ) - 1; 56*37748cd8SNickeau } 57*37748cd8SNickeau 58*37748cd8SNickeau /** 59*37748cd8SNickeau * Gets an empty {@see Vocabulary} instance. 60*37748cd8SNickeau * 61*37748cd8SNickeau * No literal or symbol names are assigned to token types, so 62*37748cd8SNickeau * {@see Vocabulary::getDisplayName()} returns the numeric value for 63*37748cd8SNickeau * all tokens except {@see Token::EOF}. 64*37748cd8SNickeau */ 65*37748cd8SNickeau public static function emptyVocabulary() : self 66*37748cd8SNickeau { 67*37748cd8SNickeau static $empty; 68*37748cd8SNickeau 69*37748cd8SNickeau return $empty ?? ($empty = new self()); 70*37748cd8SNickeau } 71*37748cd8SNickeau 72*37748cd8SNickeau /** 73*37748cd8SNickeau * Returns a {@see VocabularyImpl} instance from the specified set 74*37748cd8SNickeau * of token names. This method acts as a compatibility layer for the single 75*37748cd8SNickeau * `tokenNames` array generated by previous releases of ANTLR. 76*37748cd8SNickeau * 77*37748cd8SNickeau * The resulting vocabulary instance returns `null` for 78*37748cd8SNickeau * {@see VocabularyImpl::getLiteralName()} and {@see VocabularyImpl::getSymbolicName()}, 79*37748cd8SNickeau * and the value from `tokenNames` for the display names. 80*37748cd8SNickeau * 81*37748cd8SNickeau * @param array<string|null> $tokenNames The token names, or `null` if 82*37748cd8SNickeau * no token names are available. 83*37748cd8SNickeau * 84*37748cd8SNickeau * @return Vocabulary A {@see Vocabulary} instance which uses `tokenNames` 85*37748cd8SNickeau * for the display names of tokens. 86*37748cd8SNickeau */ 87*37748cd8SNickeau public static function fromTokenNames(array $tokenNames = []) : Vocabulary 88*37748cd8SNickeau { 89*37748cd8SNickeau if (\count($tokenNames) === 0) { 90*37748cd8SNickeau return self::emptyVocabulary(); 91*37748cd8SNickeau } 92*37748cd8SNickeau 93*37748cd8SNickeau $literalNames = $tokenNames; // copy array 94*37748cd8SNickeau $symbolicNames = $tokenNames; // copy array 95*37748cd8SNickeau 96*37748cd8SNickeau foreach ($tokenNames as $i => $tokenName) { 97*37748cd8SNickeau if ($tokenName === null) { 98*37748cd8SNickeau continue; 99*37748cd8SNickeau } 100*37748cd8SNickeau 101*37748cd8SNickeau if ($tokenName !== '') { 102*37748cd8SNickeau $firstChar = $tokenName[0]; 103*37748cd8SNickeau 104*37748cd8SNickeau if ($firstChar === '\'') { 105*37748cd8SNickeau $symbolicNames[$i] = null; 106*37748cd8SNickeau 107*37748cd8SNickeau continue; 108*37748cd8SNickeau } 109*37748cd8SNickeau 110*37748cd8SNickeau if (\ctype_upper($firstChar)) { 111*37748cd8SNickeau $literalNames[$i] = null; 112*37748cd8SNickeau 113*37748cd8SNickeau continue; 114*37748cd8SNickeau } 115*37748cd8SNickeau } 116*37748cd8SNickeau 117*37748cd8SNickeau // wasn't a literal or symbolic name 118*37748cd8SNickeau $literalNames[$i] = null; 119*37748cd8SNickeau $symbolicNames[$i] = null; 120*37748cd8SNickeau } 121*37748cd8SNickeau 122*37748cd8SNickeau return new VocabularyImpl($literalNames, $symbolicNames, $tokenNames); 123*37748cd8SNickeau } 124*37748cd8SNickeau 125*37748cd8SNickeau public function getMaxTokenType() : int 126*37748cd8SNickeau { 127*37748cd8SNickeau return $this->maxTokenType; 128*37748cd8SNickeau } 129*37748cd8SNickeau 130*37748cd8SNickeau public function getLiteralName(int $tokenType) : ?string 131*37748cd8SNickeau { 132*37748cd8SNickeau if ($tokenType >= 0 && $tokenType < \count($this->literalNames)) { 133*37748cd8SNickeau return $this->literalNames[$tokenType]; 134*37748cd8SNickeau } 135*37748cd8SNickeau 136*37748cd8SNickeau return null; 137*37748cd8SNickeau } 138*37748cd8SNickeau 139*37748cd8SNickeau public function getSymbolicName(int $tokenType) : ?string 140*37748cd8SNickeau { 141*37748cd8SNickeau if ($tokenType >= 0 && $tokenType < \count($this->symbolicNames)) { 142*37748cd8SNickeau return $this->symbolicNames[$tokenType]; 143*37748cd8SNickeau } 144*37748cd8SNickeau 145*37748cd8SNickeau if ($tokenType === Token::EOF) { 146*37748cd8SNickeau return 'EOF'; 147*37748cd8SNickeau } 148*37748cd8SNickeau 149*37748cd8SNickeau return null; 150*37748cd8SNickeau } 151*37748cd8SNickeau 152*37748cd8SNickeau public function getDisplayName(int $tokenType) : string 153*37748cd8SNickeau { 154*37748cd8SNickeau if ($tokenType >= 0 && $tokenType < \count($this->displayNames)) { 155*37748cd8SNickeau $displayName = $this->displayNames[$tokenType]; 156*37748cd8SNickeau 157*37748cd8SNickeau if ($displayName !== null) { 158*37748cd8SNickeau return $displayName; 159*37748cd8SNickeau } 160*37748cd8SNickeau } 161*37748cd8SNickeau 162*37748cd8SNickeau $literalName = $this->getLiteralName($tokenType); 163*37748cd8SNickeau 164*37748cd8SNickeau if ($literalName !== null) { 165*37748cd8SNickeau return $literalName; 166*37748cd8SNickeau } 167*37748cd8SNickeau 168*37748cd8SNickeau $symbolicName = $this->getSymbolicName($tokenType); 169*37748cd8SNickeau 170*37748cd8SNickeau if ($symbolicName !== null) { 171*37748cd8SNickeau return $symbolicName; 172*37748cd8SNickeau } 173*37748cd8SNickeau 174*37748cd8SNickeau return (string) $tokenType; 175*37748cd8SNickeau } 176*37748cd8SNickeau} 177