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 }