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 }