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 /** 42 * This class provides a default implementation of the {@link Vocabulary} 43 * interface. 44 */ 45 class VocabularyImpl : Vocabulary 46 { 47 48 public string[] EMPTY_NAMES; 49 50 public string[] literalNames; 51 52 public string[] symbolicNames; 53 54 public string[] displayNames; 55 56 /** 57 * @uml 58 * @final 59 */ 60 private int maxTokenType; 61 62 /** 63 * Constructs a new instance of {@link VocabularyImpl} from the specified 64 * literal and symbolic token names. 65 * 66 * @param literalNames The literal names assigned to tokens, or {@code null} 67 * if no literal names are assigned. 68 * @param symbolicNames The symbolic names assigned to tokens, or 69 * {@code null} if no symbolic names are assigned. 70 * 71 * @see #getLiteralName(int) 72 * @see #getSymbolicName(int) 73 */ 74 public this(const string[] literalNames, const string[] symbolicNames) 75 { 76 this(literalNames, symbolicNames, null); 77 } 78 79 /** 80 * @uml 81 * Constructs a new instance of {@link VocabularyImpl} from the specified 82 * literal, symbolic, and display token names. 83 * 84 * @param literalNames The literal names assigned to tokens, or {@code null} 85 * if no literal names are assigned. 86 * @param symbolicNames The symbolic names assigned to tokens, or 87 * {@code null} if no symbolic names are assigned. 88 * @param displayNames The display names assigned to tokens, or {@code null} 89 * to use the values in {@code literalNames} and {@code symbolicNames} as 90 * the source of display names, as described in 91 * {@link #getDisplayName(int)}. 92 * 93 * @see #getLiteralName(int) 94 * @see #getSymbolicName(int) 95 * @see #getDisplayName(int) 96 */ 97 public this(const string[] literalNames, const string[] symbolicNames, string[] displayNames) 98 { 99 this.literalNames = literalNames !is null ? to!(string[])(literalNames) : to!(string[])(EMPTY_NAMES); 100 this.symbolicNames = symbolicNames !is null ? to!(string[])(symbolicNames) : to!(string[])(EMPTY_NAMES); 101 this.displayNames = displayNames !is null ? displayNames : to!(string[])(EMPTY_NAMES); 102 // See note here on -1 part: https://github.com/antlr/antlr4/pull/1146 103 this.maxTokenType = 104 max(to!int(this.displayNames.length), 105 max(to!int(this.literalNames.length), to!int(this.symbolicNames.length))) - 1; 106 } 107 108 /** 109 * @uml 110 * Returns a {@link VocabularyImpl} instance from the specified set of token 111 * names. This method acts as a compatibility layer for the single 112 * {@code tokenNames} array generated by previous releases of ANTLR. 113 * 114 * <p>The resulting vocabulary instance returns {@code null} for 115 * {@link #getLiteralName(int)} and {@link #getSymbolicName(int)}, and the 116 * value from {@code tokenNames} for the display names.</p> 117 * 118 * @param tokenNames The token names, or {@code null} if no token names are 119 * available. 120 * @return A {@link Vocabulary} instance which uses {@code tokenNames} for 121 * the display names of tokens. 122 */ 123 public static Vocabulary fromTokenNames(string[] tokenNames) 124 { 125 if (tokenNames is null || tokenNames.length == 0) { 126 // return EMPTY_VOCABULARY; 127 return new VocabularyImpl(null, null, null); 128 } 129 130 string[] literalNames = tokenNames.dup; 131 string[] symbolicNames = tokenNames.dup; 132 for (int i = 0; i < tokenNames.length; i++) { 133 string tokenName = tokenNames[i]; 134 if (tokenName == null) { 135 continue; 136 } 137 138 if (tokenName.length > 0) { 139 char firstChar = tokenName[0]; 140 if (firstChar == '\'') { 141 symbolicNames[i] = null; 142 continue; 143 } 144 else if (isUpper(firstChar)) { 145 literalNames[i] = null; 146 continue; 147 } 148 } 149 150 // wasn't a literal or symbolic name 151 literalNames[i] = null; 152 symbolicNames[i] = null; 153 } 154 155 return new VocabularyImpl(literalNames, symbolicNames, tokenNames); 156 } 157 158 public string getSymbolicName(int tokenType) 159 { 160 if (tokenType >= 0 && tokenType < symbolicNames.length) { 161 return symbolicNames[tokenType]; 162 } 163 164 if (tokenType == TokenConstantDefinition.EOF) { 165 return "EOF"; 166 } 167 168 return null; 169 } 170 171 public int getMaxTokenType() 172 { 173 return maxTokenType; 174 } 175 176 public string getDisplayName(int tokenType) 177 { 178 if (tokenType >= 0 && tokenType < displayNames.length) { 179 string displayName = displayNames[tokenType]; 180 if (displayName !is null) { 181 return displayName; 182 } 183 } 184 185 string literalName = getLiteralName(tokenType); 186 if (literalName !is null) { 187 return literalName; 188 } 189 190 string symbolicName = getSymbolicName(tokenType); 191 if (symbolicName != null) { 192 return symbolicName; 193 } 194 195 return to!string(tokenType); 196 } 197 198 public string getLiteralName(int tokenType) 199 { 200 if (tokenType >= 0 && tokenType < literalNames.length) { 201 return literalNames[tokenType]; 202 } 203 return null; 204 } 205 206 }