1 /* 2 * Copyright (c) 1996, 2021, 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.common.Module; 26 27 import java.io.IOException; 28 import java.util.ArrayList; 29 import java.util.HashSet; 30 import java.util.Set; 31 import java.util.function.BiConsumer; 32 import java.util.function.Consumer; 33 34 import static org.openjdk.asmtools.jasm.ConstantPool.*; 35 import static org.openjdk.asmtools.jasm.JasmTokens.Token; 36 import static org.openjdk.asmtools.jasm.JasmTokens.Token.*; 37 import static org.openjdk.asmtools.jasm.RuntimeConstants.*; 38 import static org.openjdk.asmtools.jasm.Tables.*; 39 40 /** 41 * This class is used to parse Jasm statements and expressions. 42 * The result is a parse tree.<p> 43 * <p> 44 * This class implements an operator precedence parser. Errors are 45 * reported to the Environment object, if the error can't be 46 * resolved immediately, a SyntaxError exception is thrown.<p> 47 * <p> 48 * Error recovery is implemented by catching Scanner.SyntaxError exceptions 49 * and discarding input scanner.tokens until an input token is reached that 50 * is possibly a legal continuation.<p> 51 * <p> 52 * The parse tree that is constructed represents the input 53 * exactly (no rewrites to simpler forms). This is important 54 * if the resulting tree is to be used for code formatting in 55 * a programming environment. Currently only documentation comments 56 * are retained.<p> 57 * <p> 58 * A parser owns several components (scanner, constant-parser, 59 * instruction-parser, annotations-parser) to which it delegates certain 60 * parsing responsibilities. This parser contains functions to parse the 61 * overall form of a class, and any members (fields, methods, inner-classes). 62 * <p> 63 * <p> 64 * Syntax errors, should always be caught inside the 65 * parser for error recovery. 66 */ 67 class Parser extends ParseBase { 68 69 /* Parser Fields */ 70 protected ConstantPool pool = null; 71 72 ClassData cd = null; 73 74 CodeAttr curCode; 75 76 private ArrayList<ClassData> clsDataList = new ArrayList<>(); 77 private String pkg = null; 78 private String pkgPrefix = ""; 79 private ArrayList<AnnotationData> pkgAnnttns = null; 80 private ArrayList<AnnotationData> clsAnnttns = null; 81 private ArrayList<AnnotationData> memberAnnttns = null; 82 private boolean explicitcp = false; 83 private ModuleAttr moduleAttribute; 84 private CFVersion currentCFV; 85 /** 86 * other parser components 87 */ 88 private ParserAnnotation annotParser; // For parsing Annotations 89 private ParserCP cpParser; // for parsing Constants 90 private ParserInstr instrParser; // for parsing Instructions 91 92 93 /** 94 * Create a parser 95 */ 96 protected Parser(Environment sf, CFVersion cfVersion) throws IOException { 97 super.init(new Scanner(sf), this, sf); 98 this.currentCFV = cfVersion; 99 this.annotParser = new ParserAnnotation(scanner, this, env); 100 this.cpParser = new ParserCP(scanner, this, env); 101 this.instrParser = new ParserInstr(scanner, this, cpParser, env); 102 } 103 104 void setDebugFlags(boolean debugScanner, boolean debugMembers, 105 boolean debugCP, boolean debugAnnot, boolean debugInstr) { 106 107 enableDebug(debugMembers); 108 scanner.enableDebug(debugScanner); 109 cpParser.enableDebug(debugCP); 110 annotParser.enableDebug(debugAnnot); 111 instrParser.enableDebug(debugInstr); 112 } 113 114 String encodeClassString(String classname) { 115 return "L" + classname + ";"; 116 } 117 118 119 /*-------------------------------------------------------- */ 120 121 /** 122 * Parses version in package statements 123 */ 124 125 private void parseVersionPkg() throws IOException { 126 if (scanner.token == SEMICOLON) { 127 return; 128 } 129 parse_ver: 130 { 131 if (scanner.token != Token.VERSION) { 132 break parse_ver; 133 } 134 scanner.scan(); 135 if (scanner.token != Token.INTVAL) { 136 break parse_ver; 137 } 138 currentCFV.setMajorVersion((short) scanner.intValue); 139 scanner.scan(); 140 if (scanner.token != Token.COLON) { 141 break parse_ver; 142 } 143 scanner.scan(); 144 if (scanner.token != Token.INTVAL) { 145 break parse_ver; 146 } 147 currentCFV.setMinorVersion((short) scanner.intValue); 148 scanner.scan(); 149 debugScan(" [Parser.parseVersionPkg]: " + currentCFV.asString()); 150 return; 151 } 152 env.error(scanner.pos, "version.expected"); 153 throw new Scanner.SyntaxError(); 154 } 155 156 private void parseVersion() throws IOException { 157 if (scanner.token == Token.LBRACE) { 158 return; 159 } 160 parse_ver: 161 { 162 if (scanner.token != Token.VERSION) { 163 break parse_ver; 164 } 165 scanner.scan(); 166 if (scanner.token != Token.INTVAL) { 167 break parse_ver; 168 } 169 cd.cfv.setMajorVersion((short) scanner.intValue); 170 scanner.scan(); 171 if (scanner.token != Token.COLON) { 172 break parse_ver; 173 } 174 scanner.scan(); 175 if (scanner.token != Token.INTVAL) { 176 break parse_ver; 177 } 178 cd.cfv.setMinorVersion((short) scanner.intValue); 179 scanner.scan(); 180 debugStr("parseVersion: " + cd.cfv.asString()); 181 return; 182 } 183 env.error(scanner.pos, "version.expected"); 184 throw new Scanner.SyntaxError(); 185 } 186 187 188 /*---------------------------------------------*/ 189 190 /** 191 * Parse an internal name: identifier. 192 */ 193 String parseIdent() throws Scanner.SyntaxError, IOException { 194 String v = scanner.idValue; 195 scanner.expect(Token.IDENT); 196 return v; 197 } 198 199 /** 200 * Parse a local variable 201 */ 202 void parseLocVarDef() throws Scanner.SyntaxError, IOException { 203 if (scanner.token == Token.INTVAL) { 204 int v = scanner.intValue; 205 scanner.scan(); 206 curCode.LocVarDataDef(v); 207 } else { 208 String name = scanner.stringValue, type; 209 scanner.expect(Token.IDENT); 210 if (scanner.token == Token.COLON) { 211 scanner.scan(); 212 type = parseIdent(); 213 } else { 214 type = "I"; // TBD 215 } 216 curCode.LocVarDataDef(name, pool.FindCellAsciz(type)); 217 } 218 } 219 220 Argument parseLocVarRef() throws Scanner.SyntaxError, IOException { 221 if (scanner.token == Token.INTVAL) { 222 int v = scanner.intValue; 223 scanner.scan(); 224 return new Argument(v); 225 } else { 226 String name = scanner.stringValue; 227 scanner.expect(Token.IDENT); 228 return curCode.LocVarDataRef(name); 229 } 230 } 231 232 void parseLocVarEnd() throws Scanner.SyntaxError, IOException { 233 if (scanner.token == Token.INTVAL) { 234 int v = scanner.intValue; 235 scanner.scan(); 236 curCode.LocVarDataEnd(v); 237 } else { 238 String name = scanner.stringValue; 239 scanner.expect(Token.IDENT); 240 curCode.LocVarDataEnd(name); 241 } 242 } 243 244 void parseMapItem(DataVector map) throws Scanner.SyntaxError, IOException { 245 StackMapType itemType = stackMapType(scanner.intValue, null); 246 ConstType tag = null; 247 Argument arg = null; 248 Token ptoken = scanner.token; 249 int iValue = scanner.intValue; 250 String sValue = scanner.stringValue; 251 scanner.scan(); 252 resolve: 253 { 254 switch (ptoken) { 255 case INTVAL: 256 break resolve; 257 case CLASS: 258 itemType = StackMapType.ITEM_Object; 259 tag = ConstType.CONSTANT_CLASS; 260 break resolve; 261 case CPINDEX: 262 itemType = StackMapType.ITEM_Object; 263 arg = pool.getCell(iValue); 264 break resolve; 265 case IDENT: 266 itemType = stackMapType(sValue); 267 tag = Tables.tag(sValue); 268 if (itemType != null) { // itemType OK 269 if ((tag != null) // ambiguity: "int," or "int 77,"? 270 && (scanner.token != SEMICOLON) 271 && (scanner.token != COMMA)) { 272 itemType = StackMapType.ITEM_Object; 273 } 274 break resolve; 275 } else if (tag != null) { // tag OK 276 itemType = StackMapType.ITEM_Object; 277 break resolve; 278 } 279 } 280 // resolution failed: 281 itemType = StackMapType.ITEM_Bogus; 282 env.error("itemtype.expected", "<" + ptoken.printValue() + ">"); 283 } 284 switch (itemType) { 285 case ITEM_Object: // followed by CP index 286 if (arg == null) { 287 arg = pool.FindCell(cpParser.parseConstValue(tag)); 288 } 289 map.addElement(new StackMapData.StackMapItem2(itemType, arg)); 290 break; 291 case ITEM_NewObject: // followed by label 292 arg = instrParser.parseLabelRef(); 293 map.addElement(new StackMapData.StackMapItem2(itemType, arg)); 294 break; 295 default: 296 map.addElement(new StackMapData.StackMapItem1(itemType)); 297 } 298 } 299 300 /** 301 * Parse an external name: CPINDEX, string, or identifier. 302 */ 303 ConstCell parseName() throws Scanner.SyntaxError, IOException { 304 debugScan("------- [Parser.parseName]: "); 305 String v; 306 switch (scanner.token) { 307 case CPINDEX: { 308 int cpx = scanner.intValue; 309 scanner.scan(); 310 return pool.getCell(cpx); 311 } 312 case STRINGVAL: 313 v = scanner.stringValue; 314 scanner.scan(); 315 return pool.FindCellAsciz(v); 316 317 // In many cases, Identifiers can correctly have the same 318 // names as keywords. We need to allow these. 319 case OPEN: 320 case MODULE: 321 case VARARGS: 322 case REQUIRES: 323 case EXPORTS: 324 case TO: 325 case USES: 326 case PROVIDES: 327 case WITH: 328 case OPENS: 329 330 case ARRAY_TYPEPATH: 331 case INNER_TYPE_TYPEPATH: 332 case WILDCARD_TYPEPATH: 333 case TYPE_ARGUMENT_TYPEPATH: 334 case PERMITTEDSUBCLASSES: 335 case INF: 336 case NAN: 337 case COMPONENT: 338 339 case SYNTHETIC: 340 case DEPRECATED: 341 case VERSION: 342 case BITS: 343 case STACK: 344 case LOCAL: 345 case OF: 346 case INNERCLASS: 347 case STRICT: 348 case FIELDREF: 349 case METHODREF: 350 case IDENT: 351 case BRIDGE: 352 case VALUE: 353 case PRIMITIVE: 354 v = scanner.idValue; 355 scanner.scan(); 356 return pool.FindCellAsciz(v); 357 default: 358 env.error(scanner.pos, "name.expected", scanner.token); 359 throw new Scanner.SyntaxError(); 360 } 361 } 362 363 /** 364 * Parses a field or method reference for method handle. 365 */ 366 ConstCell parseMethodHandle(SubTag subtag) throws Scanner.SyntaxError, IOException { 367 ConstCell refCell; 368 final int pos = parser.env.pos; 369 switch (subtag) { 370 // If the value of the reference_kind item is 371 // 1 (REF_getField), 2 (REF_getStatic), 3 (REF_putField) or 4 (REF_putStatic), 372 // then the constant_pool entry at that index must be a CONSTANT_Fieldref_info structure (4.4.2) 373 // representing a field for which a method handle is to be created. jvms-4.4.8-200-C-A 374 case REF_GETFIELD: 375 case REF_GETSTATIC: 376 case REF_PUTFIELD: 377 case REF_PUTSTATIC: 378 refCell = pool.FindCell(cpParser.parseConstValue(ConstType.CONSTANT_FIELD)); 379 break; 380 // If the value of the reference_kind item is 381 // 5 (REF_invokeVirtual) or 8 (REF_newInvokeSpecial), 382 // then the constant_pool entry at that index must be a CONSTANT_Methodref_info structure (4.4.2) 383 // representing a class's method or constructor (2.9.1) for which a method handle is to be created. 384 // jvms-4.4.8-200-C-B 385 case REF_INVOKEVIRTUAL: 386 case REF_NEWINVOKESPECIAL: 387 cpParser.setExitImmediately(true); 388 refCell = cpParser.parseConstRef(ConstType.CONSTANT_METHOD, ConstType.CONSTANT_INTERFACEMETHOD); 389 cpParser.setExitImmediately(false); 390 checkReferenceIndex(pos, ConstType.CONSTANT_METHOD, null); 391 break; 392 case REF_INVOKESTATIC: 393 case REF_INVOKESPECIAL: 394 // CODETOOLS-7902333 395 // 4.4.8. The CONSTANT_MethodHandle_info Structure 396 // reference_index 397 // The value of the reference_index item must be a valid index into the constant_pool table. 398 // The constant_pool entry at that index must be as follows: 399 // If the value of the reference_kind item is 6 (REF_invokeStatic) or 7 (REF_invokeSpecial), 400 // then if the class file version number is less than 52.0, the constant_pool entry at that index must be 401 // a CONSTANT_Methodref_info structure representing a class's method for which a method handle is to be created; 402 // if the class file version number is 52.0 or above, the constant_pool entry at that index must be 403 // either a CONSTANT_Methodref_info structure or a CONSTANT_InterfaceMethodref_info structure (4.4.2) 404 // representing a class's or interface's method for which a method handle is to be created. 405 ConstType ctype01 = ConstType.CONSTANT_METHOD; 406 ConstType ctype02 = ConstType.CONSTANT_INTERFACEMETHOD; 407 if (this.cd.cfv.major_version() >= 52 && Modifiers.isInterface(this.cd.access)) { 408 ctype01 = ConstType.CONSTANT_INTERFACEMETHOD; 409 ctype02 = ConstType.CONSTANT_METHOD; 410 } 411 cpParser.setExitImmediately(true); 412 refCell = cpParser.parseConstRef(ctype01, ctype02); 413 cpParser.setExitImmediately(false); 414 checkReferenceIndex(pos, ctype01, ctype02); 415 break; 416 417 case REF_INVOKEINTERFACE: 418 cpParser.setExitImmediately(true); 419 refCell = cpParser.parseConstRef(ConstType.CONSTANT_INTERFACEMETHOD, ConstType.CONSTANT_METHOD); 420 cpParser.setExitImmediately(false); 421 checkReferenceIndex(pos, ConstType.CONSTANT_INTERFACEMETHOD, null); 422 break; 423 default: 424 // should not reach 425 throw new Scanner.SyntaxError(); 426 } 427 return refCell; 428 } 429 430 /** 431 * Check the pair reference_kind:reference_index where reference_kind is any from: 432 * REF_invokeVirtual, REF_newInvokeSpecial, REF_invokeStatic, REF_invokeSpecial, REF_invokeInterface 433 * and reference_index is one of [Empty], Method or InterfaceMethod 434 * There are possible entries: 435 * ldc Dynamic REF_newInvokeSpecial:InterfaceMethod LdcConDyTwice."<init>": 436 * ldc Dynamic REF_invokeInterface:LdcConDyTwice."<init>": 437 * ldc Dynamic REF_newInvokeSpecial:Method LdcConDyTwice."<init>": 438 * ldc MethodHandle REF_newInvokeSpecial:InterfaceMethod LdcConDyTwice."<init>": 439 * ldc MethodHandle REF_invokeInterface:LdcConDyTwice."<init>": 440 * ldc MethodHandle REF_newInvokeSpecial:Method LdcConDyTwice."<init>": 441 * invokedynamic MethodHandle REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants: 442 * invokedynamic MethodHandle REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants 443 * .... 444 * @param position the position in a source file 445 * @param defaultTag expected reference_index tag (Method or InterfaceMethod) 446 * @param defaultTag 2nd expected reference_index tag (Method or InterfaceMethod) 447 */ 448 private void checkReferenceIndex(int position, ConstType defaultTag, ConstType default2Tag) { 449 if ( ! scanner.token.in(COLON, SEMICOLON) ) { 450 if (default2Tag != null) { 451 env.error(position, "wrong.tag2", defaultTag.parseKey(), default2Tag.parseKey()); 452 } else { 453 env.error(position, "wrong.tag", defaultTag.parseKey()); 454 } 455 throw new Scanner.SyntaxError().Fatal(); 456 } 457 } 458 459 /** 460 * Parses a sub-tag value in method handle. 461 */ 462 SubTag parseSubtag() throws Scanner.SyntaxError, IOException { 463 SubTag subtag = null; 464 switch (scanner.token) { 465 case IDENT: 466 subtag = subtag(scanner.stringValue); 467 break; 468 case INTVAL: 469 subtag = subtag(scanner.intValue); 470 break; 471 } 472 if (subtag == null) { 473 env.error("subtag.expected"); 474 throw new Scanner.SyntaxError(); 475 } 476 scanner.scan(); 477 return subtag; 478 } 479 480 ConstCell parseClassName(boolean uncond) throws Scanner.SyntaxError, IOException { 481 String v; 482 switch (scanner.token) { 483 case CPINDEX: { 484 int cpx = scanner.intValue; 485 scanner.scan(); 486 return pool.getCell(cpx); 487 } 488 case STRINGVAL: 489 v = scanner.stringValue; 490 scanner.scan(); 491 v = prependPackage(v, uncond); 492 return pool.FindCellAsciz(v); 493 // Some identifiers might coincide with token names. 494 // these should be OK to use as identifier names. 495 case OPEN: 496 case MODULE: 497 case VARARGS: 498 case REQUIRES: 499 case EXPORTS: 500 case TO: 501 case USES: 502 case PROVIDES: 503 case WITH: 504 case OPENS: 505 506 case ARRAY_TYPEPATH: 507 case INNER_TYPE_TYPEPATH: 508 case WILDCARD_TYPEPATH: 509 case TYPE_ARGUMENT_TYPEPATH: 510 case PERMITTEDSUBCLASSES: 511 case INF: 512 case NAN: 513 case COMPONENT: 514 515 case SYNTHETIC: 516 case DEPRECATED: 517 case VERSION: 518 case BITS: 519 case STACK: 520 case LOCAL: 521 case OF: 522 case INNERCLASS: 523 case STRICT: 524 case FIELDREF: 525 case METHODREF: 526 case BRIDGE: 527 case IDENT: 528 case VALUE: 529 case PRIMITIVE: 530 v = scanner.idValue; 531 scanner.scan(); 532 v = prependPackage(v, uncond); 533 return pool.FindCellAsciz(v); 534 default: 535 ConstType key = Tables.tag(scanner.token.value()); 536 env.traceln("%%%%% Unrecognized token [" + scanner.token + "]: '" + (key == null ? "null" : key.parseKey()) + "'."); 537 env.error(scanner.prevPos, "name.expected", "\"" + scanner.token.parseKey() + "\""); 538 throw new Scanner.SyntaxError(); 539 } 540 } 541 542 private String prependPackage(String className, boolean uncond) { 543 if (uncond || (scanner.token == Token.FIELD)) { 544 if ((!className.contains("/")) // class identifier doesn't contain "/" 545 && (!className.contains("["))) { // class identifier doesn't contain "[" 546 className = pkgPrefix + className; // add package 547 } 548 } 549 return className; 550 } 551 552 /** 553 * Parse a signed integer of size bytes long. 554 * size = 1 or 2 555 */ 556 Argument parseInt(int size) throws Scanner.SyntaxError, IOException { 557 if (scanner.token == Token.BITS) { 558 scanner.scan(); 559 } 560 if (scanner.token != Token.INTVAL) { 561 env.error(scanner.pos, "int.expected"); 562 throw new Scanner.SyntaxError(); 563 } 564 int arg = scanner.intValue * scanner.sign; 565 switch (size) { 566 case 1: 567 // if ((arg>127)||(arg<-128)) { // 0xFF not allowed 568 if ((arg > 255) || (arg < -128)) { // to allow 0xFF 569 env.error(scanner.pos, "value.large", "1 byte"); 570 throw new Scanner.SyntaxError(); 571 } 572 break; 573 case 2: 574 // if ((arg > 32767) || (arg < -32768)) { //this seems 575 // natural but is not backward compatible. Some tests contain 576 // expressions like: 577 // sipush 0x8765; 578 579 if ((arg > 65535) || (arg < -32768)) { 580 env.error(scanner.pos, "value.large", "2 bytes"); 581 throw new Scanner.SyntaxError(); 582 } 583 break; 584 default: 585 throw new InternalError("parseInt(" + size + ")"); 586 } 587 scanner.scan(); 588 return new Argument(arg); 589 } 590 591 /** 592 * Parse an unsigned integer of size bytes long. 593 * size = 1 or 2 594 */ 595 Argument parseUInt(int size) throws Scanner.SyntaxError, IOException { 596 if (scanner.token != Token.INTVAL) { 597 env.error(scanner.pos, "int.expected"); 598 throw new Scanner.SyntaxError(); 599 } 600 if (scanner.sign == -1) { 601 env.error(scanner.pos, "neg.forbidden"); 602 throw new Scanner.SyntaxError(); 603 } 604 int arg = scanner.intValue; 605 switch (size) { 606 case 1: 607 if (arg > 255) { 608 env.error(scanner.pos, "value.large", "1 byte"); 609 throw new Scanner.SyntaxError(); 610 } 611 break; 612 case 2: 613 if (arg > 65535) { 614 env.error(scanner.pos, "value.large", "2 bytes"); 615 throw new Scanner.SyntaxError(); 616 } 617 break; 618 default: 619 throw new InternalError("parseUInt(" + size + ")"); 620 } 621 scanner.scan(); 622 return new Argument(arg); 623 } 624 625 /** 626 * Parse constant declaration 627 */ 628 private void parseConstDef() throws IOException { 629 for (; ; ) { 630 if (scanner.token == Token.CPINDEX) { 631 int cpx = scanner.intValue; 632 scanner.scan(); 633 scanner.expect(Token.ASSIGN); 634 env.traceln("parseConstDef:" + cpx); 635 pool.setCell(cpx, cpParser.parseConstRef(null)); 636 } else { 637 env.error("const.def.expected"); 638 throw new Scanner.SyntaxError(); 639 } 640 if (scanner.token != COMMA) { 641 scanner.expect(SEMICOLON); 642 return; 643 } 644 scanner.scan(); // COMMA 645 } 646 } 647 648 /** 649 * Parse the modifiers 650 */ 651 private int scanModifier(int mod) throws IOException { 652 int nextmod, prevpos; 653 654 while (true) { 655 nextmod = 0; 656 switch (scanner.token) { 657 case PUBLIC: 658 nextmod = ACC_PUBLIC; 659 break; 660 case PRIVATE: 661 nextmod = ACC_PRIVATE; 662 break; 663 case PROTECTED: 664 nextmod = ACC_PROTECTED; 665 break; 666 case STATIC: 667 nextmod = ACC_STATIC; 668 break; 669 case FINAL: 670 nextmod = ACC_FINAL; 671 break; 672 case SYNCHRONIZED: 673 nextmod = ACC_SYNCHRONIZED; 674 break; 675 case SUPER: 676 nextmod = ACC_SUPER; 677 break; 678 case VOLATILE: 679 nextmod = ACC_VOLATILE; 680 break; 681 case BRIDGE: 682 nextmod = ACC_BRIDGE; 683 break; 684 case TRANSIENT: 685 nextmod = ACC_TRANSIENT; 686 break; 687 case VARARGS: 688 nextmod = ACC_VARARGS; 689 break; 690 case NATIVE: 691 nextmod = ACC_NATIVE; 692 break; 693 case INTERFACE: 694 nextmod = ACC_INTERFACE; 695 break; 696 case ABSTRACT: 697 nextmod = ACC_ABSTRACT; 698 break; 699 case STRICT: 700 nextmod = ACC_STRICT; 701 break; 702 case ENUM: 703 nextmod = ACC_ENUM; 704 break; 705 case SYNTHETIC: 706 nextmod = ACC_SYNTHETIC; 707 break; 708 case ANNOTATION_ACCESS: 709 nextmod = ACC_ANNOTATION; 710 break; 711 712 case DEPRECATED: 713 nextmod = DEPRECATED_ATTRIBUTE; 714 break; 715 case MANDATED: 716 nextmod = ACC_MANDATED; 717 break; 718 case VALUE: 719 nextmod = ACC_VALUE; 720 break; 721 case PRIMITIVE: 722 nextmod = ACC_PRIMITIVE; 723 break; 724 default: 725 return nextmod; 726 } 727 prevpos = scanner.pos; 728 scanner.scan(); 729 if ((mod & nextmod) == 0) { 730 return nextmod; 731 } 732 env.error(prevpos, "warn.repeated.modifier"); 733 } 734 } 735 736 int scanModifiers() throws IOException { 737 int mod = 0, nextmod; 738 739 while (true) { 740 nextmod = scanModifier(mod); 741 if (nextmod == 0) { 742 return mod; 743 } 744 mod = mod | nextmod; 745 } 746 } 747 748 /** 749 * Parse a field. 750 */ 751 private void parseField(int mod) throws Scanner.SyntaxError, IOException { 752 debugStr(" [Parser.parseField]: <<<Begin>>>"); 753 // check access modifiers: 754 Modifiers.checkFieldModifiers(cd, mod, scanner.pos); 755 756 while (true) { 757 ConstCell nameCell = parseName(); 758 scanner.expect(Token.COLON); 759 ConstCell typeCell = parseName(); 760 761 // Define the variable 762 FieldData fld = cd.addField(mod, nameCell, typeCell); 763 764 if (memberAnnttns != null) { 765 fld.addAnnotations(memberAnnttns); 766 } 767 768 // Parse the optional attribute: signature 769 if (scanner.token == Token.COLON) { 770 scanner.scan(); 771 ConstCell signatureCell = parseName(); 772 fld.setSignatureAttr(signatureCell); 773 } 774 775 // Parse the optional initializer 776 if (scanner.token == Token.ASSIGN) { 777 scanner.scan(); 778 fld.SetValue(cpParser.parseConstRef(null)); 779 } 780 781 // If the next scanner.token is a comma, then there is more 782 debugScan(" [Parser.parseField]: Field: " + fld + " "); 783 784 if (scanner.token != COMMA) { 785 scanner.expect(SEMICOLON); 786 return; 787 } 788 scanner.scan(); 789 } // end while 790 } // end parseField 791 792 /** 793 * Scan method's signature to determine size of parameters. 794 */ 795 private int countParams(ConstCell sigCell) throws Scanner.SyntaxError { 796 String sig; 797 try { 798 ConstValue_String strConst = (ConstValue_String) sigCell.ref; 799 sig = strConst.value; 800 } catch (NullPointerException | ClassCastException e) { 801 return 0; // ??? TBD 802 } 803 int siglen = sig.length(), k = 0, loccnt = 0, errparam = 0; 804 boolean arraytype = false; 805 scan: 806 { 807 if (k >= siglen) { 808 break scan; 809 } 810 if (sig.charAt(k) != '(') { 811 errparam = 1; 812 break scan; 813 } 814 for (k = 1; k < siglen; k++) { 815 switch (sig.charAt(k)) { 816 case ')': 817 if (arraytype) { 818 errparam = 2; 819 break scan; 820 } 821 return loccnt; 822 case '[': 823 arraytype = true; 824 break; 825 case 'B': 826 case 'C': 827 case 'F': 828 case 'I': 829 case 'S': 830 case 'Z': 831 loccnt++; 832 arraytype = false; 833 break; 834 case 'D': 835 case 'J': 836 loccnt++; 837 if (arraytype) { 838 arraytype = false; 839 } else { 840 loccnt++; 841 } 842 break; 843 case 'L': 844 case 'Q': 845 for (; ; k++) { 846 if (k >= siglen) { 847 errparam = 3; 848 break scan; 849 } 850 if (sig.charAt(k) == ';') { 851 break; 852 } 853 } 854 loccnt++; 855 arraytype = false; 856 break; 857 default: 858 errparam = 4; 859 break scan; 860 } 861 } 862 } 863 env.error(scanner.pos, "msig.malformed", Integer.toString(k), Integer.toString(errparam)); 864 return loccnt; 865 } 866 867 /** 868 * Parse a method. 869 */ 870 private void parseMethod(int mod) throws Scanner.SyntaxError, IOException { 871 872 // The start of the method 873 int posa = scanner.pos; 874 debugStr(" [Parser.parseMethod]: <<<Begin>>>"); 875 876 ConstCell nameCell = parseName(); 877 ConstValue_String strConst = (ConstValue_String) nameCell.ref; 878 String name = strConst.value; 879 boolean is_clinit = name.equals("<clinit>"); 880 boolean is_init = name.equals("<init>") 881 && !Modifiers.isStatic(mod); // TODO: not a good way to detect factories... 882 DefaultAnnotationAttr defAnnot = null; 883 884 // check access modifiers: 885 Modifiers.checkMethodModifiers(cd, mod, posa, is_init, is_clinit); 886 887 scanner.expect(Token.COLON); 888 ConstCell typeCell = parseName(); 889 int paramcnt = countParams(typeCell); 890 if ((!Modifiers.isStatic(mod)) && !is_clinit) { 891 paramcnt++; 892 } 893 if (paramcnt > 255) { 894 env.error(scanner.pos, "warn.msig.more255", Integer.toString(paramcnt)); 895 } 896 // Parse throws clause 897 ArrayList<ConstCell> exc_table = null; 898 if (scanner.token == Token.THROWS) { 899 scanner.scan(); 900 exc_table = new ArrayList<>(); 901 for (; ; ) { 902 posa = scanner.pos; 903 ConstCell exc = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); 904 if (exc_table.contains(exc)) { 905 env.error(posa, "warn.exc.repeated"); 906 } else { 907 exc_table.add(exc); 908 env.traceln("THROWS:" + exc.arg); 909 } 910 if (scanner.token != COMMA) { 911 break; 912 } 913 scanner.scan(); 914 } 915 } 916 if (scanner.token == Token.DEFAULT) { 917 // need to scan the annotation value 918 defAnnot = annotParser.parseDefaultAnnotation(); 919 } 920 921 MethodData curMethod = cd.StartMethod(mod, nameCell, typeCell, exc_table); 922 Argument max_stack = null, max_locals = null; 923 924 if (scanner.token == Token.STACK) { 925 scanner.scan(); 926 max_stack = parseUInt(2); 927 } 928 if (scanner.token == Token.LOCAL) { 929 scanner.scan(); 930 max_locals = parseUInt(2); 931 } 932 if (scanner.token == Token.INTVAL) { 933 annotParser.parseParamAnnots(paramcnt, curMethod); 934 } 935 936 if (scanner.token == SEMICOLON) { 937 if ((max_stack != null) || (max_locals != null)) { 938 env.error("token.expected", "{"); 939 } 940 scanner.scan(); 941 } else { 942 scanner.expect(Token.LBRACE); 943 curCode = curMethod.startCode(posa, paramcnt, max_stack, max_locals); 944 while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { 945 instrParser.parseInstr(); 946 if (scanner.token == Token.RBRACE) { 947 break; 948 } 949 // code's type annotation(s) 950 if (scanner.token == Token.ANNOTATION) { 951 curCode.addAnnotations(annotParser.scanAnnotations()); 952 break; 953 } 954 scanner.expect(SEMICOLON); 955 } 956 curCode.endCode(); 957 scanner.expect(Token.RBRACE); 958 } 959 960 if (defAnnot != null) { 961 curMethod.addDefaultAnnotation(defAnnot); 962 } 963 if (memberAnnttns != null) { 964 curMethod.addAnnotations(memberAnnttns); 965 } 966 cd.EndMethod(); 967 debugStr(" [Parser.parseMethod]: Method: " + curMethod); 968 969 } // end parseMethod 970 971 /** 972 * Parse a (CPX based) BootstrapMethod entry. 973 */ 974 private void parseCPXBootstrapMethod() throws Scanner.SyntaxError, IOException { 975 // Parses in the form: 976 // BOOTSTRAPMETHOD CPX_MethodHandle (CPX_Arg)* ; 977 if (scanner.token == Token.CPINDEX) { 978 // CPX can be a CPX to an MethodHandle constant, 979 int cpx = scanner.intValue; 980 ConstCell MHCell = pool.getCell(cpx); 981 scanner.scan(); 982 ArrayList<ConstCell> bsm_args = new ArrayList<>(256); 983 984 while (scanner.token != SEMICOLON) { 985 if (scanner.token == Token.CPINDEX) { 986 bsm_args.add(pool.getCell(scanner.intValue)); 987 988 } else { 989 // throw error, bootstrap method is not recognizable 990 env.error(scanner.pos, "invalid.bootstrapmethod"); 991 throw new Scanner.SyntaxError(); 992 } 993 scanner.scan(); 994 } 995 BootstrapMethodData bsmData = new BootstrapMethodData(MHCell, bsm_args); 996 cd.addBootstrapMethod(bsmData); 997 } else { 998 // throw error, bootstrap method is not recognizable 999 env.error(scanner.pos, "invalid.bootstrapmethod"); 1000 throw new Scanner.SyntaxError(); 1001 } 1002 } 1003 1004 /** 1005 * Parse a NestHost entry 1006 */ 1007 private void parseNestHost() throws Scanner.SyntaxError, IOException { 1008 // Parses in the form: 1009 // NESTHOST IDENT; 1010 debugStr(" [Parser.parseNestHost]: <<<Begin>>>"); 1011 String className = prependPackage(parseIdent(), true); 1012 ConstCell hostClass = pool.FindCellClassByName(className); 1013 debugScan(" [Parser.parseNestHost]: NestHost: class " + className); 1014 scanner.expect(SEMICOLON); 1015 cd.addNestHost(hostClass); 1016 } 1017 1018 /** 1019 * Parse a list of classes belonging to the 1020 * [NestMembers | PermittedSubclasses | Preload] entry 1021 */ 1022 private void parseClasses(Consumer<ArrayList<ConstCell>> classesConsumer) 1023 throws Scanner.SyntaxError, IOException { 1024 ArrayList<ConstCell> classes = new ArrayList<>(); 1025 // Parses in the form: 1026 // (NESTMEMBERS|PERMITTEDSUBCLASSES)? IDENT(, IDENT)*; 1027 debugStr(" [Parser.parseClasses]: <<<Begin>>>"); 1028 while (true) { 1029 String className = prependPackage(parseIdent(), true); 1030 classes.add(pool.FindCellClassByName(className)); 1031 debugScan(" [Parser.parseClasses]: class " + className); 1032 if (scanner.token != COMMA) { 1033 scanner.expect(SEMICOLON); 1034 classesConsumer.accept(classes); 1035 return; 1036 } 1037 scanner.scan(); 1038 } 1039 } 1040 1041 /** 1042 * Parse the Record entry 1043 */ 1044 private void parseRecord() throws Scanner.SyntaxError, IOException { 1045 // Parses in the form: 1046 // RECORD { (COMPONENT)+ } 1047 // where 1048 // COMPONENT Component (ANNOTATION)* NAME:DESCRIPTOR(:SIGNATURE)? (,|;) 1049 // NAME = (CPINDEX | IDENT) 1050 // DESCRIPTOR = (CPINDEX | STRING) 1051 // SIGNATURE = (CPINDEX | STRING) 1052 debugScan("[Parser.parseRecord]: Begin"); 1053 scanner.expect(Token.LBRACE); 1054 1055 ArrayList<AnnotationData> componentAnntts = null; 1056 boolean grouped = false; 1057 RecordData rd = cd.setRecord(scanner.pos); 1058 1059 while (true) { 1060 if (scanner.token == Token.RBRACE) { 1061 if (rd.isEmpty()) { 1062 env.error(scanner.pos, "warn.no.components.in.record.attribute"); 1063 cd.rejectRecord(); 1064 } else if (grouped) { 1065 env.error(scanner.pos, "grouped.component.expected"); 1066 } 1067 scanner.scan(); 1068 break; 1069 } 1070 1071 ConstCell nameCell, descCell, signatureCell = null; 1072 if (scanner.token == Token.ANNOTATION) { 1073 componentAnntts = annotParser.scanAnnotations(); 1074 } 1075 1076 scanner.expect(Token.COMPONENT); 1077 1078 nameCell = parseName(); 1079 scanner.expect(Token.COLON); 1080 descCell = parseName(); 1081 // Parse the optional attribute: signature 1082 if (scanner.token == Token.COLON) { 1083 scanner.scan(); 1084 signatureCell = parseName(); 1085 } 1086 1087 rd.addComponent(nameCell, descCell, signatureCell, componentAnntts); 1088 1089 switch (scanner.token) { 1090 case COMMA: 1091 grouped = true; 1092 break; 1093 case SEMICOLON: 1094 grouped = false; 1095 componentAnntts = null; 1096 break; 1097 default: 1098 env.error(scanner.pos, "one.of.two.token.expected", 1099 "<" + SEMICOLON.printValue() + ">", 1100 "<" + COMMA.printValue() + ">"); 1101 break; 1102 } 1103 // next component 1104 scanner.scan(); 1105 } // end while 1106 debugScan("[Parser.parseRecord]: End"); 1107 } 1108 1109 /** 1110 * Parse an inner class. 1111 */ 1112 private void parseInnerClass(int mod) throws Scanner.SyntaxError, IOException { 1113 // Parses in the form: 1114 // MODIFIERS (INNERCLASSNAME =)? (INNERCLASS) (OF OUTERCLASS)? ; 1115 // 1116 // where 1117 // INNERCLASSNAME = (IDENT | CPX_IN-CL-NM) 1118 // INNERCLASS = (CLASS IDENT | CPX_IN-CL) (S2) 1119 // OUTERCLASS = (CLASS IDENT | CPX_OT-CL) (S3) 1120 // 1121 // Note: 1122 // If a class reference cannot be identified using IDENT, CPX indexes must be used. 1123 1124 // check access modifiers: 1125 debugScan("[Parser.parseInnerClass]: Begin "); 1126 Modifiers.checkInnerClassModifiers(cd, mod, scanner.pos); 1127 1128 ConstCell nameCell; 1129 ConstCell innerClass = null; 1130 ConstCell outerClass = null; 1131 1132 1133 if (scanner.token == Token.CLASS) { 1134 nameCell = pool.getCell(0); // no NameIndex 1135 parseInnerClass_s2(mod, nameCell, innerClass, outerClass); 1136 } else { 1137 if ((scanner.token == Token.IDENT) || scanner.checkTokenIdent()) { 1138 // Got a Class Name 1139 nameCell = parseName(); 1140 parseInnerClass_s1(mod, nameCell, innerClass, outerClass); 1141 } else if (scanner.token == Token.CPINDEX) { 1142 // CPX can be either a CPX to an InnerClassName, 1143 // or a CPX to an InnerClassInfo 1144 int cpx = scanner.intValue; 1145 nameCell = pool.getCell(cpx); 1146 ConstValue nameCellValue = nameCell.ref; 1147 1148 if (nameCellValue instanceof ConstValue_String) { 1149 // got a name cell 1150 scanner.scan(); 1151 parseInnerClass_s1(mod, nameCell, innerClass, outerClass); 1152 } else { 1153 // got a CPRef cell 1154 nameCell = pool.getCell(0); // no NameIndex 1155 parseInnerClass_s2(mod, nameCell, innerClass, outerClass); 1156 } 1157 } else { 1158 pic_error(); 1159 } 1160 1161 } 1162 } 1163 1164 private void parseInnerClass_s1(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) throws IOException { 1165 // next scanner.token must be '=' 1166 if (scanner.token == Token.ASSIGN) { 1167 scanner.scan(); 1168 parseInnerClass_s2(mod, nameCell, innerClass, outerClass); 1169 } else { 1170 pic_error(); 1171 } 1172 1173 } 1174 1175 private void parseInnerClass_s2(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) throws IOException { 1176 // scanner.token is either "CLASS IDENT" or "CPX_Class" 1177 if ((scanner.token == Token.CPINDEX) || (scanner.token == Token.CLASS)) { 1178 if (scanner.token == Token.CPINDEX) { 1179 innerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); 1180 } 1181 1182 if (scanner.token == Token.CLASS) { 1183 // next symbol needs to be InnerClass 1184 scanner.scan(); 1185 innerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); 1186 } 1187 1188 // See if declaration is terminated 1189 if (scanner.token == SEMICOLON) { 1190 // InnerClass is complete, no OUTERINFO; 1191 outerClass = pool.getCell(0); 1192 pic_tracecreate(mod, nameCell, innerClass, outerClass); 1193 cd.addInnerClass(mod, nameCell, innerClass, outerClass); 1194 } else if (scanner.token == Token.OF) { 1195 // got an outer class reference 1196 parseInnerClass_s3(mod, nameCell, innerClass, outerClass); 1197 } else { 1198 pic_error(); 1199 } 1200 1201 } else { 1202 pic_error(); 1203 } 1204 1205 } 1206 1207 private void parseInnerClass_s3(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) throws IOException { 1208 scanner.scan(); 1209 if ((scanner.token == Token.CLASS) || (scanner.token == Token.CPINDEX)) { 1210 if (scanner.token == Token.CLASS) { 1211 // next symbol needs to be InnerClass 1212 scanner.scan(); 1213 outerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); 1214 } 1215 if (scanner.token == Token.CPINDEX) { 1216 outerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); 1217 } 1218 1219 if (scanner.token == SEMICOLON) { 1220 pic_tracecreate(mod, nameCell, innerClass, outerClass); 1221 cd.addInnerClass(mod, nameCell, innerClass, outerClass); 1222 } else { 1223 pic_error(); 1224 } 1225 } else { 1226 pic_error(); 1227 } 1228 } 1229 1230 private void pic_tracecreate(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) { 1231 // throw error, IC is not recognizable 1232 env.trace(" Creating InnerClass: [" + Modifiers.toString(mod, CF_Context.CTX_INNERCLASS) + "], "); 1233 1234 if (nameCell != pool.getCell(0)) { 1235 ConstValue value = nameCell.ref; 1236 if (value != null) { 1237 env.trace(value.toString() + " = "); 1238 } 1239 } 1240 1241 ConstValue_Cell ici_val = (ConstValue_Cell) innerClass.ref; 1242 ConstCell ici_ascii = ici_val.cell; 1243 // Constant pool may not be numberized yet. 1244 // 1245 // check values before dereference on a trace. 1246 if (ici_ascii.ref == null) { 1247 env.trace("<#cpx-unresolved> "); 1248 } else { 1249 ConstValue_String cval = (ConstValue_String) ici_ascii.ref; 1250 if (cval.value == null) { 1251 env.trace("<#cpx-0> "); 1252 } else { 1253 env.trace(cval.value + " "); 1254 } 1255 } 1256 1257 if (outerClass != pool.getCell(0)) { 1258 if (outerClass.arg != 0) { 1259 ConstValue_Cell oci_val = (ConstValue_Cell) outerClass.ref; 1260 ConstCell oci_ascii = oci_val.cell; 1261 if (oci_ascii.ref == null) { 1262 env.trace(" of <#cpx-unresolved> "); 1263 } else { 1264 ConstValue_String cval = (ConstValue_String) oci_ascii.ref; 1265 if (cval.value == null) { 1266 env.trace(" of <#cpx-0> "); 1267 } else { 1268 env.trace(" of " + cval.value); 1269 } 1270 } 1271 } 1272 } 1273 1274 env.traceln(""); 1275 } 1276 1277 private void pic_error() { 1278 // throw error, IC is not recognizable 1279 env.error(scanner.pos, "invalid.innerclass"); 1280 throw new Scanner.SyntaxError(); 1281 } 1282 1283 /** 1284 * The match() method is used to quickly match opening 1285 * brackets (ie: '(', '{', or '[') with their closing 1286 * counter part. This is useful during error recovery.<p> 1287 * <p> 1288 * Scan to a matching '}', ']' or ')'. The current scanner.token must be 1289 * a '{', '[' or '('; 1290 */ 1291 private void match(Token open, Token close) throws IOException { 1292 int depth = 1; 1293 1294 while (true) { 1295 scanner.scan(); 1296 if (scanner.token == open) { 1297 depth++; 1298 } else if (scanner.token == close) { 1299 if (--depth == 0) { 1300 return; 1301 } 1302 } else if (scanner.token == Token.EOF) { 1303 env.error(scanner.pos, "unbalanced.paren"); 1304 return; 1305 } 1306 } 1307 } 1308 1309 /** 1310 * Recover after a syntax error in a field. This involves 1311 * discarding scanner.tokens until an EOF or a possible legal 1312 * continuation is encountered. 1313 */ 1314 private void recoverField() throws Scanner.SyntaxError, IOException { 1315 while (true) { 1316 switch (scanner.token) { 1317 case EOF: 1318 case STATIC: 1319 case FINAL: 1320 case PUBLIC: 1321 case PRIVATE: 1322 case SYNCHRONIZED: 1323 case TRANSIENT: 1324 case PROTECTED: 1325 case VOLATILE: 1326 case NATIVE: 1327 // case INTERFACE: see below 1328 case ABSTRACT: 1329 case ANNOTATION_ACCESS: 1330 // possible begin of a field, continue 1331 return; 1332 1333 case LBRACE: 1334 match(Token.LBRACE, Token.RBRACE); 1335 scanner.scan(); 1336 break; 1337 1338 case LPAREN: 1339 match(Token.LPAREN, Token.RPAREN); 1340 scanner.scan(); 1341 break; 1342 1343 case LSQBRACKET: 1344 match(Token.LSQBRACKET, Token.RSQBRACKET); 1345 scanner.scan(); 1346 break; 1347 1348 case RBRACE: 1349 case INTERFACE: 1350 case CLASS: 1351 case IMPORT: 1352 case PACKAGE: 1353 // begin of something outside a class, panic more 1354 endClass(); 1355 scanner.debugStr(" [Parser.recoverField]: pos: [" + scanner.pos + "]: "); 1356 throw new Scanner.SyntaxError().Fatal(); 1357 default: 1358 // don't know what to do, skip 1359 scanner.scan(); 1360 break; 1361 } 1362 } 1363 } 1364 1365 /** 1366 * Parse a class or interface declaration. 1367 */ 1368 private void parseClass(int mod) throws IOException { 1369 int posa = scanner.pos; 1370 debugStr(" [Parser.parseClass]: Begin "); 1371 // check access modifiers: 1372 Modifiers.checkClassModifiers(env, mod, scanner); 1373 1374 if (cd == null) { 1375 cd = new ClassData(env, currentCFV.clone()); 1376 pool = cd.pool; 1377 } 1378 1379 if (clsAnnttns != null) { 1380 cd.addAnnotations(clsAnnttns); 1381 } 1382 1383 // move the tokenizer to the identifier: 1384 if (scanner.token == Token.CLASS) { 1385 scanner.scan(); 1386 } else if (scanner.token == Token.ANNOTATION) { 1387 scanner.scan(); 1388 if (scanner.token == Token.INTERFACE) { 1389 mod |= ACC_ANNOTATION | ACC_INTERFACE; 1390 scanner.scan(); 1391 } else { 1392 env.error(scanner.prevPos, "token.expected", Token.ANNOTATION.parseKey() + Token.INTERFACE.parseKey()); 1393 throw new Scanner.SyntaxError(); 1394 } 1395 } 1396 1397 // Parse the class name 1398 ConstCell nm = cpParser.parseConstRef(ConstType.CONSTANT_CLASS, null, true); 1399 1400 if (scanner.token == Token.FIELD) { // DOT 1401 String fileExtension; 1402 scanner.scan(); 1403 switch (scanner.token) { 1404 case STRINGVAL: 1405 fileExtension = scanner.stringValue; 1406 break; 1407 case IDENT: 1408 fileExtension = scanner.idValue; 1409 break; 1410 default: 1411 env.error(scanner.pos, "name.expected"); 1412 throw new Scanner.SyntaxError(); 1413 } 1414 scanner.scan(); 1415 cd.fileExtension = "." + fileExtension; 1416 } else if (scanner.token == Token.MODULE) { 1417 env.error(scanner.prevPos, "token.expected", Token.OPEN.parseKey()); 1418 throw new Scanner.SyntaxError(); 1419 } else if (scanner.token == SEMICOLON) { 1420 // drop the semi-colon following a name 1421 scanner.scan(); 1422 } 1423 1424 // Parse extends clause 1425 ConstCell sup = null; 1426 if (scanner.token == Token.EXTENDS) { 1427 scanner.scan(); 1428 sup = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); 1429 while (scanner.token == COMMA) { 1430 scanner.scan(); 1431 env.error(posa, "multiple.inherit"); 1432 cpParser.parseConstRef(ConstType.CONSTANT_CLASS); 1433 } 1434 } 1435 1436 // Parse implements clause 1437 ArrayList<Argument> impl = new ArrayList<>(); 1438 if (scanner.token == Token.IMPLEMENTS) { 1439 do { 1440 scanner.scan(); 1441 Argument intf = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); 1442 if (impl.contains(intf)) { 1443 env.error(posa, "warn.intf.repeated", intf); 1444 } else { 1445 impl.add(intf); 1446 } 1447 } while (scanner.token == COMMA); 1448 } 1449 parseVersion(); 1450 scanner.expect(Token.LBRACE); 1451 1452 // Begin a new class 1453 cd.init(mod, nm, sup, impl); 1454 1455 // Parse constant declarations 1456 1457 // Parse class members 1458 while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { 1459 switch (scanner.token) { 1460 case SEMICOLON: 1461 // Empty fields are allowed 1462 scanner.scan(); 1463 break; 1464 case CONST: 1465 scanner.scan(); 1466 parseConstDef(); 1467 explicitcp = true; 1468 break; 1469 default: // scanner.token is some member. 1470 parseClassMembers(); 1471 } // end switch 1472 } // while 1473 scanner.expect(Token.RBRACE); 1474 // End the class 1475 endClass(); 1476 } // end parseClass 1477 1478 /** 1479 * Parses a package or type name in a module statement(s) 1480 */ 1481 private String parseTypeName() throws IOException { 1482 String name = "", field = ""; 1483 while (true) { 1484 if (scanner.token.possibleModuleName()) { 1485 name = name + field + scanner.idValue; 1486 scanner.scan(); 1487 } else { 1488 env.error(scanner.pos, "name.expected", "\"" + scanner.token.parseKey() + "\""); 1489 throw new Scanner.SyntaxError(); 1490 } 1491 if (scanner.token == Token.FIELD) { 1492 env.error(scanner.pos, "warn.dot.will.be.converted"); 1493 field = "/"; 1494 scanner.scan(); 1495 } else { 1496 break; 1497 } 1498 } 1499 return name; 1500 } 1501 1502 /** 1503 * Parses a module name in a module statement(s) 1504 */ 1505 private String parseModuleName() throws IOException { 1506 String name = "", field = ""; 1507 while (true) { 1508 if (scanner.token.possibleModuleName()) { 1509 name = name + field + scanner.idValue; 1510 scanner.scanModuleStatement(); 1511 } else { 1512 env.error(scanner.pos, "module.name.expected", "\"" + scanner.token.parseKey() + "\""); 1513 throw new Scanner.SyntaxError().Fatal(); 1514 } 1515 if (scanner.token == Token.FIELD) { 1516 field = Character.toString((char) scanner.token.value()); 1517 scanner.scanModuleStatement(); 1518 } else { 1519 break; 1520 } 1521 } 1522 return name; 1523 } 1524 1525 /** 1526 * Parse a module declaration. 1527 */ 1528 private void parseModule() throws IOException { 1529 debugStr(" [Parser.parseModule]: Begin "); 1530 if (cd == null) { 1531 cd = new ClassData(env, currentCFV.clone()); 1532 pool = cd.pool; 1533 } 1534 if (clsAnnttns != null) { 1535 cd.addAnnotations(clsAnnttns); 1536 } 1537 moduleAttribute = new ModuleAttr(cd); 1538 1539 if (scanner.token == Token.OPEN) { 1540 moduleAttribute.openModule(); 1541 scanner.scan(); 1542 } 1543 1544 // move the tokenizer to the identifier: 1545 if (scanner.token == Token.MODULE) { 1546 scanner.scanModuleStatement(); 1547 // scanner.scan(); 1548 } else { 1549 env.error(scanner.pos, "token.expected", Token.MODULE.parseKey()); 1550 throw new Scanner.SyntaxError().Fatal(); 1551 } 1552 // Parse the module name 1553 String moduleName = parseModuleName(); 1554 if (moduleName.isEmpty()) { 1555 env.error(scanner.pos, "name.expected"); 1556 throw new Scanner.SyntaxError().Fatal(); 1557 } 1558 moduleAttribute.setModuleName(moduleName); 1559 1560 parseVersion(); 1561 scanner.expect(Token.LBRACE); 1562 1563 // Begin a new class as module 1564 cd.initAsModule(); 1565 1566 // Parse module statement(s) 1567 while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) { 1568 switch (scanner.token) { 1569 case REQUIRES: 1570 scanRequires(moduleAttribute.requires); 1571 break; 1572 case EXPORTS: 1573 scanStatement(moduleAttribute.exports, 1574 this::parseTypeName, 1575 this::parseModuleName, 1576 Token.TO, 1577 true, 1578 "exports.expected"); 1579 break; 1580 case OPENS: 1581 scanStatement(moduleAttribute.opens, 1582 this::parseTypeName, 1583 this::parseModuleName, 1584 Token.TO, true, "opens.expected"); 1585 break; 1586 case USES: 1587 scanStatement(moduleAttribute.uses, "uses.expected"); 1588 break; 1589 case PROVIDES: 1590 scanStatement(moduleAttribute.provides, 1591 this::parseTypeName, 1592 this::parseTypeName, 1593 Token.WITH, 1594 false, 1595 "provides.expected"); 1596 break; 1597 case SEMICOLON: 1598 // Empty fields are allowed 1599 scanner.scan(); 1600 break; 1601 default: 1602 env.error(scanner.pos, "module.statement.expected"); 1603 throw new Scanner.SyntaxError().Fatal(); 1604 } // end switch 1605 } // while 1606 scanner.expect(Token.RBRACE); 1607 // End the module 1608 endModule(); 1609 } // end parseModule 1610 1611 /** 1612 * Scans ModuleStatement: requires [transitive] [static] ModuleName ; 1613 */ 1614 private void scanRequires(BiConsumer<String, Integer> action) throws IOException { 1615 int flags = 0; 1616 String mn = ""; 1617 scanner.scanModuleStatement(); 1618 while (scanner.token != SEMICOLON) { 1619 switch (scanner.token) { 1620 case STATIC: 1621 if (((flags & (1 << Module.Modifier.ACC_STATIC_PHASE.asInt())) != 0) || !mn.isEmpty()) { 1622 env.error(scanner.pos, "requires.expected"); 1623 throw new Scanner.SyntaxError().Fatal(); 1624 } 1625 flags |= Module.Modifier.ACC_STATIC_PHASE.asInt(); 1626 break; 1627 case TRANSITIVE: 1628 if (((flags & (1 << Module.Modifier.ACC_TRANSITIVE.asInt())) != 0) || !mn.isEmpty()) { 1629 env.error(scanner.pos, "requires.expected"); 1630 throw new Scanner.SyntaxError().Fatal(); 1631 } 1632 flags |= Module.Modifier.ACC_TRANSITIVE.asInt(); 1633 break; 1634 case IDENT: 1635 if (!mn.isEmpty()) { 1636 env.error(scanner.pos, "requires.expected"); 1637 throw new Scanner.SyntaxError().Fatal(); 1638 } 1639 mn = parseModuleName(); 1640 continue; 1641 default: 1642 if (mn.isEmpty() && scanner.token.possibleModuleName()) { 1643 mn = parseModuleName(); 1644 continue; 1645 } else { 1646 env.error(scanner.pos, "requires.expected"); 1647 throw new Scanner.SyntaxError().Fatal(); 1648 } 1649 } 1650 scanner.scanModuleStatement(); 1651 } 1652 // Token.SEMICOLON 1653 if (mn.isEmpty()) { 1654 env.error(scanner.pos, "requires.expected"); 1655 throw new Scanner.SyntaxError().Fatal(); 1656 } 1657 action.accept(mn, flags); 1658 scanner.scanModuleStatement(); 1659 } 1660 1661 /** 1662 * Scans ModuleStatement: uses TypeName; 1663 */ 1664 private void scanStatement(Consumer<Set<String>> action, String err) throws IOException { 1665 HashSet<String> names = scanList(() -> scanner.scan(), this::parseTypeName, err, true); 1666 // Token.SEMICOLON 1667 if (names.size() != 1) { 1668 env.error(scanner.pos, err); 1669 throw new Scanner.SyntaxError().Fatal(); 1670 } 1671 action.accept(names); 1672 scanner.scan(); 1673 } 1674 1675 /** 1676 * Scans Module Statement(s): 1677 * exports packageName [to ModuleName {, ModuleName}] ; 1678 * opens packageName [to ModuleName {, ModuleName}] ; 1679 * provides TypeName with TypeName [,typeName] ; 1680 */ 1681 private void scanStatement(BiConsumer<String, Set<String>> action, 1682 NameSupplier source, 1683 NameSupplier target, 1684 Token startList, 1685 boolean emptyListAllowed, 1686 String err) throws IOException { 1687 String typeName = ""; 1688 HashSet<String> names = new HashSet<>(); 1689 scanner.scan(); 1690 while (scanner.token != SEMICOLON) { 1691 if (scanner.token == Token.IDENT) { 1692 if (typeName.isEmpty()) { 1693 typeName = source.get(); 1694 continue; 1695 } 1696 env.error(scanner.pos, err); 1697 throw new Scanner.SyntaxError().Fatal(); 1698 } 1699 if (scanner.token == startList) { 1700 if (typeName.isEmpty()) { 1701 env.error(scanner.pos, err); 1702 throw new Scanner.SyntaxError().Fatal(); 1703 } 1704 names = scanList(scanner.token == Token.TO ? () -> scanner.scanModuleStatement() : () -> scanner.scan(), target, err, false); 1705 break; 1706 } else { 1707 env.error(scanner.pos, err); 1708 throw new Scanner.SyntaxError().Fatal(); 1709 } 1710 } 1711 // Token.SEMICOLON 1712 if (typeName.isEmpty() || (names.isEmpty() && !emptyListAllowed)) { 1713 env.error(scanner.pos, err); 1714 throw new Scanner.SyntaxError().Fatal(); 1715 } 1716 action.accept(typeName, names); 1717 scanner.scan(); 1718 } 1719 1720 /** 1721 * Scans the "to" or "with" part of ModuleStatement: exports PackageName [to ModuleName {, ModuleName}] ;, 1722 * opens packageName [to ModuleName {, ModuleName}] ; 1723 * provides TypeName with TypeName [,typeName] ; 1724 * uses TypeName; 1725 * : [ModuleName {, ModuleName}]; , [TypeName [,typeName]]; or TypeName; 1726 */ 1727 private HashSet<String> scanList(Method scanMethod, NameSupplier target, String err, boolean onlyOneElement) throws IOException { 1728 HashSet<String> names = new HashSet<>(); 1729 boolean comma = false, first = true; 1730 scanMethod.call(); 1731 while (scanner.token != SEMICOLON) { 1732 switch (scanner.token) { 1733 case COMMA: 1734 if (comma || first || onlyOneElement) { 1735 env.error(scanner.pos, err); 1736 throw new Scanner.SyntaxError().Fatal(); 1737 } 1738 comma = true; 1739 break; 1740 case IDENT: 1741 if (!first && !comma) { 1742 env.error(scanner.pos, err); 1743 throw new Scanner.SyntaxError().Fatal(); 1744 } 1745 names.add(target.get()); 1746 comma = false; 1747 first = false; 1748 continue; 1749 default: 1750 env.error(scanner.pos, err); 1751 throw new Scanner.SyntaxError().Fatal(); 1752 } 1753 scanner.scan(); 1754 } 1755 // Token.SEMICOLON 1756 if (names.isEmpty() || comma) { 1757 env.error(scanner.pos, err); 1758 throw new Scanner.SyntaxError().Fatal(); 1759 } 1760 return names; 1761 } 1762 1763 private void parseClassMembers() throws IOException { 1764 debugScan("[Parser.parseClassMembers]: Begin "); 1765 // Parse annotations 1766 if (scanner.token == Token.ANNOTATION) { 1767 memberAnnttns = annotParser.scanAnnotations(); 1768 } 1769 // Parse modifiers 1770 int mod = scanModifiers(); 1771 try { 1772 switch (scanner.token) { 1773 case FIELDREF: 1774 scanner.scan(); 1775 parseField(mod); 1776 break; 1777 case METHODREF: 1778 scanner.scan(); 1779 parseMethod(mod); 1780 break; 1781 case INNERCLASS: 1782 scanner.scan(); 1783 parseInnerClass(mod); 1784 break; 1785 case BOOTSTRAPMETHOD: 1786 scanner.scan(); 1787 parseCPXBootstrapMethod(); 1788 break; 1789 case NESTHOST: 1790 if (cd.nestHostAttributeExists()) { 1791 env.error(scanner.pos, "extra.nesthost.attribute"); 1792 throw new Scanner.SyntaxError(); 1793 } else if (cd.nestMembersAttributesExist()) { 1794 env.error(scanner.pos, "both.nesthost.nestmembers.found"); 1795 throw new Scanner.SyntaxError(); 1796 } 1797 scanner.scan(); 1798 parseNestHost(); 1799 break; 1800 case NESTMEMBERS: 1801 if (cd.nestMembersAttributesExist()) { 1802 env.error(scanner.pos, "extra.nestmembers.attribute"); 1803 throw new Scanner.SyntaxError(); 1804 } else if (cd.nestHostAttributeExists()) { 1805 env.error(scanner.pos, "both.nesthost.nestmembers.found"); 1806 throw new Scanner.SyntaxError(); 1807 } 1808 scanner.scan(); 1809 parseClasses(list -> cd.addNestMembers(list)); 1810 break; 1811 case PERMITTEDSUBCLASSES: // JEP 360 1812 if (cd.nestMembersAttributesExist()) { 1813 env.error(scanner.pos, "extra.permittedsubclasses.attribute"); 1814 throw new Scanner.SyntaxError(); 1815 } 1816 scanner.scan(); 1817 parseClasses(list -> cd.addPermittedSubclasses(list)); 1818 break; 1819 case RECORD: // JEP 359 1820 if (cd.recordAttributeExists()) { 1821 env.error(scanner.pos, "extra.record.attribute"); 1822 throw new Scanner.SyntaxError(); 1823 } 1824 scanner.scan(); 1825 parseRecord(); 1826 break; 1827 case PRELOAD: 1828 if (cd.preloadAttributeExists()) { 1829 env.error(scanner.pos, "extra.preload.attribute"); 1830 throw new Scanner.SyntaxError(); 1831 } 1832 scanner.scan(); 1833 parseClasses(list -> cd.addPreloads(list)); 1834 break; 1835 default: 1836 env.error(scanner.pos, "field.expected"); 1837 throw new Scanner.SyntaxError(); 1838 } // end switch 1839 } catch (Scanner.SyntaxError e) { 1840 recoverField(); 1841 } 1842 memberAnnttns = null; 1843 } 1844 1845 /** 1846 * Recover after a syntax error in the file. 1847 * This involves discarding scanner.tokens until an EOF 1848 * or a possible legal continuation is encountered. 1849 */ 1850 private void recoverFile() throws IOException { 1851 while (true) { 1852 env.traceln("recoverFile: scanner.token=" + scanner.token); 1853 switch (scanner.token) { 1854 case CLASS: 1855 case INTERFACE: 1856 // Start of a new source file statement, continue 1857 return; 1858 1859 case LBRACE: 1860 match(Token.LBRACE, Token.RBRACE); 1861 scanner.scan(); 1862 break; 1863 1864 case LPAREN: 1865 match(Token.LPAREN, Token.RPAREN); 1866 scanner.scan(); 1867 break; 1868 1869 case LSQBRACKET: 1870 match(Token.LSQBRACKET, Token.RSQBRACKET); 1871 scanner.scan(); 1872 break; 1873 1874 case EOF: 1875 return; 1876 1877 default: 1878 // Don't know what to do, skip 1879 scanner.scan(); 1880 break; 1881 } 1882 } 1883 } 1884 1885 /** 1886 * End class 1887 */ 1888 private void endClass() { 1889 if (explicitcp) { 1890 // Fix references in the constant pool (for explicitly coded CPs) 1891 pool.fixRefsInPool(); 1892 // Fix any bootstrap Method references too 1893 cd.relinkBootstrapMethods(); 1894 } 1895 cd.endClass(); 1896 clsDataList.add(cd); 1897 cd = null; 1898 } 1899 1900 /** 1901 * End module 1902 */ 1903 private void endModule() { 1904 cd.endModule(moduleAttribute); 1905 clsDataList.add(cd); 1906 cd = null; 1907 } 1908 1909 final ClassData[] getClassesData() { 1910 return clsDataList.toArray(new ClassData[0]); 1911 } 1912 1913 /** 1914 * Determines whether the JASM file is for a package-info class 1915 * or for a module-info class. 1916 * <p> 1917 * creates the correct kind of ClassData accordingly. 1918 * 1919 * @throws IOException 1920 */ 1921 private void parseJasmPackages() throws IOException { 1922 try { 1923 // starting annotations could either be 1924 // a package annotation, or a class annotation 1925 if (scanner.token == Token.ANNOTATION) { 1926 if (cd == null) { 1927 cd = new ClassData(env, currentCFV.clone()); 1928 pool = cd.pool; 1929 } 1930 pkgAnnttns = annotParser.scanAnnotations(); 1931 } 1932 if (scanner.token == Token.PACKAGE) { 1933 // Package statement 1934 scanner.scan(); 1935 int where = scanner.pos; 1936 String id = parseIdent(); 1937 parseVersionPkg(); 1938 scanner.expect(SEMICOLON); 1939 1940 if (pkg == null) { 1941 pkg = id; 1942 pkgPrefix = id + "/"; 1943 } else { 1944 env.error(where, "package.repeated"); 1945 } 1946 debugScan("[Parser.parseJasmPackages] {PARSED} package-prefix: " + pkgPrefix + " "); 1947 } 1948 } catch (Scanner.SyntaxError e) { 1949 recoverFile(); 1950 } 1951 // skip bogus semi colons 1952 while (scanner.token == SEMICOLON) { 1953 scanner.scan(); 1954 } 1955 1956 // checks that we compile module or package compilation unit 1957 if (scanner.token == Token.EOF) { 1958 env.traceln("Scanner: EOF"); 1959 String sourceName = env.getSimpleInputFileName(); 1960 int mod = ACC_INTERFACE | ACC_ABSTRACT; 1961 1962 // package-info 1963 if (sourceName.endsWith("package-info.jasm")) { 1964 env.traceln("Creating \"package-info.jasm\": package: " + pkg + " " + currentCFV.asString()); 1965 1966 if (cd == null) { 1967 cd = new ClassData(env, currentCFV.clone()); 1968 pool = cd.pool; 1969 } else { 1970 cd.cfv = currentCFV.clone(); 1971 } 1972 ConstCell me = pool.FindCellClassByName(pkgPrefix + "package-info"); 1973 1974 // Interface package-info should be marked synthetic and abstract 1975 if (currentCFV.major_version() > 49) { 1976 mod |= SYNTHETIC_ATTRIBUTE; 1977 } 1978 cd.init(mod, me, new ConstCell(0), null); 1979 1980 if (pkgAnnttns != null) { 1981 cd.addAnnotations(pkgAnnttns); 1982 } 1983 1984 endClass(); 1985 } 1986 return; 1987 } 1988 1989 if (pkg == null && pkgAnnttns != null) { // RemoveModules 1990 clsAnnttns = pkgAnnttns; 1991 pkgAnnttns = null; 1992 } 1993 } 1994 1995 /** 1996 * Parse an Jasm file. 1997 */ 1998 void parseFile() { 1999 try { 2000 // First, parse any package identifiers (and associated package annotations) 2001 parseJasmPackages(); 2002 2003 while (scanner.token != Token.EOF) { 2004 // Second, parse any class identifiers (and associated class annotations) 2005 try { 2006 // Parse annotations 2007 if (scanner.token == Token.ANNOTATION) { 2008 if (cd == null) { 2009 cd = new ClassData(env, currentCFV.clone()); 2010 pool = cd.pool; 2011 } else { 2012 cd.cfv = currentCFV.clone(); 2013 } 2014 clsAnnttns = annotParser.scanAnnotations(); 2015 } 2016 2017 // Parse class modifiers 2018 int mod = scanModifiers(); 2019 if (mod == 0) { 2020 switch (scanner.token) { 2021 case OPEN: 2022 case MODULE: 2023 case CLASS: 2024 case CPINDEX: 2025 case STRINGVAL: 2026 case IDENT: 2027 // this is a class declaration anyway 2028 break; 2029 case SEMICOLON: 2030 // Bogus semi colon 2031 scanner.scan(); 2032 continue; 2033 default: 2034 // no class declaration found 2035 debugScan(" [Parser.parseFile]: "); 2036 env.error(scanner.pos, "toplevel.expected"); 2037 throw new Scanner.SyntaxError(); 2038 } 2039 } else if (Modifiers.isInterface(mod) && (scanner.token != Token.CLASS)) { 2040 // rare syntactic sugar: 2041 // interface <ident> == abstract interface class <ident> 2042 mod |= ACC_ABSTRACT; 2043 } 2044 if (scanner.token == Token.MODULE || scanner.token == Token.OPEN) 2045 parseModule(); 2046 else 2047 parseClass(mod); 2048 clsAnnttns = null; 2049 2050 } catch (Scanner.SyntaxError e) { 2051 // KTL 2052 env.traceln("^^^^^^^ Syntax Error ^^^^^^^^^^^^"); 2053 if (scanner.debugFlag) 2054 e.printStackTrace(); 2055 if (e.isFatal()) { 2056 break; 2057 } 2058 recoverFile(); 2059 } 2060 } 2061 } catch (IOException e) { 2062 env.error(scanner.pos, "io.exception", env.getSimpleInputFileName()); 2063 } catch (Error er) { 2064 er.printStackTrace(); 2065 } 2066 } //end parseFile 2067 2068 @FunctionalInterface 2069 interface NameSupplier { 2070 String get() throws IOException; 2071 } 2072 2073 @FunctionalInterface 2074 interface Method { 2075 void call() throws IOException; 2076 } 2077 2078 /** 2079 * The main compile error for the parser 2080 */ 2081 static class CompilerError extends Error { 2082 2083 CompilerError(String message) { 2084 super(message); 2085 } 2086 } 2087 } //end Parser