1 /* 2 * Copyright (c) 2012-2019 The ANTLR Project. All rights reserved. 3 * Use of this file is governed by the BSD 3-clause license that 4 * can be found in the LICENSE.txt file in the project root. 5 */ 6 7 module antlr.v4.runtime.VocabularyImpl; 8 9 import std.conv; 10 import std.ascii; 11 import std.algorithm.comparison; 12 import antlr.v4.runtime.Vocabulary; 13 import antlr.v4.runtime.Token; 14 import antlr.v4.runtime.TokenConstantDefinition; 15 16 /** 17 * This class provides a default implementation of the {@link Vocabulary} 18 * interface. 19 */ 20 class VocabularyImpl : Vocabulary 21 { 22 23 public string[] EMPTY_NAMES; 24 25 public string[] literalNames; 26 27 public string[] symbolicNames; 28 29 public string[] displayNames; 30 31 /** 32 * @uml 33 * @final 34 */ 35 private int maxTokenType; 36 37 /** 38 * Constructs a new instance of {@link VocabularyImpl} from the specified 39 * literal and symbolic token names. 40 * 41 * @param literalNames The literal names assigned to tokens, or {@code null} 42 * if no literal names are assigned. 43 * @param symbolicNames The symbolic names assigned to tokens, or 44 * {@code null} if no symbolic names are assigned. 45 * 46 * @see #getLiteralName(int) 47 * @see #getSymbolicName(int) 48 */ 49 public this(const string[] literalNames, const string[] symbolicNames) 50 { 51 this(literalNames, symbolicNames, null); 52 } 53 54 /** 55 * Constructs a new instance of {@link VocabularyImpl} from the specified 56 * literal, symbolic, and display token names. 57 * 58 * @param literalNames The literal names assigned to tokens, or {@code null} 59 * if no literal names are assigned. 60 * @param symbolicNames The symbolic names assigned to tokens, or 61 * {@code null} if no symbolic names are assigned. 62 * @param displayNames The display names assigned to tokens, or {@code null} 63 * to use the values in {@code literalNames} and {@code symbolicNames} as 64 * the source of display names, as described in 65 * {@link #getDisplayName(int)}. 66 * 67 * @see #getLiteralName(int) 68 * @see #getSymbolicName(int) 69 * @see #getDisplayName(int) 70 * @uml 71 * Constructs a new instance of {@link VocabularyImpl} from the specified 72 * literal, symbolic, and display token names. 73 * 74 * @param literalNames The literal names assigned to tokens, or {@code null} 75 * if no literal names are assigned. 76 * @param symbolicNames The symbolic names assigned to tokens, or 77 * {@code null} if no symbolic names are assigned. 78 * @param displayNames The display names assigned to tokens, or {@code null} 79 * to use the values in {@code literalNames} and {@code symbolicNames} as 80 * the source of display names, as described in 81 * {@link #getDisplayName(int)}. 82 * 83 * @see #getLiteralName(int) 84 * @see #getSymbolicName(int) 85 * @see #getDisplayName(int) 86 */ 87 public this(const string[] literalNames, const string[] symbolicNames, string[] displayNames) 88 { 89 this.literalNames = literalNames !is null ? to!(string[])(literalNames) : to!(string[])(EMPTY_NAMES); 90 this.symbolicNames = symbolicNames !is null ? to!(string[])(symbolicNames) : to!(string[])(EMPTY_NAMES); 91 this.displayNames = displayNames !is null ? displayNames : to!(string[])(EMPTY_NAMES); 92 // See note here on -1 part: https://github.com/antlr/antlr4/pull/1146 93 this.maxTokenType = 94 max(to!int(this.displayNames.length), 95 max(to!int(this.literalNames.length), to!int(this.symbolicNames.length))) - 1; 96 } 97 98 public static Vocabulary fromTokenNames(string[] tokenNames) 99 { 100 if (tokenNames is null || tokenNames.length == 0) { 101 // return EMPTY_VOCABULARY; 102 return new VocabularyImpl(null, null, null); 103 } 104 105 string[] literalNames = tokenNames.dup; 106 string[] symbolicNames = tokenNames.dup; 107 for (int i = 0; i < tokenNames.length; i++) { 108 string tokenName = tokenNames[i]; 109 if (tokenName == null) { 110 continue; 111 } 112 113 if (tokenName.length > 0) { 114 char firstChar = tokenName[0]; 115 if (firstChar == '\'') { 116 symbolicNames[i] = null; 117 continue; 118 } 119 else if (isUpper(firstChar)) { 120 literalNames[i] = null; 121 continue; 122 } 123 } 124 125 // wasn't a literal or symbolic name 126 literalNames[i] = null; 127 symbolicNames[i] = null; 128 } 129 130 return new VocabularyImpl(literalNames, symbolicNames, tokenNames); 131 } 132 133 public string getSymbolicName(int tokenType) 134 { 135 if (tokenType >= 0 && tokenType < symbolicNames.length) { 136 return symbolicNames[tokenType]; 137 } 138 139 if (tokenType == TokenConstantDefinition.EOF) { 140 return "EOF"; 141 } 142 143 return null; 144 } 145 146 public int getMaxTokenType() 147 { 148 return maxTokenType; 149 } 150 151 public string getDisplayName(int tokenType) 152 { 153 if (tokenType >= 0 && tokenType < displayNames.length) { 154 string displayName = displayNames[tokenType]; 155 if (displayName !is null) { 156 return displayName; 157 } 158 } 159 160 string literalName = getLiteralName(tokenType); 161 if (literalName !is null) { 162 return literalName; 163 } 164 165 string symbolicName = getSymbolicName(tokenType); 166 if (symbolicName != null) { 167 return symbolicName; 168 } 169 170 return to!string(tokenType); 171 } 172 173 public string getLiteralName(int tokenType) 174 { 175 if (tokenType >= 0 && tokenType < literalNames.length) { 176 return literalNames[tokenType]; 177 } 178 return null; 179 } 180 181 }