1 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; } 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; } 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 if (this.index == previousTokenEnd 158 && (this.index == 0 || this.source[this.index-1] != '.')) { 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 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 toString() { 330 StringBuffer buffer = new StringBuffer (); 331 switch (this.token) { 332 case START: 333 buffer.append("START: "); break; 335 case PACKAGE: 336 buffer.append("PACKAGE: "); break; 338 case TYPE: 339 buffer.append("TYPE: "); break; 341 case FIELD: 342 buffer.append("FIELD: "); break; 344 case METHOD: 345 buffer.append("METHOD: "); break; 347 case ARRAY: 348 buffer.append("ARRAY: "); break; 350 case LOCAL_VAR: 351 buffer.append("LOCAL VAR: "); break; 353 case FLAGS: 354 buffer.append("MODIFIERS: "); break; 356 case WILDCARD: 357 buffer.append("WILDCARD: "); break; 359 case CAPTURE: 360 buffer.append("CAPTURE: "); break; 362 case BASE_TYPE: 363 buffer.append("BASE TYPE: "); break; 365 case END: 366 buffer.append("END: "); break; 368 } 369 if (this.index < 0) { 370 buffer.append("**"); 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("**"); } 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(""); this.scanner = parser.scanner; 399 } 400 401 public BindingKeyParser(String key) { 402 this.scanner = new Scanner(key.toCharArray()); 403 } 404 405 public void consumeArrayDimension(char[] brakets) { 406 } 408 409 public void consumeBaseType(char[] baseTypeSig) { 410 } 412 413 public void consumeCapture(int position) { 414 } 416 417 public void consumeException() { 418 } 420 421 public void consumeField(char[] fieldName) { 422 } 424 425 public void consumeParameterizedGenericMethod() { 426 } 428 429 public void consumeLocalType(char[] uniqueKey) { 430 } 432 433 public void consumeLocalVar(char[] varName) { 434 } 436 437 public void consumeMethod(char[] selector, char[] signature) { 438 } 440 441 public void consumeModifiers(char[] modifiers) { 442 } 444 445 public void consumeNonGenericType() { 446 } 448 449 public void consumeMemberType(char[] simpleTypeName) { 450 } 452 453 public void consumePackage(char[] pkgName) { 454 } 456 457 public void consumeParameterizedType(char[] simpleTypeName, boolean isRaw) { 458 } 460 461 public void consumeParser(BindingKeyParser parser) { 462 } 464 465 public void consumeRawType() { 466 } 468 469 public void consumeScope(int scopeNumber) { 470 } 472 473 public void consumeSecondaryType(char[] simpleTypeName) { 474 } 476 477 public void consumeFullyQualifiedName(char[] fullyQualifiedName) { 478 } 480 481 public void consumeKey() { 482 } 484 485 public void consumeTopLevelType() { 486 } 488 489 public void consumeType() { 490 } 492 493 public void consumeTypeParameter(char[] typeParameterName) { 494 } 496 497 public void consumeTypeVariable(char[] position, char[] typeVariableName) { 498 } 500 501 public void consumeTypeWithCapture() { 502 } 504 505 public void consumeWildCard(int kind) { 506 } 508 509 512 public String getKey() { 513 return new String (this.scanner.source); 514 } 515 516 public boolean hasTypeName() { 517 return this.hasTypeName; 518 } 519 520 public void malformedKey() { 521 } 523 524 public BindingKeyParser newParser() { 525 return new BindingKeyParser(this); 526 } 527 528 public void parse() { 529 parse(false); 530 } 531 532 public void parse(boolean pauseAfterFullyQualifiedName) { 533 try { 534 if (!this.parsingPaused) { 535 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 parseGenericType(); 555 this.scanner.skipParametersEnd(); 557 parseInnerType(); 559 } else if (this.scanner.isAtTypeArgumentStart()) 560 parseParameterizedType(null, false); 562 else if (this.scanner.isAtRawTypeEnd()) 563 parseRawType(); 565 } else { 566 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 e) { 600 } 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 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 (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 (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 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); 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); 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 |