1 /* 2 * Copyright (c) 1996, 2020, Oracle and/or its affiliates. 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.asmtools.jasm; 24 25 import org.openjdk.asmtools.jasm.TypeAnnotationTargetInfoData.*; 26 27 import static org.openjdk.asmtools.jasm.JasmTokens.AnnotationType.isInvisibleAnnotationToken; 28 import static org.openjdk.asmtools.jasm.TypeAnnotationTypes.*; 29 import static org.openjdk.asmtools.jasm.JasmTokens.*; 30 import static org.openjdk.asmtools.jasm.ConstantPool.*; 31 import static org.openjdk.asmtools.jasm.Tables.*; 32 import java.io.IOException; 33 import java.util.ArrayList; 34 import java.util.TreeMap; 35 36 /** 37 * ParserAnnotation 38 * 39 * ParserAnnotation is a parser class owned by Parser.java. It is primarily responsible 40 * for parsing Annotations (for classes, methods or fields). 41 * 42 * ParserAnnotation can parse the different types of Annotation Attributes: 43 * Runtime(In)Visible Annotations (JDK 6+) Default Annotations (JDK 6+) 44 * Runtime(In)VisibleParameter Annotations (JDK 7+) Runtime(In)VisibleType Annotations 45 * (JSR308, JDK8+) 46 */ 47 public class ParserAnnotation extends ParseBase { 48 49 /*-------------------------------------------------------- */ 50 /* Annotation Inner Classes */ 51 /** 52 * AnnotationElemValue 53 * 54 * Used to store Annotation values 55 */ 56 static class AnnotationElemValue implements Data { 57 58 AnnotationData annotation; 59 60 AnnotationElemValue(AnnotationData annotation) { 61 this.annotation = annotation; 62 } 63 64 @Override 65 public void write(CheckedDataOutputStream out) throws IOException { 66 out.writeByte('@'); 67 annotation.write(out); 68 } 69 70 @Override 71 public int getLength() { 72 return 1 + annotation.getLength(); 73 } 74 } 75 76 /** 77 * ClassElemValue 78 * 79 * Annotation Element value referring to a class 80 */ 81 static class ClassElemValue implements Data { 82 83 ConstCell indx; 84 85 ClassElemValue(ConstCell indx) { 86 this.indx = indx; 87 } 88 89 @Override 90 public void write(CheckedDataOutputStream out) throws IOException { 91 out.writeByte('c'); 92 indx.write(out); 93 } 94 95 @Override 96 public int getLength() { 97 return 3; 98 } 99 } 100 101 /** 102 * ArrayElemValue 103 * 104 * Annotation Element value referring to an Array 105 */ 106 static class ArrayElemValue implements Data { 107 108 ArrayList<Data> elemValues; 109 int arrayLength = 0; 110 111 ArrayElemValue() { 112 this.elemValues = new ArrayList<>(); 113 } 114 115 void add(Data elemValue) { 116 elemValues.add(elemValue); 117 arrayLength += elemValue.getLength(); 118 } 119 120 @Override 121 public void write(CheckedDataOutputStream out) throws IOException { 122 out.writeByte('['); 123 out.writeShort(elemValues.size()); 124 125 for (Data eval : elemValues) { 126 eval.write(out); 127 } 128 } 129 130 @Override 131 public int getLength() { 132 return 3 + arrayLength; 133 } 134 } 135 136 /** 137 * ConstElemValue 138 * 139 * Annotation Element value referring to a Constant 140 */ 141 static class ConstElemValue implements Data { 142 143 char tag; 144 ConstCell indx; 145 146 ConstElemValue(char tag, ConstCell indx) { 147 this.tag = tag; 148 this.indx = indx; 149 } 150 151 @Override 152 public void write(CheckedDataOutputStream out) throws IOException { 153 out.writeByte(tag); 154 indx.write(out); 155 } 156 157 @Override 158 public int getLength() { 159 return 3; 160 } 161 } 162 163 /** 164 * EnumElemValue 165 * 166 * Element Value for Enums 167 */ 168 static class EnumElemValue implements Data { 169 170 ConstCell type; 171 ConstCell value; 172 173 EnumElemValue(ConstCell type, ConstCell value) { 174 this.type = type; 175 this.value = value; 176 } 177 178 @Override 179 public void write(CheckedDataOutputStream out) throws IOException { 180 out.writeByte('e'); 181 type.write(out); 182 value.write(out); 183 } 184 185 @Override 186 public int getLength() { 187 return 5; 188 } 189 } 190 191 /** 192 * local handles on the scanner, main parser, and the error reporting env 193 */ 194 private static TTVis ttVisitor; 195 196 protected ParserAnnotation(Scanner scanner, Parser parser, Environment env) { 197 super.init(scanner, parser, env); 198 ttVisitor = new TTVis(); 199 ttVisitor.init(env, scanner); 200 } 201 202 protected void scanParamName(int totalParams, int paramNum, MethodData curMethod) throws IOException { 203 debugScan(" - - - > [ParserAnnotation.scanParamName]: Begin "); 204 scanner.scan(); 205 scanner.expect(Token.LBRACE); 206 // First scan the Name (String, or CPX to name) 207 ConstCell nameCell; 208 if ((scanner.token == Token.IDENT) || scanner.checkTokenIdent()) { 209 // Got a Class Name 210 nameCell = parser.parseName(); 211 } else if (scanner.token == Token.CPINDEX) { 212 int cpx = scanner.intValue; 213 nameCell = parser.pool.getCell(cpx); 214 // check the constant 215 ConstValue nameCellValue = nameCell.ref; 216 if (!(nameCellValue instanceof ConstValue_String)) { 217 // throw an error 218 env.error(scanner.pos, "paramname.constnum.invaltype", cpx); 219 throw new Scanner.SyntaxError(); 220 } 221 222 } else { 223 // throw scan error - unexpected token 224 env.error(scanner.pos, "paramname.token.unexpected", scanner.stringValue); 225 throw new Scanner.SyntaxError(); 226 } 227 228 // Got the name cell. Next, scan the access flags 229 int mod = parser.scanModifiers(); 230 231 scanner.expect(Token.RBRACE); 232 233 curMethod.addMethodParameter(totalParams, paramNum, nameCell, mod); 234 235 debugScan(" - - - > [ParserAnnotation.scanParamName]: End "); 236 } 237 238 /** 239 * The main entry for parsing an annotation list. 240 * 241 * @return An ArrayList of parsed annotations 242 * @throws IOException 243 */ 244 ArrayList<AnnotationData> scanAnnotations() throws IOException { 245 ArrayList<AnnotationData> list = new ArrayList<>(); 246 while (scanner.token == Token.ANNOTATION) { 247 if ( JasmTokens.AnnotationType.isAnnotationToken(scanner.stringValue)) { 248 list.add(parseAnnotation()); 249 } else if (JasmTokens.AnnotationType.isTypeAnnotationToken(scanner.stringValue)) { 250 list.add(parseTypeAnnotation()); 251 } else { 252 return null; 253 } 254 } 255 if (list.size() > 0) { 256 return list; 257 } else { 258 return null; 259 } 260 } 261 262 /** 263 * parseDefaultAnnotation 264 * 265 * parses a default Annotation attribute 266 * 267 * @return the parsed Annotation Attribute 268 * @throws org.openjdk.asmtools.jasm.Scanner.SyntaxError 269 * @throws IOException 270 */ 271 protected DefaultAnnotationAttr parseDefaultAnnotation() throws Scanner.SyntaxError, IOException { 272 scanner.scan(); 273 DefaultAnnotationAttr attr = null; 274 Data value = null; 275 scanner.expect(Token.LBRACE); 276 277 if ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { 278 value = scanAnnotationData("default"); 279 } 280 scanner.expect(Token.RBRACE); 281 attr = new DefaultAnnotationAttr(parser.cd, 282 AttrTag.ATT_AnnotationDefault.parsekey(), 283 value); 284 return attr; 285 } 286 287 /** 288 * parseParamAnnots 289 * 290 * Parses Parameter Annotations attributes. 291 * 292 * @param _totalParams 293 * @param curMethod 294 * @throws org.openjdk.asmtools.jasm.Scanner.SyntaxError 295 * @throws IOException 296 */ 297 protected void parseParamAnnots(int _totalParams, MethodData curMethod) throws Scanner.SyntaxError, IOException { 298 debugScan(" - - - > [ParserAnnotation.parseParamAnnots]: Begin, totalParams = " + _totalParams + " "); 299 // The _method thinks there are N+1 params in the signature 300 // (N = total params in the call list) + 1 (return value) 301 int totalParams = _totalParams - 1; 302 TreeMap<Integer, ArrayList<AnnotationData>> pAnnots = new TreeMap<>(); 303 304 while (scanner.token == Token.INTVAL) { 305 // Create the Parameter Array for Param Annotations 306 307 // Do something with Parameter annotations 308 // -------------------- 309 // First - validate that the parameter number (integer) 310 // (eg >= 0, < numParams, and param num is not previously set) 311 int paramNum = scanner.intValue; 312 Integer iParamNum = Integer.valueOf(paramNum); 313 if (paramNum < 0 || paramNum >= totalParams) { 314 //invalid Parameter number. Throw an error. 315 env.error(scanner.pos, "invalid.paramnum", paramNum); 316 } 317 if (pAnnots.get(iParamNum) != null) { 318 // paramter is already populated with annotations/pnames, Throw an error. 319 env.error(scanner.pos, "duplicate.paramnum", paramNum); 320 } 321 // 2nd - Parse the COLON (invalid if not present) 322 scanner.scan(); 323 scanner.expect(Token.COLON); 324 325 // 3rd - parse either an optional ParamName, or a list of annotations 326 if (scanner.token == Token.PARAM_NAME) { 327 //parse the ParamName 328 scanParamName(totalParams, iParamNum, curMethod); 329 } 330 331 // 4th - parse each Annotation (followed by comma, followed by annotation 332 // assign array of annotations to param array 333 if (scanner.token == Token.ANNOTATION) { 334 ArrayList<AnnotationData> pAnnot = scanAnnotations(); 335 pAnnots.put(iParamNum, pAnnot); 336 337 for (AnnotationData data : pAnnot) { 338 curMethod.addParamAnnotation(totalParams, paramNum, data); 339 } 340 } 341 342 } 343 } 344 345 /* ************************* Private Members *************************** */ 346 /** 347 * parseTypeAnnotation 348 * 349 * parses an individual annotation. 350 * 351 * @return a parsed annotation. 352 * @throws IOException 353 */ 354 private AnnotationData parseTypeAnnotation() throws Scanner.SyntaxError, IOException { 355 boolean invisible = isInvisibleAnnotationToken(scanner.stringValue); 356 scanner.scan(); 357 debugScan(" [ParserAnnotation.parseTypeAnnotation]: id = " + scanner.stringValue + " "); 358 String annoName = "L" + scanner.stringValue + ";"; 359 TypeAnnotationData anno = new TypeAnnotationData(parser.pool.FindCellAsciz(annoName), invisible); 360 scanner.scan(); 361 debugScan(" [ParserAnnotation.parseTypeAnnotation]:new type annotation: " + annoName + " "); 362 363 scanner.expect(Token.LBRACE); 364 365 // Scan the usual annotation data 366 _scanAnnotation(anno); 367 368 // scan the Target (u1: target_type, union{...}: target_info) 369 _scanTypeTarget(anno); 370 371 if( scanner.token != Token.RBRACE ) { 372 // scan the Location (type_path: target_path) 373 _scanTargetPath(anno); 374 } 375 376 scanner.expect(Token.RBRACE); 377 return anno; 378 } 379 380 /** 381 * scanAnnotation 382 * 383 * parses an individual annotation. 384 * 385 * @return a parsed annotation. 386 * @throws IOException 387 */ 388 private AnnotationData parseAnnotation() throws Scanner.SyntaxError, IOException { 389 debugScan(" - - - > [ParserAnnotation.parseAnnotation]: Begin "); 390 boolean invisible = isInvisibleAnnotationToken(scanner.stringValue); 391 scanner.scan(); 392 String annoName = "L" + scanner.stringValue + ";"; 393 394 AnnotationData anno = new AnnotationData(parser.pool.FindCellAsciz(annoName), invisible); 395 scanner.scan(); 396 debugScan("[ParserAnnotation.parseAnnotation]: new annotation: " + annoName); 397 _scanAnnotation(anno); 398 399 return anno; 400 } 401 402 /** 403 * _scanAnnotation 404 * 405 * parses an individual annotation-data. 406 * 407 * @return a parsed annotation. 408 * @throws IOException 409 */ 410 private void _scanAnnotation(AnnotationData annotData) throws Scanner.SyntaxError, IOException { 411 debugScan(" - - - > [ParserAnnotation._scanAnnotation]: Begin"); 412 scanner.expect(Token.LBRACE); 413 414 while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { 415 ConstCell nameCell = parser.parseName(); 416 scanner.expect(Token.ASSIGN); 417 418 ConstValue cellref = nameCell.ref; 419 if (cellref.tag != ConstType.CONSTANT_UTF8) { 420 throw new Scanner.SyntaxError(); 421 } 422 String name = ((ConstValue_String) cellref)._toString(); 423 debugScan(" [ParserAnnotation._scanAnnotation]: Annot - Field Name: " + name); 424 Data data = scanAnnotationData(name); 425 annotData.add(new AnnotationData.ElemValuePair(nameCell, data)); 426 427 // consume tokens inbetween annotation fields 428 if (scanner.token == Token.COMMA) { 429 scanner.scan(); 430 } 431 } 432 scanner.expect(Token.RBRACE); 433 } 434 435 /** 436 * _scanAnnotation 437 * 438 * parses an individual annotation-data. 439 * 440 * @return a parsed annotation. 441 * @throws IOException 442 */ 443 private void _scanTypeTarget(TypeAnnotationData annotData) throws Scanner.SyntaxError, IOException { 444 debugScan(" [ParserAnnotation._scanTypeTarget]: Begin "); 445 scanner.expect(Token.LBRACE); 446 447 //Scan the target_type and the target_info 448 scanner.expect(Token.IDENT); 449 debugScan(" [ParserAnnotation._scanTypeTarget]: TargetType: " + scanner.idValue); 450 ETargetType targetType = ETargetType.getTargetType(scanner.idValue); 451 if (targetType == null) { 452 env.error(scanner.pos, "incorrect.typeannot.target", scanner.idValue); 453 throw new Scanner.SyntaxError(); 454 } 455 456 debugScan(" [ParserAnnotation._scanTypeTarget]: Got TargetType: " + targetType); 457 458 if (ttVisitor.scanner == null) { 459 ttVisitor.scanner = scanner; 460 } 461 ttVisitor.visitExcept(targetType); 462 463 annotData.targetInfo = ttVisitor.getTargetInfo(); 464 annotData.targetType = targetType; 465 debugScan(" [ParserAnnotation._scanTypeTarget]: Got TargetInfo: " + annotData.targetInfo); 466 467 scanner.expect(Token.RBRACE); 468 } 469 470 /** 471 * TTVis 472 * 473 * Target Type visitor, used for constructing the target-info within a type 474 * annotation. visitExcept() is the entry point. ti is the constructed target info. 475 */ 476 private static class TTVis extends TypeAnnotationTypes.TypeAnnotationTargetVisitor { 477 478 private TypeAnnotationTargetInfoData ti; 479 private IOException IOProb; 480 private Scanner.SyntaxError SyProb; 481 private Scanner scanner; 482 private Environment env; 483 484 public TTVis() { 485 super(); 486 reset(); 487 } 488 489 public void init(Environment en, Scanner scn) { 490 if (scanner == null) { 491 scanner = scn; 492 } 493 if (env == null) { 494 env = en; 495 } 496 } 497 498 public final void reset() { 499 ti = null; 500 IOProb = null; 501 SyProb = null; 502 } 503 504 //This is the entry point for a visitor that tunnels exceptions 505 public void visitExcept(ETargetType tt) throws IOException, Scanner.SyntaxError { 506 IOProb = null; 507 SyProb = null; 508 ti = null; 509 510 visit(tt); 511 512 if (IOProb != null) { 513 throw IOProb; 514 } 515 516 if (SyProb != null) { 517 throw SyProb; 518 } 519 } 520 521 public TypeAnnotationTargetInfoData getTargetInfo() { 522 return ti; 523 } 524 525 // this fn gathers intvals, and tunnels any exceptions thrown by 526 // the scanner 527 private int scanIntVal(ETargetType tt) { 528 int ret = -1; 529 if (scanner.token == Token.INTVAL) { 530 ret = scanner.intValue; 531 try { 532 scanner.scan(); 533 } catch (IOException e) { 534 IOProb = e; 535 } catch (Scanner.SyntaxError e) { 536 SyProb = e; 537 } 538 } else { 539 env.error(scanner.pos, "incorrect.typeannot.targtype.int", tt.parseKey(), scanner.token); 540 SyProb = new Scanner.SyntaxError(); 541 } 542 return ret; 543 } 544 545 // this fn gathers intvals, and tunnels any exceptions thrown by 546 // the scanner 547 private String scanStringVal(ETargetType tt) { 548 String ret = ""; 549 if (scanner.token == Token.STRINGVAL) { 550 ret = scanner.stringValue; 551 try { 552 scanner.scan(); 553 } catch (IOException e) { 554 IOProb = e; 555 } catch (Scanner.SyntaxError e) { 556 SyProb = e; 557 } 558 } else { 559 env.error(scanner.pos, "incorrect.typeannot.targtype.string", tt.parseKey(), scanner.token); 560 SyProb = new Scanner.SyntaxError(); 561 } 562 return ret; 563 } 564 565 // this fn gathers intvals, and tunnels any exceptions thrown by 566 // the scanner 567 private void scanBrace(boolean left) { 568 try { 569 scanner.expect(left ? Token.LBRACE : Token.RBRACE); 570 } catch (IOException e) { 571 IOProb = e; 572 } catch (Scanner.SyntaxError e) { 573 SyProb = e; 574 } 575 } 576 577 private boolean error() { 578 return IOProb != null || SyProb != null; 579 } 580 581 @Override 582 public void visit_type_param_target(ETargetType tt) { 583 env.traceln("Type Param Target: "); 584 int byteval = scanIntVal(tt); // param index 585 if (!error()) { 586 ti = new TypeAnnotationTargetInfoData.type_parameter_target(tt, byteval); 587 } 588 } 589 590 @Override 591 public void visit_supertype_target(ETargetType tt) { 592 env.traceln("SuperType Target: "); 593 int shortval = scanIntVal(tt); // type index 594 if (!error()) { 595 ti = new TypeAnnotationTargetInfoData.supertype_target(tt, shortval); 596 } 597 } 598 599 @Override 600 public void visit_typeparam_bound_target(ETargetType tt) { 601 env.traceln("TypeParam Bound Target: "); 602 int byteval1 = scanIntVal(tt); // param index 603 if (error()) { 604 return; 605 } 606 int byteval2 = scanIntVal(tt); // bound index 607 if (error()) { 608 return; 609 } 610 ti = new TypeAnnotationTargetInfoData.type_parameter_bound_target(tt, byteval1, byteval2); 611 } 612 613 @Override 614 public void visit_empty_target(ETargetType tt) { 615 env.traceln("Empty Target: "); 616 if (!error()) { 617 ti = new TypeAnnotationTargetInfoData.empty_target(tt); 618 } 619 } 620 621 @Override 622 public void visit_methodformalparam_target(ETargetType tt) { 623 env.traceln("MethodParam Target: "); 624 int byteval = scanIntVal(tt); // param index 625 if (!error()) { 626 ti = new formal_parameter_target(tt, byteval); 627 } 628 } 629 630 @Override 631 public void visit_throws_target(ETargetType tt) { 632 env.traceln("Throws Target: "); 633 int shortval = scanIntVal(tt); // exception index 634 if (!error()) { 635 ti = new throws_target(tt, shortval); 636 } 637 } 638 639 @Override 640 public void visit_localvar_target(ETargetType tt) { 641 env.traceln("LocalVar Target: "); 642 localvar_target locvartab = new localvar_target(tt, 0); 643 ti = locvartab; 644 645 while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { 646 // consume the left brace 647 scanBrace(true); 648 if (error()) { 649 return; 650 } 651 // scan the local var triple 652 int shortval1 = scanIntVal(tt); // startPC 653 if (error()) { 654 return; 655 } 656 int shortval2 = scanIntVal(tt); // length 657 if (error()) { 658 return; 659 } 660 int shortval3 = scanIntVal(tt); // CPX 661 locvartab.addEntry(shortval1, shortval2, shortval3); 662 scanBrace(false); 663 if (error()) { 664 return; 665 } 666 } 667 } 668 669 @Override 670 public void visit_catch_target(ETargetType tt) { 671 env.traceln("Catch Target: "); 672 int shortval = scanIntVal(tt); // catch index 673 674 ti = new catch_target(tt, shortval); 675 } 676 677 @Override 678 public void visit_offset_target(ETargetType tt) { 679 env.traceln("Offset Target: "); 680 int shortval = scanIntVal(tt); // offset index 681 if (!error()) { 682 ti = new offset_target(tt, shortval); 683 } 684 } 685 686 @Override 687 public void visit_typearg_target(ETargetType tt) { 688 env.traceln("TypeArg Target: "); 689 int shortval = scanIntVal(tt); // offset 690 if (error()) { 691 return; 692 } 693 int byteval = scanIntVal(tt); // type index 694 if (error()) { 695 return; 696 } 697 ti = new type_argument_target(tt, shortval, byteval); 698 } 699 700 } 701 702 /** 703 * _scanTargetPath 704 * 705 * parses and fills the type_path structure (4.7.20.2) 706 * 707 * type_path { 708 * u1 path_length; 709 * { u1 type_path_kind; 710 * u1 type_argument_index; 711 * } path[path_length]; 712 * } 713 * 714 * @throws Scanner.SyntaxError, IOException 715 */ 716 private void _scanTargetPath(TypeAnnotationData annotData) throws Scanner.SyntaxError, IOException { 717 // parse the location info 718 scanner.expect(Token.LBRACE); 719 720 while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { 721 TypePathEntry tpe = _scanTypePathEntry(); 722 annotData.addTypePathEntry(tpe); 723 // throw away comma 724 if (scanner.token == Token.COMMA) { 725 scanner.scan(); 726 } 727 } 728 729 scanner.expect(Token.RBRACE); 730 } 731 732 /** 733 * _scanTypeLocation 734 * 735 * parses a path entry of the type_path. 736 * 737 * { u1 type_path_kind; 738 * u1 type_argument_index; 739 * } 740 * 741 * @return a parsed type path. 742 * @throws Scanner.SyntaxError, IOException 743 */ 744 private TypePathEntry _scanTypePathEntry() throws Scanner.SyntaxError, IOException { 745 TypePathEntry tpe; 746 747 if ( (scanner.token != Token.EOF) && scanner.token.possibleTypePathKind() ) { 748 EPathKind pathKind = EPathKind.getPathKind(scanner.stringValue); 749 if (pathKind == EPathKind.TYPE_ARGUMENT) { 750 scanner.scan(); 751 // need to scan the index 752 // Take the form: TYPE_ARGUMENT{#} 753 scanner.expect(Token.LBRACE); 754 int index = 0; 755 if ((scanner.token != Token.EOF) && (scanner.token == Token.INTVAL)) { 756 index = scanner.intValue; 757 scanner.scan(); 758 } else { 759 // incorrect Arg index 760 env.error(scanner.pos, "incorrect.typeannot.pathentry.argindex", scanner.token); 761 throw new Scanner.SyntaxError(); 762 } 763 tpe = new TypePathEntry(pathKind, index); 764 scanner.expect(Token.RBRACE); 765 } else { 766 tpe = new TypePathEntry(pathKind, 0); 767 scanner.scan(); 768 } 769 } else { 770 // unexpected Type Path 771 env.error(scanner.pos, "incorrect.typeannot.pathentry", scanner.token); 772 throw new Scanner.SyntaxError(); 773 } 774 775 return tpe; 776 } 777 778 /** 779 * scanAnnotationArray 780 * 781 * Scans an Array of annotations. 782 * 783 * @param name Name of the annotation 784 * @return Array Element 785 * @throws IOException if scanning errors exist 786 */ 787 private ArrayElemValue scanAnnotationArray(String name) throws IOException { 788 scanner.scan(); 789 ArrayElemValue arrayElem = new ArrayElemValue(); 790 791 while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { 792 Data data = scanAnnotationData(name + " {}"); 793 arrayElem.add(data); 794 795 // consume tokens inbetween annotation fields 796 if (scanner.token == Token.COMMA) { 797 scanner.scan(); 798 } 799 } 800 801 scanner.expect(Token.RBRACE); 802 return arrayElem; 803 } 804 805 /** 806 * scanAnnotationEnum 807 * 808 * Scans an annotation enum val. 809 * 810 * @param name Annotation Name 811 * @return Constant element value for the Class Annotation. 812 * @throws IOException 813 */ 814 private Data scanAnnotationClass(String name) throws IOException { 815 Data constVal = null; 816 // scan the next identifier. 817 // if it is an Ident, consume it as the class name. 818 scanner.scan(); 819 switch (scanner.token) { 820 case IDENT: 821 env.traceln("[AnnotationParser.scanAnnotationData]:: Constant Class Field: " + name + " = " + scanner.stringValue); 822 //need to encode the stringval as an (internal) descriptor. 823 String desc = parser.encodeClassString(scanner.stringValue); 824 825 // note: for annotations, a class field points to a string with the class descriptor. 826 constVal = new ConstElemValue('c', parser.pool.FindCellAsciz(desc)); 827 scanner.scan(); 828 break; 829 case CPINDEX: 830 // could be a reference to a class name 831 env.traceln("[AnnotationParser.scanAnnotationData]:: Constant Class Field: " + name + " = " + scanner.stringValue); 832 Integer ConstNmCPX = Integer.valueOf(scanner.stringValue); 833 constVal = new ClassElemValue(parser.pool.getCell(ConstNmCPX)); 834 scanner.scan(); 835 break; 836 default: 837 env.error(scanner.pos, "incorrect.annot.class", scanner.stringValue); 838 throw new Scanner.SyntaxError(); 839 } 840 841 return constVal; 842 } 843 844 /** 845 * scanAnnotationEnum 846 * 847 * Scans an annotation enum val. 848 * 849 * @param name Annotation Name 850 * @return Enumeration Element Value 851 * @throws IOException for scanning errors. 852 */ 853 private EnumElemValue scanAnnotationEnum(String name) throws IOException { 854 scanner.scan(); 855 EnumElemValue enumval = null; 856 switch (scanner.token) { 857 case IDENT: 858 // could be a string identifying enum class and name 859 String enumClassName = scanner.stringValue; 860 scanner.scan(); 861 // could be a string identifying enum class and name 862 switch (scanner.token) { 863 case IDENT: 864 // could be a string identifying enum class and name 865 String enumTypeName = scanner.stringValue; 866 env.traceln("[AnnotationParser.scanAnnotationEnum]:: Constant Enum Field: " + name + " = " + enumClassName + " " + enumTypeName); 867 String encodedClass = parser.encodeClassString(enumClassName); 868 ConstElemValue classConst = new ConstElemValue('s', parser.pool.FindCellAsciz(encodedClass)); 869 ConstElemValue typeConst = new ConstElemValue('s', parser.pool.FindCellAsciz(enumTypeName)); 870 enumval = new EnumElemValue(classConst.indx, typeConst.indx); 871 scanner.scan(); 872 break; 873 874 default: 875 env.error(scanner.pos, "incorrect.annot.enum", scanner.stringValue); 876 throw new Scanner.SyntaxError(); 877 } 878 break; 879 case CPINDEX: 880 Integer typeNmCPX = Integer.valueOf(scanner.stringValue); 881 scanner.scan(); 882 //need two indexes to form a proper enum 883 switch (scanner.token) { 884 case CPINDEX: 885 Integer ConstNmCPX = Integer.valueOf(scanner.stringValue); 886 env.traceln("[AnnotationParser.scanAnnotationEnum]:: Enumeration Field: " + name + " = #" + typeNmCPX + " #" + ConstNmCPX); 887 enumval = new EnumElemValue(parser.pool.getCell(typeNmCPX), parser.pool.getCell(ConstNmCPX)); 888 scanner.scan(); 889 break; 890 default: 891 env.error(scanner.pos, "incorrect.annot.enum.cpx"); 892 throw new Scanner.SyntaxError(); 893 } 894 break; 895 } 896 897 return enumval; 898 } 899 900 /** 901 * scanAnnotationData 902 * 903 * parses the internals of an annotation. 904 * 905 * @param name Annotation Name 906 * @return a Data data structure containing the annotation data. 907 * @throws IOException for scanning errors. 908 */ 909 private Data scanAnnotationData(String name) throws IOException { 910 Data data = null; 911 switch (scanner.token) { 912 // This handles the Annotation types (as normalized in the constant pool) 913 // Some primitive types (Boolean, char, short, byte) are identified by a keyword. 914 case INTVAL: 915 env.traceln("[AnnotationParser.scanAnnotationData]:: Integer Field: " + name + " = " + scanner.intValue); 916 data = new ConstElemValue('I', parser.pool.FindCell(ConstType.CONSTANT_INTEGER, scanner.intValue)); 917 scanner.scan(); 918 break; 919 case DOUBLEVAL: 920 env.traceln("[AnnotationParser.scanAnnotationData]:: Double Field: " + name + " = " + scanner.doubleValue); 921 double dval = scanner.doubleValue; 922 long ivdal = Double.doubleToLongBits(dval); 923 Long val = ivdal; 924 data = new ConstElemValue('D', parser.pool.FindCell(ConstType.CONSTANT_DOUBLE, val)); 925 scanner.scan(); 926 break; 927 case FLOATVAL: 928 env.traceln("[AnnotationParser.scanAnnotationData]:: Float Field: " + name + " = " + scanner.floatValue); 929 float fval = scanner.floatValue; 930 int ifval = Float.floatToIntBits(fval); 931 Integer val1 = ifval; 932 data = new ConstElemValue('F', parser.pool.FindCell(ConstType.CONSTANT_FLOAT, val1)); 933 scanner.scan(); 934 break; 935 case LONGVAL: 936 env.traceln("[AnnotationParser.scanAnnotationData]:: Long Field: " + name + " = " + scanner.longValue); 937 data = new ConstElemValue('J', parser.pool.FindCell(ConstType.CONSTANT_LONG, scanner.longValue)); 938 scanner.scan(); 939 break; 940 case STRINGVAL: 941 env.traceln("[AnnotationParser.scanAnnotationData]:: String Field: " + name + " = " + scanner.stringValue); 942 data = new ConstElemValue('s', parser.pool.FindCellAsciz(scanner.stringValue)); 943 scanner.scan(); 944 break; 945 case CLASS: 946 env.traceln("[AnnotationParser.scanAnnotationData]:: Class) keyword: " + scanner.stringValue); 947 data = scanAnnotationClass(name); 948 break; 949 case ENUM: 950 // scan the next two identifiers (eg ident.ident), or 2 CPRefs. 951 // if it is an Ident, use consume it as the class name. 952 env.traceln("[AnnotationParser.scanAnnotationData]:: Enum) keyword: " + scanner.stringValue); 953 data = scanAnnotationEnum(name); 954 break; 955 case IDENT: 956 env.traceln("[AnnotationParser.scanAnnotationData]:: JASM Keyword: (annotation field name: " + name + ") keyword: " + scanner.stringValue); 957 data = scanAnnotationIdent(scanner.stringValue, name); 958 break; 959 case ANNOTATION: 960 env.traceln("[AnnotationParser.scanAnnotationData]:: Annotation Field: " + name + " = " + scanner.stringValue); 961 data = new AnnotationElemValue(parseAnnotation()); 962 break; 963 case LBRACE: 964 env.traceln("[AnnotationParser.scanAnnotationData]:: Annotation Array Field: " + name); 965 data = scanAnnotationArray(name); 966 break; 967 default: 968 env.error(scanner.pos, "incorrect.annot.token", scanner.token); 969 throw new Scanner.SyntaxError(); 970 } 971 972 return data; 973 } 974 975 /** 976 * scanAnnotationIdent 977 * 978 * parses the identifier of an annotation. 979 * 980 * @param ident Basic Type identifier 981 * @param name Annotation Name 982 * @return Basic Type Annotation data 983 * @throws IOException if scanning errors occur 984 */ 985 private Data scanAnnotationIdent(String ident, String name) throws IOException { 986 // Handle JASM annotation Keyword Identifiers 987 Data data; 988 BasicType type = basictype(ident); 989 switch (type) { 990 991 case T_BOOLEAN: 992 // consume the keyword, get the value 993 scanner.scan(); 994 switch (scanner.token) { 995 case INTVAL: 996 // Handle Boolean value in integer form 997 env.traceln("Boolean Field: " + name + " = " + scanner.intValue); 998 Integer val = scanner.intValue; 999 if (val > 1 || val < 0) { 1000 env.traceln("Warning: Boolean Field: " + name + " value is not 0 or 1, value = " + scanner.intValue); 1001 } 1002 data = new ConstElemValue('Z', parser.pool.FindCell(ConstType.CONSTANT_INTEGER, val)); 1003 scanner.scan(); 1004 break; 1005 case IDENT: 1006 // handle boolean value with true/false keywords 1007 int val1; 1008 switch (scanner.stringValue) { 1009 case "true": 1010 val1 = 1; 1011 break; 1012 case "false": 1013 val1 = 0; 1014 break; 1015 default: 1016 throw new IOException("Incorrect Annotation (boolean), expected true/false), got \"" + scanner.stringValue + "\"."); 1017 } 1018 env.traceln("Boolean Field: " + name + " = " + scanner.stringValue); 1019 data = new ConstElemValue('Z', parser.pool.FindCell(ConstType.CONSTANT_INTEGER, val1)); 1020 scanner.scan(); 1021 break; 1022 default: 1023 env.error(scanner.pos, "incorrect.annot.bool", scanner.stringValue); 1024 throw new Scanner.SyntaxError(); 1025 } 1026 break; 1027 case T_BYTE: 1028 // consume the keyword, get the value 1029 scanner.scan(); 1030 switch (scanner.token) { 1031 case INTVAL: 1032 env.traceln("Byte Field: " + name + " = " + scanner.intValue); 1033 Integer val = scanner.intValue; 1034 if (val > 0xFF) { 1035 env.traceln("Warning: Byte Field: " + name + " value is greater than 0xFF, value = " + scanner.intValue); 1036 } 1037 data = new ConstElemValue('B', parser.pool.FindCell(ConstType.CONSTANT_INTEGER, val)); 1038 scanner.scan(); 1039 break; 1040 default: 1041 env.error(scanner.pos, "incorrect.annot.byte", scanner.stringValue); 1042 throw new Scanner.SyntaxError(); 1043 } 1044 break; 1045 case T_CHAR: 1046 // consume the keyword, get the value 1047 scanner.scan(); 1048 switch (scanner.token) { 1049 case INTVAL: 1050 env.traceln("Char Field: " + name + " = " + scanner.intValue); 1051 Integer val = scanner.intValue; 1052 // Bounds check? 1053 data = new ConstElemValue('C', parser.pool.FindCell(ConstType.CONSTANT_INTEGER, val)); 1054 scanner.scan(); 1055 break; 1056 default: 1057 env.error(scanner.pos, "incorrect.annot.char", scanner.stringValue); 1058 throw new Scanner.SyntaxError(); 1059 } 1060 break; 1061 case T_SHORT: 1062 // consume the keyword, get the value 1063 scanner.scan(); 1064 switch (scanner.token) { 1065 case INTVAL: 1066 env.traceln("Short Field: " + name + " = " + scanner.intValue); 1067 Integer val = scanner.intValue; 1068 if (val > 0xFFFF) { 1069 env.traceln("Warning: Short Field: " + name + " value is greater than 0xFFFF, value = " + scanner.intValue); 1070 } 1071 data = new ConstElemValue('S', parser.pool.FindCell(ConstType.CONSTANT_INTEGER, val)); 1072 scanner.scan(); 1073 break; 1074 default: 1075 env.error(scanner.pos, "incorrect.annot.short", scanner.stringValue); 1076 throw new Scanner.SyntaxError(); 1077 } 1078 break; 1079 default: 1080 env.error(scanner.pos, "incorrect.annot.keyword", ident); 1081 throw new Scanner.SyntaxError(); 1082 } 1083 return data; 1084 } 1085 }