blob: 083e9a497dc1eda713f958d9e22b4da68592ceeb [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.reflect.generics.parser;
27
28
29import java.lang.reflect.GenericSignatureFormatError;
30import java.util.*;
31import sun.reflect.generics.tree.*;
32
33
34/**
35 * Parser for type signatures, as defined in the Java Virtual
36// Machine Specification (JVMS) chapter 4.
37 * Converts the signatures into an abstract syntax tree (AST) representation.
38// See the package sun.reflect.generics.tree for details of the AST.
39 */
40public class SignatureParser {
41 // The input is conceptually a character stream (though currently it's
42 // a string). This is slightly different than traditional parsers,
43 // because there is no lexical scanner performing tokenization.
44 // Having a separate tokenizer does not fit with the nature of the
45 // input format.
46 // Other than the absence of a tokenizer, this parser is a classic
47 // recursive descent parser. Its structure corresponds as closely
48 // as possible to the grammar in the JVMS.
49 //
50 // A note on asserts vs. errors: The code contains assertions
51 // in situations that should never occur. An assertion failure
52 // indicates a failure of the parser logic. A common pattern
53 // is an assertion that the current input is a particular
54 // character. This is often paired with a separate check
55 // that this is the case, which seems redundant. For example:
56 //
57 // assert(current() != x);
58 // if (current != x {error("expected an x");
59 //
60 // where x is some character constant.
61 // The assertion inidcates, that, as currently written,
62 // the code should nver reach this point unless the input is an
63 // x. On the other hand, the test is there to check the legality
64 // of the input wrt to a given production. It may be that at a later
65 // time the code might be called directly, and if the input is
66 // invalid, the parser should flag an error in accordance
67 // with its logic.
68
69 private char[] input; // the input signature
70 private int index = 0; // index into the input
71// used to mark end of input
72 private static final char EOI = ':';
73 private static final boolean DEBUG = false;
74
75 // private constructor - enforces use of static factory
76 private SignatureParser(){}
77
78 // Utility methods.
79
80 // Most parsing routines use the following routines to access the
81 // input stream, and advance it as necessary.
82 // This makes it easy to adapt the parser to operate on streams
83 // of various kinds as well as strings.
84
85 // returns current element of the input and advances the input
86 private char getNext(){
87 assert(index <= input.length);
88 try {
89 return input[index++];
90 } catch (ArrayIndexOutOfBoundsException e) { return EOI;}
91 }
92
93 // returns current element of the input
94 private char current(){
95 assert(index <= input.length);
96 try {
97 return input[index];
98 } catch (ArrayIndexOutOfBoundsException e) { return EOI;}
99 }
100
101 // advance the input
102 private void advance(){
103 assert(index <= input.length);
104 index++;
105 }
106
107 // Match c against a "set" of characters
108 private boolean matches(char c, char... set) {
109 for (char e : set) {
110 if (c == e) return true;
111 }
112 return false;
113 }
114
115 // Error handling routine. Encapsulates error handling.
116 // Takes a string error message as argument.
117 // Currently throws a GenericSignatureFormatError.
118
119 private Error error(String errorMsg) {
120 if (DEBUG) System.out.println("Parse error:" + errorMsg);
121 return new GenericSignatureFormatError();
122 }
123
124 /**
125 * Static factory method. Produces a parser instance.
126 * @return an instance of <tt>SignatureParser</tt>
127 */
128 public static SignatureParser make() {
129 return new SignatureParser();
130 }
131
132 /**
133 * Parses a class signature (as defined in the JVMS, chapter 4)
134 * and produces an abstract syntax tree representing it.
135 * @param s a string representing the input class signature
136 * @return An abstract syntax tree for a class signature
137 * corresponding to the input string
138 * @throws GenericSignatureFormatError if the input is not a valid
139 * class signature
140 */
141 public ClassSignature parseClassSig(String s) {
142 if (DEBUG) System.out.println("Parsing class sig:" + s);
143 input = s.toCharArray();
144 return parseClassSignature();
145 }
146
147 /**
148 * Parses a method signature (as defined in the JVMS, chapter 4)
149 * and produces an abstract syntax tree representing it.
150 * @param s a string representing the input method signature
151 * @return An abstract syntax tree for a method signature
152 * corresponding to the input string
153 * @throws GenericSignatureFormatError if the input is not a valid
154 * method signature
155 */
156 public MethodTypeSignature parseMethodSig(String s) {
157 if (DEBUG) System.out.println("Parsing method sig:" + s);
158 input = s.toCharArray();
159 return parseMethodTypeSignature();
160 }
161
162
163 /**
164 * Parses a type signature
165 * and produces an abstract syntax tree representing it.
166 * @param s a string representing the input type signature
167 * @return An abstract syntax tree for a type signature
168 * corresponding to the input string
169 * @throws GenericSignatureFormatError if the input is not a valid
170 * type signature
171 */
172 public TypeSignature parseTypeSig(String s) {
173 if (DEBUG) System.out.println("Parsing type sig:" + s);
174 input = s.toCharArray();
175 return parseTypeSignature();
176 }
177
178 // Parsing routines.
179 // As a rule, the parsing routines access the input using the
180 // utilities current(), getNext() and/or advance().
181 // The convention is that when a parsing routine is invoked
182 // it expects the current input to be the first character it should parse
183 // and when it completes parsing, it leaves the input at the first
184 // character after the input parses.
185
186 // parse a class signature based on the implicit input.
187 private ClassSignature parseClassSignature() {
188 assert(index == 0);
189 return ClassSignature.make(parseZeroOrMoreFormalTypeParameters(),
190 parseClassTypeSignature(),
191 parseSuperInterfaces());
192 }
193
194 private FormalTypeParameter[] parseZeroOrMoreFormalTypeParameters(){
195 if (current() == '<') { return parseFormalTypeParameters();}
196 else {return new FormalTypeParameter[0];}
197 }
198
199
200 private FormalTypeParameter[] parseFormalTypeParameters(){
201 Collection<FormalTypeParameter> ftps =
202 new ArrayList<FormalTypeParameter>(3);
203 assert(current() == '<'); // should not have been called at all
204 if (current() != '<') { throw error("expected <");}
205 advance();
206 ftps.add(parseFormalTypeParameter());
207 while (current() != '>') {
208 ftps.add(parseFormalTypeParameter());
209 }
210 advance();
211 FormalTypeParameter[] ftpa = new FormalTypeParameter[ftps.size()];
212 return ftps.toArray(ftpa);
213 }
214
215 private FormalTypeParameter parseFormalTypeParameter(){
216 String id = parseIdentifier();
217 FieldTypeSignature[] bs = parseZeroOrMoreBounds();
218 return FormalTypeParameter.make(id, bs);
219 }
220
221 private String parseIdentifier(){
222 StringBuilder result = new StringBuilder();
223 while (!Character.isWhitespace(current())) {
224 char c = current();
225 switch(c) {
226 case ';':
227 case '.':
228 case '/':
229 case '[':
230 case ':':
231 case '>':
232 case '<': return result.toString();
233 default:{
234 result.append(c);
235 advance();
236 }
237
238 }
239 }
240 return result.toString();
241 }
242
243 private FieldTypeSignature parseFieldTypeSignature() {
244 switch(current()) {
245 case 'L':
246 return parseClassTypeSignature();
247 case 'T':
248 return parseTypeVariableSignature();
249 case '[':
250 return parseArrayTypeSignature();
251 default: throw error("Expected Field Type Signature");
252 }
253 }
254
255 private ClassTypeSignature parseClassTypeSignature(){
256 assert(current() == 'L');
257 if (current() != 'L') { throw error("expected a class type");}
258 advance();
259 List<SimpleClassTypeSignature> scts =
260 new ArrayList<SimpleClassTypeSignature>(5);
261 scts.add(parseSimpleClassTypeSignature(false));
262 parseClassTypeSignatureSuffix(scts);
263 if (current() != ';')
264 throw error("expected ';' got '" + current() + "'");
265
266 advance();
267 return ClassTypeSignature.make(scts);
268 }
269
270 private SimpleClassTypeSignature parseSimpleClassTypeSignature(boolean dollar){
271 String id = parseIdentifier();
272 char c = current();
273 switch (c) {
274 case ';':
275 case '/':
276 return SimpleClassTypeSignature.make(id, dollar, new TypeArgument[0]) ;
277 case '<': {
278 return SimpleClassTypeSignature.make(id, dollar, parseTypeArguments());
279 }
280 default: {throw error("expected < or ; or /");}
281 }
282 }
283
284 private void parseClassTypeSignatureSuffix(List<SimpleClassTypeSignature> scts) {
285 while (current() == '/' || current() == '.') {
286 boolean dollar = (current() == '.');
287 advance();
288 scts.add(parseSimpleClassTypeSignature(dollar));
289 }
290 }
291
292 private TypeArgument[] parseTypeArgumentsOpt() {
293 if (current() == '<') {return parseTypeArguments();}
294 else {return new TypeArgument[0];}
295 }
296
297 private TypeArgument[] parseTypeArguments() {
298 Collection<TypeArgument> tas = new ArrayList<TypeArgument>(3);
299 assert(current() == '<');
300 if (current() != '<') { throw error("expected <");}
301 advance();
302 tas.add(parseTypeArgument());
303 while (current() != '>') {
304 //(matches(current(), '+', '-', 'L', '[', 'T', '*')) {
305 tas.add(parseTypeArgument());
306 }
307 advance();
308 TypeArgument[] taa = new TypeArgument[tas.size()];
309 return tas.toArray(taa);
310 }
311
312 private TypeArgument parseTypeArgument() {
313 FieldTypeSignature[] ub, lb;
314 ub = new FieldTypeSignature[1];
315 lb = new FieldTypeSignature[1];
316 TypeArgument[] ta = new TypeArgument[0];
317 char c = current();
318 switch (c) {
319 case '+': {
320 advance();
321 ub[0] = parseFieldTypeSignature();
322 lb[0] = BottomSignature.make(); // bottom
323 return Wildcard.make(ub, lb);
324 }
325 case '*':{
326 advance();
327 ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta);
328 lb[0] = BottomSignature.make(); // bottom
329 return Wildcard.make(ub, lb);
330 }
331 case '-': {
332 advance();
333 lb[0] = parseFieldTypeSignature();
334 ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta);
335 return Wildcard.make(ub, lb);
336 }
337 default: return parseFieldTypeSignature();
338 }
339 }
340
341 // TypeVariableSignature -> T identifier
342
343 private TypeVariableSignature parseTypeVariableSignature(){
344 assert(current() == 'T');
345 if (current() != 'T') { throw error("expected a type variable usage");}
346 advance();
347 TypeVariableSignature ts =
348 TypeVariableSignature.make(parseIdentifier());
349 if (current() != ';') {
350 throw error("; expected in signature of type variable named" +
351 ts.getIdentifier());
352 }
353 advance();
354 return ts;
355 }
356
357 // ArrayTypeSignature -> [ TypeSignature
358
359 private ArrayTypeSignature parseArrayTypeSignature() {
360 if (current() != '[') {throw error("expected array type signature");}
361 advance();
362 return ArrayTypeSignature.make(parseTypeSignature());
363 }
364
365 // TypeSignature -> BaseType | FieldTypeSignature
366
367 private TypeSignature parseTypeSignature() {
368 switch (current()) {
369 case 'B':
370 case 'C':
371 case 'D':
372 case 'F':
373 case 'I':
374 case 'J':
375 case 'S':
376 case 'Z':return parseBaseType();
377 default: return parseFieldTypeSignature();
378 }
379 }
380
381 private BaseType parseBaseType() {
382 switch(current()) {
383 case 'B':
384 advance();
385 return ByteSignature.make();
386 case 'C':
387 advance();
388 return CharSignature.make();
389 case 'D':
390 advance();
391 return DoubleSignature.make();
392 case 'F':
393 advance();
394 return FloatSignature.make();
395 case 'I':
396 advance();
397 return IntSignature.make();
398 case 'J':
399 advance();
400 return LongSignature.make();
401 case 'S':
402 advance();
403 return ShortSignature.make();
404 case 'Z':
405 advance();
406 return BooleanSignature.make();
407 default: {
408 assert(false);
409 throw error("expected primitive type");
410 }
411 }
412 }
413
414 private FieldTypeSignature[] parseZeroOrMoreBounds() {
415 Collection<FieldTypeSignature> fts =
416 new ArrayList<FieldTypeSignature>(3);
417
418 if (current() == ':') {
419 advance();
420 switch(current()) {
421 case ':': // empty class bound
422 break;
423
424 default: // parse class bound
425 fts.add(parseFieldTypeSignature());
426 }
427
428 // zero or more interface bounds
429 while (current() == ':') {
430 advance();
431 fts.add(parseFieldTypeSignature());
432 }
433 }
434
435 FieldTypeSignature[] fta = new FieldTypeSignature[fts.size()];
436 return fts.toArray(fta);
437 }
438
439 private ClassTypeSignature[] parseSuperInterfaces() {
440 Collection<ClassTypeSignature> cts =
441 new ArrayList<ClassTypeSignature>(5);
442 while(current() == 'L') {
443 cts.add(parseClassTypeSignature());
444 }
445 ClassTypeSignature[] cta = new ClassTypeSignature[cts.size()];
446 return cts.toArray(cta);
447 }
448
449 // parse a method signature based on the implicit input.
450 private MethodTypeSignature parseMethodTypeSignature() {
451 FieldTypeSignature[] ets;
452
453 assert(index == 0);
454 return MethodTypeSignature.make(parseZeroOrMoreFormalTypeParameters(),
455 parseFormalParameters(),
456 parseReturnType(),
457 parseZeroOrMoreThrowsSignatures());
458 }
459
460 // (TypeSignature*)
461 private TypeSignature[] parseFormalParameters() {
462 if (current() != '(') {throw error("expected (");}
463 advance();
464 TypeSignature[] pts = parseZeroOrMoreTypeSignatures();
465 if (current() != ')') {throw error("expected )");}
466 advance();
467 return pts;
468 }
469
470 // TypeSignature*
471 private TypeSignature[] parseZeroOrMoreTypeSignatures() {
472 Collection<TypeSignature> ts = new ArrayList<TypeSignature>();
473 boolean stop = false;
474 while (!stop) {
475 switch(current()) {
476 case 'B':
477 case 'C':
478 case 'D':
479 case 'F':
480 case 'I':
481 case 'J':
482 case 'S':
483 case 'Z':
484 case 'L':
485 case 'T':
486 case '[': {
487 ts.add(parseTypeSignature());
488 break;
489 }
490 default: stop = true;
491 }
492 }
493 /* while( matches(current(),
494 'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 'L', 'T', '[')
495 ) {
496 ts.add(parseTypeSignature());
497 }*/
498 TypeSignature[] ta = new TypeSignature[ts.size()];
499 return ts.toArray(ta);
500 }
501
502 // ReturnType -> V | TypeSignature
503
504 private ReturnType parseReturnType(){
505 if (current() == 'V') {
506 advance();
507 return VoidDescriptor.make();
508 } else return parseTypeSignature();
509 }
510
511 // ThrowSignature*
512 private FieldTypeSignature[] parseZeroOrMoreThrowsSignatures(){
513 Collection<FieldTypeSignature> ets =
514 new ArrayList<FieldTypeSignature>(3);
515 while( current() == '^') {
516 ets.add(parseThrowsSignature());
517 }
518 FieldTypeSignature[] eta = new FieldTypeSignature[ets.size()];
519 return ets.toArray(eta);
520 }
521
522 // ThrowSignature -> ^ FieldTypeSignature
523
524 private FieldTypeSignature parseThrowsSignature() {
525 assert(current() == '^');
526 if (current() != '^') { throw error("expected throws signature");}
527 advance();
528 return parseFieldTypeSignature();
529 }
530 }