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 }