1 /* 2 * [The "BSD license"] 3 * Copyright (c) 2016 Terence Parr 4 * Copyright (c) 2016 Sam Harwell 5 * Copyright (c) 2017 Egbert Voigt 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 module antlr.v4.runtime.VocabularyImpl; 33 34 import std.conv; 35 import std.ascii; 36 import std.algorithm.comparison; 37 import antlr.v4.runtime.Vocabulary; 38 import antlr.v4.runtime.Token; 39 import antlr.v4.runtime.TokenConstantDefinition; 40 41 // Class VocabularyImpl 42 /** 43 * This class provides a default implementation of the {@link Vocabulary} 44 * interface. 45 */ 46 class VocabularyImpl : Vocabulary 47 { 48 49 public string[] EMPTY_NAMES; 50 51 public string[] literalNames; 52 53 public string[] symbolicNames; 54 55 public string[] displayNames; 56 57 /** 58 * @uml 59 * @final 60 */ 61 private int maxTokenType; 62 63 /** 64 * Constructs a new instance of {@link VocabularyImpl} from the specified 65 * literal and symbolic token names. 66 * 67 * @param literalNames The literal names assigned to tokens, or {@code null} 68 * if no literal names are assigned. 69 * @param symbolicNames The symbolic names assigned to tokens, or 70 * {@code null} if no symbolic names are assigned. 71 * 72 * @see #getLiteralName(int) 73 * @see #getSymbolicName(int) 74 */ 75 public this(const string[] literalNames, const string[] symbolicNames) 76 { 77 this(literalNames, symbolicNames, null); 78 } 79 80 /** 81 * @uml 82 * Constructs a new instance of {@link VocabularyImpl} from the specified 83 * literal, symbolic, and display token names. 84 * 85 * @param literalNames The literal names assigned to tokens, or {@code null} 86 * if no literal names are assigned. 87 * @param symbolicNames The symbolic names assigned to tokens, or 88 * {@code null} if no symbolic names are assigned. 89 * @param displayNames The display names assigned to tokens, or {@code null} 90 * to use the values in {@code literalNames} and {@code symbolicNames} as 91 * the source of display names, as described in 92 * {@link #getDisplayName(int)}. 93 * 94 * @see #getLiteralName(int) 95 * @see #getSymbolicName(int) 96 * @see #getDisplayName(int) 97 */ 98 public this(const string[] literalNames, const string[] symbolicNames, string[] displayNames) 99 { 100 this.literalNames = literalNames !is null ? to!(string[])(literalNames) : to!(string[])(EMPTY_NAMES); 101 this.symbolicNames = symbolicNames !is null ? to!(string[])(symbolicNames) : to!(string[])(EMPTY_NAMES); 102 this.displayNames = displayNames !is null ? displayNames : to!(string[])(EMPTY_NAMES); 103 // See note here on -1 part: https://github.com/antlr/antlr4/pull/1146 104 this.maxTokenType = 105 max(to!int(this.displayNames.length), 106 max(to!int(this.literalNames.length), to!int(this.symbolicNames.length))) - 1; 107 } 108 109 /** 110 * @uml 111 * Returns a {@link VocabularyImpl} instance from the specified set of token 112 * names. This method acts as a compatibility layer for the single 113 * {@code tokenNames} array generated by previous releases of ANTLR. 114 * 115 * <p>The resulting vocabulary instance returns {@code null} for 116 * {@link #getLiteralName(int)} and {@link #getSymbolicName(int)}, and the 117 * value from {@code tokenNames} for the display names.</p> 118 * 119 * @param tokenNames The token names, or {@code null} if no token names are 120 * available. 121 * @return A {@link Vocabulary} instance which uses {@code tokenNames} for 122 * the display names of tokens. 123 */ 124 public static Vocabulary fromTokenNames(string[] tokenNames) 125 { 126 if (tokenNames is null || tokenNames.length == 0) { 127 // return EMPTY_VOCABULARY; 128 return new VocabularyImpl(null, null, null); 129 } 130 131 string[] literalNames = tokenNames.dup; 132 string[] symbolicNames = tokenNames.dup; 133 for (int i = 0; i < tokenNames.length; i++) { 134 string tokenName = tokenNames[i]; 135 if (tokenName == null) { 136 continue; 137 } 138 139 if (tokenName.length > 0) { 140 char firstChar = tokenName[0]; 141 if (firstChar == '\'') { 142 symbolicNames[i] = null; 143 continue; 144 } 145 else if (isUpper(firstChar)) { 146 literalNames[i] = null; 147 continue; 148 } 149 } 150 151 // wasn't a literal or symbolic name 152 literalNames[i] = null; 153 symbolicNames[i] = null; 154 } 155 156 return new VocabularyImpl(literalNames, symbolicNames, tokenNames); 157 } 158 159 public string getSymbolicName(int tokenType) 160 { 161 if (tokenType >= 0 && tokenType < symbolicNames.length) { 162 return symbolicNames[tokenType]; 163 } 164 165 if (tokenType == TokenConstantDefinition.EOF) { 166 return "EOF"; 167 } 168 169 return null; 170 } 171 172 public int getMaxTokenType() 173 { 174 return maxTokenType; 175 } 176 177 public string getDisplayName(int tokenType) 178 { 179 if (tokenType >= 0 && tokenType < displayNames.length) { 180 string displayName = displayNames[tokenType]; 181 if (displayName !is null) { 182 return displayName; 183 } 184 } 185 186 string literalName = getLiteralName(tokenType); 187 if (literalName !is null) { 188 return literalName; 189 } 190 191 string symbolicName = getSymbolicName(tokenType); 192 if (symbolicName != null) { 193 return symbolicName; 194 } 195 196 return to!string(tokenType); 197 } 198 199 public string getLiteralName(int tokenType) 200 { 201 if (tokenType >= 0 && tokenType < literalNames.length) { 202 return literalNames[tokenType]; 203 } 204 return null; 205 } 206 207 }