1 /* 2 * Copyright 2016 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.turbine.parse; 18 19 import static com.google.turbine.parse.Token.COMMA; 20 import static com.google.turbine.parse.Token.INTERFACE; 21 import static com.google.turbine.parse.Token.LPAREN; 22 import static com.google.turbine.parse.Token.RPAREN; 23 import static com.google.turbine.tree.TurbineModifier.PROTECTED; 24 import static com.google.turbine.tree.TurbineModifier.PUBLIC; 25 26 import com.google.common.base.Optional; 27 import com.google.common.collect.ImmutableList; 28 import com.google.common.collect.ImmutableSet; 29 import com.google.turbine.diag.SourceFile; 30 import com.google.turbine.diag.TurbineError; 31 import com.google.turbine.diag.TurbineError.ErrorKind; 32 import com.google.turbine.model.TurbineConstantTypeKind; 33 import com.google.turbine.model.TurbineTyKind; 34 import com.google.turbine.tree.Tree; 35 import com.google.turbine.tree.Tree.Anno; 36 import com.google.turbine.tree.Tree.ArrTy; 37 import com.google.turbine.tree.Tree.ClassTy; 38 import com.google.turbine.tree.Tree.CompUnit; 39 import com.google.turbine.tree.Tree.Expression; 40 import com.google.turbine.tree.Tree.ImportDecl; 41 import com.google.turbine.tree.Tree.Kind; 42 import com.google.turbine.tree.Tree.MethDecl; 43 import com.google.turbine.tree.Tree.PkgDecl; 44 import com.google.turbine.tree.Tree.PrimTy; 45 import com.google.turbine.tree.Tree.TyDecl; 46 import com.google.turbine.tree.Tree.TyParam; 47 import com.google.turbine.tree.Tree.Type; 48 import com.google.turbine.tree.Tree.VarDecl; 49 import com.google.turbine.tree.Tree.WildTy; 50 import com.google.turbine.tree.TurbineModifier; 51 import java.util.ArrayDeque; 52 import java.util.Deque; 53 import java.util.EnumSet; 54 import java.util.List; 55 import javax.annotation.Nullable; 56 57 /** 58 * A parser for the subset of Java required for header compilation. 59 * 60 * <p>See JLS 19: https://docs.oracle.com/javase/specs/jls/se8/html/jls-19.html 61 */ 62 public class Parser { 63 64 private static final String CTOR_NAME = "<init>"; 65 private final Lexer lexer; 66 67 private Token token; 68 private int position; 69 70 public static CompUnit parse(String source) { 71 return parse(new SourceFile(null, source)); 72 } 73 74 public static CompUnit parse(SourceFile source) { 75 return new Parser(new StreamLexer(new UnicodeEscapePreprocessor(source))).compilationUnit(); 76 } 77 78 private Parser(Lexer lexer) { 79 this.lexer = lexer; 80 this.token = lexer.next(); 81 } 82 83 public CompUnit compilationUnit() { 84 // TODO(cushon): consider enforcing package, import, and declaration order 85 // and make it bug-compatible with javac: 86 // http://mail.openjdk.java.net/pipermail/compiler-dev/2013-August/006968.html 87 Optional<PkgDecl> pkg = Optional.absent(); 88 EnumSet<TurbineModifier> access = EnumSet.noneOf(TurbineModifier.class); 89 ImmutableList.Builder<ImportDecl> imports = ImmutableList.builder(); 90 ImmutableList.Builder<TyDecl> decls = ImmutableList.builder(); 91 ImmutableList.Builder<Anno> annos = ImmutableList.builder(); 92 while (true) { 93 switch (token) { 94 case PACKAGE: 95 { 96 next(); 97 pkg = Optional.of(packageDeclaration(annos.build())); 98 annos = ImmutableList.builder(); 99 break; 100 } 101 case IMPORT: 102 { 103 next(); 104 ImportDecl i = importDeclaration(); 105 if (i == null) { 106 continue; 107 } 108 imports.add(i); 109 break; 110 } 111 case PUBLIC: 112 next(); 113 access.add(PUBLIC); 114 break; 115 case PROTECTED: 116 next(); 117 access.add(PROTECTED); 118 break; 119 case PRIVATE: 120 next(); 121 access.add(TurbineModifier.PRIVATE); 122 break; 123 case STATIC: 124 next(); 125 access.add(TurbineModifier.STATIC); 126 break; 127 case ABSTRACT: 128 next(); 129 access.add(TurbineModifier.ABSTRACT); 130 break; 131 case FINAL: 132 next(); 133 access.add(TurbineModifier.FINAL); 134 break; 135 case STRICTFP: 136 next(); 137 access.add(TurbineModifier.STRICTFP); 138 break; 139 case AT: 140 { 141 next(); 142 if (token == INTERFACE) { 143 decls.add(annotationDeclaration(access, annos.build())); 144 access = EnumSet.noneOf(TurbineModifier.class); 145 annos = ImmutableList.builder(); 146 } else { 147 annos.add(annotation()); 148 } 149 break; 150 } 151 case CLASS: 152 decls.add(classDeclaration(access, annos.build())); 153 access = EnumSet.noneOf(TurbineModifier.class); 154 annos = ImmutableList.builder(); 155 break; 156 case INTERFACE: 157 decls.add(interfaceDeclaration(access, annos.build())); 158 access = EnumSet.noneOf(TurbineModifier.class); 159 annos = ImmutableList.builder(); 160 break; 161 case ENUM: 162 decls.add(enumDeclaration(access, annos.build())); 163 access = EnumSet.noneOf(TurbineModifier.class); 164 annos = ImmutableList.builder(); 165 break; 166 case EOF: 167 // TODO(cushon): check for dangling modifiers? 168 return new CompUnit(position, pkg, imports.build(), decls.build(), lexer.source()); 169 case SEMI: 170 // TODO(cushon): check for dangling modifiers? 171 next(); 172 continue; 173 default: 174 throw error(token); 175 } 176 } 177 } 178 179 private void next() { 180 token = lexer.next(); 181 position = lexer.position(); 182 } 183 184 private TyDecl interfaceDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) { 185 eat(Token.INTERFACE); 186 String name = eatIdent(); 187 ImmutableList<TyParam> typarams; 188 if (token == Token.LT) { 189 typarams = typarams(); 190 } else { 191 typarams = ImmutableList.of(); 192 } 193 ImmutableList.Builder<ClassTy> interfaces = ImmutableList.builder(); 194 if (token == Token.EXTENDS) { 195 next(); 196 do { 197 interfaces.add(classty()); 198 } while (maybe(Token.COMMA)); 199 } 200 eat(Token.LBRACE); 201 ImmutableList<Tree> members = classMembers(); 202 eat(Token.RBRACE); 203 return new TyDecl( 204 position, 205 access, 206 annos, 207 name, 208 typarams, 209 Optional.<ClassTy>absent(), 210 interfaces.build(), 211 members, 212 TurbineTyKind.INTERFACE); 213 } 214 215 private TyDecl annotationDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) { 216 eat(Token.INTERFACE); 217 String name = eatIdent(); 218 eat(Token.LBRACE); 219 ImmutableList<Tree> members = classMembers(); 220 eat(Token.RBRACE); 221 return new TyDecl( 222 position, 223 access, 224 annos, 225 name, 226 ImmutableList.<TyParam>of(), 227 Optional.<ClassTy>absent(), 228 ImmutableList.<ClassTy>of(), 229 members, 230 TurbineTyKind.ANNOTATION); 231 } 232 233 private TyDecl enumDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) { 234 eat(Token.ENUM); 235 String name = eatIdent(); 236 ImmutableList.Builder<ClassTy> interfaces = ImmutableList.builder(); 237 if (token == Token.IMPLEMENTS) { 238 next(); 239 do { 240 interfaces.add(classty()); 241 } while (maybe(Token.COMMA)); 242 } 243 eat(Token.LBRACE); 244 ImmutableList<Tree> members = 245 ImmutableList.<Tree>builder().addAll(enumMembers(name)).addAll(classMembers()).build(); 246 eat(Token.RBRACE); 247 return new TyDecl( 248 position, 249 access, 250 annos, 251 name, 252 ImmutableList.<TyParam>of(), 253 Optional.<ClassTy>absent(), 254 interfaces.build(), 255 members, 256 TurbineTyKind.ENUM); 257 } 258 259 private static final ImmutableSet<TurbineModifier> ENUM_CONSTANT_MODIFIERS = 260 ImmutableSet.of( 261 TurbineModifier.PUBLIC, 262 TurbineModifier.STATIC, 263 TurbineModifier.ACC_ENUM, 264 TurbineModifier.FINAL); 265 266 private ImmutableList<Tree> enumMembers(String enumName) { 267 ImmutableList.Builder<Tree> result = ImmutableList.builder(); 268 ImmutableList.Builder<Anno> annos = ImmutableList.builder(); 269 OUTER: 270 while (true) { 271 switch (token) { 272 case IDENT: 273 { 274 String name = eatIdent(); 275 if (token == Token.LPAREN) { 276 dropParens(); 277 } 278 // TODO(cushon): consider desugaring enum constants later 279 if (token == Token.LBRACE) { 280 dropBlocks(); 281 } 282 maybe(Token.COMMA); 283 result.add( 284 new VarDecl( 285 position, 286 ENUM_CONSTANT_MODIFIERS, 287 annos.build(), 288 new ClassTy( 289 position, 290 Optional.<ClassTy>absent(), 291 enumName, 292 ImmutableList.<Type>of(), 293 ImmutableList.of()), 294 name, 295 Optional.<Expression>absent())); 296 annos = ImmutableList.builder(); 297 break; 298 } 299 case SEMI: 300 next(); 301 annos = ImmutableList.builder(); 302 break OUTER; 303 case RBRACE: 304 annos = ImmutableList.builder(); 305 break OUTER; 306 case AT: 307 next(); 308 annos.add(annotation()); 309 break; 310 default: 311 throw error(token); 312 } 313 } 314 return result.build(); 315 } 316 317 private TyDecl classDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) { 318 eat(Token.CLASS); 319 String name = eatIdent(); 320 ImmutableList<TyParam> tyParams = ImmutableList.of(); 321 if (token == Token.LT) { 322 tyParams = typarams(); 323 } 324 ClassTy xtnds = null; 325 if (token == Token.EXTENDS) { 326 next(); 327 xtnds = classty(); 328 } 329 ImmutableList.Builder<ClassTy> interfaces = ImmutableList.builder(); 330 if (token == Token.IMPLEMENTS) { 331 next(); 332 do { 333 interfaces.add(classty()); 334 } while (maybe(Token.COMMA)); 335 } 336 eat(Token.LBRACE); 337 ImmutableList<Tree> members = classMembers(); 338 eat(Token.RBRACE); 339 return new TyDecl( 340 position, 341 access, 342 annos, 343 name, 344 tyParams, 345 Optional.fromNullable(xtnds), 346 interfaces.build(), 347 members, 348 TurbineTyKind.CLASS); 349 } 350 351 private ImmutableList<Tree> classMembers() { 352 ImmutableList.Builder<Tree> acc = ImmutableList.builder(); 353 EnumSet<TurbineModifier> access = EnumSet.noneOf(TurbineModifier.class); 354 ImmutableList.Builder<Anno> annos = ImmutableList.builder(); 355 while (true) { 356 switch (token) { 357 case PUBLIC: 358 next(); 359 access.add(TurbineModifier.PUBLIC); 360 break; 361 case PROTECTED: 362 next(); 363 access.add(TurbineModifier.PROTECTED); 364 break; 365 case PRIVATE: 366 next(); 367 access.add(TurbineModifier.PRIVATE); 368 break; 369 case STATIC: 370 next(); 371 access.add(TurbineModifier.STATIC); 372 break; 373 case ABSTRACT: 374 next(); 375 access.add(TurbineModifier.ABSTRACT); 376 break; 377 case FINAL: 378 next(); 379 access.add(TurbineModifier.FINAL); 380 break; 381 case NATIVE: 382 next(); 383 access.add(TurbineModifier.NATIVE); 384 break; 385 case SYNCHRONIZED: 386 next(); 387 access.add(TurbineModifier.SYNCHRONIZED); 388 break; 389 case TRANSIENT: 390 next(); 391 access.add(TurbineModifier.TRANSIENT); 392 break; 393 case VOLATILE: 394 next(); 395 access.add(TurbineModifier.VOLATILE); 396 break; 397 case STRICTFP: 398 next(); 399 access.add(TurbineModifier.STRICTFP); 400 break; 401 case DEFAULT: 402 next(); 403 access.add(TurbineModifier.DEFAULT); 404 break; 405 case AT: 406 { 407 // TODO(cushon): de-dup with top-level parsing 408 next(); 409 if (token == INTERFACE) { 410 acc.add(annotationDeclaration(access, annos.build())); 411 access = EnumSet.noneOf(TurbineModifier.class); 412 annos = ImmutableList.builder(); 413 } else { 414 annos.add(annotation()); 415 } 416 break; 417 } 418 419 case IDENT: 420 case BOOLEAN: 421 case BYTE: 422 case SHORT: 423 case INT: 424 case LONG: 425 case CHAR: 426 case DOUBLE: 427 case FLOAT: 428 case VOID: 429 case LT: 430 acc.addAll(classMember(access, annos.build())); 431 access = EnumSet.noneOf(TurbineModifier.class); 432 annos = ImmutableList.builder(); 433 break; 434 case LBRACE: 435 dropBlocks(); 436 access = EnumSet.noneOf(TurbineModifier.class); 437 annos = ImmutableList.builder(); 438 break; 439 case CLASS: 440 acc.add(classDeclaration(access, annos.build())); 441 access = EnumSet.noneOf(TurbineModifier.class); 442 annos = ImmutableList.builder(); 443 break; 444 case INTERFACE: 445 acc.add(interfaceDeclaration(access, annos.build())); 446 access = EnumSet.noneOf(TurbineModifier.class); 447 annos = ImmutableList.builder(); 448 break; 449 case ENUM: 450 acc.add(enumDeclaration(access, annos.build())); 451 access = EnumSet.noneOf(TurbineModifier.class); 452 annos = ImmutableList.builder(); 453 break; 454 case RBRACE: 455 return acc.build(); 456 case SEMI: 457 next(); 458 continue; 459 default: 460 throw error(token); 461 } 462 } 463 } 464 465 private ImmutableList<Tree> classMember( 466 EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) { 467 ImmutableList<TyParam> typaram = ImmutableList.of(); 468 Type result; 469 String name; 470 471 if (token == Token.LT) { 472 typaram = typarams(); 473 } 474 475 if (token == Token.AT) { 476 annos = ImmutableList.<Anno>builder().addAll(annos).addAll(maybeAnnos()).build(); 477 } 478 479 switch (token) { 480 case VOID: 481 { 482 result = new Tree.VoidTy(position); 483 next(); 484 int pos = position; 485 name = eatIdent(); 486 return memberRest(pos, access, annos, typaram, result, name); 487 } 488 case BOOLEAN: 489 case BYTE: 490 case SHORT: 491 case INT: 492 case LONG: 493 case CHAR: 494 case DOUBLE: 495 case FLOAT: 496 { 497 result = referenceType(ImmutableList.of()); 498 int pos = position; 499 name = eatIdent(); 500 return memberRest(pos, access, annos, typaram, result, name); 501 } 502 case IDENT: 503 { 504 int pos = position; 505 String ident = eatIdent(); 506 switch (token) { 507 case LPAREN: 508 { 509 name = ident; 510 return ImmutableList.of(methodRest(pos, access, annos, typaram, null, name)); 511 } 512 case IDENT: 513 { 514 result = 515 new ClassTy( 516 position, 517 Optional.<ClassTy>absent(), 518 ident, 519 ImmutableList.<Type>of(), 520 ImmutableList.of()); 521 pos = position; 522 name = eatIdent(); 523 return memberRest(pos, access, annos, typaram, result, name); 524 } 525 case AT: 526 case LBRACK: 527 { 528 result = 529 new ClassTy( 530 position, 531 Optional.<ClassTy>absent(), 532 ident, 533 ImmutableList.<Type>of(), 534 ImmutableList.of()); 535 result = maybeDims(maybeAnnos(), result); 536 break; 537 } 538 case LT: 539 { 540 result = 541 new ClassTy( 542 position, Optional.<ClassTy>absent(), ident, tyargs(), ImmutableList.of()); 543 result = maybeDims(maybeAnnos(), result); 544 break; 545 } 546 case DOT: 547 result = 548 new ClassTy( 549 position, 550 Optional.<ClassTy>absent(), 551 ident, 552 ImmutableList.<Type>of(), 553 ImmutableList.of()); 554 break; 555 default: 556 throw error(token); 557 } 558 if (result == null) { 559 throw error(token); 560 } 561 if (token == Token.DOT) { 562 next(); 563 // TODO(cushon): is this cast OK? 564 result = classty((ClassTy) result); 565 } 566 result = maybeDims(maybeAnnos(), result); 567 pos = position; 568 name = eatIdent(); 569 switch (token) { 570 case LPAREN: 571 return ImmutableList.of(methodRest(pos, access, annos, typaram, result, name)); 572 case LBRACK: 573 case SEMI: 574 case ASSIGN: 575 case COMMA: 576 { 577 if (!typaram.isEmpty()) { 578 throw error(ErrorKind.UNEXPECTED_TYPE_PARAMETER, typaram); 579 } 580 return fieldRest(pos, access, annos, result, name); 581 } 582 default: 583 throw error(token); 584 } 585 } 586 default: 587 throw error(token); 588 } 589 } 590 591 private ImmutableList<Anno> maybeAnnos() { 592 if (token != Token.AT) { 593 return ImmutableList.of(); 594 } 595 ImmutableList.Builder<Anno> builder = ImmutableList.builder(); 596 while (token == Token.AT) { 597 next(); 598 builder.add(annotation()); 599 } 600 return builder.build(); 601 } 602 603 private ImmutableList<Tree> memberRest( 604 int pos, 605 EnumSet<TurbineModifier> access, 606 ImmutableList<Anno> annos, 607 ImmutableList<TyParam> typaram, 608 Type result, 609 String name) { 610 switch (token) { 611 case ASSIGN: 612 case SEMI: 613 case LBRACK: 614 case COMMA: 615 { 616 if (!typaram.isEmpty()) { 617 throw error(ErrorKind.UNEXPECTED_TYPE_PARAMETER, typaram); 618 } 619 return fieldRest(pos, access, annos, result, name); 620 } 621 case LPAREN: 622 return ImmutableList.of(methodRest(pos, access, annos, typaram, result, name)); 623 default: 624 throw error(token); 625 } 626 } 627 628 private ImmutableList<Tree> fieldRest( 629 int pos, 630 EnumSet<TurbineModifier> access, 631 ImmutableList<Anno> annos, 632 Type baseTy, 633 String name) { 634 ImmutableList.Builder<Tree> result = ImmutableList.builder(); 635 VariableInitializerParser initializerParser = new VariableInitializerParser(token, lexer); 636 List<List<SavedToken>> bits = initializerParser.parseInitializers(); 637 token = initializerParser.token; 638 639 boolean first = true; 640 for (List<SavedToken> bit : bits) { 641 IteratorLexer lexer = new IteratorLexer(this.lexer.source(), bit.iterator()); 642 Parser parser = new Parser(lexer); 643 if (first) { 644 first = false; 645 } else { 646 name = parser.eatIdent(); 647 } 648 Type ty = baseTy; 649 ty = parser.extraDims(ty); 650 // TODO(cushon): skip more fields that are definitely non-const 651 Expression init = new ConstExpressionParser(lexer, lexer.next()).expression(); 652 if (init != null && init.kind() == Tree.Kind.ARRAY_INIT) { 653 init = null; 654 } 655 result.add(new VarDecl(pos, access, annos, ty, name, Optional.fromNullable(init))); 656 } 657 eat(Token.SEMI); 658 return result.build(); 659 } 660 661 private Tree methodRest( 662 int pos, 663 EnumSet<TurbineModifier> access, 664 ImmutableList<Anno> annos, 665 ImmutableList<TyParam> typaram, 666 Type result, 667 String name) { 668 eat(Token.LPAREN); 669 ImmutableList.Builder<VarDecl> formals = ImmutableList.builder(); 670 formalParams(formals, access); 671 eat(Token.RPAREN); 672 673 result = extraDims(result); 674 675 ImmutableList.Builder<ClassTy> exceptions = ImmutableList.builder(); 676 if (token == Token.THROWS) { 677 next(); 678 exceptions.addAll(exceptions()); 679 } 680 Tree defaultValue = null; 681 switch (token) { 682 case SEMI: 683 next(); 684 break; 685 case LBRACE: 686 dropBlocks(); 687 break; 688 case DEFAULT: 689 { 690 ConstExpressionParser cparser = new ConstExpressionParser(lexer, lexer.next()); 691 Tree expr = cparser.expression(); 692 token = cparser.token; 693 if (expr == null && token == Token.AT) { 694 next(); 695 expr = annotation(); 696 } 697 if (expr == null) { 698 throw error(token); 699 } 700 defaultValue = expr; 701 eat(Token.SEMI); 702 break; 703 } 704 default: 705 throw error(token); 706 } 707 if (result == null) { 708 name = CTOR_NAME; 709 } 710 return new MethDecl( 711 pos, 712 access, 713 annos, 714 typaram, 715 Optional.<Tree>fromNullable(result), 716 name, 717 formals.build(), 718 exceptions.build(), 719 Optional.fromNullable(defaultValue)); 720 } 721 722 /** 723 * Given a base {@code type} and some number of {@code extra} c-style array dimension specifiers, 724 * construct a new array type. 725 * 726 * <p>For reasons that are unclear from the spec, {@code int @A [] x []} is equivalent to {@code 727 * int [] @A [] x}, not {@code int @A [] [] x}. 728 */ 729 private Type extraDims(Type ty) { 730 ImmutableList<Anno> annos = maybeAnnos(); 731 if (!annos.isEmpty() && token != Token.LBRACK) { 732 // orphaned type annotations 733 throw error(token); 734 } 735 Deque<ImmutableList<Anno>> extra = new ArrayDeque<>(); 736 while (maybe(Token.LBRACK)) { 737 eat(Token.RBRACK); 738 extra.push(annos); 739 annos = maybeAnnos(); 740 } 741 ty = extraDims(ty, extra); 742 return ty; 743 } 744 745 private Type extraDims(Type type, Deque<ImmutableList<Anno>> extra) { 746 if (extra.isEmpty()) { 747 return type; 748 } 749 if (type.kind() == Kind.ARR_TY) { 750 ArrTy arrTy = (ArrTy) type; 751 return new ArrTy(arrTy.position(), arrTy.annos(), extraDims(arrTy.elem(), extra)); 752 } 753 return new ArrTy(type.position(), extra.pop(), extraDims(type, extra)); 754 } 755 756 private ImmutableList<ClassTy> exceptions() { 757 ImmutableList.Builder<ClassTy> result = ImmutableList.builder(); 758 result.add(classty()); 759 while (maybe(Token.COMMA)) { 760 result.add(classty()); 761 } 762 return result.build(); 763 } 764 765 private void formalParams( 766 ImmutableList.Builder<VarDecl> builder, EnumSet<TurbineModifier> access) { 767 while (token != Token.RPAREN) { 768 VarDecl formal = formalParam(); 769 builder.add(formal); 770 if (formal.mods().contains(TurbineModifier.VARARGS)) { 771 access.add(TurbineModifier.VARARGS); 772 } 773 if (token != Token.COMMA) { 774 break; 775 } 776 next(); 777 } 778 } 779 780 private VarDecl formalParam() { 781 ImmutableList.Builder<Anno> annos = ImmutableList.builder(); 782 EnumSet<TurbineModifier> access = modifiersAndAnnotations(annos); 783 Type ty = referenceType(ImmutableList.of()); 784 ImmutableList<Anno> typeAnnos = maybeAnnos(); 785 if (maybe(Token.ELLIPSIS)) { 786 access.add(TurbineModifier.VARARGS); 787 ty = new ArrTy(position, typeAnnos, ty); 788 } else { 789 ty = maybeDims(typeAnnos, ty); 790 } 791 // the parameter name is `this` for receiver parameters, and a qualified this expression 792 // for inner classes 793 String name = identOrThis(); 794 while (token == Token.DOT) { 795 eat(Token.DOT); 796 // Overwrite everything up to the terminal 'this' for inner classes; we don't need it 797 name = identOrThis(); 798 } 799 ty = extraDims(ty); 800 return new VarDecl(position, access, annos.build(), ty, name, Optional.<Expression>absent()); 801 } 802 803 private String identOrThis() { 804 switch (token) { 805 case IDENT: 806 return eatIdent(); 807 case THIS: 808 eat(Token.THIS); 809 return "this"; 810 default: 811 throw error(token); 812 } 813 } 814 815 private void dropParens() { 816 eat(Token.LPAREN); 817 int depth = 1; 818 while (depth > 0) { 819 switch (token) { 820 case RPAREN: 821 depth--; 822 break; 823 case LPAREN: 824 depth++; 825 break; 826 default: 827 break; 828 } 829 next(); 830 } 831 } 832 833 private void dropBlocks() { 834 eat(Token.LBRACE); 835 int depth = 1; 836 while (depth > 0) { 837 switch (token) { 838 case RBRACE: 839 depth--; 840 break; 841 case LBRACE: 842 depth++; 843 break; 844 default: 845 break; 846 } 847 next(); 848 } 849 } 850 851 private ImmutableList<TyParam> typarams() { 852 ImmutableList.Builder<TyParam> acc = ImmutableList.builder(); 853 eat(Token.LT); 854 OUTER: 855 while (true) { 856 ImmutableList<Anno> annotations = maybeAnnos(); 857 String name = eatIdent(); 858 ImmutableList<Tree> bounds = ImmutableList.of(); 859 if (token == Token.EXTENDS) { 860 next(); 861 bounds = tybounds(); 862 } 863 acc.add(new TyParam(position, name, bounds, annotations)); 864 switch (token) { 865 case COMMA: 866 eat(Token.COMMA); 867 continue; 868 case GT: 869 next(); 870 break OUTER; 871 default: 872 throw error(token); 873 } 874 } 875 return acc.build(); 876 } 877 878 private ImmutableList<Tree> tybounds() { 879 ImmutableList.Builder<Tree> acc = ImmutableList.builder(); 880 do { 881 acc.add(classty()); 882 } while (maybe(Token.AND)); 883 return acc.build(); 884 } 885 886 private ClassTy classty() { 887 return classty(null); 888 } 889 890 private ClassTy classty(ClassTy ty) { 891 return classty(ty, null); 892 } 893 894 private ClassTy classty(ClassTy ty, @Nullable ImmutableList<Anno> typeAnnos) { 895 int pos = position; 896 do { 897 if (typeAnnos == null) { 898 typeAnnos = maybeAnnos(); 899 } 900 String name = eatIdent(); 901 ImmutableList<Type> tyargs = ImmutableList.of(); 902 if (token == Token.LT) { 903 tyargs = tyargs(); 904 } 905 ty = new ClassTy(pos, Optional.fromNullable(ty), name, tyargs, typeAnnos); 906 typeAnnos = null; 907 } while (maybe(Token.DOT)); 908 return ty; 909 } 910 911 private ImmutableList<Type> tyargs() { 912 ImmutableList.Builder<Type> acc = ImmutableList.builder(); 913 eat(Token.LT); 914 OUTER: 915 do { 916 ImmutableList<Anno> typeAnnos = maybeAnnos(); 917 switch (token) { 918 case COND: 919 { 920 next(); 921 switch (token) { 922 case EXTENDS: 923 next(); 924 Type upper = referenceType(maybeAnnos()); 925 acc.add( 926 new WildTy(position, typeAnnos, Optional.of(upper), Optional.<Type>absent())); 927 break; 928 case SUPER: 929 next(); 930 Type lower = referenceType(maybeAnnos()); 931 acc.add( 932 new WildTy(position, typeAnnos, Optional.<Type>absent(), Optional.of(lower))); 933 break; 934 case COMMA: 935 acc.add( 936 new WildTy( 937 position, typeAnnos, Optional.<Type>absent(), Optional.<Type>absent())); 938 continue OUTER; 939 case GT: 940 case GTGT: 941 case GTGTGT: 942 acc.add( 943 new WildTy( 944 position, typeAnnos, Optional.<Type>absent(), Optional.<Type>absent())); 945 break OUTER; 946 default: 947 throw error(token); 948 } 949 break; 950 } 951 case IDENT: 952 case BOOLEAN: 953 case BYTE: 954 case SHORT: 955 case INT: 956 case LONG: 957 case CHAR: 958 case DOUBLE: 959 case FLOAT: 960 acc.add(referenceType(typeAnnos)); 961 break; 962 default: 963 throw error(token); 964 } 965 } while (maybe(Token.COMMA)); 966 switch (token) { 967 case GT: 968 next(); 969 break; 970 case GTGT: 971 token = Token.GT; 972 break; 973 case GTGTGT: 974 token = Token.GTGT; 975 break; 976 default: 977 throw error(token); 978 } 979 return acc.build(); 980 } 981 982 private Type referenceType(ImmutableList<Anno> typeAnnos) { 983 Type ty; 984 switch (token) { 985 case IDENT: 986 ty = classty(null, typeAnnos); 987 break; 988 case BOOLEAN: 989 next(); 990 ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.BOOLEAN); 991 break; 992 case BYTE: 993 next(); 994 ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.BYTE); 995 break; 996 case SHORT: 997 next(); 998 ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.SHORT); 999 break; 1000 case INT: 1001 next(); 1002 ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.INT); 1003 break; 1004 case LONG: 1005 next(); 1006 ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.LONG); 1007 break; 1008 case CHAR: 1009 next(); 1010 ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.CHAR); 1011 break; 1012 case DOUBLE: 1013 next(); 1014 ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.DOUBLE); 1015 break; 1016 case FLOAT: 1017 next(); 1018 ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.FLOAT); 1019 break; 1020 default: 1021 throw error(token); 1022 } 1023 ty = maybeDims(maybeAnnos(), ty); 1024 return ty; 1025 } 1026 1027 private Type maybeDims(ImmutableList<Anno> typeAnnos, Type ty) { 1028 while (maybe(Token.LBRACK)) { 1029 eat(Token.RBRACK); 1030 ty = new ArrTy(position, typeAnnos, ty); 1031 typeAnnos = maybeAnnos(); 1032 } 1033 return ty; 1034 } 1035 1036 private EnumSet<TurbineModifier> modifiersAndAnnotations(ImmutableList.Builder<Anno> annos) { 1037 EnumSet<TurbineModifier> access = EnumSet.noneOf(TurbineModifier.class); 1038 while (true) { 1039 switch (token) { 1040 case PUBLIC: 1041 next(); 1042 access.add(TurbineModifier.PUBLIC); 1043 break; 1044 case PROTECTED: 1045 next(); 1046 access.add(TurbineModifier.PROTECTED); 1047 break; 1048 case PRIVATE: 1049 next(); 1050 access.add(TurbineModifier.PRIVATE); 1051 break; 1052 case STATIC: 1053 next(); 1054 access.add(TurbineModifier.STATIC); 1055 break; 1056 case ABSTRACT: 1057 next(); 1058 access.add(TurbineModifier.ABSTRACT); 1059 break; 1060 case FINAL: 1061 next(); 1062 access.add(TurbineModifier.FINAL); 1063 break; 1064 case NATIVE: 1065 next(); 1066 access.add(TurbineModifier.NATIVE); 1067 break; 1068 case SYNCHRONIZED: 1069 next(); 1070 access.add(TurbineModifier.SYNCHRONIZED); 1071 break; 1072 case TRANSIENT: 1073 next(); 1074 access.add(TurbineModifier.TRANSIENT); 1075 break; 1076 case VOLATILE: 1077 next(); 1078 access.add(TurbineModifier.VOLATILE); 1079 break; 1080 case STRICTFP: 1081 next(); 1082 access.add(TurbineModifier.STRICTFP); 1083 break; 1084 case AT: 1085 next(); 1086 annos.add(annotation()); 1087 break; 1088 default: 1089 return access; 1090 } 1091 } 1092 } 1093 1094 private ImportDecl importDeclaration() { 1095 boolean stat = maybe(Token.STATIC); 1096 1097 int pos = position; 1098 ImmutableList.Builder<String> type = ImmutableList.builder(); 1099 type.add(eatIdent()); 1100 boolean wild = false; 1101 OUTER: 1102 while (maybe(Token.DOT)) { 1103 switch (token) { 1104 case IDENT: 1105 type.add(eatIdent()); 1106 break; 1107 case MULT: 1108 eat(Token.MULT); 1109 wild = true; 1110 break OUTER; 1111 default: 1112 break; 1113 } 1114 } 1115 eat(Token.SEMI); 1116 return new ImportDecl(pos, type.build(), stat, wild); 1117 } 1118 1119 private PkgDecl packageDeclaration(ImmutableList<Anno> annos) { 1120 PkgDecl result = new PkgDecl(position, qualIdent(), annos); 1121 eat(Token.SEMI); 1122 return result; 1123 } 1124 1125 private ImmutableList<String> qualIdent() { 1126 ImmutableList.Builder<String> name = ImmutableList.builder(); 1127 name.add(eatIdent()); 1128 while (maybe(Token.DOT)) { 1129 name.add(eatIdent()); 1130 } 1131 return name.build(); 1132 } 1133 1134 private Anno annotation() { 1135 int pos = position; 1136 ImmutableList<String> name = qualIdent(); 1137 1138 ImmutableList.Builder<Expression> args = ImmutableList.builder(); 1139 if (token == Token.LPAREN) { 1140 eat(LPAREN); 1141 while (token != RPAREN) { 1142 ConstExpressionParser cparser = new ConstExpressionParser(lexer, token); 1143 Expression arg = cparser.expression(); 1144 if (arg == null) { 1145 throw error(ErrorKind.INVALID_ANNOTATION_ARGUMENT); 1146 } 1147 args.add(arg); 1148 token = cparser.token; 1149 if (!maybe(COMMA)) { 1150 break; 1151 } 1152 } 1153 eat(Token.RPAREN); 1154 } 1155 1156 return new Anno(pos, name, args.build()); 1157 } 1158 1159 private String eatIdent() { 1160 String value = lexer.stringValue(); 1161 eat(Token.IDENT); 1162 return value; 1163 } 1164 1165 private void eat(Token kind) { 1166 if (token != kind) { 1167 throw error(ErrorKind.EXPECTED_TOKEN, kind); 1168 } 1169 next(); 1170 } 1171 1172 private boolean maybe(Token kind) { 1173 if (token == kind) { 1174 next(); 1175 return true; 1176 } 1177 return false; 1178 } 1179 1180 TurbineError error(Token token) { 1181 switch (token) { 1182 case IDENT: 1183 return error(ErrorKind.UNEXPECTED_IDENTIFIER, lexer.stringValue()); 1184 case EOF: 1185 return error(ErrorKind.UNEXPECTED_EOF); 1186 default: 1187 return error(ErrorKind.UNEXPECTED_TOKEN, token); 1188 } 1189 } 1190 1191 private TurbineError error(ErrorKind kind, Object... args) { 1192 return TurbineError.format( 1193 lexer.source(), 1194 Math.min(lexer.position(), lexer.source().source().length() - 1), 1195 kind, 1196 args); 1197 } 1198 } 1199