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