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 }