001: /*
002: * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.reflect.generics.parser;
027:
028: import java.lang.reflect.GenericSignatureFormatError;
029: import java.util.*;
030: import sun.reflect.generics.tree.*;
031:
032: /**
033: * Parser for type signatures, as defined in the Java Virtual
034: // Machine Specification (JVMS) chapter 4.
035: * Converts the signatures into an abstract syntax tree (AST) representation.
036: // See the package sun.reflect.generics.tree for details of the AST.
037: */
038: public class SignatureParser {
039: // The input is conceptually a character stream (though currently it's
040: // a string). This is slightly different than traditional parsers,
041: // because there is no lexical scanner performing tokenization.
042: // Having a separate tokenizer does not fit with the nature of the
043: // input format.
044: // Other than the absence of a tokenizer, this parser is a classic
045: // recursive descent parser. Its structure corresponds as closely
046: // as possible to the grammar in the JVMS.
047: //
048: // A note on asserts vs. errors: The code contains assertions
049: // in situations that should never occur. An assertion failure
050: // indicates a failure of the parser logic. A common pattern
051: // is an assertion that the current input is a particular
052: // character. This is often paired with a separate check
053: // that this is the case, which seems redundant. For example:
054: //
055: // assert(current() != x);
056: // if (current != x {error("expected an x");
057: //
058: // where x is some character constant.
059: // The assertion inidcates, that, as currently written,
060: // the code should nver reach this point unless the input is an
061: // x. On the other hand, the test is there to check the legality
062: // of the input wrt to a given production. It may be that at a later
063: // time the code might be called directly, and if the input is
064: // invalid, the parser should flag an error in accordance
065: // with its logic.
066:
067: private char[] input; // the input signature
068: private int index = 0; // index into the input
069: // used to mark end of input
070: private static final char EOI = ':';
071: private static final boolean DEBUG = false;
072:
073: // private constructor - enforces use of static factory
074: private SignatureParser() {
075: }
076:
077: // Utility methods.
078:
079: // Most parsing routines use the following routines to access the
080: // input stream, and advance it as necessary.
081: // This makes it easy to adapt the parser to operate on streams
082: // of various kinds as well as strings.
083:
084: // returns current element of the input and advances the input
085: private char getNext() {
086: assert (index <= input.length);
087: try {
088: return input[index++];
089: } catch (ArrayIndexOutOfBoundsException e) {
090: return EOI;
091: }
092: }
093:
094: // returns current element of the input
095: private char current() {
096: assert (index <= input.length);
097: try {
098: return input[index];
099: } catch (ArrayIndexOutOfBoundsException e) {
100: return EOI;
101: }
102: }
103:
104: // advance the input
105: private void advance() {
106: assert (index <= input.length);
107: index++;
108: }
109:
110: // Match c against a "set" of characters
111: private boolean matches(char c, char... set) {
112: for (char e : set) {
113: if (c == e)
114: return true;
115: }
116: return false;
117: }
118:
119: // Error handling routine. Encapsulates error handling.
120: // Takes a string error message as argument.
121: // Currently throws a GenericSignatureFormatError.
122:
123: private Error error(String errorMsg) {
124: if (DEBUG)
125: System.out.println("Parse error:" + errorMsg);
126: return new GenericSignatureFormatError();
127: }
128:
129: /**
130: * Static factory method. Produces a parser instance.
131: * @return an instance of <tt>SignatureParser</tt>
132: */
133: public static SignatureParser make() {
134: return new SignatureParser();
135: }
136:
137: /**
138: * Parses a class signature (as defined in the JVMS, chapter 4)
139: * and produces an abstract syntax tree representing it.
140: * @param s a string representing the input class signature
141: * @return An abstract syntax tree for a class signature
142: * corresponding to the input string
143: * @throws GenericSignatureFormatError if the input is not a valid
144: * class signature
145: */
146: public ClassSignature parseClassSig(String s) {
147: if (DEBUG)
148: System.out.println("Parsing class sig:" + s);
149: input = s.toCharArray();
150: return parseClassSignature();
151: }
152:
153: /**
154: * Parses a method signature (as defined in the JVMS, chapter 4)
155: * and produces an abstract syntax tree representing it.
156: * @param s a string representing the input method signature
157: * @return An abstract syntax tree for a method signature
158: * corresponding to the input string
159: * @throws GenericSignatureFormatError if the input is not a valid
160: * method signature
161: */
162: public MethodTypeSignature parseMethodSig(String s) {
163: if (DEBUG)
164: System.out.println("Parsing method sig:" + s);
165: input = s.toCharArray();
166: return parseMethodTypeSignature();
167: }
168:
169: /**
170: * Parses a type signature
171: * and produces an abstract syntax tree representing it.
172: * @param s a string representing the input type signature
173: * @return An abstract syntax tree for a type signature
174: * corresponding to the input string
175: * @throws GenericSignatureFormatError if the input is not a valid
176: * type signature
177: */
178: public TypeSignature parseTypeSig(String s) {
179: if (DEBUG)
180: System.out.println("Parsing type sig:" + s);
181: input = s.toCharArray();
182: return parseTypeSignature();
183: }
184:
185: // Parsing routines.
186: // As a rule, the parsing routines access the input using the
187: // utilities current(), getNext() and/or advance().
188: // The convention is that when a parsing routine is invoked
189: // it expects the current input to be the first character it should parse
190: // and when it completes parsing, it leaves the input at the first
191: // character after the input parses.
192:
193: // parse a class signature based on the implicit input.
194: private ClassSignature parseClassSignature() {
195: assert (index == 0);
196: return ClassSignature.make(
197: parseZeroOrMoreFormalTypeParameters(),
198: parseClassTypeSignature(), parseSuperInterfaces());
199: }
200:
201: private FormalTypeParameter[] parseZeroOrMoreFormalTypeParameters() {
202: if (current() == '<') {
203: return parseFormalTypeParameters();
204: } else {
205: return new FormalTypeParameter[0];
206: }
207: }
208:
209: private FormalTypeParameter[] parseFormalTypeParameters() {
210: Collection<FormalTypeParameter> ftps = new ArrayList<FormalTypeParameter>(
211: 3);
212: assert (current() == '<'); // should not have been called at all
213: if (current() != '<') {
214: throw error("expected <");
215: }
216: advance();
217: ftps.add(parseFormalTypeParameter());
218: while (current() != '>') {
219: ftps.add(parseFormalTypeParameter());
220: }
221: advance();
222: FormalTypeParameter[] ftpa = new FormalTypeParameter[ftps
223: .size()];
224: return ftps.toArray(ftpa);
225: }
226:
227: private FormalTypeParameter parseFormalTypeParameter() {
228: String id = parseIdentifier();
229: FieldTypeSignature[] bs = parseZeroOrMoreBounds();
230: return FormalTypeParameter.make(id, bs);
231: }
232:
233: private String parseIdentifier() {
234: StringBuilder result = new StringBuilder();
235: while (!Character.isWhitespace(current())) {
236: char c = current();
237: switch (c) {
238: case ';':
239: case '.':
240: case '/':
241: case '[':
242: case ':':
243: case '>':
244: case '<':
245: return result.toString();
246: default: {
247: result.append(c);
248: advance();
249: }
250:
251: }
252: }
253: return result.toString();
254: }
255:
256: private FieldTypeSignature parseFieldTypeSignature() {
257: switch (current()) {
258: case 'L':
259: return parseClassTypeSignature();
260: case 'T':
261: return parseTypeVariableSignature();
262: case '[':
263: return parseArrayTypeSignature();
264: default:
265: throw error("Expected Field Type Signature");
266: }
267: }
268:
269: private ClassTypeSignature parseClassTypeSignature() {
270: assert (current() == 'L');
271: if (current() != 'L') {
272: throw error("expected a class type");
273: }
274: advance();
275: List<SimpleClassTypeSignature> scts = new ArrayList<SimpleClassTypeSignature>(
276: 5);
277: scts.add(parseSimpleClassTypeSignature(false));
278: parseClassTypeSignatureSuffix(scts);
279: if (current() != ';')
280: throw error("expected ';' got '" + current() + "'");
281:
282: advance();
283: return ClassTypeSignature.make(scts);
284: }
285:
286: private SimpleClassTypeSignature parseSimpleClassTypeSignature(
287: boolean dollar) {
288: String id = parseIdentifier();
289: char c = current();
290: switch (c) {
291: case ';':
292: case '/':
293: return SimpleClassTypeSignature.make(id, dollar,
294: new TypeArgument[0]);
295: case '<': {
296: return SimpleClassTypeSignature.make(id, dollar,
297: parseTypeArguments());
298: }
299: default: {
300: throw error("expected < or ; or /");
301: }
302: }
303: }
304:
305: private void parseClassTypeSignatureSuffix(
306: List<SimpleClassTypeSignature> scts) {
307: while (current() == '/' || current() == '.') {
308: boolean dollar = (current() == '.');
309: advance();
310: scts.add(parseSimpleClassTypeSignature(dollar));
311: }
312: }
313:
314: private TypeArgument[] parseTypeArgumentsOpt() {
315: if (current() == '<') {
316: return parseTypeArguments();
317: } else {
318: return new TypeArgument[0];
319: }
320: }
321:
322: private TypeArgument[] parseTypeArguments() {
323: Collection<TypeArgument> tas = new ArrayList<TypeArgument>(3);
324: assert (current() == '<');
325: if (current() != '<') {
326: throw error("expected <");
327: }
328: advance();
329: tas.add(parseTypeArgument());
330: while (current() != '>') {
331: //(matches(current(), '+', '-', 'L', '[', 'T', '*')) {
332: tas.add(parseTypeArgument());
333: }
334: advance();
335: TypeArgument[] taa = new TypeArgument[tas.size()];
336: return tas.toArray(taa);
337: }
338:
339: private TypeArgument parseTypeArgument() {
340: FieldTypeSignature[] ub, lb;
341: ub = new FieldTypeSignature[1];
342: lb = new FieldTypeSignature[1];
343: TypeArgument[] ta = new TypeArgument[0];
344: char c = current();
345: switch (c) {
346: case '+': {
347: advance();
348: ub[0] = parseFieldTypeSignature();
349: lb[0] = BottomSignature.make(); // bottom
350: return Wildcard.make(ub, lb);
351: }
352: case '*': {
353: advance();
354: ub[0] = SimpleClassTypeSignature.make("java.lang.Object",
355: false, ta);
356: lb[0] = BottomSignature.make(); // bottom
357: return Wildcard.make(ub, lb);
358: }
359: case '-': {
360: advance();
361: lb[0] = parseFieldTypeSignature();
362: ub[0] = SimpleClassTypeSignature.make("java.lang.Object",
363: false, ta);
364: return Wildcard.make(ub, lb);
365: }
366: default:
367: return parseFieldTypeSignature();
368: }
369: }
370:
371: // TypeVariableSignature -> T identifier
372:
373: private TypeVariableSignature parseTypeVariableSignature() {
374: assert (current() == 'T');
375: if (current() != 'T') {
376: throw error("expected a type variable usage");
377: }
378: advance();
379: TypeVariableSignature ts = TypeVariableSignature
380: .make(parseIdentifier());
381: if (current() != ';') {
382: throw error("; expected in signature of type variable named"
383: + ts.getIdentifier());
384: }
385: advance();
386: return ts;
387: }
388:
389: // ArrayTypeSignature -> [ TypeSignature
390:
391: private ArrayTypeSignature parseArrayTypeSignature() {
392: if (current() != '[') {
393: throw error("expected array type signature");
394: }
395: advance();
396: return ArrayTypeSignature.make(parseTypeSignature());
397: }
398:
399: // TypeSignature -> BaseType | FieldTypeSignature
400:
401: private TypeSignature parseTypeSignature() {
402: switch (current()) {
403: case 'B':
404: case 'C':
405: case 'D':
406: case 'F':
407: case 'I':
408: case 'J':
409: case 'S':
410: case 'Z':
411: return parseBaseType();
412: default:
413: return parseFieldTypeSignature();
414: }
415: }
416:
417: private BaseType parseBaseType() {
418: switch (current()) {
419: case 'B':
420: advance();
421: return ByteSignature.make();
422: case 'C':
423: advance();
424: return CharSignature.make();
425: case 'D':
426: advance();
427: return DoubleSignature.make();
428: case 'F':
429: advance();
430: return FloatSignature.make();
431: case 'I':
432: advance();
433: return IntSignature.make();
434: case 'J':
435: advance();
436: return LongSignature.make();
437: case 'S':
438: advance();
439: return ShortSignature.make();
440: case 'Z':
441: advance();
442: return BooleanSignature.make();
443: default: {
444: assert (false);
445: throw error("expected primitive type");
446: }
447: }
448: }
449:
450: private FieldTypeSignature[] parseZeroOrMoreBounds() {
451: Collection<FieldTypeSignature> fts = new ArrayList<FieldTypeSignature>(
452: 3);
453:
454: if (current() == ':') {
455: advance();
456: switch (current()) {
457: case ':': // empty class bound
458: break;
459:
460: default: // parse class bound
461: fts.add(parseFieldTypeSignature());
462: }
463:
464: // zero or more interface bounds
465: while (current() == ':') {
466: advance();
467: fts.add(parseFieldTypeSignature());
468: }
469: }
470:
471: FieldTypeSignature[] fta = new FieldTypeSignature[fts.size()];
472: return fts.toArray(fta);
473: }
474:
475: private ClassTypeSignature[] parseSuperInterfaces() {
476: Collection<ClassTypeSignature> cts = new ArrayList<ClassTypeSignature>(
477: 5);
478: while (current() == 'L') {
479: cts.add(parseClassTypeSignature());
480: }
481: ClassTypeSignature[] cta = new ClassTypeSignature[cts.size()];
482: return cts.toArray(cta);
483: }
484:
485: // parse a method signature based on the implicit input.
486: private MethodTypeSignature parseMethodTypeSignature() {
487: FieldTypeSignature[] ets;
488:
489: assert (index == 0);
490: return MethodTypeSignature.make(
491: parseZeroOrMoreFormalTypeParameters(),
492: parseFormalParameters(), parseReturnType(),
493: parseZeroOrMoreThrowsSignatures());
494: }
495:
496: // (TypeSignature*)
497: private TypeSignature[] parseFormalParameters() {
498: if (current() != '(') {
499: throw error("expected (");
500: }
501: advance();
502: TypeSignature[] pts = parseZeroOrMoreTypeSignatures();
503: if (current() != ')') {
504: throw error("expected )");
505: }
506: advance();
507: return pts;
508: }
509:
510: // TypeSignature*
511: private TypeSignature[] parseZeroOrMoreTypeSignatures() {
512: Collection<TypeSignature> ts = new ArrayList<TypeSignature>();
513: boolean stop = false;
514: while (!stop) {
515: switch (current()) {
516: case 'B':
517: case 'C':
518: case 'D':
519: case 'F':
520: case 'I':
521: case 'J':
522: case 'S':
523: case 'Z':
524: case 'L':
525: case 'T':
526: case '[': {
527: ts.add(parseTypeSignature());
528: break;
529: }
530: default:
531: stop = true;
532: }
533: }
534: /* while( matches(current(),
535: 'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 'L', 'T', '[')
536: ) {
537: ts.add(parseTypeSignature());
538: }*/
539: TypeSignature[] ta = new TypeSignature[ts.size()];
540: return ts.toArray(ta);
541: }
542:
543: // ReturnType -> V | TypeSignature
544:
545: private ReturnType parseReturnType() {
546: if (current() == 'V') {
547: advance();
548: return VoidDescriptor.make();
549: } else
550: return parseTypeSignature();
551: }
552:
553: // ThrowSignature*
554: private FieldTypeSignature[] parseZeroOrMoreThrowsSignatures() {
555: Collection<FieldTypeSignature> ets = new ArrayList<FieldTypeSignature>(
556: 3);
557: while (current() == '^') {
558: ets.add(parseThrowsSignature());
559: }
560: FieldTypeSignature[] eta = new FieldTypeSignature[ets.size()];
561: return ets.toArray(eta);
562: }
563:
564: // ThrowSignature -> ^ FieldTypeSignature
565:
566: private FieldTypeSignature parseThrowsSignature() {
567: assert (current() == '^');
568: if (current() != '^') {
569: throw error("expected throws signature");
570: }
571: advance();
572: return parseFieldTypeSignature();
573: }
574: }
|