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 }