KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > util > BindingKeyParser


1 /*******************************************************************************
2  * Copyright (c) 2005, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core.util;
12
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ast.Wildcard;
15
16 public class BindingKeyParser {
17     
18     int keyStart;
19     
20     static final char C_THROWN = '|';
21
22     static class Scanner {
23         static final int PACKAGE = 0;
24         static final int TYPE = 1;
25         static final int FIELD = 2;
26         static final int METHOD = 3;
27         static final int ARRAY = 4;
28         static final int LOCAL_VAR = 5;
29         static final int FLAGS = 6;
30         static final int WILDCARD = 7;
31         static final int CAPTURE = 8;
32         static final int BASE_TYPE = 9;
33         static final int END = 10;
34         
35         static final int START = -1;
36         
37         int index = 0, start;
38         char[] source;
39         int token = START;
40     
41         Scanner(char[] source) {
42             this.source = source;
43         }
44         
45         char[] getTokenSource() {
46             int length = this.index-this.start;
47             char[] result = new char[length];
48             System.arraycopy(this.source, this.start, result, 0, length);
49             return result;
50         }
51         
52         boolean isAtCaptureStart() {
53             return
54                 this.index < this.source.length
55                 && this.source[this.index] == '!';
56         }
57         
58         boolean isAtFieldOrMethodStart() {
59             return
60                 this.index < this.source.length
61                 && this.source[this.index] == '.';
62         }
63         
64         boolean isAtLocalVariableStart() {
65             return
66                 this.index < this.source.length
67                 && this.source[this.index] == '#';
68         }
69         
70         boolean isAtMemberTypeStart() {
71             return
72                 this.index < this.source.length
73                 && (this.source[this.index] == '$'
74                     || (this.source[this.index] == '.' && this.source[this.index-1] == '>'));
75         }
76         
77         boolean isAtParametersEnd() {
78             return
79                 this.index < this.source.length
80                     && this.source[this.index] == '>';
81         }
82         
83         boolean isAtParametersStart() {
84             char currentChar;
85             return
86                 this.index > 0
87                 && this.index < this.source.length
88                 && ((currentChar = this.source[this.index]) == '<'
89                     || currentChar == '%');
90         }
91         
92         boolean isAtRawTypeEnd() {
93             return
94                 this.index > 0
95                 && this.index < this.source.length
96                 && this.source[this.index] == '>';
97         }
98         
99         boolean isAtSecondaryTypeStart() {
100             return
101                 this.index < this.source.length
102                 && this.source[this.index] == '~';
103         }
104         
105         boolean isAtWildcardStart() {
106             return
107                 this.index < this.source.length
108                 && "*+-".indexOf(this.source[this.index]) != -1; //$NON-NLS-1$
109
}
110         
111         boolean isAtTypeParameterStart() {
112             return
113                 this.index < this.source.length
114                 && this.source[this.index] == 'T';
115         }
116     
117         boolean isAtTypeArgumentStart() {
118             return this.index < this.source.length && "LIZVCDBFJS[!".indexOf(this.source[this.index]) != -1; //$NON-NLS-1$
119
}
120         
121         boolean isAtThrownStart() {
122             return
123                 this.index < this.source.length
124                 && this.source[this.index] == C_THROWN;
125         }
126         
127         boolean isAtTypeVariableStart() {
128             return
129                 this.index < this.source.length
130                 && this.source[this.index] == ':';
131         }
132         
133         boolean isAtTypeWithCaptureStart() {
134             return
135                 this.index < this.source.length
136                 && this.source[this.index] == '&';
137         }
138         
139         int nextToken() {
140             int previousTokenEnd = this.index;
141             this.start = this.index;
142             int length = this.source.length;
143             while (this.index <= length) {
144                 char currentChar = this.index == length ? Character.MIN_VALUE : this.source[this.index];
145                 switch (currentChar) {
146                     case 'B':
147                     case 'C':
148                     case 'D':
149                     case 'F':
150                     case 'I':
151                     case 'J':
152                     case 'N':
153                     case 'S':
154                     case 'V':
155                     case 'Z':
156                         // base type
157
if (this.index == previousTokenEnd
158                                 && (this.index == 0 || this.source[this.index-1] != '.')) { // case of field or method starting with one of the character above
159
this.index++;
160                             this.token = BASE_TYPE;
161                             return this.token;
162                         }
163                         break;
164                     case 'L':
165                     case 'T':
166                         if (this.index == previousTokenEnd) {
167                             this.start = this.index+1;
168                         }
169                         break;
170                     case ';':
171                         if (this.index == previousTokenEnd) {
172                             this.start = this.index+1;
173                             previousTokenEnd = this.start;
174                         } else {
175                             this.token = TYPE;
176                             return this.token;
177                         }
178                         break;
179                     case '$':
180                     case '~':
181                         if (this.index == previousTokenEnd) {
182                             this.start = this.index+1;
183                         } else {
184                             this.token = TYPE;
185                             return this.token;
186                         }
187                         break;
188                     case '.':
189                     case '%':
190                     case ':':
191                     case '>':
192                         this.start = this.index+1;
193                         previousTokenEnd = this.start;
194                         break;
195                     case '[':
196                         while (this.index < length && this.source[this.index] == '[')
197                             this.index++;
198                         this.token = ARRAY;
199                         return this.token;
200                     case '<':
201                         if (this.start > 0) {
202                             switch (this.source[this.start-1]) {
203                                 case '.':
204                                     if (this.source[this.start-2] == '>')
205                                         // case of member type where enclosing type is parameterized
206
this.token = TYPE;
207                                     else
208                                         this.token = METHOD;
209                                     return this.token;
210                                 default:
211                                     if (this.index == previousTokenEnd) {
212                                         this.start = this.index+1;
213                                         previousTokenEnd = this.start;
214                                     } else {
215                                         this.token = TYPE;
216                                         return this.token;
217                                     }
218                             }
219                         }
220                         break;
221                     case '(':
222                         this.token = METHOD;
223                         return this.token;
224                     case ')':
225                         if (this.token == TYPE) {
226                             this.token = FIELD;
227                             return this.token;
228                         }
229                         this.start = this.index+1;
230                         previousTokenEnd = this.start;
231                         break;
232                     case '#':
233                         if (this.index == previousTokenEnd) {
234                             this.start = this.index+1;
235                             previousTokenEnd = this.start;
236                         } else {
237                             this.token = LOCAL_VAR;
238                             return this.token;
239                         }
240                         break;
241                     case Character.MIN_VALUE:
242                         switch (this.token) {
243                             case START:
244                                 this.token = PACKAGE;
245                                 break;
246                             case METHOD:
247                             case LOCAL_VAR:
248                                 this.token = LOCAL_VAR;
249                                 break;
250                             case TYPE:
251                                 if (this.index > this.start && this.source[this.start-1] == '.')
252                                     this.token = FIELD;
253                                 else
254                                     this.token = END;
255                                 break;
256                             case WILDCARD:
257                                 this.token = TYPE;
258                                 break;
259                             default:
260                                 this.token = END;
261                                 break;
262                         }
263                         return this.token;
264                     case '*':
265                     case '+':
266                     case '-':
267                         this.index++;
268                         this.token = WILDCARD;
269                         return this.token;
270                     case '!':
271                     case '&':
272                         this.index++;
273                         this.token = CAPTURE;
274                         return this.token;
275                 }
276                 this.index++;
277             }
278             this.token = END;
279             return this.token;
280         }
281         
282         void skipMethodSignature() {
283             this.start = this.index;
284             int braket = 0;
285             while (this.index < this.source.length) {
286                 switch (this.source[this.index]) {
287                     case '#':
288                     case '%':
289                     case C_THROWN:
290                         return;
291                     case ':':
292                         if (braket == 0)
293                             return;
294                         break;
295                     case '<':
296                     case '(':
297                         braket++;
298                         break;
299                     case '>':
300                     case ')':
301                         braket--;
302                         break;
303                 }
304                 this.index++;
305             }
306         }
307         
308         void skipThrownStart() {
309             while (this.index < this.source.length && this.source[this.index] == C_THROWN)
310                 this.index++;
311         }
312
313         void skipParametersStart() {
314             while (this.index < this.source.length && (this.source[this.index] == '<' || this.source[this.index] == '%'))
315                 this.index++;
316         }
317         
318         void skipParametersEnd() {
319             while (this.index < this.source.length && this.source[this.index] != '>')
320                 this.index++;
321             this.index++;
322         }
323         
324         void skipTypeEnd() {
325             if (this.index < this.source.length && this.source[this.index] == ';')
326                 this.index++;
327         }
328         
329         public String JavaDoc toString() {
330             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
331             switch (this.token) {
332                 case START:
333                     buffer.append("START: "); //$NON-NLS-1$
334
break;
335                 case PACKAGE:
336                     buffer.append("PACKAGE: "); //$NON-NLS-1$
337
break;
338                 case TYPE:
339                     buffer.append("TYPE: "); //$NON-NLS-1$
340
break;
341                 case FIELD:
342                     buffer.append("FIELD: "); //$NON-NLS-1$
343
break;
344                 case METHOD:
345                     buffer.append("METHOD: "); //$NON-NLS-1$
346
break;
347                 case ARRAY:
348                     buffer.append("ARRAY: "); //$NON-NLS-1$
349
break;
350                 case LOCAL_VAR:
351                     buffer.append("LOCAL VAR: "); //$NON-NLS-1$
352
break;
353                 case FLAGS:
354                     buffer.append("MODIFIERS: "); //$NON-NLS-1$
355
break;
356                 case WILDCARD:
357                     buffer.append("WILDCARD: "); //$NON-NLS-1$
358
break;
359                 case CAPTURE:
360                     buffer.append("CAPTURE: "); //$NON-NLS-1$
361
break;
362                 case BASE_TYPE:
363                     buffer.append("BASE TYPE: "); //$NON-NLS-1$
364
break;
365                 case END:
366                     buffer.append("END: "); //$NON-NLS-1$
367
break;
368             }
369             if (this.index < 0) {
370                 buffer.append("**"); //$NON-NLS-1$
371
buffer.append(this.source);
372             } else if (this.index <= this.source.length) {
373                 buffer.append(this.source, 0, this.start);
374                 buffer.append('*');
375                 if (this.start <= this.index) {
376                     buffer.append(this.source, this.start, this.index - this.start);
377                     buffer.append('*');
378                     buffer.append(this.source, this.index, this.source.length - this.index);
379                 } else {
380                     buffer.append('*');
381                     buffer.append(this.source, this.start, this.source.length - this.start);
382                 }
383             } else {
384                 buffer.append(this.source);
385                 buffer.append("**"); //$NON-NLS-1$
386
}
387             return buffer.toString();
388         }
389     }
390     private boolean parsingPaused;
391     
392     private Scanner scanner;
393     
394     private boolean hasTypeName = true;
395     
396     public BindingKeyParser(BindingKeyParser parser) {
397         this(""); //$NON-NLS-1$
398
this.scanner = parser.scanner;
399     }
400     
401     public BindingKeyParser(String JavaDoc key) {
402         this.scanner = new Scanner(key.toCharArray());
403     }
404     
405     public void consumeArrayDimension(char[] brakets) {
406         // default is to do nothing
407
}
408     
409     public void consumeBaseType(char[] baseTypeSig) {
410         // default is to do nothing
411
}
412
413     public void consumeCapture(int position) {
414         // default is to do nothing
415
}
416     
417     public void consumeException() {
418         // default is to do nothing
419
}
420
421     public void consumeField(char[] fieldName) {
422         // default is to do nothing
423
}
424     
425     public void consumeParameterizedGenericMethod() {
426         // default is to do nothing
427
}
428     
429     public void consumeLocalType(char[] uniqueKey) {
430         // default is to do nothing
431
}
432     
433     public void consumeLocalVar(char[] varName) {
434         // default is to do nothing
435
}
436     
437     public void consumeMethod(char[] selector, char[] signature) {
438         // default is to do nothing
439
}
440     
441     public void consumeModifiers(char[] modifiers) {
442         // default is to do nothing
443
}
444     
445     public void consumeNonGenericType() {
446         // default is to do nothing
447
}
448
449     public void consumeMemberType(char[] simpleTypeName) {
450         // default is to do nothing
451
}
452
453     public void consumePackage(char[] pkgName) {
454         // default is to do nothing
455
}
456     
457     public void consumeParameterizedType(char[] simpleTypeName, boolean isRaw) {
458         // default is to do nothing
459
}
460     
461     public void consumeParser(BindingKeyParser parser) {
462         // default is to do nothing
463
}
464     
465     public void consumeRawType() {
466         // default is to do nothing
467
}
468     
469     public void consumeScope(int scopeNumber) {
470         // default is to do nothing
471
}
472     
473     public void consumeSecondaryType(char[] simpleTypeName) {
474         // default is to do nothing
475
}
476
477     public void consumeFullyQualifiedName(char[] fullyQualifiedName) {
478         // default is to do nothing
479
}
480
481     public void consumeKey() {
482         // default is to do nothing
483
}
484
485     public void consumeTopLevelType() {
486         // default is to do nothing
487
}
488     
489     public void consumeType() {
490         // default is to do nothing
491
}
492     
493     public void consumeTypeParameter(char[] typeParameterName) {
494         // default is to do nothing
495
}
496     
497     public void consumeTypeVariable(char[] position, char[] typeVariableName) {
498         // default is to do nothing
499
}
500     
501     public void consumeTypeWithCapture() {
502         // default is to do nothing
503
}
504
505     public void consumeWildCard(int kind) {
506         // default is to do nothing
507
}
508     
509     /*
510      * Returns the string that this binding key wraps.
511      */

512     public String JavaDoc getKey() {
513         return new String JavaDoc(this.scanner.source);
514     }
515     
516     public boolean hasTypeName() {
517         return this.hasTypeName;
518     }
519     
520     public void malformedKey() {
521         // default is to do nothing
522
}
523     
524     public BindingKeyParser newParser() {
525         return new BindingKeyParser(this);
526     }
527     
528     public void parse() {
529         parse(false/*don't pause after fully qualified name*/);
530     }
531
532     public void parse(boolean pauseAfterFullyQualifiedName) {
533         try {
534             if (!this.parsingPaused) {
535                 // fully qualified name
536
parseFullyQualifiedName();
537                 parseSecondaryType();
538                 if (pauseAfterFullyQualifiedName) {
539                     this.parsingPaused = true;
540                     return;
541                 }
542             }
543             if (!hasTypeName()) {
544                 consumeKey();
545                 return;
546             }
547             consumeTopLevelType();
548             parseInnerType();
549             
550             if (this.scanner.isAtParametersStart()) {
551                 this.scanner.skipParametersStart();
552                 if (this.scanner.isAtTypeParameterStart()) {
553                     // generic type
554
parseGenericType();
555                     // skip ";>"
556
this.scanner.skipParametersEnd();
557                     // local type in generic type
558
parseInnerType();
559                 } else if (this.scanner.isAtTypeArgumentStart())
560                     // parameterized type
561
parseParameterizedType(null/*top level type or member type with raw enclosing type*/, false/*no raw*/);
562                 else if (this.scanner.isAtRawTypeEnd())
563                     // raw type
564
parseRawType();
565             } else {
566                 // non-generic type
567
consumeNonGenericType();
568             }
569             
570             consumeType();
571             this.scanner.skipTypeEnd();
572             
573             if (this.scanner.isAtFieldOrMethodStart()) {
574                 switch (this.scanner.nextToken()) {
575                     case Scanner.FIELD:
576                         parseField();
577                         return;
578                     case Scanner.METHOD:
579                         parseMethod();
580                         if (this.scanner.isAtLocalVariableStart()) {
581                             parseLocalVariable();
582                         } else if (this.scanner.isAtTypeVariableStart()) {
583                             parseTypeVariable();
584                         }
585                         break;
586                     default:
587                         malformedKey();
588                         return;
589                 }
590             } else if (this.scanner.isAtTypeVariableStart()) {
591                 parseTypeVariable();
592             } else if (this.scanner.isAtWildcardStart()) {
593                 parseWildcard();
594             } else if (this.scanner.isAtTypeWithCaptureStart()) {
595                 parseTypeWithCapture();
596             }
597             
598             consumeKey();
599         } catch (IllegalArgumentException JavaDoc e) {
600             // the given key was illegal
601
}
602     }
603     
604     private void parseFullyQualifiedName() {
605         if (this.scanner.isAtCaptureStart()) {
606             parseCapture();
607             this.hasTypeName = false;
608             return;
609         }
610         switch(this.scanner.nextToken()) {
611             case Scanner.PACKAGE:
612                 this.keyStart = 0;
613                 consumePackage(this.scanner.getTokenSource());
614                 this.hasTypeName = false;
615                 return;
616             case Scanner.TYPE:
617                 this.keyStart = this.scanner.start-1;
618                 consumeFullyQualifiedName(this.scanner.getTokenSource());
619                 break;
620             case Scanner.BASE_TYPE:
621                 this.keyStart = this.scanner.start-1;
622                 consumeBaseType(this.scanner.getTokenSource());
623                 this.hasTypeName = false;
624                 break;
625             case Scanner.ARRAY:
626                 this.keyStart = this.scanner.start;
627                 consumeArrayDimension(this.scanner.getTokenSource());
628                 switch (this.scanner.nextToken()) {
629                     case Scanner.TYPE:
630                         consumeFullyQualifiedName(this.scanner.getTokenSource());
631                         break;
632                     case Scanner.BASE_TYPE:
633                         consumeBaseType(this.scanner.getTokenSource());
634                         this.hasTypeName = false;
635                         break;
636                     default:
637                         malformedKey();
638                         return;
639                 }
640                 break;
641             default:
642                 malformedKey();
643                 return;
644         }
645     }
646     
647     private void parseParameterizedMethod() {
648         this.scanner.skipParametersStart();
649         while (!this.scanner.isAtParametersEnd()) {
650             parseTypeArgument();
651         }
652         consumeParameterizedGenericMethod();
653     }
654     
655     private void parseGenericType() {
656         while (!this.scanner.isAtParametersEnd()) {
657             if (this.scanner.nextToken() != Scanner.TYPE) {
658                 malformedKey();
659                 return;
660             }
661             consumeTypeParameter(this.scanner.getTokenSource());
662             this.scanner.skipTypeEnd();
663         }
664     }
665     
666     private void parseInnerType() {
667         if (!this.scanner.isAtMemberTypeStart() || this.scanner.nextToken() != Scanner.TYPE)
668             return;
669         char[] typeName = this.scanner.getTokenSource();
670         if (Character.isDigit(typeName[0])) {
671             // anonymous or local type
672
int nextToken = Scanner.TYPE;
673             while (this.scanner.isAtMemberTypeStart())
674                 nextToken = this.scanner.nextToken();
675             typeName = nextToken == Scanner.END ? this.scanner.source : CharOperation.subarray(this.scanner.source, this.keyStart, this.scanner.index+1);
676             consumeLocalType(typeName);
677         } else {
678             consumeMemberType(typeName);
679             parseInnerType();
680         }
681     }
682     
683     private void parseLocalVariable() {
684         if (this.scanner.nextToken() != Scanner.LOCAL_VAR) {
685             malformedKey();
686             return;
687         }
688         char[] varName = this.scanner.getTokenSource();
689         if (Character.isDigit(varName[0])) {
690             int index = Integer.parseInt(new String JavaDoc(varName));
691             consumeScope(index);
692             if (!this.scanner.isAtLocalVariableStart()) {
693                 malformedKey();
694                 return;
695             }
696             parseLocalVariable();
697         } else {
698             consumeLocalVar(varName);
699         }
700     }
701     
702     private void parseMethod() {
703         char[] selector = this.scanner.getTokenSource();
704         this.scanner.skipMethodSignature();
705         char[] signature = this.scanner.getTokenSource();
706         consumeMethod(selector, signature);
707         if (this.scanner.isAtThrownStart()) {
708             parseThrownExceptions();
709         }
710         if (this.scanner.isAtParametersStart())
711             parseParameterizedMethod();
712     }
713     
714     private void parseCapture() {
715         if (this.scanner.nextToken() != Scanner.CAPTURE) return;
716         parseCaptureWildcard();
717         if (this.scanner.nextToken() != Scanner.TYPE) {
718             malformedKey();
719             return;
720         }
721         char[] positionChars = this.scanner.getTokenSource();
722         int position = Integer.parseInt(new String JavaDoc(positionChars));
723         consumeCapture(position);
724         this.scanner.skipTypeEnd();
725     }
726     
727     private void parseCaptureWildcard() {
728         BindingKeyParser parser = newParser();
729         parser.parse();
730         consumeParser(parser);
731     }
732     
733     private void parseField() {
734         char[] fieldName = this.scanner.getTokenSource();
735         parseReturnType();
736         consumeField(fieldName);
737     }
738     
739     private void parseThrownExceptions() {
740         while (this.scanner.isAtThrownStart()) {
741             this.scanner.skipThrownStart();
742             BindingKeyParser parser = newParser();
743             parser.parse();
744             consumeParser(parser);
745             consumeException();
746         }
747     }
748     
749     private void parseParameterizedType(char[] typeName, boolean isRaw) {
750         if (!isRaw) {
751             while (!this.scanner.isAtParametersEnd()) {
752                 parseTypeArgument();
753             }
754         }
755         // skip ";>"
756
this.scanner.skipParametersEnd();
757         consumeParameterizedType(typeName, isRaw);
758         this.scanner.skipTypeEnd();
759         if (this.scanner.isAtMemberTypeStart() && this.scanner.nextToken() == Scanner.TYPE) {
760             typeName = this.scanner.getTokenSource();
761             if (this.scanner.isAtParametersStart()) {
762                 this.scanner.skipParametersStart();
763                 parseParameterizedType(typeName, this.scanner.isAtRawTypeEnd());
764             } else
765                 consumeParameterizedType(typeName, true/*raw*/);
766         }
767     }
768     
769     private void parseRawType() {
770         this.scanner.skipParametersEnd();
771         consumeRawType();
772         this.scanner.skipTypeEnd();
773         if (this.scanner.isAtMemberTypeStart() && this.scanner.nextToken() == Scanner.TYPE) {
774             char[] typeName = this.scanner.getTokenSource();
775             if (this.scanner.isAtParametersStart()) {
776                 this.scanner.skipParametersStart();
777                 parseParameterizedType(typeName, this.scanner.isAtRawTypeEnd());
778             } else
779                 consumeParameterizedType(typeName, true/*raw*/);
780         }
781     }
782     
783     private void parseReturnType() {
784         BindingKeyParser parser = newParser();
785         parser.parse();
786         consumeParser(parser);
787     }
788
789     private void parseSecondaryType() {
790         if (!this.scanner.isAtSecondaryTypeStart() || this.scanner.nextToken() != Scanner.TYPE) return;
791         consumeSecondaryType(this.scanner.getTokenSource());
792     }
793     
794     private void parseTypeArgument() {
795         BindingKeyParser parser = newParser();
796         parser.parse();
797         consumeParser(parser);
798     }
799     
800     private void parseTypeWithCapture() {
801         if (this.scanner.nextToken() != Scanner.CAPTURE) return;
802         BindingKeyParser parser = newParser();
803         parser.parse();
804         consumeParser(parser);
805         consumeTypeWithCapture();
806     }
807     
808     private void parseTypeVariable() {
809         if (this.scanner.nextToken() != Scanner.TYPE) {
810             malformedKey();
811             return;
812         }
813         char[] typeVariableName = this.scanner.getTokenSource();
814         char[] position;
815         int length = typeVariableName.length;
816         if (length > 0 && Character.isDigit(typeVariableName[0])) {
817             int firstT = CharOperation.indexOf('T', typeVariableName);
818             position = CharOperation.subarray(typeVariableName, 0, firstT);
819             typeVariableName = CharOperation.subarray(typeVariableName, firstT+1, typeVariableName.length);
820         } else {
821             position = CharOperation.NO_CHAR;
822         }
823         consumeTypeVariable(position, typeVariableName);
824         this.scanner.skipTypeEnd();
825     }
826     
827     private void parseWildcard() {
828         if (this.scanner.nextToken() != Scanner.WILDCARD) return;
829         char[] source = this.scanner.getTokenSource();
830         if (source.length == 0) {
831             malformedKey();
832             return;
833         }
834         int kind = -1;
835         switch (source[0]) {
836             case '*':
837                 kind = Wildcard.UNBOUND;
838                 break;
839             case '+':
840                 kind = Wildcard.EXTENDS;
841                 break;
842             case '-':
843                 kind = Wildcard.SUPER;
844                 break;
845         }
846         if (kind == -1) {
847             malformedKey();
848             return;
849         }
850         if (kind != Wildcard.UNBOUND)
851             parseWildcardBound();
852         consumeWildCard(kind);
853     }
854     
855     private void parseWildcardBound() {
856         BindingKeyParser parser = newParser();
857         parser.parse();
858         consumeParser(parser);
859     }
860     
861 }
862
Popular Tags