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 }