1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.incubator.code.extern.impl;
27
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.function.Predicate;
32
33 /**
34 * A class that defines codes/utilities for Java source tokens
35 * returned from lexical analysis.
36 *
37 * <p><b>This is NOT part of any supported API.
38 * If you write code that depends on this, you do so at your own risk.
39 * This code and its internal interfaces are subject to change or
40 * deletion without notice.</b>
41 */
42 public final class Tokens {
43
44 /**
45 * Keyword array. Maps name indices to Token.
46 */
47 private final Map<String, TokenKind> keywords = new HashMap<>();
48
49 Tokens() {
50 for (TokenKind t : TokenKind.values()) {
51 if (t.name != null) {
52 keywords.put(t.name, t);
53 }
54 }
55 }
56
57 TokenKind lookupKind(String name, TokenKind identifier) {
58 TokenKind t = keywords.get(name);
59 return (t != null) ? t : identifier;
60 }
61
62 /**
63 * This enum defines all tokens used by the javac scanner. A token is
64 * optionally associated with a name.
65 */
66 public enum TokenKind implements Predicate<TokenKind> {
67 EOF(),
68 ERROR(),
69 IDENTIFIER(Token.Tag.NAMED),
70 VALUE_IDENTIFIER(Token.Tag.NAMED),
71 INTLITERAL(Token.Tag.NUMERIC),
72 LONGLITERAL(Token.Tag.NUMERIC),
73 FLOATLITERAL(Token.Tag.NUMERIC),
74 DOUBLELITERAL(Token.Tag.NUMERIC),
75 CHARLITERAL(Token.Tag.NUMERIC),
76 STRINGLITERAL(Token.Tag.STRING),
77 TRUE("true", Token.Tag.NAMED),
78 FALSE("false", Token.Tag.NAMED),
79 NULL("null", Token.Tag.NAMED),
80 UNDERSCORE("_", Token.Tag.NAMED),
81 ARROW("->"),
82 LPAREN("("),
83 RPAREN(")"),
84 LBRACE("{"),
85 RBRACE("}"),
86 LBRACKET("["),
87 RBRACKET("]"),
88 COMMA(","),
89 DOT("."),
90 EQ("="),
91 GT(">"),
92 LT("<"),
93 QUES("?"),
94 COLON(":"),
95 COLCOL("::"),
96 SEMI(";"),
97 PLUS("+"),
98 SUB("-"),
99 AMP("&"),
100 CARET("^"),
101 MONKEYS_AT("@"),
102 HASH("#"),
103 CUSTOM;
104
105 public final String name;
106 public final Token.Tag tag;
107
108 TokenKind() {
109 this(null, Token.Tag.DEFAULT);
110 }
111
112 TokenKind(String name) {
113 this(name, Token.Tag.DEFAULT);
114 }
115
116 TokenKind(Token.Tag tag) {
117 this(null, tag);
118 }
119
120 TokenKind(String name, Token.Tag tag) {
121 this.name = name;
122 this.tag = tag;
123 }
124
125 public String toString() {
126 return switch (this) {
127 case IDENTIFIER -> "token.identifier";
128 case VALUE_IDENTIFIER -> "token.value-identifier";
129 case CHARLITERAL -> "token.character";
130 case STRINGLITERAL -> "token.string";
131 case INTLITERAL -> "token.integer";
132 case LONGLITERAL -> "token.long-integer";
133 case FLOATLITERAL -> "token.float";
134 case DOUBLELITERAL -> "token.double";
135 case ERROR -> "token.bad-symbol";
136 case EOF -> "token.end-of-input";
137 case DOT, COMMA, LPAREN, RPAREN, LBRACKET, RBRACKET, LBRACE, RBRACE -> "'" + name + "'";
138 default -> name;
139 };
140 }
141
142 @Override
143 public boolean test(TokenKind that) {
144 return this == that;
145 }
146 }
147
148 public interface Comment {
149
150 enum CommentStyle {
151 LINE,
152 BLOCK,
153 }
154
155 String text();
156
157 CommentStyle style();
158 }
159
160 /**
161 * This is the class representing a javac token. Each token has several fields
162 * that are set by the javac lexer (i.e. start/end position, string value, etc).
163 */
164 public static class Token {
165
166 /**
167 * tags constants
168 **/
169 public enum Tag {
170 DEFAULT,
171 NAMED,
172 STRING,
173 NUMERIC
174 }
175
176 /**
177 * The token kind
178 */
179 public final TokenKind kind;
180
181 /**
182 * The start position of this token
183 */
184 public final int pos;
185
186 /**
187 * The end position of this token
188 */
189 public final int endPos;
190
191 /**
192 * Comment reader associated with this token
193 */
194 public final List<Comment> comments;
195
196 Token(TokenKind kind, int pos, int endPos, List<Comment> comments) {
197 this.kind = kind;
198 this.pos = pos;
199 this.endPos = endPos;
200 this.comments = comments == null ? null : List.copyOf(comments);
201 checkKind();
202 }
203
204 void checkKind() {
205 if (kind.tag != Tag.DEFAULT) {
206 throw new AssertionError("Bad token kind - expected " + Tag.DEFAULT);
207 }
208 }
209
210 public String name() {
211 throw new UnsupportedOperationException();
212 }
213
214 public String stringVal() {
215 throw new UnsupportedOperationException();
216 }
217
218 public int radix() {
219 throw new UnsupportedOperationException();
220 }
221 }
222
223 static final class NamedToken extends Token {
224 /**
225 * The name of this token
226 */
227 public final String name;
228
229 NamedToken(TokenKind kind, int pos, int endPos, String name, List<Comment> comments) {
230 super(kind, pos, endPos, comments);
231 this.name = name;
232 }
233
234 void checkKind() {
235 if (kind.tag != Tag.NAMED) {
236 throw new AssertionError("Bad token kind - expected " + Tag.NAMED);
237 }
238 }
239
240 @Override
241 public String name() {
242 return name;
243 }
244 }
245
246 static class StringToken extends Token {
247 /**
248 * The string value of this token
249 */
250 public final String stringVal;
251
252 StringToken(TokenKind kind, int pos, int endPos, String stringVal, List<Comment> comments) {
253 super(kind, pos, endPos, comments);
254 this.stringVal = stringVal;
255 }
256
257 void checkKind() {
258 if (kind.tag != Tag.STRING) {
259 throw new AssertionError("Bad token kind - expected " + Tag.STRING);
260 }
261 }
262
263 @Override
264 public String stringVal() {
265 return stringVal;
266 }
267 }
268
269 static final class NumericToken extends StringToken {
270 /**
271 * The 'radix' value of this token
272 */
273 public final int radix;
274
275 NumericToken(TokenKind kind, int pos, int endPos, String stringVal, int radix, List<Comment> comments) {
276 super(kind, pos, endPos, stringVal, comments);
277 this.radix = radix;
278 }
279
280 void checkKind() {
281 if (kind.tag != Tag.NUMERIC) {
282 throw new AssertionError("Bad token kind - expected " + Tag.NUMERIC);
283 }
284 }
285
286 @Override
287 public int radix() {
288 return radix;
289 }
290 }
291
292 public static final Token DUMMY =
293 new Token(TokenKind.ERROR, 0, 0, null);
294 }