1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.apache.harmony.luni.lang.reflect;
18
19import java.lang.reflect.Constructor;
20import java.lang.reflect.GenericDeclaration;
21import java.lang.reflect.GenericSignatureFormatError;
22import java.lang.reflect.Method;
23import java.lang.reflect.Type;
24import java.lang.reflect.TypeVariable;
25
26/**
27 * Implements a parser for the generics signature attribute.
28 * Uses a top-down, recursive descent parsing approach for the following grammar:
29 * <pre>
30 * ClassSignature ::=
31 *     OptFormalTypeParams SuperclassSignature {SuperinterfaceSignature}.
32 * SuperclassSignature ::= ClassTypeSignature.
33 * SuperinterfaceSignature ::= ClassTypeSignature.
34 *
35 * OptFormalTypeParams ::=
36 *     ["<" FormalTypeParameter {FormalTypeParameter} ">"].
37 *
38 * FormalTypeParameter ::= Ident ClassBound {InterfaceBound}.
39 * ClassBound ::= ":" [FieldTypeSignature].
40 * InterfaceBound ::= ":" FieldTypeSignature.
41 *
42 * FieldTypeSignature ::=
43 *     ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature.
44 * ArrayTypeSignature ::= "[" TypSignature.
45 *
46 * ClassTypeSignature ::=
47 *     "L" {Ident "/"} Ident OptTypeArguments {"." Ident OptTypeArguments} ";".
48 *
49 * OptTypeArguments ::= "<" TypeArgument {TypeArgument} ">".
50 *
51 * TypeArgument ::= ([WildcardIndicator] FieldTypeSignature) | "*".
52 * WildcardIndicator ::= "+" | "-".
53 *
54 * TypeVariableSignature ::= "T" Ident ";".
55 *
56 * TypSignature ::= FieldTypeSignature | BaseType.
57 * BaseType ::= "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z".
58 *
59 * MethodTypeSignature ::=
60 *     OptFormalTypeParams "(" {TypeSignature} ")" ReturnType {ThrowsSignature}.
61 * ThrowsSignature ::= ("^" ClassTypeSignature) | ("^" TypeVariableSignature).
62 *
63 * ReturnType ::= TypSignature | VoidDescriptor.
64 * VoidDescriptor ::= "V".
65 * </pre>
66 */
67public class GenericSignatureParser {
68
69    public ListOfTypes exceptionTypes;
70    public ListOfTypes parameterTypes;
71    public TypeVariable[] formalTypeParameters;
72    public Type returnType;
73    public Type fieldType;
74    public ListOfTypes interfaceTypes;
75    public Type superclassType;
76    public ClassLoader loader;
77
78    GenericDeclaration genericDecl;
79
80    /*
81     * Parser:
82     */
83    char symbol; // 0: eof; else valid term symbol or first char of identifier.
84    String identifier;
85
86
87    /*
88     * Scanner:
89     * eof is private to the scan methods
90     * and it's set only when a scan is issued at the end of the buffer.
91     */
92    private boolean eof;
93
94    char[] buffer;
95    int pos;
96
97    public GenericSignatureParser(ClassLoader loader) {
98        this.loader = loader;
99    }
100
101    void setInput(GenericDeclaration genericDecl, String input) {
102        if (input != null) {
103            this.genericDecl = genericDecl;
104            this.buffer = input.toCharArray();
105            this.eof = false;
106            scanSymbol();
107        }
108        else {
109            this.eof = true;
110        }
111    }
112
113    /**
114     * Parses the generic signature of a class and creates the data structure
115     * representing the signature.
116     *
117     * @param genericDecl the GenericDeclaration calling this method
118     * @param signature the generic signature of the class
119     */
120    public void parseForClass(GenericDeclaration genericDecl,
121            String signature) {
122        setInput(genericDecl, signature);
123        if (!eof) {
124            parseClassSignature();
125        } else {
126            if(genericDecl instanceof Class) {
127                Class c = (Class) genericDecl;
128                this.formalTypeParameters = ListOfVariables.EMPTY;
129                this.superclassType = c.getSuperclass();
130                this.interfaceTypes = new ListOfTypes(c.getInterfaces());
131            } else {
132                this.formalTypeParameters = ListOfVariables.EMPTY;
133                this.superclassType = Object.class;
134                this.interfaceTypes = ListOfTypes.EMPTY;
135            }
136        }
137    }
138
139    /**
140     * Parses the generic signature of a method and creates the data structure
141     * representing the signature.
142     *
143     * @param genericDecl the GenericDeclaration calling this method
144     * @param signature the generic signature of the class
145     */
146    public void parseForMethod(GenericDeclaration genericDecl,
147            String signature, Class<?>[] rawExceptionTypes) {
148        setInput(genericDecl, signature);
149        if (!eof) {
150            parseMethodTypeSignature(rawExceptionTypes);
151        } else {
152            if(genericDecl instanceof Method) {
153                Method m = (Method) genericDecl;
154                this.formalTypeParameters = ListOfVariables.EMPTY;
155                this.parameterTypes = new ListOfTypes(m.getParameterTypes());
156                this.exceptionTypes = new ListOfTypes(m.getExceptionTypes());
157                this.returnType = m.getReturnType();
158            } else {
159                this.formalTypeParameters = ListOfVariables.EMPTY;
160                this.parameterTypes = ListOfTypes.EMPTY;
161                this.exceptionTypes = ListOfTypes.EMPTY;
162                this.returnType = void.class;
163            }
164        }
165    }
166
167    /**
168     * Parses the generic signature of a constructor and creates the data
169     * structure representing the signature.
170     *
171     * @param genericDecl the GenericDeclaration calling this method
172     * @param signature the generic signature of the class
173     */
174    public void parseForConstructor(GenericDeclaration genericDecl,
175            String signature, Class<?>[] rawExceptionTypes) {
176        setInput(genericDecl, signature);
177        if (!eof) {
178            parseMethodTypeSignature(rawExceptionTypes);
179        } else {
180            if(genericDecl instanceof Constructor) {
181                Constructor c = (Constructor) genericDecl;
182                this.formalTypeParameters = ListOfVariables.EMPTY;
183                this.parameterTypes = new ListOfTypes(c.getParameterTypes());
184                this.exceptionTypes = new ListOfTypes(c.getExceptionTypes());
185            } else {
186                this.formalTypeParameters = ListOfVariables.EMPTY;
187                this.parameterTypes = ListOfTypes.EMPTY;
188                this.exceptionTypes = ListOfTypes.EMPTY;
189            }
190        }
191    }
192
193    /**
194     * Parses the generic signature of a field and creates the data structure
195     * representing the signature.
196     *
197     * @param genericDecl the GenericDeclaration calling this method
198     * @param signature the generic signature of the class
199     */
200    public void parseForField(GenericDeclaration genericDecl,
201            String signature) {
202        setInput(genericDecl, signature);
203        if (!eof) {
204            this.fieldType = parseFieldTypeSignature();
205        }
206    }
207
208
209    //
210    // Parser:
211    //
212
213    void parseClassSignature() {
214        // ClassSignature ::=
215        // OptFormalTypeParameters SuperclassSignature {SuperinterfaceSignature}.
216
217        parseOptFormalTypeParameters();
218
219        // SuperclassSignature ::= ClassTypeSignature.
220        this.superclassType = parseClassTypeSignature();
221
222        interfaceTypes = new ListOfTypes(16);
223        while (symbol > 0) {
224            // SuperinterfaceSignature ::= ClassTypeSignature.
225            interfaceTypes.add(parseClassTypeSignature());
226        }
227    }
228
229    void parseOptFormalTypeParameters() {
230        // OptFormalTypeParameters ::=
231        // ["<" FormalTypeParameter {FormalTypeParameter} ">"].
232
233        ListOfVariables typeParams = new ListOfVariables();
234
235        if (symbol == '<') {
236            scanSymbol();
237            typeParams.add(parseFormalTypeParameter());
238            while ((symbol != '>') && (symbol > 0)) {
239                typeParams.add(parseFormalTypeParameter());
240            }
241            expect('>');
242        }
243        this.formalTypeParameters = typeParams.getArray();
244    }
245
246    ImplForVariable<GenericDeclaration> parseFormalTypeParameter() {
247        // FormalTypeParameter ::= Ident ClassBound {InterfaceBound}.
248
249        scanIdentifier();
250        String name = identifier.intern(); // FIXME: is this o.k.?
251
252        ListOfTypes bounds = new ListOfTypes(8);
253
254        // ClassBound ::= ":" [FieldTypeSignature].
255        expect(':');
256        if (symbol == 'L' || symbol == '[' || symbol == 'T') {
257            bounds.add(parseFieldTypeSignature());
258        }
259
260        while (symbol == ':') {
261            // InterfaceBound ::= ":" FieldTypeSignature.
262            scanSymbol();
263            bounds.add(parseFieldTypeSignature());
264        }
265
266        return new ImplForVariable<GenericDeclaration>(genericDecl, name, bounds);
267    }
268
269    Type parseFieldTypeSignature() {
270        // FieldTypeSignature ::= ClassTypeSignature | ArrayTypeSignature
271        //         | TypeVariableSignature.
272
273        switch (symbol) {
274        case 'L':
275            return parseClassTypeSignature();
276        case '[':
277            // ArrayTypeSignature ::= "[" TypSignature.
278            scanSymbol();
279            return new ImplForArray(parseTypeSignature());
280        case 'T':
281            return parseTypeVariableSignature();
282        default:
283            throw new GenericSignatureFormatError();
284        }
285    }
286
287    Type parseClassTypeSignature() {
288        // ClassTypeSignature ::= "L" {Ident "/"} Ident
289        //         OptTypeArguments {"." Ident OptTypeArguments} ";".
290
291        expect('L');
292
293        StringBuilder qualIdent = new StringBuilder();
294        scanIdentifier();
295        while (symbol == '/') {
296            scanSymbol();
297            qualIdent.append(identifier).append(".");
298            scanIdentifier();
299        }
300
301        qualIdent.append(this.identifier);
302
303        ListOfTypes typeArgs = parseOptTypeArguments();
304        ImplForType parentType =
305                new ImplForType(null, qualIdent.toString(), typeArgs, loader);
306        ImplForType type = parentType;
307
308        while (symbol == '.') {
309            // Deal with Member Classes:
310            scanSymbol();
311            scanIdentifier();
312            qualIdent.append("$").append(identifier); // FIXME: is "$" correct?
313            typeArgs = parseOptTypeArguments();
314            type = new ImplForType(parentType, qualIdent.toString(), typeArgs,
315                    loader);
316        }
317
318        expect(';');
319
320        return type;
321    }
322
323    ListOfTypes parseOptTypeArguments() {
324        // OptTypeArguments ::= "<" TypeArgument {TypeArgument} ">".
325
326        ListOfTypes typeArgs = new ListOfTypes(8);
327        if (symbol == '<') {
328            scanSymbol();
329
330            typeArgs.add(parseTypeArgument());
331            while ((symbol != '>') && (symbol > 0)) {
332                typeArgs.add(parseTypeArgument());
333            }
334            expect('>');
335        }
336        return typeArgs;
337    }
338
339    Type parseTypeArgument() {
340        // TypeArgument ::= (["+" | "-"] FieldTypeSignature) | "*".
341        ListOfTypes extendsBound = new ListOfTypes(1);
342        ListOfTypes superBound = new ListOfTypes(1);
343        if (symbol == '*') {
344            scanSymbol();
345            extendsBound.add(Object.class);
346            return new ImplForWildcard(extendsBound, superBound);
347        }
348        else if (symbol == '+') {
349            scanSymbol();
350            extendsBound.add(parseFieldTypeSignature());
351            return new ImplForWildcard(extendsBound, superBound);
352        }
353        else if (symbol == '-') {
354            scanSymbol();
355            superBound.add(parseFieldTypeSignature());
356            extendsBound.add(Object.class);
357            return new ImplForWildcard(extendsBound, superBound);
358        }
359        else {
360            return parseFieldTypeSignature();
361        }
362    }
363
364    ImplForVariable<GenericDeclaration> parseTypeVariableSignature() {
365        // TypeVariableSignature ::= "T" Ident ";".
366        expect('T');
367        scanIdentifier();
368        expect(';');
369        // Reference to type variable:
370        // Note: we don't know the declaring GenericDeclaration yet.
371        return new ImplForVariable<GenericDeclaration>(genericDecl, identifier);
372    }
373
374    Type parseTypeSignature() {
375        switch (symbol) {
376        case 'B': scanSymbol(); return byte.class;
377        case 'C': scanSymbol(); return char.class;
378        case 'D': scanSymbol(); return double.class;
379        case 'F': scanSymbol(); return float.class;
380        case 'I': scanSymbol(); return int.class;
381        case 'J': scanSymbol(); return long.class;
382        case 'S': scanSymbol(); return short.class;
383        case 'Z': scanSymbol(); return boolean.class;
384        default:
385            // Not an elementary type, but a FieldTypeSignature.
386            return parseFieldTypeSignature();
387        }
388    }
389
390    /**
391     * @param rawExceptionTypes the non-generic exceptions. This is necessary
392     *     because the signature may omit the exceptions when none are generic.
393     *     May be null for methods that declare no exceptions.
394     */
395    void parseMethodTypeSignature(Class<?>[] rawExceptionTypes) {
396        // MethodTypeSignature ::= [FormalTypeParameters]
397        //         "(" {TypeSignature} ")" ReturnType {ThrowsSignature}.
398
399        parseOptFormalTypeParameters();
400
401        parameterTypes = new ListOfTypes(16);
402        expect('(');
403        while (symbol != ')' && (symbol > 0)) {
404            parameterTypes.add(parseTypeSignature());
405        }
406        expect(')');
407
408        returnType = parseReturnType();
409
410        if (symbol == '^') {
411            exceptionTypes = new ListOfTypes(8);
412            do {
413                scanSymbol();
414
415                // ThrowsSignature ::= ("^" ClassTypeSignature) |
416                //     ("^" TypeVariableSignature).
417                if (symbol == 'T') {
418                    exceptionTypes.add(parseTypeVariableSignature());
419                } else {
420                    exceptionTypes.add(parseClassTypeSignature());
421                }
422            } while (symbol == '^');
423        } else if (rawExceptionTypes != null) {
424            exceptionTypes = new ListOfTypes(rawExceptionTypes);
425        } else {
426            exceptionTypes = new ListOfTypes(0);
427        }
428    }
429
430    Type parseReturnType() {
431        // ReturnType ::= TypeSignature | "V".
432        if (symbol != 'V') { return parseTypeSignature(); }
433        else { scanSymbol(); return void.class; }
434    }
435
436
437    //
438    // Scanner:
439    //
440
441    void scanSymbol() {
442        if (!eof) {
443            if (pos < buffer.length) {
444                symbol = buffer[pos];
445                pos++;
446            } else {
447                symbol = 0;
448                eof = true;
449            }
450        } else {
451            throw new GenericSignatureFormatError();
452        }
453    }
454
455    void expect(char c) {
456        if (symbol == c) {
457            scanSymbol();
458        } else {
459            throw new GenericSignatureFormatError();
460        }
461    }
462
463    boolean isStopSymbol(char ch) {
464        switch (ch) {
465        case ':':
466        case '/':
467        case ';':
468        case '<':
469        case '.':
470            return true;
471        }
472        return false;
473    }
474
475    // PRE: symbol is the first char of the identifier.
476    // POST: symbol = the next symbol AFTER the identifier.
477    void scanIdentifier() {
478        if (!eof) {
479            StringBuilder identBuf = new StringBuilder(32);
480            if (!isStopSymbol(symbol)) {
481                identBuf.append(symbol);
482                do {
483                    char ch = buffer[pos];
484                    if ((ch >= 'a') && (ch <= 'z') || (ch >= 'A') && (ch <= 'Z')
485                            || !isStopSymbol(ch)) {
486                        identBuf.append(buffer[pos]);
487                        pos++;
488                    } else {
489                        identifier = identBuf.toString();
490                        scanSymbol();
491                        return;
492                    }
493                } while (pos != buffer.length);
494                identifier = identBuf.toString();
495                symbol = 0;
496                eof = true;
497            } else {
498                // Ident starts with incorrect char.
499                symbol = 0;
500                eof = true;
501                throw new GenericSignatureFormatError();
502            }
503        } else {
504            throw new GenericSignatureFormatError();
505        }
506    }
507
508}
509