src/share/classes/com/sun/tools/javac/parser/JavacParser.java

Tue, 18 Dec 2012 00:24:54 -0800

author
darcy
date
Tue, 18 Dec 2012 00:24:54 -0800
changeset 1459
bc74006c2d8d
parent 1444
170e486632d9
child 1503
2d2b2be57c78
permissions
-rw-r--r--

8005046: Provide checking for a default method in javax.lang.model
Reviewed-by: jjg

duke@1 1 /*
ksrini@1249 2 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
ohair@554 7 * published by the Free Software Foundation. Oracle designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
ohair@554 9 * by Oracle in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
ohair@554 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554 22 * or visit www.oracle.com if you need additional information or have any
ohair@554 23 * questions.
duke@1 24 */
duke@1 25
duke@1 26 package com.sun.tools.javac.parser;
duke@1 27
duke@1 28 import java.util.*;
duke@1 29
mcimadamore@1145 30 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
mcimadamore@1145 31
ksrini@1074 32 import com.sun.tools.javac.code.*;
mcimadamore@1113 33 import com.sun.tools.javac.parser.Tokens.*;
mcimadamore@1125 34 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
duke@1 35 import com.sun.tools.javac.tree.*;
ksrini@1074 36 import com.sun.tools.javac.tree.JCTree.*;
duke@1 37 import com.sun.tools.javac.util.*;
jjg@726 38 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
ksrini@1074 39 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
duke@1 40 import com.sun.tools.javac.util.List;
ksrini@1074 41
jjg@1127 42 import static com.sun.tools.javac.parser.Tokens.TokenKind.*;
jjg@1127 43 import static com.sun.tools.javac.parser.Tokens.TokenKind.ASSERT;
jjg@1127 44 import static com.sun.tools.javac.parser.Tokens.TokenKind.CASE;
jjg@1127 45 import static com.sun.tools.javac.parser.Tokens.TokenKind.CATCH;
jjg@1127 46 import static com.sun.tools.javac.parser.Tokens.TokenKind.EQ;
jjg@1127 47 import static com.sun.tools.javac.parser.Tokens.TokenKind.GT;
jjg@1127 48 import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
jjg@1127 49 import static com.sun.tools.javac.parser.Tokens.TokenKind.LT;
jjg@1409 50 import static com.sun.tools.javac.tree.JCTree.Tag.*;
duke@1 51 import static com.sun.tools.javac.util.ListBuffer.lb;
duke@1 52
duke@1 53 /** The parser maps a token sequence into an abstract syntax
duke@1 54 * tree. It operates by recursive descent, with code derived
duke@1 55 * systematically from an LL(1) grammar. For efficiency reasons, an
duke@1 56 * operator precedence scheme is used for parsing binary operation
duke@1 57 * expressions.
duke@1 58 *
jjg@581 59 * <p><b>This is NOT part of any supported API.
jjg@581 60 * If you write code that depends on this, you do so at your own risk.
duke@1 61 * This code and its internal interfaces are subject to change or
duke@1 62 * deletion without notice.</b>
duke@1 63 */
jjg@111 64 public class JavacParser implements Parser {
duke@1 65
duke@1 66 /** The number of precedence levels of infix operators.
duke@1 67 */
duke@1 68 private static final int infixPrecedenceLevels = 10;
duke@1 69
duke@1 70 /** The scanner used for lexical analysis.
duke@1 71 */
ksrini@1062 72 protected Lexer S;
duke@1 73
duke@1 74 /** The factory to be used for abstract syntax tree construction.
duke@1 75 */
duke@1 76 protected TreeMaker F;
duke@1 77
duke@1 78 /** The log to be used for error diagnostics.
duke@1 79 */
duke@1 80 private Log log;
duke@1 81
duke@1 82 /** The Source language setting. */
duke@1 83 private Source source;
duke@1 84
duke@1 85 /** The name table. */
jjg@113 86 private Names names;
duke@1 87
ksrini@1138 88 /** End position mappings container */
ksrini@1138 89 private final AbstractEndPosTable endPosTable;
ksrini@1138 90
vromero@1400 91 interface ErrorRecoveryAction {
vromero@1400 92 JCTree doRecover(JavacParser parser);
vromero@1400 93 }
vromero@1400 94
vromero@1400 95 enum BasicErrorRecoveryAction implements ErrorRecoveryAction {
vromero@1400 96 BLOCK_STMT {public JCTree doRecover(JavacParser parser) { return parser.parseStatementAsBlock(); }},
vromero@1400 97 CATCH_CLAUSE {public JCTree doRecover(JavacParser parser) { return parser.catchClause(); }}
vromero@1400 98 }
vromero@1400 99
duke@1 100 /** Construct a parser from a given scanner, tree factory and log.
duke@1 101 */
jjg@111 102 protected JavacParser(ParserFactory fac,
duke@1 103 Lexer S,
jjg@111 104 boolean keepDocComments,
ksrini@1138 105 boolean keepLineMap,
ksrini@1138 106 boolean keepEndPositions) {
duke@1 107 this.S = S;
mcimadamore@1113 108 nextToken(); // prime the pump
duke@1 109 this.F = fac.F;
duke@1 110 this.log = fac.log;
duke@1 111 this.names = fac.names;
duke@1 112 this.source = fac.source;
duke@1 113 this.allowGenerics = source.allowGenerics();
duke@1 114 this.allowVarargs = source.allowVarargs();
duke@1 115 this.allowAsserts = source.allowAsserts();
duke@1 116 this.allowEnums = source.allowEnums();
duke@1 117 this.allowForeach = source.allowForeach();
duke@1 118 this.allowStaticImport = source.allowStaticImport();
duke@1 119 this.allowAnnotations = source.allowAnnotations();
darcy@609 120 this.allowTWR = source.allowTryWithResources();
mcimadamore@537 121 this.allowDiamond = source.allowDiamond();
mcimadamore@550 122 this.allowMulticatch = source.allowMulticatch();
ksrini@1062 123 this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true);
mcimadamore@1415 124 this.allowLambda = source.allowLambda();
mcimadamore@1415 125 this.allowMethodReferences = source.allowMethodReferences();
mcimadamore@1415 126 this.allowDefaultMethods = source.allowDefaultMethods();
mcimadamore@1436 127 this.allowIntersectionTypesInCast =
mcimadamore@1436 128 source.allowIntersectionTypesInCast() &&
mcimadamore@1436 129 fac.options.isSet("allowIntersectionTypes");
duke@1 130 this.keepDocComments = keepDocComments;
jjg@1409 131 docComments = newDocCommentTable(keepDocComments, fac);
jjg@111 132 this.keepLineMap = keepLineMap;
duke@1 133 this.errorTree = F.Erroneous();
ksrini@1138 134 endPosTable = newEndPosTable(keepEndPositions);
duke@1 135 }
duke@1 136
ksrini@1138 137 protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
ksrini@1138 138 return keepEndPositions
ksrini@1138 139 ? new SimpleEndPosTable()
ksrini@1138 140 : new EmptyEndPosTable();
ksrini@1138 141 }
jjg@1280 142
jjg@1409 143 protected DocCommentTable newDocCommentTable(boolean keepDocComments, ParserFactory fac) {
jjg@1409 144 return keepDocComments ? new LazyDocCommentTable(fac) : null;
jjg@1280 145 }
jjg@1280 146
duke@1 147 /** Switch: Should generics be recognized?
duke@1 148 */
duke@1 149 boolean allowGenerics;
duke@1 150
mcimadamore@537 151 /** Switch: Should diamond operator be recognized?
mcimadamore@537 152 */
mcimadamore@537 153 boolean allowDiamond;
mcimadamore@537 154
mcimadamore@550 155 /** Switch: Should multicatch clause be accepted?
mcimadamore@550 156 */
mcimadamore@550 157 boolean allowMulticatch;
mcimadamore@550 158
duke@1 159 /** Switch: Should varargs be recognized?
duke@1 160 */
duke@1 161 boolean allowVarargs;
duke@1 162
duke@1 163 /** Switch: should we recognize assert statements, or just give a warning?
duke@1 164 */
duke@1 165 boolean allowAsserts;
duke@1 166
duke@1 167 /** Switch: should we recognize enums, or just give a warning?
duke@1 168 */
duke@1 169 boolean allowEnums;
duke@1 170
duke@1 171 /** Switch: should we recognize foreach?
duke@1 172 */
duke@1 173 boolean allowForeach;
duke@1 174
duke@1 175 /** Switch: should we recognize foreach?
duke@1 176 */
duke@1 177 boolean allowStaticImport;
duke@1 178
duke@1 179 /** Switch: should we recognize annotations?
duke@1 180 */
duke@1 181 boolean allowAnnotations;
duke@1 182
darcy@840 183 /** Switch: should we recognize try-with-resources?
darcy@609 184 */
darcy@609 185 boolean allowTWR;
darcy@609 186
ksrini@1062 187 /** Switch: should we fold strings?
ksrini@1062 188 */
ksrini@1062 189 boolean allowStringFolding;
ksrini@1062 190
mcimadamore@1144 191 /** Switch: should we recognize lambda expressions?
mcimadamore@1144 192 */
mcimadamore@1144 193 boolean allowLambda;
mcimadamore@1144 194
mcimadamore@1145 195 /** Switch: should we allow method/constructor references?
mcimadamore@1145 196 */
mcimadamore@1145 197 boolean allowMethodReferences;
mcimadamore@1145 198
mcimadamore@1366 199 /** Switch: should we allow default methods in interfaces?
mcimadamore@1366 200 */
mcimadamore@1366 201 boolean allowDefaultMethods;
mcimadamore@1366 202
mcimadamore@1436 203 /** Switch: should we allow intersection types in cast?
mcimadamore@1436 204 */
mcimadamore@1436 205 boolean allowIntersectionTypesInCast;
mcimadamore@1436 206
duke@1 207 /** Switch: should we keep docComments?
duke@1 208 */
duke@1 209 boolean keepDocComments;
duke@1 210
jjg@111 211 /** Switch: should we keep line table?
jjg@111 212 */
jjg@111 213 boolean keepLineMap;
jjg@111 214
duke@1 215 /** When terms are parsed, the mode determines which is expected:
duke@1 216 * mode = EXPR : an expression
duke@1 217 * mode = TYPE : a type
duke@1 218 * mode = NOPARAMS : no parameters allowed for type
duke@1 219 * mode = TYPEARG : type argument
duke@1 220 */
mcimadamore@537 221 static final int EXPR = 0x1;
mcimadamore@537 222 static final int TYPE = 0x2;
mcimadamore@537 223 static final int NOPARAMS = 0x4;
mcimadamore@537 224 static final int TYPEARG = 0x8;
mcimadamore@537 225 static final int DIAMOND = 0x10;
duke@1 226
duke@1 227 /** The current mode.
duke@1 228 */
duke@1 229 private int mode = 0;
duke@1 230
duke@1 231 /** The mode of the term that was parsed last.
duke@1 232 */
duke@1 233 private int lastmode = 0;
duke@1 234
mcimadamore@1113 235 /* ---------- token management -------------- */
mcimadamore@1113 236
mcimadamore@1113 237 protected Token token;
mcimadamore@1113 238
jjg@1409 239 public Token token() {
jjg@1409 240 return token;
jjg@1409 241 }
jjg@1409 242
jjg@1409 243 public void nextToken() {
mcimadamore@1113 244 S.nextToken();
mcimadamore@1113 245 token = S.token();
mcimadamore@1113 246 }
mcimadamore@1113 247
mcimadamore@1144 248 protected boolean peekToken(TokenKind tk) {
mcimadamore@1436 249 return peekToken(0, tk);
mcimadamore@1436 250 }
mcimadamore@1436 251
mcimadamore@1436 252 protected boolean peekToken(int lookahead, TokenKind tk) {
mcimadamore@1436 253 return S.token(lookahead + 1).kind == tk;
mcimadamore@1144 254 }
mcimadamore@1144 255
mcimadamore@1144 256 protected boolean peekToken(TokenKind tk1, TokenKind tk2) {
mcimadamore@1436 257 return peekToken(0, tk1, tk2);
mcimadamore@1436 258 }
mcimadamore@1436 259
mcimadamore@1436 260 protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2) {
mcimadamore@1436 261 return S.token(lookahead + 1).kind == tk1 &&
mcimadamore@1436 262 S.token(lookahead + 2).kind == tk2;
mcimadamore@1144 263 }
mcimadamore@1144 264
mcimadamore@1144 265 protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) {
mcimadamore@1436 266 return peekToken(0, tk1, tk2, tk3);
mcimadamore@1436 267 }
mcimadamore@1436 268
mcimadamore@1436 269 protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2, TokenKind tk3) {
mcimadamore@1436 270 return S.token(lookahead + 1).kind == tk1 &&
mcimadamore@1436 271 S.token(lookahead + 2).kind == tk2 &&
mcimadamore@1436 272 S.token(lookahead + 3).kind == tk3;
mcimadamore@1144 273 }
mcimadamore@1144 274
mcimadamore@1144 275 protected boolean peekToken(TokenKind... kinds) {
mcimadamore@1436 276 return peekToken(0, kinds);
mcimadamore@1436 277 }
mcimadamore@1436 278
mcimadamore@1436 279 protected boolean peekToken(int lookahead, TokenKind... kinds) {
mcimadamore@1436 280 for (; lookahead < kinds.length ; lookahead++) {
mcimadamore@1144 281 if (S.token(lookahead + 1).kind != kinds[lookahead]) {
mcimadamore@1144 282 return false;
mcimadamore@1144 283 }
mcimadamore@1144 284 }
mcimadamore@1144 285 return true;
mcimadamore@1144 286 }
mcimadamore@1144 287
mcimadamore@1113 288 /* ---------- error recovery -------------- */
duke@1 289
duke@1 290 private JCErroneous errorTree;
duke@1 291
duke@1 292 /** Skip forward until a suitable stop token is found.
duke@1 293 */
duke@1 294 private void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) {
duke@1 295 while (true) {
mcimadamore@1113 296 switch (token.kind) {
duke@1 297 case SEMI:
mcimadamore@1113 298 nextToken();
duke@1 299 return;
duke@1 300 case PUBLIC:
duke@1 301 case FINAL:
duke@1 302 case ABSTRACT:
duke@1 303 case MONKEYS_AT:
duke@1 304 case EOF:
duke@1 305 case CLASS:
duke@1 306 case INTERFACE:
duke@1 307 case ENUM:
duke@1 308 return;
duke@1 309 case IMPORT:
duke@1 310 if (stopAtImport)
duke@1 311 return;
duke@1 312 break;
duke@1 313 case LBRACE:
duke@1 314 case RBRACE:
duke@1 315 case PRIVATE:
duke@1 316 case PROTECTED:
duke@1 317 case STATIC:
duke@1 318 case TRANSIENT:
duke@1 319 case NATIVE:
duke@1 320 case VOLATILE:
duke@1 321 case SYNCHRONIZED:
duke@1 322 case STRICTFP:
duke@1 323 case LT:
duke@1 324 case BYTE:
duke@1 325 case SHORT:
duke@1 326 case CHAR:
duke@1 327 case INT:
duke@1 328 case LONG:
duke@1 329 case FLOAT:
duke@1 330 case DOUBLE:
duke@1 331 case BOOLEAN:
duke@1 332 case VOID:
duke@1 333 if (stopAtMemberDecl)
duke@1 334 return;
duke@1 335 break;
duke@1 336 case IDENTIFIER:
duke@1 337 if (stopAtIdentifier)
duke@1 338 return;
duke@1 339 break;
duke@1 340 case CASE:
duke@1 341 case DEFAULT:
duke@1 342 case IF:
duke@1 343 case FOR:
duke@1 344 case WHILE:
duke@1 345 case DO:
duke@1 346 case TRY:
duke@1 347 case SWITCH:
duke@1 348 case RETURN:
duke@1 349 case THROW:
duke@1 350 case BREAK:
duke@1 351 case CONTINUE:
duke@1 352 case ELSE:
duke@1 353 case FINALLY:
duke@1 354 case CATCH:
duke@1 355 if (stopAtStatement)
duke@1 356 return;
duke@1 357 break;
duke@1 358 }
mcimadamore@1113 359 nextToken();
duke@1 360 }
duke@1 361 }
duke@1 362
mcimadamore@1113 363 private JCErroneous syntaxError(int pos, String key, TokenKind... args) {
ksrini@1074 364 return syntaxError(pos, List.<JCTree>nil(), key, args);
duke@1 365 }
duke@1 366
mcimadamore@1113 367 private JCErroneous syntaxError(int pos, List<JCTree> errs, String key, TokenKind... args) {
duke@1 368 setErrorEndPos(pos);
ksrini@1074 369 JCErroneous err = F.at(pos).Erroneous(errs);
ksrini@1074 370 reportSyntaxError(err, key, (Object[])args);
ksrini@1074 371 if (errs != null) {
ksrini@1074 372 JCTree last = errs.last();
ksrini@1074 373 if (last != null)
ksrini@1074 374 storeEnd(last, pos);
ksrini@1074 375 }
ksrini@1074 376 return toP(err);
duke@1 377 }
duke@1 378
duke@1 379 private int errorPos = Position.NOPOS;
ksrini@1074 380
duke@1 381 /**
ksrini@1074 382 * Report a syntax using the given the position parameter and arguments,
ksrini@1074 383 * unless one was already reported at the same position.
duke@1 384 */
mcimadamore@80 385 private void reportSyntaxError(int pos, String key, Object... args) {
ksrini@1074 386 JCDiagnostic.DiagnosticPosition diag = new JCDiagnostic.SimpleDiagnosticPosition(pos);
ksrini@1074 387 reportSyntaxError(diag, key, args);
ksrini@1074 388 }
ksrini@1074 389
ksrini@1074 390 /**
ksrini@1074 391 * Report a syntax error using the given DiagnosticPosition object and
ksrini@1074 392 * arguments, unless one was already reported at the same position.
ksrini@1074 393 */
ksrini@1074 394 private void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, String key, Object... args) {
ksrini@1074 395 int pos = diagPos.getPreferredPosition();
duke@1 396 if (pos > S.errPos() || pos == Position.NOPOS) {
mcimadamore@1113 397 if (token.kind == EOF) {
ksrini@1074 398 error(diagPos, "premature.eof");
ksrini@1074 399 } else {
ksrini@1074 400 error(diagPos, key, args);
ksrini@1074 401 }
duke@1 402 }
duke@1 403 S.errPos(pos);
mcimadamore@1113 404 if (token.pos == errorPos)
mcimadamore@1113 405 nextToken(); // guarantee progress
mcimadamore@1113 406 errorPos = token.pos;
duke@1 407 }
duke@1 408
duke@1 409
duke@1 410 /** Generate a syntax error at current position unless one was already
duke@1 411 * reported at the same position.
duke@1 412 */
duke@1 413 private JCErroneous syntaxError(String key) {
mcimadamore@1113 414 return syntaxError(token.pos, key);
duke@1 415 }
duke@1 416
duke@1 417 /** Generate a syntax error at current position unless one was
duke@1 418 * already reported at the same position.
duke@1 419 */
mcimadamore@1113 420 private JCErroneous syntaxError(String key, TokenKind arg) {
mcimadamore@1113 421 return syntaxError(token.pos, key, arg);
duke@1 422 }
duke@1 423
duke@1 424 /** If next input token matches given token, skip it, otherwise report
duke@1 425 * an error.
duke@1 426 */
mcimadamore@1113 427 public void accept(TokenKind tk) {
mcimadamore@1113 428 if (token.kind == tk) {
mcimadamore@1113 429 nextToken();
duke@1 430 } else {
mcimadamore@1113 431 setErrorEndPos(token.pos);
mcimadamore@1113 432 reportSyntaxError(S.prevToken().endPos, "expected", tk);
duke@1 433 }
duke@1 434 }
duke@1 435
duke@1 436 /** Report an illegal start of expression/type error at given position.
duke@1 437 */
duke@1 438 JCExpression illegal(int pos) {
ksrini@1074 439 setErrorEndPos(pos);
duke@1 440 if ((mode & EXPR) != 0)
duke@1 441 return syntaxError(pos, "illegal.start.of.expr");
duke@1 442 else
duke@1 443 return syntaxError(pos, "illegal.start.of.type");
duke@1 444
duke@1 445 }
duke@1 446
duke@1 447 /** Report an illegal start of expression/type error at current position.
duke@1 448 */
duke@1 449 JCExpression illegal() {
mcimadamore@1113 450 return illegal(token.pos);
duke@1 451 }
duke@1 452
duke@1 453 /** Diagnose a modifier flag from the set, if any. */
duke@1 454 void checkNoMods(long mods) {
duke@1 455 if (mods != 0) {
duke@1 456 long lowestMod = mods & -mods;
mcimadamore@1113 457 error(token.pos, "mod.not.allowed.here",
mcimadamore@80 458 Flags.asFlagSet(lowestMod));
duke@1 459 }
duke@1 460 }
duke@1 461
duke@1 462 /* ---------- doc comments --------- */
duke@1 463
jjg@1280 464 /** A table to store all documentation comments
duke@1 465 * indexed by the tree nodes they refer to.
duke@1 466 * defined only if option flag keepDocComment is set.
duke@1 467 */
jjg@1280 468 private final DocCommentTable docComments;
duke@1 469
duke@1 470 /** Make an entry into docComments hashtable,
duke@1 471 * provided flag keepDocComments is set and given doc comment is non-null.
duke@1 472 * @param tree The tree to be used as index in the hashtable
duke@1 473 * @param dc The doc comment to associate with the tree, or null.
duke@1 474 */
jjg@1280 475 void attach(JCTree tree, Comment dc) {
duke@1 476 if (keepDocComments && dc != null) {
duke@1 477 // System.out.println("doc comment = ");System.out.println(dc);//DEBUG
jjg@1280 478 docComments.putComment(tree, dc);
duke@1 479 }
duke@1 480 }
duke@1 481
duke@1 482 /* -------- source positions ------- */
duke@1 483
duke@1 484 private void setErrorEndPos(int errPos) {
ksrini@1138 485 endPosTable.setErrorEndPos(errPos);
duke@1 486 }
duke@1 487
ksrini@1138 488 private void storeEnd(JCTree tree, int endpos) {
ksrini@1138 489 endPosTable.storeEnd(tree, endpos);
duke@1 490 }
duke@1 491
ksrini@1138 492 private <T extends JCTree> T to(T t) {
ksrini@1138 493 return endPosTable.to(t);
ksrini@1138 494 }
duke@1 495
ksrini@1138 496 private <T extends JCTree> T toP(T t) {
ksrini@1138 497 return endPosTable.toP(t);
ksrini@1138 498 }
duke@1 499
duke@1 500 /** Get the start position for a tree node. The start position is
duke@1 501 * defined to be the position of the first character of the first
duke@1 502 * token of the node's source text.
duke@1 503 * @param tree The tree node
duke@1 504 */
duke@1 505 public int getStartPos(JCTree tree) {
duke@1 506 return TreeInfo.getStartPos(tree);
duke@1 507 }
duke@1 508
duke@1 509 /**
duke@1 510 * Get the end position for a tree node. The end position is
duke@1 511 * defined to be the position of the last character of the last
duke@1 512 * token of the node's source text. Returns Position.NOPOS if end
duke@1 513 * positions are not generated or the position is otherwise not
duke@1 514 * found.
duke@1 515 * @param tree The tree node
duke@1 516 */
duke@1 517 public int getEndPos(JCTree tree) {
ksrini@1138 518 return endPosTable.getEndPos(tree);
duke@1 519 }
duke@1 520
duke@1 521
duke@1 522
duke@1 523 /* ---------- parsing -------------- */
duke@1 524
duke@1 525 /**
duke@1 526 * Ident = IDENTIFIER
duke@1 527 */
duke@1 528 Name ident() {
mcimadamore@1113 529 if (token.kind == IDENTIFIER) {
mcimadamore@1113 530 Name name = token.name();
mcimadamore@1113 531 nextToken();
duke@1 532 return name;
mcimadamore@1113 533 } else if (token.kind == ASSERT) {
duke@1 534 if (allowAsserts) {
mcimadamore@1113 535 error(token.pos, "assert.as.identifier");
mcimadamore@1113 536 nextToken();
duke@1 537 return names.error;
duke@1 538 } else {
mcimadamore@1113 539 warning(token.pos, "assert.as.identifier");
mcimadamore@1113 540 Name name = token.name();
mcimadamore@1113 541 nextToken();
duke@1 542 return name;
duke@1 543 }
mcimadamore@1113 544 } else if (token.kind == ENUM) {
duke@1 545 if (allowEnums) {
mcimadamore@1113 546 error(token.pos, "enum.as.identifier");
mcimadamore@1113 547 nextToken();
duke@1 548 return names.error;
duke@1 549 } else {
mcimadamore@1113 550 warning(token.pos, "enum.as.identifier");
mcimadamore@1113 551 Name name = token.name();
mcimadamore@1113 552 nextToken();
duke@1 553 return name;
duke@1 554 }
duke@1 555 } else {
duke@1 556 accept(IDENTIFIER);
duke@1 557 return names.error;
duke@1 558 }
duke@1 559 }
duke@1 560
duke@1 561 /**
duke@1 562 * Qualident = Ident { DOT Ident }
duke@1 563 */
duke@1 564 public JCExpression qualident() {
mcimadamore@1113 565 JCExpression t = toP(F.at(token.pos).Ident(ident()));
mcimadamore@1113 566 while (token.kind == DOT) {
mcimadamore@1113 567 int pos = token.pos;
mcimadamore@1113 568 nextToken();
duke@1 569 t = toP(F.at(pos).Select(t, ident()));
duke@1 570 }
duke@1 571 return t;
duke@1 572 }
duke@1 573
ksrini@1074 574 JCExpression literal(Name prefix) {
mcimadamore@1113 575 return literal(prefix, token.pos);
ksrini@1074 576 }
ksrini@1074 577
duke@1 578 /**
duke@1 579 * Literal =
duke@1 580 * INTLITERAL
duke@1 581 * | LONGLITERAL
duke@1 582 * | FLOATLITERAL
duke@1 583 * | DOUBLELITERAL
duke@1 584 * | CHARLITERAL
duke@1 585 * | STRINGLITERAL
duke@1 586 * | TRUE
duke@1 587 * | FALSE
duke@1 588 * | NULL
duke@1 589 */
ksrini@1074 590 JCExpression literal(Name prefix, int pos) {
duke@1 591 JCExpression t = errorTree;
mcimadamore@1113 592 switch (token.kind) {
duke@1 593 case INTLITERAL:
duke@1 594 try {
duke@1 595 t = F.at(pos).Literal(
jjg@1374 596 TypeTag.INT,
mcimadamore@1113 597 Convert.string2int(strval(prefix), token.radix()));
duke@1 598 } catch (NumberFormatException ex) {
mcimadamore@1113 599 error(token.pos, "int.number.too.large", strval(prefix));
duke@1 600 }
duke@1 601 break;
duke@1 602 case LONGLITERAL:
duke@1 603 try {
duke@1 604 t = F.at(pos).Literal(
jjg@1374 605 TypeTag.LONG,
mcimadamore@1113 606 new Long(Convert.string2long(strval(prefix), token.radix())));
duke@1 607 } catch (NumberFormatException ex) {
mcimadamore@1113 608 error(token.pos, "int.number.too.large", strval(prefix));
duke@1 609 }
duke@1 610 break;
duke@1 611 case FLOATLITERAL: {
mcimadamore@1113 612 String proper = token.radix() == 16 ?
mcimadamore@1113 613 ("0x"+ token.stringVal()) :
mcimadamore@1113 614 token.stringVal();
duke@1 615 Float n;
duke@1 616 try {
duke@1 617 n = Float.valueOf(proper);
duke@1 618 } catch (NumberFormatException ex) {
jjg@788 619 // error already reported in scanner
duke@1 620 n = Float.NaN;
duke@1 621 }
duke@1 622 if (n.floatValue() == 0.0f && !isZero(proper))
mcimadamore@1113 623 error(token.pos, "fp.number.too.small");
duke@1 624 else if (n.floatValue() == Float.POSITIVE_INFINITY)
mcimadamore@1113 625 error(token.pos, "fp.number.too.large");
duke@1 626 else
jjg@1374 627 t = F.at(pos).Literal(TypeTag.FLOAT, n);
duke@1 628 break;
duke@1 629 }
duke@1 630 case DOUBLELITERAL: {
mcimadamore@1113 631 String proper = token.radix() == 16 ?
mcimadamore@1113 632 ("0x"+ token.stringVal()) :
mcimadamore@1113 633 token.stringVal();
duke@1 634 Double n;
duke@1 635 try {
duke@1 636 n = Double.valueOf(proper);
duke@1 637 } catch (NumberFormatException ex) {
duke@1 638 // error already reported in scanner
duke@1 639 n = Double.NaN;
duke@1 640 }
duke@1 641 if (n.doubleValue() == 0.0d && !isZero(proper))
mcimadamore@1113 642 error(token.pos, "fp.number.too.small");
duke@1 643 else if (n.doubleValue() == Double.POSITIVE_INFINITY)
mcimadamore@1113 644 error(token.pos, "fp.number.too.large");
duke@1 645 else
jjg@1374 646 t = F.at(pos).Literal(TypeTag.DOUBLE, n);
duke@1 647 break;
duke@1 648 }
duke@1 649 case CHARLITERAL:
duke@1 650 t = F.at(pos).Literal(
jjg@1374 651 TypeTag.CHAR,
mcimadamore@1113 652 token.stringVal().charAt(0) + 0);
duke@1 653 break;
duke@1 654 case STRINGLITERAL:
duke@1 655 t = F.at(pos).Literal(
jjg@1374 656 TypeTag.CLASS,
mcimadamore@1113 657 token.stringVal());
duke@1 658 break;
duke@1 659 case TRUE: case FALSE:
duke@1 660 t = F.at(pos).Literal(
jjg@1374 661 TypeTag.BOOLEAN,
mcimadamore@1113 662 (token.kind == TRUE ? 1 : 0));
duke@1 663 break;
duke@1 664 case NULL:
duke@1 665 t = F.at(pos).Literal(
jjg@1374 666 TypeTag.BOT,
duke@1 667 null);
duke@1 668 break;
duke@1 669 default:
jjg@816 670 Assert.error();
duke@1 671 }
duke@1 672 if (t == errorTree)
duke@1 673 t = F.at(pos).Erroneous();
mcimadamore@1113 674 storeEnd(t, token.endPos);
mcimadamore@1113 675 nextToken();
duke@1 676 return t;
duke@1 677 }
duke@1 678 //where
duke@1 679 boolean isZero(String s) {
duke@1 680 char[] cs = s.toCharArray();
jjg@408 681 int base = ((cs.length > 1 && Character.toLowerCase(cs[1]) == 'x') ? 16 : 10);
duke@1 682 int i = ((base==16) ? 2 : 0);
duke@1 683 while (i < cs.length && (cs[i] == '0' || cs[i] == '.')) i++;
duke@1 684 return !(i < cs.length && (Character.digit(cs[i], base) > 0));
duke@1 685 }
duke@1 686
duke@1 687 String strval(Name prefix) {
mcimadamore@1113 688 String s = token.stringVal();
jjg@113 689 return prefix.isEmpty() ? s : prefix + s;
duke@1 690 }
duke@1 691
duke@1 692 /** terms can be either expressions or types.
duke@1 693 */
jjg@111 694 public JCExpression parseExpression() {
duke@1 695 return term(EXPR);
duke@1 696 }
duke@1 697
jjg@111 698 public JCExpression parseType() {
duke@1 699 return term(TYPE);
duke@1 700 }
duke@1 701
duke@1 702 JCExpression term(int newmode) {
duke@1 703 int prevmode = mode;
duke@1 704 mode = newmode;
duke@1 705 JCExpression t = term();
duke@1 706 lastmode = mode;
duke@1 707 mode = prevmode;
duke@1 708 return t;
duke@1 709 }
duke@1 710
duke@1 711 /**
jjg@1326 712 * {@literal
duke@1 713 * Expression = Expression1 [ExpressionRest]
duke@1 714 * ExpressionRest = [AssignmentOperator Expression1]
duke@1 715 * AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" |
duke@1 716 * "&=" | "|=" | "^=" |
duke@1 717 * "%=" | "<<=" | ">>=" | ">>>="
duke@1 718 * Type = Type1
duke@1 719 * TypeNoParams = TypeNoParams1
duke@1 720 * StatementExpression = Expression
duke@1 721 * ConstantExpression = Expression
jjg@1326 722 * }
duke@1 723 */
duke@1 724 JCExpression term() {
duke@1 725 JCExpression t = term1();
duke@1 726 if ((mode & EXPR) != 0 &&
mcimadamore@1113 727 token.kind == EQ || PLUSEQ.compareTo(token.kind) <= 0 && token.kind.compareTo(GTGTGTEQ) <= 0)
duke@1 728 return termRest(t);
duke@1 729 else
duke@1 730 return t;
duke@1 731 }
duke@1 732
duke@1 733 JCExpression termRest(JCExpression t) {
mcimadamore@1113 734 switch (token.kind) {
duke@1 735 case EQ: {
mcimadamore@1113 736 int pos = token.pos;
mcimadamore@1113 737 nextToken();
duke@1 738 mode = EXPR;
duke@1 739 JCExpression t1 = term();
duke@1 740 return toP(F.at(pos).Assign(t, t1));
duke@1 741 }
duke@1 742 case PLUSEQ:
duke@1 743 case SUBEQ:
duke@1 744 case STAREQ:
duke@1 745 case SLASHEQ:
duke@1 746 case PERCENTEQ:
duke@1 747 case AMPEQ:
duke@1 748 case BAREQ:
duke@1 749 case CARETEQ:
duke@1 750 case LTLTEQ:
duke@1 751 case GTGTEQ:
duke@1 752 case GTGTGTEQ:
mcimadamore@1113 753 int pos = token.pos;
mcimadamore@1113 754 TokenKind tk = token.kind;
mcimadamore@1113 755 nextToken();
duke@1 756 mode = EXPR;
duke@1 757 JCExpression t1 = term();
mcimadamore@1113 758 return F.at(pos).Assignop(optag(tk), t, t1);
duke@1 759 default:
duke@1 760 return t;
duke@1 761 }
duke@1 762 }
duke@1 763
duke@1 764 /** Expression1 = Expression2 [Expression1Rest]
duke@1 765 * Type1 = Type2
duke@1 766 * TypeNoParams1 = TypeNoParams2
duke@1 767 */
duke@1 768 JCExpression term1() {
duke@1 769 JCExpression t = term2();
mcimadamore@1113 770 if ((mode & EXPR) != 0 && token.kind == QUES) {
duke@1 771 mode = EXPR;
duke@1 772 return term1Rest(t);
duke@1 773 } else {
duke@1 774 return t;
duke@1 775 }
duke@1 776 }
duke@1 777
duke@1 778 /** Expression1Rest = ["?" Expression ":" Expression1]
duke@1 779 */
duke@1 780 JCExpression term1Rest(JCExpression t) {
mcimadamore@1113 781 if (token.kind == QUES) {
mcimadamore@1113 782 int pos = token.pos;
mcimadamore@1113 783 nextToken();
duke@1 784 JCExpression t1 = term();
duke@1 785 accept(COLON);
duke@1 786 JCExpression t2 = term1();
duke@1 787 return F.at(pos).Conditional(t, t1, t2);
duke@1 788 } else {
duke@1 789 return t;
duke@1 790 }
duke@1 791 }
duke@1 792
duke@1 793 /** Expression2 = Expression3 [Expression2Rest]
duke@1 794 * Type2 = Type3
duke@1 795 * TypeNoParams2 = TypeNoParams3
duke@1 796 */
duke@1 797 JCExpression term2() {
duke@1 798 JCExpression t = term3();
mcimadamore@1113 799 if ((mode & EXPR) != 0 && prec(token.kind) >= TreeInfo.orPrec) {
duke@1 800 mode = EXPR;
duke@1 801 return term2Rest(t, TreeInfo.orPrec);
duke@1 802 } else {
duke@1 803 return t;
duke@1 804 }
duke@1 805 }
duke@1 806
duke@1 807 /* Expression2Rest = {infixop Expression3}
duke@1 808 * | Expression3 instanceof Type
duke@1 809 * infixop = "||"
duke@1 810 * | "&&"
duke@1 811 * | "|"
duke@1 812 * | "^"
duke@1 813 * | "&"
duke@1 814 * | "==" | "!="
duke@1 815 * | "<" | ">" | "<=" | ">="
duke@1 816 * | "<<" | ">>" | ">>>"
duke@1 817 * | "+" | "-"
duke@1 818 * | "*" | "/" | "%"
duke@1 819 */
duke@1 820 JCExpression term2Rest(JCExpression t, int minprec) {
duke@1 821 JCExpression[] odStack = newOdStack();
duke@1 822 Token[] opStack = newOpStack();
mcimadamore@1113 823
duke@1 824 // optimization, was odStack = new Tree[...]; opStack = new Tree[...];
duke@1 825 int top = 0;
duke@1 826 odStack[0] = t;
mcimadamore@1113 827 int startPos = token.pos;
mcimadamore@1113 828 Token topOp = Tokens.DUMMY;
mcimadamore@1113 829 while (prec(token.kind) >= minprec) {
duke@1 830 opStack[top] = topOp;
duke@1 831 top++;
mcimadamore@1113 832 topOp = token;
mcimadamore@1113 833 nextToken();
mcimadamore@1165 834 odStack[top] = (topOp.kind == INSTANCEOF) ? parseType() : term3();
mcimadamore@1113 835 while (top > 0 && prec(topOp.kind) >= prec(token.kind)) {
mcimadamore@1113 836 odStack[top-1] = makeOp(topOp.pos, topOp.kind, odStack[top-1],
duke@1 837 odStack[top]);
duke@1 838 top--;
duke@1 839 topOp = opStack[top];
duke@1 840 }
duke@1 841 }
jjg@816 842 Assert.check(top == 0);
duke@1 843 t = odStack[0];
duke@1 844
jjg@1127 845 if (t.hasTag(JCTree.Tag.PLUS)) {
jjg@1362 846 StringBuilder buf = foldStrings(t);
duke@1 847 if (buf != null) {
jjg@1374 848 t = toP(F.at(startPos).Literal(TypeTag.CLASS, buf.toString()));
duke@1 849 }
duke@1 850 }
duke@1 851
jlahoda@1444 852 odStackSupply.add(odStack);
jlahoda@1444 853 opStackSupply.add(opStack);
duke@1 854 return t;
duke@1 855 }
duke@1 856 //where
duke@1 857 /** Construct a binary or type test node.
duke@1 858 */
duke@1 859 private JCExpression makeOp(int pos,
mcimadamore@1113 860 TokenKind topOp,
duke@1 861 JCExpression od1,
duke@1 862 JCExpression od2)
duke@1 863 {
duke@1 864 if (topOp == INSTANCEOF) {
duke@1 865 return F.at(pos).TypeTest(od1, od2);
duke@1 866 } else {
duke@1 867 return F.at(pos).Binary(optag(topOp), od1, od2);
duke@1 868 }
duke@1 869 }
duke@1 870 /** If tree is a concatenation of string literals, replace it
duke@1 871 * by a single literal representing the concatenated string.
duke@1 872 */
jjg@1362 873 protected StringBuilder foldStrings(JCTree tree) {
ksrini@1062 874 if (!allowStringFolding)
ksrini@1062 875 return null;
duke@1 876 List<String> buf = List.nil();
duke@1 877 while (true) {
jjg@1127 878 if (tree.hasTag(LITERAL)) {
duke@1 879 JCLiteral lit = (JCLiteral) tree;
jjg@1374 880 if (lit.typetag == TypeTag.CLASS) {
jjg@1362 881 StringBuilder sbuf =
jjg@1362 882 new StringBuilder((String)lit.value);
duke@1 883 while (buf.nonEmpty()) {
duke@1 884 sbuf.append(buf.head);
duke@1 885 buf = buf.tail;
duke@1 886 }
duke@1 887 return sbuf;
duke@1 888 }
jjg@1127 889 } else if (tree.hasTag(JCTree.Tag.PLUS)) {
duke@1 890 JCBinary op = (JCBinary)tree;
jjg@1127 891 if (op.rhs.hasTag(LITERAL)) {
duke@1 892 JCLiteral lit = (JCLiteral) op.rhs;
jjg@1374 893 if (lit.typetag == TypeTag.CLASS) {
duke@1 894 buf = buf.prepend((String) lit.value);
duke@1 895 tree = op.lhs;
duke@1 896 continue;
duke@1 897 }
duke@1 898 }
duke@1 899 }
duke@1 900 return null;
duke@1 901 }
duke@1 902 }
duke@1 903
duke@1 904 /** optimization: To save allocating a new operand/operator stack
duke@1 905 * for every binary operation, we use supplys.
duke@1 906 */
jlahoda@1444 907 ArrayList<JCExpression[]> odStackSupply = new ArrayList<JCExpression[]>();
jlahoda@1444 908 ArrayList<Token[]> opStackSupply = new ArrayList<Token[]>();
duke@1 909
duke@1 910 private JCExpression[] newOdStack() {
jlahoda@1444 911 if (odStackSupply.isEmpty())
jlahoda@1444 912 return new JCExpression[infixPrecedenceLevels + 1];
jlahoda@1444 913 return odStackSupply.remove(odStackSupply.size() - 1);
duke@1 914 }
duke@1 915
duke@1 916 private Token[] newOpStack() {
jlahoda@1444 917 if (opStackSupply.isEmpty())
jlahoda@1444 918 return new Token[infixPrecedenceLevels + 1];
jlahoda@1444 919 return opStackSupply.remove(opStackSupply.size() - 1);
duke@1 920 }
duke@1 921
jjg@1326 922 /**
jjg@1326 923 * Expression3 = PrefixOp Expression3
duke@1 924 * | "(" Expr | TypeNoParams ")" Expression3
duke@1 925 * | Primary {Selector} {PostfixOp}
jjg@1326 926 *
jjg@1326 927 * {@literal
duke@1 928 * Primary = "(" Expression ")"
duke@1 929 * | Literal
duke@1 930 * | [TypeArguments] THIS [Arguments]
duke@1 931 * | [TypeArguments] SUPER SuperSuffix
duke@1 932 * | NEW [TypeArguments] Creator
mcimadamore@1144 933 * | "(" Arguments ")" "->" ( Expression | Block )
mcimadamore@1144 934 * | Ident "->" ( Expression | Block )
jjg@722 935 * | Ident { "." Ident }
mcimadamore@1145 936 * | Expression3 MemberReferenceSuffix
jjg@722 937 * [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
duke@1 938 * | Arguments
duke@1 939 * | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
duke@1 940 * ]
duke@1 941 * | BasicType BracketsOpt "." CLASS
jjg@1326 942 * }
jjg@1326 943 *
duke@1 944 * PrefixOp = "++" | "--" | "!" | "~" | "+" | "-"
duke@1 945 * PostfixOp = "++" | "--"
duke@1 946 * Type3 = Ident { "." Ident } [TypeArguments] {TypeSelector} BracketsOpt
duke@1 947 * | BasicType
duke@1 948 * TypeNoParams3 = Ident { "." Ident } BracketsOpt
duke@1 949 * Selector = "." [TypeArguments] Ident [Arguments]
duke@1 950 * | "." THIS
duke@1 951 * | "." [TypeArguments] SUPER SuperSuffix
duke@1 952 * | "." NEW [TypeArguments] InnerCreator
duke@1 953 * | "[" Expression "]"
duke@1 954 * TypeSelector = "." Ident [TypeArguments]
duke@1 955 * SuperSuffix = Arguments | "." Ident [Arguments]
duke@1 956 */
duke@1 957 protected JCExpression term3() {
mcimadamore@1113 958 int pos = token.pos;
duke@1 959 JCExpression t;
duke@1 960 List<JCExpression> typeArgs = typeArgumentsOpt(EXPR);
mcimadamore@1113 961 switch (token.kind) {
duke@1 962 case QUES:
duke@1 963 if ((mode & TYPE) != 0 && (mode & (TYPEARG|NOPARAMS)) == TYPEARG) {
duke@1 964 mode = TYPE;
duke@1 965 return typeArgument();
duke@1 966 } else
duke@1 967 return illegal();
duke@1 968 case PLUSPLUS: case SUBSUB: case BANG: case TILDE: case PLUS: case SUB:
duke@1 969 if (typeArgs == null && (mode & EXPR) != 0) {
mcimadamore@1113 970 TokenKind tk = token.kind;
mcimadamore@1113 971 nextToken();
duke@1 972 mode = EXPR;
mcimadamore@1113 973 if (tk == SUB &&
mcimadamore@1113 974 (token.kind == INTLITERAL || token.kind == LONGLITERAL) &&
mcimadamore@1113 975 token.radix() == 10) {
duke@1 976 mode = EXPR;
ksrini@1074 977 t = literal(names.hyphen, pos);
duke@1 978 } else {
mcimadamore@1165 979 t = term3();
mcimadamore@1113 980 return F.at(pos).Unary(unoptag(tk), t);
duke@1 981 }
duke@1 982 } else return illegal();
duke@1 983 break;
duke@1 984 case LPAREN:
duke@1 985 if (typeArgs == null && (mode & EXPR) != 0) {
mcimadamore@1436 986 ParensResult pres = analyzeParens();
mcimadamore@1436 987 switch (pres) {
mcimadamore@1436 988 case CAST:
mcimadamore@1436 989 accept(LPAREN);
mcimadamore@1436 990 mode = TYPE;
mcimadamore@1436 991 int pos1 = pos;
mcimadamore@1436 992 List<JCExpression> targets = List.of(t = term3());
mcimadamore@1436 993 while (token.kind == AMP) {
mcimadamore@1436 994 checkIntersectionTypesInCast();
mcimadamore@1436 995 accept(AMP);
mcimadamore@1436 996 targets = targets.prepend(term3());
mcimadamore@1436 997 }
mcimadamore@1436 998 if (targets.length() > 1) {
mcimadamore@1436 999 t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
mcimadamore@1436 1000 }
mcimadamore@1436 1001 accept(RPAREN);
mcimadamore@1436 1002 mode = EXPR;
mcimadamore@1436 1003 JCExpression t1 = term3();
mcimadamore@1436 1004 return F.at(pos).TypeCast(t, t1);
mcimadamore@1436 1005 case IMPLICIT_LAMBDA:
mcimadamore@1436 1006 case EXPLICIT_LAMBDA:
mcimadamore@1436 1007 t = lambdaExpressionOrStatement(true, pres == ParensResult.EXPLICIT_LAMBDA, pos);
mcimadamore@1436 1008 break;
mcimadamore@1436 1009 default: //PARENS
mcimadamore@1436 1010 accept(LPAREN);
mcimadamore@1144 1011 mode = EXPR;
mcimadamore@1436 1012 t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec)));
mcimadamore@1436 1013 accept(RPAREN);
mcimadamore@1436 1014 t = toP(F.at(pos).Parens(t));
mcimadamore@1144 1015 break;
duke@1 1016 }
mcimadamore@1144 1017 } else {
mcimadamore@1144 1018 return illegal();
mcimadamore@1144 1019 }
duke@1 1020 break;
duke@1 1021 case THIS:
duke@1 1022 if ((mode & EXPR) != 0) {
duke@1 1023 mode = EXPR;
duke@1 1024 t = to(F.at(pos).Ident(names._this));
mcimadamore@1113 1025 nextToken();
duke@1 1026 if (typeArgs == null)
duke@1 1027 t = argumentsOpt(null, t);
duke@1 1028 else
duke@1 1029 t = arguments(typeArgs, t);
duke@1 1030 typeArgs = null;
duke@1 1031 } else return illegal();
duke@1 1032 break;
duke@1 1033 case SUPER:
duke@1 1034 if ((mode & EXPR) != 0) {
duke@1 1035 mode = EXPR;
jjg@482 1036 t = to(F.at(pos).Ident(names._super));
jjg@482 1037 t = superSuffix(typeArgs, t);
duke@1 1038 typeArgs = null;
duke@1 1039 } else return illegal();
duke@1 1040 break;
duke@1 1041 case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL:
duke@1 1042 case CHARLITERAL: case STRINGLITERAL:
duke@1 1043 case TRUE: case FALSE: case NULL:
duke@1 1044 if (typeArgs == null && (mode & EXPR) != 0) {
duke@1 1045 mode = EXPR;
duke@1 1046 t = literal(names.empty);
duke@1 1047 } else return illegal();
duke@1 1048 break;
duke@1 1049 case NEW:
duke@1 1050 if (typeArgs != null) return illegal();
duke@1 1051 if ((mode & EXPR) != 0) {
duke@1 1052 mode = EXPR;
mcimadamore@1113 1053 nextToken();
mcimadamore@1113 1054 if (token.kind == LT) typeArgs = typeArguments(false);
duke@1 1055 t = creator(pos, typeArgs);
duke@1 1056 typeArgs = null;
duke@1 1057 } else return illegal();
duke@1 1058 break;
duke@1 1059 case IDENTIFIER: case ASSERT: case ENUM:
duke@1 1060 if (typeArgs != null) return illegal();
mcimadamore@1144 1061 if ((mode & EXPR) != 0 && peekToken(ARROW)) {
mcimadamore@1144 1062 t = lambdaExpressionOrStatement(false, false, pos);
mcimadamore@1144 1063 } else {
mcimadamore@1144 1064 t = toP(F.at(token.pos).Ident(ident()));
mcimadamore@1144 1065 loop: while (true) {
mcimadamore@1144 1066 pos = token.pos;
mcimadamore@1144 1067 switch (token.kind) {
mcimadamore@1144 1068 case LBRACKET:
mcimadamore@1113 1069 nextToken();
mcimadamore@1144 1070 if (token.kind == RBRACKET) {
mcimadamore@1144 1071 nextToken();
mcimadamore@1144 1072 t = bracketsOpt(t);
mcimadamore@1144 1073 t = toP(F.at(pos).TypeArray(t));
mcimadamore@1144 1074 t = bracketsSuffix(t);
mcimadamore@1144 1075 } else {
mcimadamore@1144 1076 if ((mode & EXPR) != 0) {
mcimadamore@1144 1077 mode = EXPR;
mcimadamore@1144 1078 JCExpression t1 = term();
mcimadamore@1144 1079 t = to(F.at(pos).Indexed(t, t1));
mcimadamore@1144 1080 }
mcimadamore@1144 1081 accept(RBRACKET);
mcimadamore@1144 1082 }
mcimadamore@1144 1083 break loop;
mcimadamore@1144 1084 case LPAREN:
duke@1 1085 if ((mode & EXPR) != 0) {
duke@1 1086 mode = EXPR;
mcimadamore@1144 1087 t = arguments(typeArgs, t);
mcimadamore@1144 1088 typeArgs = null;
duke@1 1089 }
mcimadamore@1144 1090 break loop;
mcimadamore@1144 1091 case DOT:
mcimadamore@1144 1092 nextToken();
mcimadamore@1144 1093 int oldmode = mode;
mcimadamore@1144 1094 mode &= ~NOPARAMS;
mcimadamore@1144 1095 typeArgs = typeArgumentsOpt(EXPR);
mcimadamore@1144 1096 mode = oldmode;
mcimadamore@1144 1097 if ((mode & EXPR) != 0) {
mcimadamore@1144 1098 switch (token.kind) {
mcimadamore@1144 1099 case CLASS:
mcimadamore@1144 1100 if (typeArgs != null) return illegal();
mcimadamore@1144 1101 mode = EXPR;
mcimadamore@1144 1102 t = to(F.at(pos).Select(t, names._class));
mcimadamore@1144 1103 nextToken();
mcimadamore@1144 1104 break loop;
mcimadamore@1144 1105 case THIS:
mcimadamore@1144 1106 if (typeArgs != null) return illegal();
mcimadamore@1144 1107 mode = EXPR;
mcimadamore@1144 1108 t = to(F.at(pos).Select(t, names._this));
mcimadamore@1144 1109 nextToken();
mcimadamore@1144 1110 break loop;
mcimadamore@1144 1111 case SUPER:
mcimadamore@1144 1112 mode = EXPR;
mcimadamore@1144 1113 t = to(F.at(pos).Select(t, names._super));
mcimadamore@1144 1114 t = superSuffix(typeArgs, t);
mcimadamore@1144 1115 typeArgs = null;
mcimadamore@1144 1116 break loop;
mcimadamore@1144 1117 case NEW:
mcimadamore@1144 1118 if (typeArgs != null) return illegal();
mcimadamore@1144 1119 mode = EXPR;
mcimadamore@1144 1120 int pos1 = token.pos;
mcimadamore@1144 1121 nextToken();
mcimadamore@1144 1122 if (token.kind == LT) typeArgs = typeArguments(false);
mcimadamore@1144 1123 t = innerCreator(pos1, typeArgs, t);
mcimadamore@1144 1124 typeArgs = null;
mcimadamore@1144 1125 break loop;
mcimadamore@1144 1126 }
mcimadamore@1144 1127 }
mcimadamore@1144 1128 // typeArgs saved for next loop iteration.
mcimadamore@1144 1129 t = toP(F.at(pos).Select(t, ident()));
mcimadamore@1144 1130 break;
mcimadamore@1165 1131 case LT:
mcimadamore@1165 1132 if ((mode & TYPE) == 0 && isUnboundMemberRef()) {
mcimadamore@1165 1133 //this is an unbound method reference whose qualifier
mcimadamore@1352 1134 //is a generic type i.e. A<S>::m
mcimadamore@1165 1135 int pos1 = token.pos;
mcimadamore@1165 1136 accept(LT);
mcimadamore@1165 1137 ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
mcimadamore@1165 1138 args.append(typeArgument());
mcimadamore@1165 1139 while (token.kind == COMMA) {
mcimadamore@1165 1140 nextToken();
mcimadamore@1165 1141 args.append(typeArgument());
mcimadamore@1165 1142 }
mcimadamore@1165 1143 accept(GT);
mcimadamore@1165 1144 t = toP(F.at(pos1).TypeApply(t, args.toList()));
mcimadamore@1165 1145 checkGenerics();
mcimadamore@1165 1146 while (token.kind == DOT) {
mcimadamore@1165 1147 nextToken();
mcimadamore@1165 1148 mode = TYPE;
mcimadamore@1165 1149 t = toP(F.at(token.pos).Select(t, ident()));
mcimadamore@1165 1150 t = typeArgumentsOpt(t);
mcimadamore@1165 1151 }
mcimadamore@1352 1152 t = bracketsOpt(t);
mcimadamore@1352 1153 if (token.kind != COLCOL) {
mcimadamore@1165 1154 //method reference expected here
mcimadamore@1165 1155 t = illegal();
mcimadamore@1165 1156 }
mcimadamore@1165 1157 mode = EXPR;
mcimadamore@1165 1158 return term3Rest(t, typeArgs);
mcimadamore@1165 1159 }
mcimadamore@1165 1160 break loop;
mcimadamore@1144 1161 default:
mcimadamore@1144 1162 break loop;
duke@1 1163 }
duke@1 1164 }
duke@1 1165 }
duke@1 1166 if (typeArgs != null) illegal();
duke@1 1167 t = typeArgumentsOpt(t);
duke@1 1168 break;
duke@1 1169 case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
duke@1 1170 case DOUBLE: case BOOLEAN:
duke@1 1171 if (typeArgs != null) illegal();
duke@1 1172 t = bracketsSuffix(bracketsOpt(basicType()));
duke@1 1173 break;
duke@1 1174 case VOID:
duke@1 1175 if (typeArgs != null) illegal();
duke@1 1176 if ((mode & EXPR) != 0) {
mcimadamore@1113 1177 nextToken();
mcimadamore@1113 1178 if (token.kind == DOT) {
jjg@1374 1179 JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTag.VOID));
duke@1 1180 t = bracketsSuffix(ti);
duke@1 1181 } else {
duke@1 1182 return illegal(pos);
duke@1 1183 }
duke@1 1184 } else {
jrose@267 1185 // Support the corner case of myMethodHandle.<void>invoke() by passing
jrose@267 1186 // a void type (like other primitive types) to the next phase.
jrose@267 1187 // The error will be reported in Attr.attribTypes or Attr.visitApply.
jjg@1374 1188 JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTag.VOID));
mcimadamore@1113 1189 nextToken();
jrose@267 1190 return ti;
jrose@267 1191 //return illegal();
duke@1 1192 }
duke@1 1193 break;
duke@1 1194 default:
duke@1 1195 return illegal();
duke@1 1196 }
mcimadamore@1144 1197 return term3Rest(t, typeArgs);
mcimadamore@1144 1198 }
mcimadamore@1144 1199
mcimadamore@1144 1200 JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
duke@1 1201 if (typeArgs != null) illegal();
duke@1 1202 while (true) {
mcimadamore@1113 1203 int pos1 = token.pos;
mcimadamore@1113 1204 if (token.kind == LBRACKET) {
mcimadamore@1113 1205 nextToken();
duke@1 1206 if ((mode & TYPE) != 0) {
duke@1 1207 int oldmode = mode;
duke@1 1208 mode = TYPE;
mcimadamore@1113 1209 if (token.kind == RBRACKET) {
mcimadamore@1113 1210 nextToken();
jjg@722 1211 t = bracketsOpt(t);
duke@1 1212 t = toP(F.at(pos1).TypeArray(t));
mcimadamore@1352 1213 if (token.kind == COLCOL) {
mcimadamore@1352 1214 mode = EXPR;
mcimadamore@1352 1215 continue;
mcimadamore@1352 1216 }
duke@1 1217 return t;
duke@1 1218 }
duke@1 1219 mode = oldmode;
duke@1 1220 }
duke@1 1221 if ((mode & EXPR) != 0) {
duke@1 1222 mode = EXPR;
duke@1 1223 JCExpression t1 = term();
duke@1 1224 t = to(F.at(pos1).Indexed(t, t1));
duke@1 1225 }
duke@1 1226 accept(RBRACKET);
mcimadamore@1113 1227 } else if (token.kind == DOT) {
mcimadamore@1113 1228 nextToken();
duke@1 1229 typeArgs = typeArgumentsOpt(EXPR);
mcimadamore@1113 1230 if (token.kind == SUPER && (mode & EXPR) != 0) {
duke@1 1231 mode = EXPR;
duke@1 1232 t = to(F.at(pos1).Select(t, names._super));
mcimadamore@1113 1233 nextToken();
duke@1 1234 t = arguments(typeArgs, t);
duke@1 1235 typeArgs = null;
mcimadamore@1113 1236 } else if (token.kind == NEW && (mode & EXPR) != 0) {
duke@1 1237 if (typeArgs != null) return illegal();
duke@1 1238 mode = EXPR;
mcimadamore@1113 1239 int pos2 = token.pos;
mcimadamore@1113 1240 nextToken();
mcimadamore@1113 1241 if (token.kind == LT) typeArgs = typeArguments(false);
duke@1 1242 t = innerCreator(pos2, typeArgs, t);
duke@1 1243 typeArgs = null;
duke@1 1244 } else {
duke@1 1245 t = toP(F.at(pos1).Select(t, ident()));
duke@1 1246 t = argumentsOpt(typeArgs, typeArgumentsOpt(t));
duke@1 1247 typeArgs = null;
duke@1 1248 }
mcimadamore@1352 1249 } else if ((mode & EXPR) != 0 && token.kind == COLCOL) {
mcimadamore@1145 1250 mode = EXPR;
mcimadamore@1145 1251 if (typeArgs != null) return illegal();
mcimadamore@1352 1252 accept(COLCOL);
mcimadamore@1145 1253 t = memberReferenceSuffix(pos1, t);
duke@1 1254 } else {
duke@1 1255 break;
duke@1 1256 }
duke@1 1257 }
mcimadamore@1113 1258 while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && (mode & EXPR) != 0) {
duke@1 1259 mode = EXPR;
mcimadamore@1113 1260 t = to(F.at(token.pos).Unary(
jjg@1127 1261 token.kind == PLUSPLUS ? POSTINC : POSTDEC, t));
mcimadamore@1113 1262 nextToken();
duke@1 1263 }
duke@1 1264 return toP(t);
duke@1 1265 }
duke@1 1266
mcimadamore@1165 1267 /**
mcimadamore@1165 1268 * If we see an identifier followed by a '&lt;' it could be an unbound
mcimadamore@1165 1269 * method reference or a binary expression. To disambiguate, look for a
mcimadamore@1165 1270 * matching '&gt;' and see if the subsequent terminal is either '.' or '#'.
mcimadamore@1165 1271 */
mcimadamore@1165 1272 @SuppressWarnings("fallthrough")
mcimadamore@1165 1273 boolean isUnboundMemberRef() {
mcimadamore@1165 1274 int pos = 0, depth = 0;
mcimadamore@1165 1275 for (Token t = S.token(pos) ; ; t = S.token(++pos)) {
mcimadamore@1165 1276 switch (t.kind) {
mcimadamore@1165 1277 case IDENTIFIER: case QUES: case EXTENDS: case SUPER:
mcimadamore@1165 1278 case DOT: case RBRACKET: case LBRACKET: case COMMA:
mcimadamore@1165 1279 case BYTE: case SHORT: case INT: case LONG: case FLOAT:
mcimadamore@1165 1280 case DOUBLE: case BOOLEAN: case CHAR:
mcimadamore@1165 1281 break;
mcimadamore@1165 1282 case LT:
mcimadamore@1165 1283 depth++; break;
mcimadamore@1165 1284 case GTGTGT:
mcimadamore@1165 1285 depth--;
mcimadamore@1165 1286 case GTGT:
mcimadamore@1165 1287 depth--;
mcimadamore@1165 1288 case GT:
mcimadamore@1165 1289 depth--;
mcimadamore@1165 1290 if (depth == 0) {
mcimadamore@1352 1291 TokenKind nextKind = S.token(pos + 1).kind;
mcimadamore@1165 1292 return
mcimadamore@1352 1293 nextKind == TokenKind.DOT ||
mcimadamore@1352 1294 nextKind == TokenKind.LBRACKET ||
mcimadamore@1352 1295 nextKind == TokenKind.COLCOL;
mcimadamore@1165 1296 }
mcimadamore@1165 1297 break;
mcimadamore@1165 1298 default:
mcimadamore@1165 1299 return false;
mcimadamore@1165 1300 }
mcimadamore@1165 1301 }
mcimadamore@1165 1302 }
mcimadamore@1165 1303
mcimadamore@1436 1304 /**
mcimadamore@1436 1305 * If we see an identifier followed by a '&lt;' it could be an unbound
mcimadamore@1436 1306 * method reference or a binary expression. To disambiguate, look for a
mcimadamore@1436 1307 * matching '&gt;' and see if the subsequent terminal is either '.' or '#'.
mcimadamore@1436 1308 */
mcimadamore@1436 1309 @SuppressWarnings("fallthrough")
mcimadamore@1436 1310 ParensResult analyzeParens() {
mcimadamore@1436 1311 int depth = 0;
mcimadamore@1436 1312 boolean type = false;
mcimadamore@1436 1313 for (int lookahead = 0 ; ; lookahead++) {
mcimadamore@1436 1314 TokenKind tk = S.token(lookahead).kind;
mcimadamore@1436 1315 switch (tk) {
mcimadamore@1436 1316 case EXTENDS: case SUPER: case COMMA:
mcimadamore@1436 1317 type = true;
mcimadamore@1436 1318 case QUES: case DOT: case AMP:
mcimadamore@1436 1319 //skip
mcimadamore@1436 1320 break;
mcimadamore@1436 1321 case BYTE: case SHORT: case INT: case LONG: case FLOAT:
mcimadamore@1436 1322 case DOUBLE: case BOOLEAN: case CHAR:
mcimadamore@1436 1323 if (peekToken(lookahead, RPAREN)) {
mcimadamore@1436 1324 //Type, ')' -> cast
mcimadamore@1436 1325 return ParensResult.CAST;
mcimadamore@1436 1326 } else if (peekToken(lookahead, IDENTIFIER)) {
mcimadamore@1436 1327 //Type, 'Identifier -> explicit lambda
mcimadamore@1436 1328 return ParensResult.EXPLICIT_LAMBDA;
mcimadamore@1436 1329 }
mcimadamore@1436 1330 break;
mcimadamore@1436 1331 case LPAREN:
mcimadamore@1436 1332 if (lookahead != 0) {
mcimadamore@1436 1333 // '(' in a non-starting position -> parens
mcimadamore@1436 1334 return ParensResult.PARENS;
mcimadamore@1436 1335 } else if (peekToken(lookahead, RPAREN)) {
mcimadamore@1436 1336 // '(', ')' -> explicit lambda
mcimadamore@1436 1337 return ParensResult.EXPLICIT_LAMBDA;
mcimadamore@1436 1338 }
mcimadamore@1436 1339 break;
mcimadamore@1436 1340 case RPAREN:
mcimadamore@1436 1341 // if we have seen something that looks like a type,
mcimadamore@1436 1342 // then it's a cast expression
mcimadamore@1436 1343 if (type) return ParensResult.CAST;
mcimadamore@1436 1344 // otherwise, disambiguate cast vs. parenthesized expression
mcimadamore@1436 1345 // based on subsequent token.
mcimadamore@1436 1346 switch (S.token(lookahead + 1).kind) {
mcimadamore@1436 1347 /*case PLUSPLUS: case SUBSUB: */
mcimadamore@1436 1348 case BANG: case TILDE:
mcimadamore@1436 1349 case LPAREN: case THIS: case SUPER:
mcimadamore@1436 1350 case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
mcimadamore@1436 1351 case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
mcimadamore@1436 1352 case TRUE: case FALSE: case NULL:
mcimadamore@1436 1353 case NEW: case IDENTIFIER: case ASSERT: case ENUM:
mcimadamore@1436 1354 case BYTE: case SHORT: case CHAR: case INT:
mcimadamore@1436 1355 case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
mcimadamore@1436 1356 return ParensResult.CAST;
mcimadamore@1436 1357 default:
mcimadamore@1436 1358 return ParensResult.PARENS;
mcimadamore@1436 1359 }
mcimadamore@1436 1360 case IDENTIFIER:
mcimadamore@1436 1361 if (peekToken(lookahead, IDENTIFIER)) {
mcimadamore@1436 1362 // Identifier, Identifier -> explicit lambda
mcimadamore@1436 1363 return ParensResult.EXPLICIT_LAMBDA;
mcimadamore@1436 1364 } else if (peekToken(lookahead, RPAREN, ARROW)) {
mcimadamore@1436 1365 // Identifier, ')' '->' -> implicit lambda
mcimadamore@1436 1366 return ParensResult.IMPLICIT_LAMBDA;
mcimadamore@1436 1367 }
mcimadamore@1436 1368 break;
mcimadamore@1436 1369 case FINAL:
mcimadamore@1436 1370 case ELLIPSIS:
mcimadamore@1436 1371 case MONKEYS_AT:
mcimadamore@1436 1372 //those can only appear in explicit lambdas
mcimadamore@1436 1373 return ParensResult.EXPLICIT_LAMBDA;
mcimadamore@1436 1374 case LBRACKET:
mcimadamore@1436 1375 if (peekToken(lookahead, RBRACKET, IDENTIFIER)) {
mcimadamore@1436 1376 // '[', ']', Identifier -> explicit lambda
mcimadamore@1436 1377 return ParensResult.EXPLICIT_LAMBDA;
mcimadamore@1436 1378 } else if (peekToken(lookahead, RBRACKET, RPAREN) ||
mcimadamore@1436 1379 peekToken(lookahead, RBRACKET, AMP)) {
mcimadamore@1436 1380 // '[', ']', ')' -> cast
mcimadamore@1436 1381 // '[', ']', '&' -> cast (intersection type)
mcimadamore@1436 1382 return ParensResult.CAST;
mcimadamore@1436 1383 } else if (peekToken(lookahead, RBRACKET)) {
mcimadamore@1436 1384 //consume the ']' and skip
mcimadamore@1436 1385 type = true;
mcimadamore@1436 1386 lookahead++;
mcimadamore@1436 1387 break;
mcimadamore@1436 1388 } else {
mcimadamore@1436 1389 return ParensResult.PARENS;
mcimadamore@1436 1390 }
mcimadamore@1436 1391 case LT:
mcimadamore@1436 1392 depth++; break;
mcimadamore@1436 1393 case GTGTGT:
mcimadamore@1436 1394 depth--;
mcimadamore@1436 1395 case GTGT:
mcimadamore@1436 1396 depth--;
mcimadamore@1436 1397 case GT:
mcimadamore@1436 1398 depth--;
mcimadamore@1436 1399 if (depth == 0) {
mcimadamore@1436 1400 if (peekToken(lookahead, RPAREN) ||
mcimadamore@1436 1401 peekToken(lookahead, AMP)) {
mcimadamore@1436 1402 // '>', ')' -> cast
mcimadamore@1436 1403 // '>', '&' -> cast
mcimadamore@1436 1404 return ParensResult.CAST;
mcimadamore@1436 1405 } else if (peekToken(lookahead, IDENTIFIER, COMMA) ||
mcimadamore@1436 1406 peekToken(lookahead, IDENTIFIER, RPAREN, ARROW) ||
mcimadamore@1436 1407 peekToken(lookahead, ELLIPSIS)) {
mcimadamore@1436 1408 // '>', Identifier, ',' -> explicit lambda
mcimadamore@1436 1409 // '>', Identifier, ')', '->' -> explicit lambda
mcimadamore@1436 1410 // '>', '...' -> explicit lambda
mcimadamore@1436 1411 return ParensResult.EXPLICIT_LAMBDA;
mcimadamore@1436 1412 }
mcimadamore@1436 1413 //it looks a type, but could still be (i) a cast to generic type,
mcimadamore@1436 1414 //(ii) an unbound method reference or (iii) an explicit lambda
mcimadamore@1436 1415 type = true;
mcimadamore@1436 1416 break;
mcimadamore@1436 1417 } else if (depth < 0) {
mcimadamore@1436 1418 //unbalanced '<', '>' - not a generic type
mcimadamore@1436 1419 return ParensResult.PARENS;
mcimadamore@1436 1420 }
mcimadamore@1436 1421 break;
mcimadamore@1436 1422 default:
mcimadamore@1436 1423 //this includes EOF
mcimadamore@1436 1424 return ParensResult.PARENS;
mcimadamore@1436 1425 }
mcimadamore@1436 1426 }
mcimadamore@1436 1427 }
mcimadamore@1436 1428
mcimadamore@1436 1429 enum ParensResult {
mcimadamore@1436 1430 CAST,
mcimadamore@1436 1431 EXPLICIT_LAMBDA,
mcimadamore@1436 1432 IMPLICIT_LAMBDA,
mcimadamore@1436 1433 PARENS;
mcimadamore@1436 1434 }
mcimadamore@1436 1435
mcimadamore@1144 1436 JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
mcimadamore@1144 1437 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
mcimadamore@1144 1438 params.append(firstParam);
mcimadamore@1144 1439 JCVariableDecl lastParam = firstParam;
mcimadamore@1144 1440 while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
mcimadamore@1144 1441 nextToken();
mcimadamore@1144 1442 params.append(lastParam = formalParameter());
mcimadamore@1144 1443 }
mcimadamore@1144 1444 accept(RPAREN);
mcimadamore@1144 1445 return lambdaExpressionOrStatementRest(params.toList(), pos);
mcimadamore@1144 1446 }
mcimadamore@1144 1447
mcimadamore@1144 1448 JCExpression lambdaExpressionOrStatement(boolean hasParens, boolean explicitParams, int pos) {
mcimadamore@1144 1449 List<JCVariableDecl> params = explicitParams ?
mcimadamore@1144 1450 formalParameters() :
mcimadamore@1144 1451 implicitParameters(hasParens);
mcimadamore@1144 1452
mcimadamore@1144 1453 return lambdaExpressionOrStatementRest(params, pos);
mcimadamore@1144 1454 }
mcimadamore@1144 1455
mcimadamore@1144 1456 JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
mcimadamore@1144 1457 checkLambda();
mcimadamore@1144 1458 accept(ARROW);
mcimadamore@1144 1459
mcimadamore@1144 1460 return token.kind == LBRACE ?
mcimadamore@1144 1461 lambdaStatement(args, pos, pos) :
mcimadamore@1144 1462 lambdaExpression(args, pos);
mcimadamore@1144 1463 }
mcimadamore@1144 1464
mcimadamore@1144 1465 JCExpression lambdaStatement(List<JCVariableDecl> args, int pos, int pos2) {
mcimadamore@1144 1466 JCBlock block = block(pos2, 0);
mcimadamore@1144 1467 return toP(F.at(pos).Lambda(args, block));
mcimadamore@1144 1468 }
mcimadamore@1144 1469
mcimadamore@1144 1470 JCExpression lambdaExpression(List<JCVariableDecl> args, int pos) {
mcimadamore@1144 1471 JCTree expr = parseExpression();
mcimadamore@1144 1472 return toP(F.at(pos).Lambda(args, expr));
mcimadamore@1144 1473 }
mcimadamore@1144 1474
duke@1 1475 /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments]
duke@1 1476 */
duke@1 1477 JCExpression superSuffix(List<JCExpression> typeArgs, JCExpression t) {
mcimadamore@1113 1478 nextToken();
mcimadamore@1113 1479 if (token.kind == LPAREN || typeArgs != null) {
duke@1 1480 t = arguments(typeArgs, t);
mcimadamore@1352 1481 } else if (token.kind == COLCOL) {
mcimadamore@1145 1482 if (typeArgs != null) return illegal();
mcimadamore@1145 1483 t = memberReferenceSuffix(t);
duke@1 1484 } else {
mcimadamore@1113 1485 int pos = token.pos;
duke@1 1486 accept(DOT);
mcimadamore@1113 1487 typeArgs = (token.kind == LT) ? typeArguments(false) : null;
duke@1 1488 t = toP(F.at(pos).Select(t, ident()));
duke@1 1489 t = argumentsOpt(typeArgs, t);
duke@1 1490 }
duke@1 1491 return t;
duke@1 1492 }
duke@1 1493
duke@1 1494 /** BasicType = BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE | BOOLEAN
duke@1 1495 */
duke@1 1496 JCPrimitiveTypeTree basicType() {
mcimadamore@1113 1497 JCPrimitiveTypeTree t = to(F.at(token.pos).TypeIdent(typetag(token.kind)));
mcimadamore@1113 1498 nextToken();
duke@1 1499 return t;
duke@1 1500 }
duke@1 1501
duke@1 1502 /** ArgumentsOpt = [ Arguments ]
duke@1 1503 */
duke@1 1504 JCExpression argumentsOpt(List<JCExpression> typeArgs, JCExpression t) {
mcimadamore@1113 1505 if ((mode & EXPR) != 0 && token.kind == LPAREN || typeArgs != null) {
duke@1 1506 mode = EXPR;
duke@1 1507 return arguments(typeArgs, t);
duke@1 1508 } else {
duke@1 1509 return t;
duke@1 1510 }
duke@1 1511 }
duke@1 1512
duke@1 1513 /** Arguments = "(" [Expression { COMMA Expression }] ")"
duke@1 1514 */
duke@1 1515 List<JCExpression> arguments() {
duke@1 1516 ListBuffer<JCExpression> args = lb();
mcimadamore@1113 1517 if (token.kind == LPAREN) {
mcimadamore@1113 1518 nextToken();
mcimadamore@1113 1519 if (token.kind != RPAREN) {
jjg@111 1520 args.append(parseExpression());
mcimadamore@1113 1521 while (token.kind == COMMA) {
mcimadamore@1113 1522 nextToken();
jjg@111 1523 args.append(parseExpression());
duke@1 1524 }
duke@1 1525 }
duke@1 1526 accept(RPAREN);
duke@1 1527 } else {
mcimadamore@1113 1528 syntaxError(token.pos, "expected", LPAREN);
duke@1 1529 }
duke@1 1530 return args.toList();
duke@1 1531 }
duke@1 1532
duke@1 1533 JCMethodInvocation arguments(List<JCExpression> typeArgs, JCExpression t) {
mcimadamore@1113 1534 int pos = token.pos;
duke@1 1535 List<JCExpression> args = arguments();
duke@1 1536 return toP(F.at(pos).Apply(typeArgs, t, args));
duke@1 1537 }
duke@1 1538
duke@1 1539 /** TypeArgumentsOpt = [ TypeArguments ]
duke@1 1540 */
duke@1 1541 JCExpression typeArgumentsOpt(JCExpression t) {
mcimadamore@1113 1542 if (token.kind == LT &&
duke@1 1543 (mode & TYPE) != 0 &&
duke@1 1544 (mode & NOPARAMS) == 0) {
duke@1 1545 mode = TYPE;
duke@1 1546 checkGenerics();
mcimadamore@948 1547 return typeArguments(t, false);
duke@1 1548 } else {
duke@1 1549 return t;
duke@1 1550 }
duke@1 1551 }
duke@1 1552 List<JCExpression> typeArgumentsOpt() {
duke@1 1553 return typeArgumentsOpt(TYPE);
duke@1 1554 }
duke@1 1555
duke@1 1556 List<JCExpression> typeArgumentsOpt(int useMode) {
mcimadamore@1113 1557 if (token.kind == LT) {
duke@1 1558 checkGenerics();
duke@1 1559 if ((mode & useMode) == 0 ||
duke@1 1560 (mode & NOPARAMS) != 0) {
duke@1 1561 illegal();
duke@1 1562 }
duke@1 1563 mode = useMode;
mcimadamore@948 1564 return typeArguments(false);
duke@1 1565 }
duke@1 1566 return null;
duke@1 1567 }
duke@1 1568
jjg@1326 1569 /**
jjg@1326 1570 * {@literal
jjg@1326 1571 * TypeArguments = "<" TypeArgument {"," TypeArgument} ">"
jjg@1326 1572 * }
duke@1 1573 */
mcimadamore@948 1574 List<JCExpression> typeArguments(boolean diamondAllowed) {
mcimadamore@1113 1575 if (token.kind == LT) {
mcimadamore@1113 1576 nextToken();
mcimadamore@1113 1577 if (token.kind == GT && diamondAllowed) {
mcimadamore@537 1578 checkDiamond();
mcimadamore@948 1579 mode |= DIAMOND;
mcimadamore@1113 1580 nextToken();
mcimadamore@537 1581 return List.nil();
mcimadamore@948 1582 } else {
mcimadamore@948 1583 ListBuffer<JCExpression> args = ListBuffer.lb();
jjg@111 1584 args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
mcimadamore@1113 1585 while (token.kind == COMMA) {
mcimadamore@1113 1586 nextToken();
mcimadamore@948 1587 args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
mcimadamore@948 1588 }
mcimadamore@1113 1589 switch (token.kind) {
mcimadamore@1113 1590
mcimadamore@1113 1591 case GTGTGTEQ: case GTGTEQ: case GTEQ:
mcimadamore@1113 1592 case GTGTGT: case GTGT:
mcimadamore@1113 1593 token = S.split();
mcimadamore@948 1594 break;
ksrini@1074 1595 case GT:
mcimadamore@1113 1596 nextToken();
ksrini@1074 1597 break;
mcimadamore@948 1598 default:
mcimadamore@1113 1599 args.append(syntaxError(token.pos, "expected", GT));
mcimadamore@948 1600 break;
mcimadamore@948 1601 }
mcimadamore@948 1602 return args.toList();
duke@1 1603 }
duke@1 1604 } else {
mcimadamore@1113 1605 return List.<JCExpression>of(syntaxError(token.pos, "expected", LT));
duke@1 1606 }
duke@1 1607 }
duke@1 1608
jjg@1326 1609 /**
jjg@1326 1610 * {@literal
jjg@1326 1611 * TypeArgument = Type
jjg@722 1612 * | "?"
jjg@722 1613 * | "?" EXTENDS Type {"&" Type}
jjg@722 1614 * | "?" SUPER Type
jjg@1326 1615 * }
duke@1 1616 */
duke@1 1617 JCExpression typeArgument() {
mcimadamore@1113 1618 if (token.kind != QUES) return parseType();
mcimadamore@1113 1619 int pos = token.pos;
mcimadamore@1113 1620 nextToken();
mcimadamore@1113 1621 if (token.kind == EXTENDS) {
jjg@482 1622 TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.EXTENDS));
mcimadamore@1113 1623 nextToken();
jjg@482 1624 JCExpression bound = parseType();
jjg@722 1625 return F.at(pos).Wildcard(t, bound);
mcimadamore@1113 1626 } else if (token.kind == SUPER) {
jjg@482 1627 TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.SUPER));
mcimadamore@1113 1628 nextToken();
jjg@482 1629 JCExpression bound = parseType();
jjg@722 1630 return F.at(pos).Wildcard(t, bound);
mcimadamore@1113 1631 } else if (token.kind == IDENTIFIER) {
duke@1 1632 //error recovery
duke@1 1633 TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
duke@1 1634 JCExpression wc = toP(F.at(pos).Wildcard(t, null));
mcimadamore@1113 1635 JCIdent id = toP(F.at(token.pos).Ident(ident()));
ksrini@1074 1636 JCErroneous err = F.at(pos).Erroneous(List.<JCTree>of(wc, id));
ksrini@1074 1637 reportSyntaxError(err, "expected3", GT, EXTENDS, SUPER);
ksrini@1074 1638 return err;
duke@1 1639 } else {
jjg@482 1640 TypeBoundKind t = toP(F.at(pos).TypeBoundKind(BoundKind.UNBOUND));
jjg@722 1641 return toP(F.at(pos).Wildcard(t, null));
duke@1 1642 }
duke@1 1643 }
duke@1 1644
mcimadamore@948 1645 JCTypeApply typeArguments(JCExpression t, boolean diamondAllowed) {
mcimadamore@1113 1646 int pos = token.pos;
mcimadamore@948 1647 List<JCExpression> args = typeArguments(diamondAllowed);
duke@1 1648 return toP(F.at(pos).TypeApply(t, args));
duke@1 1649 }
duke@1 1650
jjg@722 1651 /** BracketsOpt = {"[" "]"}
duke@1 1652 */
jjg@722 1653 private JCExpression bracketsOpt(JCExpression t) {
mcimadamore@1113 1654 if (token.kind == LBRACKET) {
mcimadamore@1113 1655 int pos = token.pos;
mcimadamore@1113 1656 nextToken();
jjg@722 1657 t = bracketsOptCont(t, pos);
jjg@722 1658 F.at(pos);
duke@1 1659 }
duke@1 1660 return t;
duke@1 1661 }
duke@1 1662
jjg@722 1663 private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos) {
duke@1 1664 accept(RBRACKET);
jjg@722 1665 t = bracketsOpt(t);
duke@1 1666 return toP(F.at(pos).TypeArray(t));
duke@1 1667 }
duke@1 1668
duke@1 1669 /** BracketsSuffixExpr = "." CLASS
duke@1 1670 * BracketsSuffixType =
duke@1 1671 */
duke@1 1672 JCExpression bracketsSuffix(JCExpression t) {
mcimadamore@1113 1673 if ((mode & EXPR) != 0 && token.kind == DOT) {
duke@1 1674 mode = EXPR;
mcimadamore@1113 1675 int pos = token.pos;
mcimadamore@1113 1676 nextToken();
duke@1 1677 accept(CLASS);
ksrini@1138 1678 if (token.pos == endPosTable.errorEndPos) {
duke@1 1679 // error recovery
duke@1 1680 Name name = null;
mcimadamore@1113 1681 if (token.kind == IDENTIFIER) {
mcimadamore@1113 1682 name = token.name();
mcimadamore@1113 1683 nextToken();
duke@1 1684 } else {
duke@1 1685 name = names.error;
duke@1 1686 }
duke@1 1687 t = F.at(pos).Erroneous(List.<JCTree>of(toP(F.at(pos).Select(t, name))));
duke@1 1688 } else {
duke@1 1689 t = toP(F.at(pos).Select(t, names._class));
duke@1 1690 }
duke@1 1691 } else if ((mode & TYPE) != 0) {
mcimadamore@1352 1692 if (token.kind != COLCOL) {
mcimadamore@1352 1693 mode = TYPE;
mcimadamore@1352 1694 }
mcimadamore@1352 1695 } else if (token.kind != COLCOL) {
mcimadamore@1113 1696 syntaxError(token.pos, "dot.class.expected");
duke@1 1697 }
duke@1 1698 return t;
duke@1 1699 }
duke@1 1700
mcimadamore@1145 1701 /**
mcimadamore@1352 1702 * MemberReferenceSuffix = "::" [TypeArguments] Ident
mcimadamore@1352 1703 * | "::" [TypeArguments] "new"
mcimadamore@1145 1704 */
mcimadamore@1145 1705 JCExpression memberReferenceSuffix(JCExpression t) {
mcimadamore@1145 1706 int pos1 = token.pos;
mcimadamore@1352 1707 accept(COLCOL);
mcimadamore@1145 1708 return memberReferenceSuffix(pos1, t);
mcimadamore@1145 1709 }
mcimadamore@1145 1710
mcimadamore@1145 1711 JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
mcimadamore@1145 1712 checkMethodReferences();
mcimadamore@1145 1713 mode = EXPR;
mcimadamore@1145 1714 List<JCExpression> typeArgs = null;
mcimadamore@1145 1715 if (token.kind == LT) {
mcimadamore@1145 1716 typeArgs = typeArguments(false);
mcimadamore@1145 1717 }
mcimadamore@1145 1718 Name refName = null;
mcimadamore@1145 1719 ReferenceMode refMode = null;
mcimadamore@1145 1720 if (token.kind == NEW) {
mcimadamore@1145 1721 refMode = ReferenceMode.NEW;
mcimadamore@1145 1722 refName = names.init;
mcimadamore@1145 1723 nextToken();
mcimadamore@1145 1724 } else {
mcimadamore@1145 1725 refMode = ReferenceMode.INVOKE;
mcimadamore@1145 1726 refName = ident();
mcimadamore@1145 1727 }
mcimadamore@1145 1728 return toP(F.at(t.getStartPosition()).Reference(refMode, refName, t, typeArgs));
mcimadamore@1145 1729 }
mcimadamore@1145 1730
jjg@722 1731 /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
duke@1 1732 */
duke@1 1733 JCExpression creator(int newpos, List<JCExpression> typeArgs) {
mcimadamore@1113 1734 switch (token.kind) {
duke@1 1735 case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
duke@1 1736 case DOUBLE: case BOOLEAN:
jjg@722 1737 if (typeArgs == null)
jjg@722 1738 return arrayCreatorRest(newpos, basicType());
duke@1 1739 break;
duke@1 1740 default:
duke@1 1741 }
duke@1 1742 JCExpression t = qualident();
duke@1 1743 int oldmode = mode;
mcimadamore@948 1744 mode = TYPE;
mcimadamore@948 1745 boolean diamondFound = false;
mcimadamore@1061 1746 int lastTypeargsPos = -1;
mcimadamore@1113 1747 if (token.kind == LT) {
duke@1 1748 checkGenerics();
mcimadamore@1113 1749 lastTypeargsPos = token.pos;
mcimadamore@948 1750 t = typeArguments(t, true);
mcimadamore@948 1751 diamondFound = (mode & DIAMOND) != 0;
duke@1 1752 }
mcimadamore@1113 1753 while (token.kind == DOT) {
mcimadamore@948 1754 if (diamondFound) {
mcimadamore@948 1755 //cannot select after a diamond
ksrini@1074 1756 illegal();
mcimadamore@948 1757 }
mcimadamore@1113 1758 int pos = token.pos;
mcimadamore@1113 1759 nextToken();
duke@1 1760 t = toP(F.at(pos).Select(t, ident()));
mcimadamore@1113 1761 if (token.kind == LT) {
mcimadamore@1113 1762 lastTypeargsPos = token.pos;
duke@1 1763 checkGenerics();
mcimadamore@948 1764 t = typeArguments(t, true);
mcimadamore@948 1765 diamondFound = (mode & DIAMOND) != 0;
duke@1 1766 }
duke@1 1767 }
duke@1 1768 mode = oldmode;
mcimadamore@1113 1769 if (token.kind == LBRACKET) {
duke@1 1770 JCExpression e = arrayCreatorRest(newpos, t);
mcimadamore@1061 1771 if (diamondFound) {
mcimadamore@1061 1772 reportSyntaxError(lastTypeargsPos, "cannot.create.array.with.diamond");
mcimadamore@1061 1773 return toP(F.at(newpos).Erroneous(List.of(e)));
mcimadamore@1061 1774 }
mcimadamore@1061 1775 else if (typeArgs != null) {
duke@1 1776 int pos = newpos;
duke@1 1777 if (!typeArgs.isEmpty() && typeArgs.head.pos != Position.NOPOS) {
duke@1 1778 // note: this should always happen but we should
duke@1 1779 // not rely on this as the parser is continuously
duke@1 1780 // modified to improve error recovery.
duke@1 1781 pos = typeArgs.head.pos;
duke@1 1782 }
mcimadamore@1113 1783 setErrorEndPos(S.prevToken().endPos);
ksrini@1074 1784 JCErroneous err = F.at(pos).Erroneous(typeArgs.prepend(e));
ksrini@1074 1785 reportSyntaxError(err, "cannot.create.array.with.type.arguments");
ksrini@1074 1786 return toP(err);
duke@1 1787 }
duke@1 1788 return e;
mcimadamore@1113 1789 } else if (token.kind == LPAREN) {
jjg@722 1790 return classCreatorRest(newpos, null, typeArgs, t);
duke@1 1791 } else {
mcimadamore@1113 1792 setErrorEndPos(token.pos);
mcimadamore@1113 1793 reportSyntaxError(token.pos, "expected2", LPAREN, LBRACKET);
duke@1 1794 t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.<JCExpression>nil(), null));
duke@1 1795 return toP(F.at(newpos).Erroneous(List.<JCTree>of(t)));
duke@1 1796 }
duke@1 1797 }
duke@1 1798
duke@1 1799 /** InnerCreator = Ident [TypeArguments] ClassCreatorRest
duke@1 1800 */
duke@1 1801 JCExpression innerCreator(int newpos, List<JCExpression> typeArgs, JCExpression encl) {
mcimadamore@1113 1802 JCExpression t = toP(F.at(token.pos).Ident(ident()));
mcimadamore@1113 1803 if (token.kind == LT) {
mcimadamore@537 1804 int oldmode = mode;
duke@1 1805 checkGenerics();
mcimadamore@948 1806 t = typeArguments(t, true);
mcimadamore@537 1807 mode = oldmode;
duke@1 1808 }
duke@1 1809 return classCreatorRest(newpos, encl, typeArgs, t);
duke@1 1810 }
duke@1 1811
jjg@722 1812 /** ArrayCreatorRest = "[" ( "]" BracketsOpt ArrayInitializer
jjg@722 1813 * | Expression "]" {"[" Expression "]"} BracketsOpt )
duke@1 1814 */
duke@1 1815 JCExpression arrayCreatorRest(int newpos, JCExpression elemtype) {
duke@1 1816 accept(LBRACKET);
mcimadamore@1113 1817 if (token.kind == RBRACKET) {
duke@1 1818 accept(RBRACKET);
jjg@722 1819 elemtype = bracketsOpt(elemtype);
mcimadamore@1113 1820 if (token.kind == LBRACE) {
jjg@722 1821 return arrayInitializer(newpos, elemtype);
duke@1 1822 } else {
ksrini@1074 1823 JCExpression t = toP(F.at(newpos).NewArray(elemtype, List.<JCExpression>nil(), null));
mcimadamore@1113 1824 return syntaxError(token.pos, List.<JCTree>of(t), "array.dimension.missing");
duke@1 1825 }
duke@1 1826 } else {
duke@1 1827 ListBuffer<JCExpression> dims = new ListBuffer<JCExpression>();
jjg@111 1828 dims.append(parseExpression());
duke@1 1829 accept(RBRACKET);
mcimadamore@1113 1830 while (token.kind == LBRACKET) {
mcimadamore@1113 1831 int pos = token.pos;
mcimadamore@1113 1832 nextToken();
mcimadamore@1113 1833 if (token.kind == RBRACKET) {
jjg@722 1834 elemtype = bracketsOptCont(elemtype, pos);
duke@1 1835 } else {
jjg@722 1836 dims.append(parseExpression());
jjg@722 1837 accept(RBRACKET);
duke@1 1838 }
duke@1 1839 }
jjg@722 1840 return toP(F.at(newpos).NewArray(elemtype, dims.toList(), null));
duke@1 1841 }
duke@1 1842 }
duke@1 1843
duke@1 1844 /** ClassCreatorRest = Arguments [ClassBody]
duke@1 1845 */
jjg@308 1846 JCNewClass classCreatorRest(int newpos,
duke@1 1847 JCExpression encl,
duke@1 1848 List<JCExpression> typeArgs,
duke@1 1849 JCExpression t)
duke@1 1850 {
duke@1 1851 List<JCExpression> args = arguments();
duke@1 1852 JCClassDecl body = null;
mcimadamore@1113 1853 if (token.kind == LBRACE) {
mcimadamore@1113 1854 int pos = token.pos;
duke@1 1855 List<JCTree> defs = classOrInterfaceBody(names.empty, false);
duke@1 1856 JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
duke@1 1857 body = toP(F.at(pos).AnonymousClassDef(mods, defs));
duke@1 1858 }
duke@1 1859 return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
duke@1 1860 }
duke@1 1861
duke@1 1862 /** ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}"
duke@1 1863 */
duke@1 1864 JCExpression arrayInitializer(int newpos, JCExpression t) {
duke@1 1865 accept(LBRACE);
duke@1 1866 ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>();
mcimadamore@1113 1867 if (token.kind == COMMA) {
mcimadamore@1113 1868 nextToken();
mcimadamore@1113 1869 } else if (token.kind != RBRACE) {
duke@1 1870 elems.append(variableInitializer());
mcimadamore@1113 1871 while (token.kind == COMMA) {
mcimadamore@1113 1872 nextToken();
mcimadamore@1113 1873 if (token.kind == RBRACE) break;
duke@1 1874 elems.append(variableInitializer());
duke@1 1875 }
duke@1 1876 }
duke@1 1877 accept(RBRACE);
duke@1 1878 return toP(F.at(newpos).NewArray(t, List.<JCExpression>nil(), elems.toList()));
duke@1 1879 }
duke@1 1880
duke@1 1881 /** VariableInitializer = ArrayInitializer | Expression
duke@1 1882 */
duke@1 1883 public JCExpression variableInitializer() {
mcimadamore@1113 1884 return token.kind == LBRACE ? arrayInitializer(token.pos, null) : parseExpression();
duke@1 1885 }
duke@1 1886
duke@1 1887 /** ParExpression = "(" Expression ")"
duke@1 1888 */
duke@1 1889 JCExpression parExpression() {
ksrini@1138 1890 int pos = token.pos;
duke@1 1891 accept(LPAREN);
jjg@111 1892 JCExpression t = parseExpression();
duke@1 1893 accept(RPAREN);
ksrini@1138 1894 return toP(F.at(pos).Parens(t));
duke@1 1895 }
duke@1 1896
duke@1 1897 /** Block = "{" BlockStatements "}"
duke@1 1898 */
duke@1 1899 JCBlock block(int pos, long flags) {
duke@1 1900 accept(LBRACE);
duke@1 1901 List<JCStatement> stats = blockStatements();
duke@1 1902 JCBlock t = F.at(pos).Block(flags, stats);
mcimadamore@1113 1903 while (token.kind == CASE || token.kind == DEFAULT) {
mcimadamore@1113 1904 syntaxError("orphaned", token.kind);
duke@1 1905 switchBlockStatementGroups();
duke@1 1906 }
duke@1 1907 // the Block node has a field "endpos" for first char of last token, which is
duke@1 1908 // usually but not necessarily the last char of the last token.
mcimadamore@1113 1909 t.endpos = token.pos;
duke@1 1910 accept(RBRACE);
duke@1 1911 return toP(t);
duke@1 1912 }
duke@1 1913
duke@1 1914 public JCBlock block() {
mcimadamore@1113 1915 return block(token.pos, 0);
duke@1 1916 }
duke@1 1917
duke@1 1918 /** BlockStatements = { BlockStatement }
duke@1 1919 * BlockStatement = LocalVariableDeclarationStatement
duke@1 1920 * | ClassOrInterfaceOrEnumDeclaration
duke@1 1921 * | [Ident ":"] Statement
duke@1 1922 * LocalVariableDeclarationStatement
duke@1 1923 * = { FINAL | '@' Annotation } Type VariableDeclarators ";"
duke@1 1924 */
duke@1 1925 @SuppressWarnings("fallthrough")
duke@1 1926 List<JCStatement> blockStatements() {
ksrini@1249 1927 //todo: skip to anchor on error(?)
duke@1 1928 ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>();
duke@1 1929 while (true) {
ksrini@1249 1930 List<JCStatement> stat = blockStatement();
ksrini@1249 1931 if (stat.isEmpty()) {
duke@1 1932 return stats.toList();
ksrini@1249 1933 } else {
ksrini@1249 1934 if (token.pos <= endPosTable.errorEndPos) {
ksrini@1249 1935 skip(false, true, true, true);
ksrini@1249 1936 }
ksrini@1249 1937 stats.addAll(stat);
ksrini@1249 1938 }
ksrini@1249 1939 }
ksrini@1249 1940 }
ksrini@1249 1941
ksrini@1249 1942 /*
ksrini@1249 1943 * This method parses a statement treating it as a block, relaxing the
ksrini@1249 1944 * JLS restrictions, allows us to parse more faulty code, doing so
ksrini@1249 1945 * enables us to provide better and accurate diagnostics to the user.
ksrini@1249 1946 */
ksrini@1249 1947 JCStatement parseStatementAsBlock() {
ksrini@1249 1948 int pos = token.pos;
ksrini@1249 1949 List<JCStatement> stats = blockStatement();
ksrini@1249 1950 if (stats.isEmpty()) {
ksrini@1249 1951 JCErroneous e = F.at(pos).Erroneous();
ksrini@1249 1952 error(e, "illegal.start.of.stmt");
ksrini@1249 1953 return F.at(pos).Exec(e);
ksrini@1249 1954 } else {
ksrini@1249 1955 JCStatement first = stats.head;
ksrini@1249 1956 String error = null;
ksrini@1249 1957 switch (first.getTag()) {
ksrini@1249 1958 case CLASSDEF:
ksrini@1249 1959 error = "class.not.allowed";
duke@1 1960 break;
ksrini@1249 1961 case VARDEF:
ksrini@1249 1962 error = "variable.not.allowed";
duke@1 1963 break;
duke@1 1964 }
ksrini@1249 1965 if (error != null) {
ksrini@1249 1966 error(first, error);
ksrini@1249 1967 List<JCBlock> blist = List.of(F.at(first.pos).Block(0, stats));
ksrini@1249 1968 return toP(F.at(pos).Exec(F.at(first.pos).Erroneous(blist)));
duke@1 1969 }
ksrini@1249 1970 return first;
ksrini@1249 1971 }
ksrini@1249 1972 }
ksrini@1249 1973
ksrini@1249 1974 @SuppressWarnings("fallthrough")
ksrini@1249 1975 List<JCStatement> blockStatement() {
ksrini@1249 1976 //todo: skip to anchor on error(?)
ksrini@1249 1977 int pos = token.pos;
ksrini@1249 1978 switch (token.kind) {
ksrini@1249 1979 case RBRACE: case CASE: case DEFAULT: case EOF:
ksrini@1249 1980 return List.nil();
ksrini@1249 1981 case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY:
ksrini@1249 1982 case SWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK:
ksrini@1249 1983 case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH:
ksrini@1249 1984 return List.of(parseStatement());
ksrini@1249 1985 case MONKEYS_AT:
ksrini@1249 1986 case FINAL: {
jjg@1280 1987 Comment dc = token.comment(CommentStyle.JAVADOC);
ksrini@1249 1988 JCModifiers mods = modifiersOpt();
ksrini@1249 1989 if (token.kind == INTERFACE ||
ksrini@1249 1990 token.kind == CLASS ||
ksrini@1249 1991 allowEnums && token.kind == ENUM) {
ksrini@1249 1992 return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
ksrini@1249 1993 } else {
ksrini@1249 1994 JCExpression t = parseType();
ksrini@1249 1995 ListBuffer<JCStatement> stats =
ksrini@1249 1996 variableDeclarators(mods, t, new ListBuffer<JCStatement>());
ksrini@1249 1997 // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
jlahoda@1444 1998 storeEnd(stats.last(), token.endPos);
ksrini@1249 1999 accept(SEMI);
ksrini@1249 2000 return stats.toList();
duke@1 2001 }
ksrini@1249 2002 }
ksrini@1249 2003 case ABSTRACT: case STRICTFP: {
jjg@1280 2004 Comment dc = token.comment(CommentStyle.JAVADOC);
ksrini@1249 2005 JCModifiers mods = modifiersOpt();
ksrini@1249 2006 return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
ksrini@1249 2007 }
ksrini@1249 2008 case INTERFACE:
ksrini@1249 2009 case CLASS:
jjg@1280 2010 Comment dc = token.comment(CommentStyle.JAVADOC);
ksrini@1249 2011 return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
ksrini@1249 2012 case ENUM:
ksrini@1249 2013 case ASSERT:
ksrini@1249 2014 if (allowEnums && token.kind == ENUM) {
ksrini@1249 2015 error(token.pos, "local.enum");
ksrini@1249 2016 dc = token.comment(CommentStyle.JAVADOC);
ksrini@1249 2017 return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
ksrini@1249 2018 } else if (allowAsserts && token.kind == ASSERT) {
ksrini@1249 2019 return List.of(parseStatement());
ksrini@1249 2020 }
ksrini@1249 2021 /* fall through to default */
ksrini@1249 2022 default:
ksrini@1249 2023 Token prevToken = token;
ksrini@1249 2024 JCExpression t = term(EXPR | TYPE);
ksrini@1249 2025 if (token.kind == COLON && t.hasTag(IDENT)) {
ksrini@1249 2026 nextToken();
ksrini@1249 2027 JCStatement stat = parseStatement();
ksrini@1249 2028 return List.<JCStatement>of(F.at(pos).Labelled(prevToken.name(), stat));
ksrini@1249 2029 } else if ((lastmode & TYPE) != 0 &&
ksrini@1249 2030 (token.kind == IDENTIFIER ||
ksrini@1249 2031 token.kind == ASSERT ||
ksrini@1249 2032 token.kind == ENUM)) {
ksrini@1249 2033 pos = token.pos;
ksrini@1249 2034 JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
ksrini@1249 2035 F.at(pos);
ksrini@1249 2036 ListBuffer<JCStatement> stats =
ksrini@1249 2037 variableDeclarators(mods, t, new ListBuffer<JCStatement>());
ksrini@1249 2038 // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
jlahoda@1444 2039 storeEnd(stats.last(), token.endPos);
ksrini@1249 2040 accept(SEMI);
duke@1 2041 return stats.toList();
ksrini@1249 2042 } else {
ksrini@1249 2043 // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
ksrini@1249 2044 JCExpressionStatement expr = to(F.at(pos).Exec(checkExprStat(t)));
ksrini@1249 2045 accept(SEMI);
ksrini@1249 2046 return List.<JCStatement>of(expr);
duke@1 2047 }
duke@1 2048 }
duke@1 2049 }
duke@1 2050
duke@1 2051 /** Statement =
duke@1 2052 * Block
duke@1 2053 * | IF ParExpression Statement [ELSE Statement]
duke@1 2054 * | FOR "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement
duke@1 2055 * | FOR "(" FormalParameter : Expression ")" Statement
duke@1 2056 * | WHILE ParExpression Statement
duke@1 2057 * | DO Statement WHILE ParExpression ";"
duke@1 2058 * | TRY Block ( Catches | [Catches] FinallyPart )
darcy@850 2059 * | TRY "(" ResourceSpecification ";"opt ")" Block [Catches] [FinallyPart]
duke@1 2060 * | SWITCH ParExpression "{" SwitchBlockStatementGroups "}"
duke@1 2061 * | SYNCHRONIZED ParExpression Block
duke@1 2062 * | RETURN [Expression] ";"
duke@1 2063 * | THROW Expression ";"
duke@1 2064 * | BREAK [Ident] ";"
duke@1 2065 * | CONTINUE [Ident] ";"
duke@1 2066 * | ASSERT Expression [ ":" Expression ] ";"
duke@1 2067 * | ";"
duke@1 2068 * | ExpressionStatement
duke@1 2069 * | Ident ":" Statement
duke@1 2070 */
duke@1 2071 @SuppressWarnings("fallthrough")
jjg@111 2072 public JCStatement parseStatement() {
mcimadamore@1113 2073 int pos = token.pos;
mcimadamore@1113 2074 switch (token.kind) {
duke@1 2075 case LBRACE:
duke@1 2076 return block();
duke@1 2077 case IF: {
mcimadamore@1113 2078 nextToken();
duke@1 2079 JCExpression cond = parExpression();
ksrini@1249 2080 JCStatement thenpart = parseStatementAsBlock();
duke@1 2081 JCStatement elsepart = null;
mcimadamore@1113 2082 if (token.kind == ELSE) {
mcimadamore@1113 2083 nextToken();
ksrini@1249 2084 elsepart = parseStatementAsBlock();
duke@1 2085 }
duke@1 2086 return F.at(pos).If(cond, thenpart, elsepart);
duke@1 2087 }
duke@1 2088 case FOR: {
mcimadamore@1113 2089 nextToken();
duke@1 2090 accept(LPAREN);
mcimadamore@1113 2091 List<JCStatement> inits = token.kind == SEMI ? List.<JCStatement>nil() : forInit();
duke@1 2092 if (inits.length() == 1 &&
jjg@1127 2093 inits.head.hasTag(VARDEF) &&
duke@1 2094 ((JCVariableDecl) inits.head).init == null &&
mcimadamore@1113 2095 token.kind == COLON) {
duke@1 2096 checkForeach();
duke@1 2097 JCVariableDecl var = (JCVariableDecl)inits.head;
duke@1 2098 accept(COLON);
jjg@111 2099 JCExpression expr = parseExpression();
duke@1 2100 accept(RPAREN);
ksrini@1249 2101 JCStatement body = parseStatementAsBlock();
duke@1 2102 return F.at(pos).ForeachLoop(var, expr, body);
duke@1 2103 } else {
duke@1 2104 accept(SEMI);
mcimadamore@1113 2105 JCExpression cond = token.kind == SEMI ? null : parseExpression();
duke@1 2106 accept(SEMI);
mcimadamore@1113 2107 List<JCExpressionStatement> steps = token.kind == RPAREN ? List.<JCExpressionStatement>nil() : forUpdate();
duke@1 2108 accept(RPAREN);
ksrini@1249 2109 JCStatement body = parseStatementAsBlock();
duke@1 2110 return F.at(pos).ForLoop(inits, cond, steps, body);
duke@1 2111 }
duke@1 2112 }
duke@1 2113 case WHILE: {
mcimadamore@1113 2114 nextToken();
duke@1 2115 JCExpression cond = parExpression();
ksrini@1249 2116 JCStatement body = parseStatementAsBlock();
duke@1 2117 return F.at(pos).WhileLoop(cond, body);
duke@1 2118 }
duke@1 2119 case DO: {
mcimadamore@1113 2120 nextToken();
ksrini@1249 2121 JCStatement body = parseStatementAsBlock();
duke@1 2122 accept(WHILE);
duke@1 2123 JCExpression cond = parExpression();
duke@1 2124 JCDoWhileLoop t = to(F.at(pos).DoLoop(body, cond));
duke@1 2125 accept(SEMI);
duke@1 2126 return t;
duke@1 2127 }
duke@1 2128 case TRY: {
mcimadamore@1113 2129 nextToken();
darcy@609 2130 List<JCTree> resources = List.<JCTree>nil();
mcimadamore@1113 2131 if (token.kind == LPAREN) {
mcimadamore@743 2132 checkTryWithResources();
mcimadamore@1113 2133 nextToken();
darcy@609 2134 resources = resources();
darcy@609 2135 accept(RPAREN);
darcy@609 2136 }
duke@1 2137 JCBlock body = block();
duke@1 2138 ListBuffer<JCCatch> catchers = new ListBuffer<JCCatch>();
duke@1 2139 JCBlock finalizer = null;
mcimadamore@1113 2140 if (token.kind == CATCH || token.kind == FINALLY) {
mcimadamore@1113 2141 while (token.kind == CATCH) catchers.append(catchClause());
mcimadamore@1113 2142 if (token.kind == FINALLY) {
mcimadamore@1113 2143 nextToken();
duke@1 2144 finalizer = block();
duke@1 2145 }
duke@1 2146 } else {
darcy@609 2147 if (allowTWR) {
darcy@609 2148 if (resources.isEmpty())
jjg@726 2149 error(pos, "try.without.catch.finally.or.resource.decls");
darcy@609 2150 } else
jjg@726 2151 error(pos, "try.without.catch.or.finally");
duke@1 2152 }
darcy@609 2153 return F.at(pos).Try(resources, body, catchers.toList(), finalizer);
duke@1 2154 }
duke@1 2155 case SWITCH: {
mcimadamore@1113 2156 nextToken();
duke@1 2157 JCExpression selector = parExpression();
duke@1 2158 accept(LBRACE);
duke@1 2159 List<JCCase> cases = switchBlockStatementGroups();
duke@1 2160 JCSwitch t = to(F.at(pos).Switch(selector, cases));
duke@1 2161 accept(RBRACE);
duke@1 2162 return t;
duke@1 2163 }
duke@1 2164 case SYNCHRONIZED: {
mcimadamore@1113 2165 nextToken();
duke@1 2166 JCExpression lock = parExpression();
duke@1 2167 JCBlock body = block();
duke@1 2168 return F.at(pos).Synchronized(lock, body);
duke@1 2169 }
duke@1 2170 case RETURN: {
mcimadamore@1113 2171 nextToken();
mcimadamore@1113 2172 JCExpression result = token.kind == SEMI ? null : parseExpression();
duke@1 2173 JCReturn t = to(F.at(pos).Return(result));
duke@1 2174 accept(SEMI);
duke@1 2175 return t;
duke@1 2176 }
duke@1 2177 case THROW: {
mcimadamore@1113 2178 nextToken();
jjg@111 2179 JCExpression exc = parseExpression();
duke@1 2180 JCThrow t = to(F.at(pos).Throw(exc));
duke@1 2181 accept(SEMI);
duke@1 2182 return t;
duke@1 2183 }
duke@1 2184 case BREAK: {
mcimadamore@1113 2185 nextToken();
mcimadamore@1113 2186 Name label = (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM) ? ident() : null;
duke@1 2187 JCBreak t = to(F.at(pos).Break(label));
duke@1 2188 accept(SEMI);
duke@1 2189 return t;
duke@1 2190 }
duke@1 2191 case CONTINUE: {
mcimadamore@1113 2192 nextToken();
mcimadamore@1113 2193 Name label = (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM) ? ident() : null;
duke@1 2194 JCContinue t = to(F.at(pos).Continue(label));
duke@1 2195 accept(SEMI);
duke@1 2196 return t;
duke@1 2197 }
duke@1 2198 case SEMI:
mcimadamore@1113 2199 nextToken();
duke@1 2200 return toP(F.at(pos).Skip());
duke@1 2201 case ELSE:
vromero@1400 2202 int elsePos = token.pos;
vromero@1400 2203 nextToken();
vromero@1400 2204 return doRecover(elsePos, BasicErrorRecoveryAction.BLOCK_STMT, "else.without.if");
duke@1 2205 case FINALLY:
vromero@1400 2206 int finallyPos = token.pos;
vromero@1400 2207 nextToken();
vromero@1400 2208 return doRecover(finallyPos, BasicErrorRecoveryAction.BLOCK_STMT, "finally.without.try");
duke@1 2209 case CATCH:
vromero@1400 2210 return doRecover(token.pos, BasicErrorRecoveryAction.CATCH_CLAUSE, "catch.without.try");
duke@1 2211 case ASSERT: {
mcimadamore@1113 2212 if (allowAsserts && token.kind == ASSERT) {
mcimadamore@1113 2213 nextToken();
jjg@111 2214 JCExpression assertion = parseExpression();
duke@1 2215 JCExpression message = null;
mcimadamore@1113 2216 if (token.kind == COLON) {
mcimadamore@1113 2217 nextToken();
jjg@111 2218 message = parseExpression();
duke@1 2219 }
duke@1 2220 JCAssert t = to(F.at(pos).Assert(assertion, message));
duke@1 2221 accept(SEMI);
duke@1 2222 return t;
duke@1 2223 }
duke@1 2224 /* else fall through to default case */
duke@1 2225 }
duke@1 2226 case ENUM:
duke@1 2227 default:
mcimadamore@1113 2228 Token prevToken = token;
jjg@111 2229 JCExpression expr = parseExpression();
jjg@1127 2230 if (token.kind == COLON && expr.hasTag(IDENT)) {
mcimadamore@1113 2231 nextToken();
jjg@111 2232 JCStatement stat = parseStatement();
mcimadamore@1113 2233 return F.at(pos).Labelled(prevToken.name(), stat);
duke@1 2234 } else {
duke@1 2235 // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
duke@1 2236 JCExpressionStatement stat = to(F.at(pos).Exec(checkExprStat(expr)));
duke@1 2237 accept(SEMI);
duke@1 2238 return stat;
duke@1 2239 }
duke@1 2240 }
duke@1 2241 }
duke@1 2242
vromero@1400 2243 private JCStatement doRecover(int startPos, ErrorRecoveryAction action, String key) {
vromero@1400 2244 int errPos = S.errPos();
vromero@1400 2245 JCTree stm = action.doRecover(this);
vromero@1400 2246 S.errPos(errPos);
vromero@1400 2247 return toP(F.Exec(syntaxError(startPos, List.<JCTree>of(stm), key)));
vromero@1400 2248 }
vromero@1400 2249
duke@1 2250 /** CatchClause = CATCH "(" FormalParameter ")" Block
duke@1 2251 */
ksrini@1074 2252 protected JCCatch catchClause() {
mcimadamore@1113 2253 int pos = token.pos;
duke@1 2254 accept(CATCH);
duke@1 2255 accept(LPAREN);
mcimadamore@550 2256 JCModifiers mods = optFinal(Flags.PARAMETER);
mcimadamore@550 2257 List<JCExpression> catchTypes = catchTypes();
mcimadamore@550 2258 JCExpression paramType = catchTypes.size() > 1 ?
darcy@969 2259 toP(F.at(catchTypes.head.getStartPosition()).TypeUnion(catchTypes)) :
mcimadamore@550 2260 catchTypes.head;
mcimadamore@550 2261 JCVariableDecl formal = variableDeclaratorId(mods, paramType);
duke@1 2262 accept(RPAREN);
duke@1 2263 JCBlock body = block();
duke@1 2264 return F.at(pos).Catch(formal, body);
duke@1 2265 }
duke@1 2266
mcimadamore@550 2267 List<JCExpression> catchTypes() {
mcimadamore@550 2268 ListBuffer<JCExpression> catchTypes = ListBuffer.lb();
mcimadamore@550 2269 catchTypes.add(parseType());
mcimadamore@1113 2270 while (token.kind == BAR) {
mcimadamore@550 2271 checkMulticatch();
mcimadamore@1113 2272 nextToken();
mcimadamore@550 2273 catchTypes.add(qualident());
mcimadamore@550 2274 }
mcimadamore@550 2275 return catchTypes.toList();
mcimadamore@550 2276 }
mcimadamore@550 2277
duke@1 2278 /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup }
duke@1 2279 * SwitchBlockStatementGroup = SwitchLabel BlockStatements
duke@1 2280 * SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":"
duke@1 2281 */
duke@1 2282 List<JCCase> switchBlockStatementGroups() {
duke@1 2283 ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
duke@1 2284 while (true) {
mcimadamore@1113 2285 int pos = token.pos;
mcimadamore@1113 2286 switch (token.kind) {
ksrini@1346 2287 case CASE:
ksrini@1346 2288 case DEFAULT:
ksrini@1346 2289 cases.append(switchBlockStatementGroup());
duke@1 2290 break;
duke@1 2291 case RBRACE: case EOF:
duke@1 2292 return cases.toList();
duke@1 2293 default:
mcimadamore@1113 2294 nextToken(); // to ensure progress
duke@1 2295 syntaxError(pos, "expected3",
mcimadamore@80 2296 CASE, DEFAULT, RBRACE);
duke@1 2297 }
duke@1 2298 }
duke@1 2299 }
duke@1 2300
ksrini@1346 2301 protected JCCase switchBlockStatementGroup() {
ksrini@1346 2302 int pos = token.pos;
ksrini@1346 2303 List<JCStatement> stats;
ksrini@1346 2304 JCCase c;
ksrini@1346 2305 switch (token.kind) {
ksrini@1346 2306 case CASE:
ksrini@1346 2307 nextToken();
ksrini@1346 2308 JCExpression pat = parseExpression();
ksrini@1346 2309 accept(COLON);
ksrini@1346 2310 stats = blockStatements();
ksrini@1346 2311 c = F.at(pos).Case(pat, stats);
ksrini@1346 2312 if (stats.isEmpty())
ksrini@1346 2313 storeEnd(c, S.prevToken().endPos);
ksrini@1346 2314 return c;
ksrini@1346 2315 case DEFAULT:
ksrini@1346 2316 nextToken();
ksrini@1346 2317 accept(COLON);
ksrini@1346 2318 stats = blockStatements();
ksrini@1346 2319 c = F.at(pos).Case(null, stats);
ksrini@1346 2320 if (stats.isEmpty())
ksrini@1346 2321 storeEnd(c, S.prevToken().endPos);
ksrini@1346 2322 return c;
ksrini@1346 2323 }
ksrini@1346 2324 throw new AssertionError("should not reach here");
ksrini@1346 2325 }
ksrini@1346 2326
duke@1 2327 /** MoreStatementExpressions = { COMMA StatementExpression }
duke@1 2328 */
duke@1 2329 <T extends ListBuffer<? super JCExpressionStatement>> T moreStatementExpressions(int pos,
duke@1 2330 JCExpression first,
duke@1 2331 T stats) {
duke@1 2332 // This Exec is a "StatementExpression"; it subsumes no terminating token
duke@1 2333 stats.append(toP(F.at(pos).Exec(checkExprStat(first))));
mcimadamore@1113 2334 while (token.kind == COMMA) {
mcimadamore@1113 2335 nextToken();
mcimadamore@1113 2336 pos = token.pos;
jjg@111 2337 JCExpression t = parseExpression();
duke@1 2338 // This Exec is a "StatementExpression"; it subsumes no terminating token
duke@1 2339 stats.append(toP(F.at(pos).Exec(checkExprStat(t))));
duke@1 2340 }
duke@1 2341 return stats;
duke@1 2342 }
duke@1 2343
duke@1 2344 /** ForInit = StatementExpression MoreStatementExpressions
duke@1 2345 * | { FINAL | '@' Annotation } Type VariableDeclarators
duke@1 2346 */
duke@1 2347 List<JCStatement> forInit() {
duke@1 2348 ListBuffer<JCStatement> stats = lb();
mcimadamore@1113 2349 int pos = token.pos;
mcimadamore@1113 2350 if (token.kind == FINAL || token.kind == MONKEYS_AT) {
jjg@111 2351 return variableDeclarators(optFinal(0), parseType(), stats).toList();
duke@1 2352 } else {
duke@1 2353 JCExpression t = term(EXPR | TYPE);
duke@1 2354 if ((lastmode & TYPE) != 0 &&
ksrini@1259 2355 (token.kind == IDENTIFIER || token.kind == ASSERT ||
ksrini@1259 2356 token.kind == ENUM)) {
duke@1 2357 return variableDeclarators(modifiersOpt(), t, stats).toList();
ksrini@1259 2358 } else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
ksrini@1259 2359 error(pos, "bad.initializer", "for-loop");
ksrini@1259 2360 return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
ksrini@1259 2361 } else {
duke@1 2362 return moreStatementExpressions(pos, t, stats).toList();
ksrini@1259 2363 }
duke@1 2364 }
duke@1 2365 }
duke@1 2366
duke@1 2367 /** ForUpdate = StatementExpression MoreStatementExpressions
duke@1 2368 */
duke@1 2369 List<JCExpressionStatement> forUpdate() {
mcimadamore@1113 2370 return moreStatementExpressions(token.pos,
jjg@111 2371 parseExpression(),
duke@1 2372 new ListBuffer<JCExpressionStatement>()).toList();
duke@1 2373 }
duke@1 2374
duke@1 2375 /** AnnotationsOpt = { '@' Annotation }
duke@1 2376 */
jjg@722 2377 List<JCAnnotation> annotationsOpt() {
mcimadamore@1113 2378 if (token.kind != MONKEYS_AT) return List.nil(); // optimization
duke@1 2379 ListBuffer<JCAnnotation> buf = new ListBuffer<JCAnnotation>();
mcimadamore@1113 2380 while (token.kind == MONKEYS_AT) {
mcimadamore@1113 2381 int pos = token.pos;
mcimadamore@1113 2382 nextToken();
jjg@722 2383 buf.append(annotation(pos));
duke@1 2384 }
jjg@722 2385 return buf.toList();
duke@1 2386 }
duke@1 2387
duke@1 2388 /** ModifiersOpt = { Modifier }
duke@1 2389 * Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL
duke@1 2390 * | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@"
duke@1 2391 * | "@" Annotation
duke@1 2392 */
duke@1 2393 JCModifiers modifiersOpt() {
duke@1 2394 return modifiersOpt(null);
duke@1 2395 }
ksrini@1074 2396 protected JCModifiers modifiersOpt(JCModifiers partial) {
jjg@482 2397 long flags;
jjg@482 2398 ListBuffer<JCAnnotation> annotations = new ListBuffer<JCAnnotation>();
jjg@482 2399 int pos;
jjg@482 2400 if (partial == null) {
jjg@482 2401 flags = 0;
mcimadamore@1113 2402 pos = token.pos;
jjg@482 2403 } else {
jjg@482 2404 flags = partial.flags;
jjg@482 2405 annotations.appendList(partial.annotations);
jjg@482 2406 pos = partial.pos;
jjg@482 2407 }
mcimadamore@1125 2408 if (token.deprecatedFlag()) {
duke@1 2409 flags |= Flags.DEPRECATED;
duke@1 2410 }
duke@1 2411 int lastPos = Position.NOPOS;
duke@1 2412 loop:
duke@1 2413 while (true) {
duke@1 2414 long flag;
mcimadamore@1113 2415 switch (token.kind) {
duke@1 2416 case PRIVATE : flag = Flags.PRIVATE; break;
duke@1 2417 case PROTECTED : flag = Flags.PROTECTED; break;
duke@1 2418 case PUBLIC : flag = Flags.PUBLIC; break;
duke@1 2419 case STATIC : flag = Flags.STATIC; break;
duke@1 2420 case TRANSIENT : flag = Flags.TRANSIENT; break;
duke@1 2421 case FINAL : flag = Flags.FINAL; break;
duke@1 2422 case ABSTRACT : flag = Flags.ABSTRACT; break;
duke@1 2423 case NATIVE : flag = Flags.NATIVE; break;
duke@1 2424 case VOLATILE : flag = Flags.VOLATILE; break;
duke@1 2425 case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break;
duke@1 2426 case STRICTFP : flag = Flags.STRICTFP; break;
duke@1 2427 case MONKEYS_AT : flag = Flags.ANNOTATION; break;
mcimadamore@1366 2428 case DEFAULT : checkDefaultMethods(); flag = Flags.DEFAULT; break;
mcimadamore@1113 2429 case ERROR : flag = 0; nextToken(); break;
duke@1 2430 default: break loop;
duke@1 2431 }
mcimadamore@1113 2432 if ((flags & flag) != 0) error(token.pos, "repeated.modifier");
mcimadamore@1113 2433 lastPos = token.pos;
mcimadamore@1113 2434 nextToken();
duke@1 2435 if (flag == Flags.ANNOTATION) {
duke@1 2436 checkAnnotations();
mcimadamore@1113 2437 if (token.kind != INTERFACE) {
jjg@722 2438 JCAnnotation ann = annotation(lastPos);
jjg@482 2439 // if first modifier is an annotation, set pos to annotation's.
jjg@482 2440 if (flags == 0 && annotations.isEmpty())
jjg@482 2441 pos = ann.pos;
jjg@482 2442 annotations.append(ann);
jjg@482 2443 lastPos = ann.pos;
duke@1 2444 flag = 0;
duke@1 2445 }
duke@1 2446 }
duke@1 2447 flags |= flag;
duke@1 2448 }
mcimadamore@1113 2449 switch (token.kind) {
duke@1 2450 case ENUM: flags |= Flags.ENUM; break;
duke@1 2451 case INTERFACE: flags |= Flags.INTERFACE; break;
duke@1 2452 default: break;
duke@1 2453 }
duke@1 2454
duke@1 2455 /* A modifiers tree with no modifier tokens or annotations
duke@1 2456 * has no text position. */
jjg@613 2457 if ((flags & (Flags.ModifierFlags | Flags.ANNOTATION)) == 0 && annotations.isEmpty())
duke@1 2458 pos = Position.NOPOS;
duke@1 2459
duke@1 2460 JCModifiers mods = F.at(pos).Modifiers(flags, annotations.toList());
duke@1 2461 if (pos != Position.NOPOS)
mcimadamore@1113 2462 storeEnd(mods, S.prevToken().endPos);
duke@1 2463 return mods;
duke@1 2464 }
duke@1 2465
duke@1 2466 /** Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ]
duke@1 2467 * @param pos position of "@" token
duke@1 2468 */
jjg@722 2469 JCAnnotation annotation(int pos) {
duke@1 2470 // accept(AT); // AT consumed by caller
duke@1 2471 checkAnnotations();
duke@1 2472 JCTree ident = qualident();
duke@1 2473 List<JCExpression> fieldValues = annotationFieldValuesOpt();
jjg@722 2474 JCAnnotation ann = F.at(pos).Annotation(ident, fieldValues);
mcimadamore@1113 2475 storeEnd(ann, S.prevToken().endPos);
duke@1 2476 return ann;
duke@1 2477 }
duke@1 2478
duke@1 2479 List<JCExpression> annotationFieldValuesOpt() {
mcimadamore@1113 2480 return (token.kind == LPAREN) ? annotationFieldValues() : List.<JCExpression>nil();
duke@1 2481 }
duke@1 2482
duke@1 2483 /** AnnotationFieldValues = "(" [ AnnotationFieldValue { "," AnnotationFieldValue } ] ")" */
duke@1 2484 List<JCExpression> annotationFieldValues() {
duke@1 2485 accept(LPAREN);
duke@1 2486 ListBuffer<JCExpression> buf = new ListBuffer<JCExpression>();
mcimadamore@1113 2487 if (token.kind != RPAREN) {
duke@1 2488 buf.append(annotationFieldValue());
mcimadamore@1113 2489 while (token.kind == COMMA) {
mcimadamore@1113 2490 nextToken();
duke@1 2491 buf.append(annotationFieldValue());
duke@1 2492 }
duke@1 2493 }
duke@1 2494 accept(RPAREN);
duke@1 2495 return buf.toList();
duke@1 2496 }
duke@1 2497
duke@1 2498 /** AnnotationFieldValue = AnnotationValue
duke@1 2499 * | Identifier "=" AnnotationValue
duke@1 2500 */
duke@1 2501 JCExpression annotationFieldValue() {
mcimadamore@1113 2502 if (token.kind == IDENTIFIER) {
duke@1 2503 mode = EXPR;
duke@1 2504 JCExpression t1 = term1();
jjg@1127 2505 if (t1.hasTag(IDENT) && token.kind == EQ) {
mcimadamore@1113 2506 int pos = token.pos;
duke@1 2507 accept(EQ);
jjg@482 2508 JCExpression v = annotationValue();
jjg@482 2509 return toP(F.at(pos).Assign(t1, v));
duke@1 2510 } else {
duke@1 2511 return t1;
duke@1 2512 }
duke@1 2513 }
duke@1 2514 return annotationValue();
duke@1 2515 }
duke@1 2516
duke@1 2517 /* AnnotationValue = ConditionalExpression
duke@1 2518 * | Annotation
darcy@417 2519 * | "{" [ AnnotationValue { "," AnnotationValue } ] [","] "}"
duke@1 2520 */
duke@1 2521 JCExpression annotationValue() {
duke@1 2522 int pos;
mcimadamore@1113 2523 switch (token.kind) {
duke@1 2524 case MONKEYS_AT:
mcimadamore@1113 2525 pos = token.pos;
mcimadamore@1113 2526 nextToken();
jjg@722 2527 return annotation(pos);
duke@1 2528 case LBRACE:
mcimadamore@1113 2529 pos = token.pos;
duke@1 2530 accept(LBRACE);
duke@1 2531 ListBuffer<JCExpression> buf = new ListBuffer<JCExpression>();
mcimadamore@1113 2532 if (token.kind != RBRACE) {
duke@1 2533 buf.append(annotationValue());
mcimadamore@1113 2534 while (token.kind == COMMA) {
mcimadamore@1113 2535 nextToken();
mcimadamore@1113 2536 if (token.kind == RBRACE) break;
duke@1 2537 buf.append(annotationValue());
duke@1 2538 }
duke@1 2539 }
duke@1 2540 accept(RBRACE);
duke@1 2541 return toP(F.at(pos).NewArray(null, List.<JCExpression>nil(), buf.toList()));
duke@1 2542 default:
duke@1 2543 mode = EXPR;
duke@1 2544 return term1();
duke@1 2545 }
duke@1 2546 }
duke@1 2547
duke@1 2548 /** VariableDeclarators = VariableDeclarator { "," VariableDeclarator }
duke@1 2549 */
duke@1 2550 public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
duke@1 2551 JCExpression type,
duke@1 2552 T vdefs)
duke@1 2553 {
mcimadamore@1113 2554 return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs);
duke@1 2555 }
duke@1 2556
duke@1 2557 /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
duke@1 2558 * ConstantDeclaratorsRest = ConstantDeclaratorRest { "," ConstantDeclarator }
duke@1 2559 *
duke@1 2560 * @param reqInit Is an initializer always required?
duke@1 2561 * @param dc The documentation comment for the variable declarations, or null.
duke@1 2562 */
duke@1 2563 <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos,
duke@1 2564 JCModifiers mods,
duke@1 2565 JCExpression type,
duke@1 2566 Name name,
duke@1 2567 boolean reqInit,
jjg@1280 2568 Comment dc,
duke@1 2569 T vdefs)
duke@1 2570 {
duke@1 2571 vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc));
mcimadamore@1113 2572 while (token.kind == COMMA) {
duke@1 2573 // All but last of multiple declarators subsume a comma
jlahoda@1444 2574 storeEnd((JCTree)vdefs.last(), token.endPos);
mcimadamore@1113 2575 nextToken();
duke@1 2576 vdefs.append(variableDeclarator(mods, type, reqInit, dc));
duke@1 2577 }
duke@1 2578 return vdefs;
duke@1 2579 }
duke@1 2580
duke@1 2581 /** VariableDeclarator = Ident VariableDeclaratorRest
duke@1 2582 * ConstantDeclarator = Ident ConstantDeclaratorRest
duke@1 2583 */
jjg@1280 2584 JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
mcimadamore@1113 2585 return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
duke@1 2586 }
duke@1 2587
duke@1 2588 /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
duke@1 2589 * ConstantDeclaratorRest = BracketsOpt "=" VariableInitializer
duke@1 2590 *
duke@1 2591 * @param reqInit Is an initializer always required?
duke@1 2592 * @param dc The documentation comment for the variable declarations, or null.
duke@1 2593 */
duke@1 2594 JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
jjg@1280 2595 boolean reqInit, Comment dc) {
duke@1 2596 type = bracketsOpt(type);
duke@1 2597 JCExpression init = null;
mcimadamore@1113 2598 if (token.kind == EQ) {
mcimadamore@1113 2599 nextToken();
duke@1 2600 init = variableInitializer();
duke@1 2601 }
mcimadamore@1113 2602 else if (reqInit) syntaxError(token.pos, "expected", EQ);
duke@1 2603 JCVariableDecl result =
duke@1 2604 toP(F.at(pos).VarDef(mods, name, type, init));
duke@1 2605 attach(result, dc);
duke@1 2606 return result;
duke@1 2607 }
duke@1 2608
duke@1 2609 /** VariableDeclaratorId = Ident BracketsOpt
duke@1 2610 */
duke@1 2611 JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
mcimadamore@1113 2612 int pos = token.pos;
duke@1 2613 Name name = ident();
mcimadamore@831 2614 if ((mods.flags & Flags.VARARGS) != 0 &&
mcimadamore@1113 2615 token.kind == LBRACKET) {
mcimadamore@1113 2616 log.error(token.pos, "varargs.and.old.array.syntax");
mcimadamore@831 2617 }
mcimadamore@831 2618 type = bracketsOpt(type);
duke@1 2619 return toP(F.at(pos).VarDef(mods, name, type, null));
duke@1 2620 }
duke@1 2621
darcy@609 2622 /** Resources = Resource { ";" Resources }
darcy@609 2623 */
darcy@609 2624 List<JCTree> resources() {
darcy@609 2625 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
darcy@609 2626 defs.append(resource());
mcimadamore@1113 2627 while (token.kind == SEMI) {
darcy@850 2628 // All but last of multiple declarators must subsume a semicolon
jlahoda@1444 2629 storeEnd(defs.last(), token.endPos);
mcimadamore@1113 2630 int semiColonPos = token.pos;
mcimadamore@1113 2631 nextToken();
mcimadamore@1113 2632 if (token.kind == RPAREN) { // Optional trailing semicolon
darcy@840 2633 // after last resource
darcy@840 2634 break;
darcy@840 2635 }
darcy@609 2636 defs.append(resource());
darcy@609 2637 }
darcy@609 2638 return defs.toList();
darcy@609 2639 }
darcy@609 2640
darcy@840 2641 /** Resource = VariableModifiersOpt Type VariableDeclaratorId = Expression
darcy@609 2642 */
ksrini@1074 2643 protected JCTree resource() {
ksrini@1074 2644 JCModifiers optFinal = optFinal(Flags.FINAL);
ksrini@1074 2645 JCExpression type = parseType();
mcimadamore@1113 2646 int pos = token.pos;
ksrini@1074 2647 Name ident = ident();
ksrini@1074 2648 return variableDeclaratorRest(pos, optFinal, type, ident, true, null);
darcy@609 2649 }
darcy@609 2650
duke@1 2651 /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration}
duke@1 2652 */
jjg@111 2653 public JCTree.JCCompilationUnit parseCompilationUnit() {
mcimadamore@1113 2654 Token firstToken = token;
duke@1 2655 JCExpression pid = null;
duke@1 2656 JCModifiers mods = null;
mcimadamore@1113 2657 boolean consumedToplevelDoc = false;
mcimadamore@1113 2658 boolean seenImport = false;
mcimadamore@1113 2659 boolean seenPackage = false;
duke@1 2660 List<JCAnnotation> packageAnnotations = List.nil();
mcimadamore@1113 2661 if (token.kind == MONKEYS_AT)
duke@1 2662 mods = modifiersOpt();
duke@1 2663
mcimadamore@1113 2664 if (token.kind == PACKAGE) {
mcimadamore@1113 2665 seenPackage = true;
duke@1 2666 if (mods != null) {
duke@1 2667 checkNoMods(mods.flags);
duke@1 2668 packageAnnotations = mods.annotations;
duke@1 2669 mods = null;
duke@1 2670 }
mcimadamore@1113 2671 nextToken();
duke@1 2672 pid = qualident();
duke@1 2673 accept(SEMI);
duke@1 2674 }
duke@1 2675 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
jjg@111 2676 boolean checkForImports = true;
mcimadamore@1113 2677 boolean firstTypeDecl = true;
mcimadamore@1113 2678 while (token.kind != EOF) {
ksrini@1138 2679 if (token.pos <= endPosTable.errorEndPos) {
duke@1 2680 // error recovery
duke@1 2681 skip(checkForImports, false, false, false);
mcimadamore@1113 2682 if (token.kind == EOF)
duke@1 2683 break;
duke@1 2684 }
mcimadamore@1113 2685 if (checkForImports && mods == null && token.kind == IMPORT) {
mcimadamore@1113 2686 seenImport = true;
duke@1 2687 defs.append(importDeclaration());
duke@1 2688 } else {
jjg@1280 2689 Comment docComment = token.comment(CommentStyle.JAVADOC);
mcimadamore@1113 2690 if (firstTypeDecl && !seenImport && !seenPackage) {
mcimadamore@1125 2691 docComment = firstToken.comment(CommentStyle.JAVADOC);
mcimadamore@1113 2692 consumedToplevelDoc = true;
jjg@695 2693 }
mcimadamore@1113 2694 JCTree def = typeDeclaration(mods, docComment);
duke@1 2695 if (def instanceof JCExpressionStatement)
duke@1 2696 def = ((JCExpressionStatement)def).expr;
duke@1 2697 defs.append(def);
duke@1 2698 if (def instanceof JCClassDecl)
duke@1 2699 checkForImports = false;
duke@1 2700 mods = null;
mcimadamore@1113 2701 firstTypeDecl = false;
duke@1 2702 }
duke@1 2703 }
mcimadamore@1113 2704 JCTree.JCCompilationUnit toplevel = F.at(firstToken.pos).TopLevel(packageAnnotations, pid, defs.toList());
mcimadamore@1113 2705 if (!consumedToplevelDoc)
mcimadamore@1125 2706 attach(toplevel, firstToken.comment(CommentStyle.JAVADOC));
jlahoda@1444 2707 if (defs.isEmpty())
mcimadamore@1113 2708 storeEnd(toplevel, S.prevToken().endPos);
jjg@111 2709 if (keepDocComments)
jjg@111 2710 toplevel.docComments = docComments;
jjg@111 2711 if (keepLineMap)
jjg@111 2712 toplevel.lineMap = S.getLineMap();
ksrini@1138 2713 toplevel.endPositions = this.endPosTable;
duke@1 2714 return toplevel;
duke@1 2715 }
duke@1 2716
duke@1 2717 /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";"
duke@1 2718 */
duke@1 2719 JCTree importDeclaration() {
mcimadamore@1113 2720 int pos = token.pos;
mcimadamore@1113 2721 nextToken();
duke@1 2722 boolean importStatic = false;
mcimadamore@1113 2723 if (token.kind == STATIC) {
duke@1 2724 checkStaticImports();
duke@1 2725 importStatic = true;
mcimadamore@1113 2726 nextToken();
duke@1 2727 }
mcimadamore@1113 2728 JCExpression pid = toP(F.at(token.pos).Ident(ident()));
duke@1 2729 do {
mcimadamore@1113 2730 int pos1 = token.pos;
duke@1 2731 accept(DOT);
mcimadamore@1113 2732 if (token.kind == STAR) {
duke@1 2733 pid = to(F.at(pos1).Select(pid, names.asterisk));
mcimadamore@1113 2734 nextToken();
duke@1 2735 break;
duke@1 2736 } else {
duke@1 2737 pid = toP(F.at(pos1).Select(pid, ident()));
duke@1 2738 }
mcimadamore@1113 2739 } while (token.kind == DOT);
duke@1 2740 accept(SEMI);
duke@1 2741 return toP(F.at(pos).Import(pid, importStatic));
duke@1 2742 }
duke@1 2743
duke@1 2744 /** TypeDeclaration = ClassOrInterfaceOrEnumDeclaration
duke@1 2745 * | ";"
duke@1 2746 */
jjg@1280 2747 JCTree typeDeclaration(JCModifiers mods, Comment docComment) {
mcimadamore@1113 2748 int pos = token.pos;
mcimadamore@1113 2749 if (mods == null && token.kind == SEMI) {
mcimadamore@1113 2750 nextToken();
duke@1 2751 return toP(F.at(pos).Skip());
duke@1 2752 } else {
mcimadamore@1113 2753 return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment);
duke@1 2754 }
duke@1 2755 }
duke@1 2756
duke@1 2757 /** ClassOrInterfaceOrEnumDeclaration = ModifiersOpt
duke@1 2758 * (ClassDeclaration | InterfaceDeclaration | EnumDeclaration)
duke@1 2759 * @param mods Any modifiers starting the class or interface declaration
duke@1 2760 * @param dc The documentation comment for the class, or null.
duke@1 2761 */
jjg@1280 2762 JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
mcimadamore@1113 2763 if (token.kind == CLASS) {
duke@1 2764 return classDeclaration(mods, dc);
mcimadamore@1113 2765 } else if (token.kind == INTERFACE) {
duke@1 2766 return interfaceDeclaration(mods, dc);
duke@1 2767 } else if (allowEnums) {
mcimadamore@1113 2768 if (token.kind == ENUM) {
duke@1 2769 return enumDeclaration(mods, dc);
duke@1 2770 } else {
mcimadamore@1113 2771 int pos = token.pos;
duke@1 2772 List<JCTree> errs;
mcimadamore@1113 2773 if (token.kind == IDENTIFIER) {
duke@1 2774 errs = List.<JCTree>of(mods, toP(F.at(pos).Ident(ident())));
mcimadamore@1113 2775 setErrorEndPos(token.pos);
duke@1 2776 } else {
duke@1 2777 errs = List.<JCTree>of(mods);
duke@1 2778 }
duke@1 2779 return toP(F.Exec(syntaxError(pos, errs, "expected3",
mcimadamore@80 2780 CLASS, INTERFACE, ENUM)));
duke@1 2781 }
duke@1 2782 } else {
mcimadamore@1113 2783 if (token.kind == ENUM) {
mcimadamore@1113 2784 error(token.pos, "enums.not.supported.in.source", source.name);
duke@1 2785 allowEnums = true;
duke@1 2786 return enumDeclaration(mods, dc);
duke@1 2787 }
mcimadamore@1113 2788 int pos = token.pos;
duke@1 2789 List<JCTree> errs;
mcimadamore@1113 2790 if (token.kind == IDENTIFIER) {
duke@1 2791 errs = List.<JCTree>of(mods, toP(F.at(pos).Ident(ident())));
mcimadamore@1113 2792 setErrorEndPos(token.pos);
duke@1 2793 } else {
duke@1 2794 errs = List.<JCTree>of(mods);
duke@1 2795 }
duke@1 2796 return toP(F.Exec(syntaxError(pos, errs, "expected2",
mcimadamore@80 2797 CLASS, INTERFACE)));
duke@1 2798 }
duke@1 2799 }
duke@1 2800
duke@1 2801 /** ClassDeclaration = CLASS Ident TypeParametersOpt [EXTENDS Type]
duke@1 2802 * [IMPLEMENTS TypeList] ClassBody
duke@1 2803 * @param mods The modifiers starting the class declaration
duke@1 2804 * @param dc The documentation comment for the class, or null.
duke@1 2805 */
jjg@1280 2806 protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
mcimadamore@1113 2807 int pos = token.pos;
duke@1 2808 accept(CLASS);
duke@1 2809 Name name = ident();
duke@1 2810
duke@1 2811 List<JCTypeParameter> typarams = typeParametersOpt();
duke@1 2812
jjg@904 2813 JCExpression extending = null;
mcimadamore@1113 2814 if (token.kind == EXTENDS) {
mcimadamore@1113 2815 nextToken();
jjg@111 2816 extending = parseType();
duke@1 2817 }
duke@1 2818 List<JCExpression> implementing = List.nil();
mcimadamore@1113 2819 if (token.kind == IMPLEMENTS) {
mcimadamore@1113 2820 nextToken();
duke@1 2821 implementing = typeList();
duke@1 2822 }
duke@1 2823 List<JCTree> defs = classOrInterfaceBody(name, false);
duke@1 2824 JCClassDecl result = toP(F.at(pos).ClassDef(
duke@1 2825 mods, name, typarams, extending, implementing, defs));
duke@1 2826 attach(result, dc);
duke@1 2827 return result;
duke@1 2828 }
duke@1 2829
duke@1 2830 /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
duke@1 2831 * [EXTENDS TypeList] InterfaceBody
duke@1 2832 * @param mods The modifiers starting the interface declaration
duke@1 2833 * @param dc The documentation comment for the interface, or null.
duke@1 2834 */
jjg@1280 2835 protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
mcimadamore@1113 2836 int pos = token.pos;
duke@1 2837 accept(INTERFACE);
duke@1 2838 Name name = ident();
duke@1 2839
duke@1 2840 List<JCTypeParameter> typarams = typeParametersOpt();
duke@1 2841
duke@1 2842 List<JCExpression> extending = List.nil();
mcimadamore@1113 2843 if (token.kind == EXTENDS) {
mcimadamore@1113 2844 nextToken();
duke@1 2845 extending = typeList();
duke@1 2846 }
duke@1 2847 List<JCTree> defs = classOrInterfaceBody(name, true);
duke@1 2848 JCClassDecl result = toP(F.at(pos).ClassDef(
duke@1 2849 mods, name, typarams, null, extending, defs));
duke@1 2850 attach(result, dc);
duke@1 2851 return result;
duke@1 2852 }
duke@1 2853
duke@1 2854 /** EnumDeclaration = ENUM Ident [IMPLEMENTS TypeList] EnumBody
duke@1 2855 * @param mods The modifiers starting the enum declaration
duke@1 2856 * @param dc The documentation comment for the enum, or null.
duke@1 2857 */
jjg@1280 2858 protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
mcimadamore@1113 2859 int pos = token.pos;
duke@1 2860 accept(ENUM);
duke@1 2861 Name name = ident();
duke@1 2862
duke@1 2863 List<JCExpression> implementing = List.nil();
mcimadamore@1113 2864 if (token.kind == IMPLEMENTS) {
mcimadamore@1113 2865 nextToken();
duke@1 2866 implementing = typeList();
duke@1 2867 }
duke@1 2868
duke@1 2869 List<JCTree> defs = enumBody(name);
jjg@482 2870 mods.flags |= Flags.ENUM;
duke@1 2871 JCClassDecl result = toP(F.at(pos).
jjg@482 2872 ClassDef(mods, name, List.<JCTypeParameter>nil(),
duke@1 2873 null, implementing, defs));
duke@1 2874 attach(result, dc);
duke@1 2875 return result;
duke@1 2876 }
duke@1 2877
duke@1 2878 /** EnumBody = "{" { EnumeratorDeclarationList } [","]
duke@1 2879 * [ ";" {ClassBodyDeclaration} ] "}"
duke@1 2880 */
duke@1 2881 List<JCTree> enumBody(Name enumName) {
duke@1 2882 accept(LBRACE);
duke@1 2883 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
mcimadamore@1113 2884 if (token.kind == COMMA) {
mcimadamore@1113 2885 nextToken();
mcimadamore@1113 2886 } else if (token.kind != RBRACE && token.kind != SEMI) {
duke@1 2887 defs.append(enumeratorDeclaration(enumName));
mcimadamore@1113 2888 while (token.kind == COMMA) {
mcimadamore@1113 2889 nextToken();
mcimadamore@1113 2890 if (token.kind == RBRACE || token.kind == SEMI) break;
duke@1 2891 defs.append(enumeratorDeclaration(enumName));
duke@1 2892 }
mcimadamore@1113 2893 if (token.kind != SEMI && token.kind != RBRACE) {
mcimadamore@1113 2894 defs.append(syntaxError(token.pos, "expected3",
mcimadamore@80 2895 COMMA, RBRACE, SEMI));
mcimadamore@1113 2896 nextToken();
duke@1 2897 }
duke@1 2898 }
mcimadamore@1113 2899 if (token.kind == SEMI) {
mcimadamore@1113 2900 nextToken();
mcimadamore@1113 2901 while (token.kind != RBRACE && token.kind != EOF) {
duke@1 2902 defs.appendList(classOrInterfaceBodyDeclaration(enumName,
duke@1 2903 false));
ksrini@1138 2904 if (token.pos <= endPosTable.errorEndPos) {
duke@1 2905 // error recovery
duke@1 2906 skip(false, true, true, false);
duke@1 2907 }
duke@1 2908 }
duke@1 2909 }
duke@1 2910 accept(RBRACE);
duke@1 2911 return defs.toList();
duke@1 2912 }
duke@1 2913
duke@1 2914 /** EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ]
duke@1 2915 */
duke@1 2916 JCTree enumeratorDeclaration(Name enumName) {
jjg@1280 2917 Comment dc = token.comment(CommentStyle.JAVADOC);
duke@1 2918 int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM;
mcimadamore@1125 2919 if (token.deprecatedFlag()) {
duke@1 2920 flags |= Flags.DEPRECATED;
duke@1 2921 }
mcimadamore@1113 2922 int pos = token.pos;
jjg@722 2923 List<JCAnnotation> annotations = annotationsOpt();
duke@1 2924 JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations);
duke@1 2925 List<JCExpression> typeArgs = typeArgumentsOpt();
mcimadamore@1113 2926 int identPos = token.pos;
duke@1 2927 Name name = ident();
mcimadamore@1113 2928 int createPos = token.pos;
mcimadamore@1113 2929 List<JCExpression> args = (token.kind == LPAREN)
duke@1 2930 ? arguments() : List.<JCExpression>nil();
duke@1 2931 JCClassDecl body = null;
mcimadamore@1113 2932 if (token.kind == LBRACE) {
duke@1 2933 JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC);
duke@1 2934 List<JCTree> defs = classOrInterfaceBody(names.empty, false);
duke@1 2935 body = toP(F.at(identPos).AnonymousClassDef(mods1, defs));
duke@1 2936 }
duke@1 2937 if (args.isEmpty() && body == null)
jjg@469 2938 createPos = identPos;
jjg@469 2939 JCIdent ident = F.at(identPos).Ident(enumName);
duke@1 2940 JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body);
jjg@469 2941 if (createPos != identPos)
mcimadamore@1113 2942 storeEnd(create, S.prevToken().endPos);
jjg@469 2943 ident = F.at(identPos).Ident(enumName);
duke@1 2944 JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create));
duke@1 2945 attach(result, dc);
duke@1 2946 return result;
duke@1 2947 }
duke@1 2948
duke@1 2949 /** TypeList = Type {"," Type}
duke@1 2950 */
duke@1 2951 List<JCExpression> typeList() {
duke@1 2952 ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>();
jjg@111 2953 ts.append(parseType());
mcimadamore@1113 2954 while (token.kind == COMMA) {
mcimadamore@1113 2955 nextToken();
jjg@111 2956 ts.append(parseType());
duke@1 2957 }
duke@1 2958 return ts.toList();
duke@1 2959 }
duke@1 2960
duke@1 2961 /** ClassBody = "{" {ClassBodyDeclaration} "}"
duke@1 2962 * InterfaceBody = "{" {InterfaceBodyDeclaration} "}"
duke@1 2963 */
duke@1 2964 List<JCTree> classOrInterfaceBody(Name className, boolean isInterface) {
duke@1 2965 accept(LBRACE);
ksrini@1138 2966 if (token.pos <= endPosTable.errorEndPos) {
duke@1 2967 // error recovery
duke@1 2968 skip(false, true, false, false);
mcimadamore@1113 2969 if (token.kind == LBRACE)
mcimadamore@1113 2970 nextToken();
duke@1 2971 }
duke@1 2972 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
mcimadamore@1113 2973 while (token.kind != RBRACE && token.kind != EOF) {
duke@1 2974 defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface));
ksrini@1138 2975 if (token.pos <= endPosTable.errorEndPos) {
duke@1 2976 // error recovery
duke@1 2977 skip(false, true, true, false);
duke@1 2978 }
duke@1 2979 }
duke@1 2980 accept(RBRACE);
duke@1 2981 return defs.toList();
duke@1 2982 }
duke@1 2983
duke@1 2984 /** ClassBodyDeclaration =
duke@1 2985 * ";"
duke@1 2986 * | [STATIC] Block
duke@1 2987 * | ModifiersOpt
duke@1 2988 * ( Type Ident
duke@1 2989 * ( VariableDeclaratorsRest ";" | MethodDeclaratorRest )
duke@1 2990 * | VOID Ident MethodDeclaratorRest
duke@1 2991 * | TypeParameters (Type | VOID) Ident MethodDeclaratorRest
duke@1 2992 * | Ident ConstructorDeclaratorRest
duke@1 2993 * | TypeParameters Ident ConstructorDeclaratorRest
duke@1 2994 * | ClassOrInterfaceOrEnumDeclaration
duke@1 2995 * )
duke@1 2996 * InterfaceBodyDeclaration =
duke@1 2997 * ";"
duke@1 2998 * | ModifiersOpt Type Ident
duke@1 2999 * ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" )
duke@1 3000 */
ksrini@1074 3001 protected List<JCTree> classOrInterfaceBodyDeclaration(Name className, boolean isInterface) {
mcimadamore@1113 3002 if (token.kind == SEMI) {
mcimadamore@1113 3003 nextToken();
jjg@667 3004 return List.<JCTree>nil();
duke@1 3005 } else {
jjg@1280 3006 Comment dc = token.comment(CommentStyle.JAVADOC);
mcimadamore@1113 3007 int pos = token.pos;
duke@1 3008 JCModifiers mods = modifiersOpt();
mcimadamore@1113 3009 if (token.kind == CLASS ||
mcimadamore@1113 3010 token.kind == INTERFACE ||
mcimadamore@1113 3011 allowEnums && token.kind == ENUM) {
duke@1 3012 return List.<JCTree>of(classOrInterfaceOrEnumDeclaration(mods, dc));
mcimadamore@1113 3013 } else if (token.kind == LBRACE && !isInterface &&
duke@1 3014 (mods.flags & Flags.StandardFlags & ~Flags.STATIC) == 0 &&
duke@1 3015 mods.annotations.isEmpty()) {
duke@1 3016 return List.<JCTree>of(block(pos, mods.flags));
duke@1 3017 } else {
mcimadamore@1113 3018 pos = token.pos;
duke@1 3019 List<JCTypeParameter> typarams = typeParametersOpt();
jjg@817 3020 // if there are type parameters but no modifiers, save the start
jjg@817 3021 // position of the method in the modifiers.
jjg@817 3022 if (typarams.nonEmpty() && mods.pos == Position.NOPOS) {
jjg@817 3023 mods.pos = pos;
jjg@817 3024 storeEnd(mods, pos);
jjg@817 3025 }
mcimadamore@1113 3026 Token tk = token;
mcimadamore@1113 3027 pos = token.pos;
duke@1 3028 JCExpression type;
mcimadamore@1113 3029 boolean isVoid = token.kind == VOID;
duke@1 3030 if (isVoid) {
jjg@1374 3031 type = to(F.at(pos).TypeIdent(TypeTag.VOID));
mcimadamore@1113 3032 nextToken();
duke@1 3033 } else {
jjg@722 3034 type = parseType();
duke@1 3035 }
jjg@1127 3036 if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
mcimadamore@1113 3037 if (isInterface || tk.name() != className)
jjg@726 3038 error(pos, "invalid.meth.decl.ret.type.req");
duke@1 3039 return List.of(methodDeclaratorRest(
duke@1 3040 pos, mods, null, names.init, typarams,
duke@1 3041 isInterface, true, dc));
duke@1 3042 } else {
mcimadamore@1113 3043 pos = token.pos;
mcimadamore@1113 3044 Name name = ident();
mcimadamore@1113 3045 if (token.kind == LPAREN) {
duke@1 3046 return List.of(methodDeclaratorRest(
duke@1 3047 pos, mods, type, name, typarams,
duke@1 3048 isInterface, isVoid, dc));
duke@1 3049 } else if (!isVoid && typarams.isEmpty()) {
duke@1 3050 List<JCTree> defs =
duke@1 3051 variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
duke@1 3052 new ListBuffer<JCTree>()).toList();
mcimadamore@1113 3053 storeEnd(defs.last(), token.endPos);
duke@1 3054 accept(SEMI);
duke@1 3055 return defs;
duke@1 3056 } else {
mcimadamore@1113 3057 pos = token.pos;
duke@1 3058 List<JCTree> err = isVoid
duke@1 3059 ? List.<JCTree>of(toP(F.at(pos).MethodDef(mods, name, type, typarams,
duke@1 3060 List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null)))
duke@1 3061 : null;
mcimadamore@1113 3062 return List.<JCTree>of(syntaxError(token.pos, err, "expected", LPAREN));
duke@1 3063 }
duke@1 3064 }
duke@1 3065 }
duke@1 3066 }
duke@1 3067 }
duke@1 3068
duke@1 3069 /** MethodDeclaratorRest =
jjg@722 3070 * FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
duke@1 3071 * VoidMethodDeclaratorRest =
jjg@722 3072 * FormalParameters [Throws TypeList] ( MethodBody | ";")
duke@1 3073 * InterfaceMethodDeclaratorRest =
jjg@722 3074 * FormalParameters BracketsOpt [THROWS TypeList] ";"
duke@1 3075 * VoidInterfaceMethodDeclaratorRest =
jjg@722 3076 * FormalParameters [THROWS TypeList] ";"
duke@1 3077 * ConstructorDeclaratorRest =
jjg@722 3078 * "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody
duke@1 3079 */
ksrini@1148 3080 protected JCTree methodDeclaratorRest(int pos,
duke@1 3081 JCModifiers mods,
duke@1 3082 JCExpression type,
duke@1 3083 Name name,
duke@1 3084 List<JCTypeParameter> typarams,
duke@1 3085 boolean isInterface, boolean isVoid,
jjg@1280 3086 Comment dc) {
duke@1 3087 List<JCVariableDecl> params = formalParameters();
jjg@722 3088 if (!isVoid) type = bracketsOpt(type);
duke@1 3089 List<JCExpression> thrown = List.nil();
mcimadamore@1113 3090 if (token.kind == THROWS) {
mcimadamore@1113 3091 nextToken();
duke@1 3092 thrown = qualidentList();
duke@1 3093 }
duke@1 3094 JCBlock body = null;
duke@1 3095 JCExpression defaultValue;
mcimadamore@1113 3096 if (token.kind == LBRACE) {
duke@1 3097 body = block();
duke@1 3098 defaultValue = null;
duke@1 3099 } else {
mcimadamore@1113 3100 if (token.kind == DEFAULT) {
duke@1 3101 accept(DEFAULT);
duke@1 3102 defaultValue = annotationValue();
duke@1 3103 } else {
duke@1 3104 defaultValue = null;
duke@1 3105 }
duke@1 3106 accept(SEMI);
ksrini@1138 3107 if (token.pos <= endPosTable.errorEndPos) {
duke@1 3108 // error recovery
duke@1 3109 skip(false, true, false, false);
mcimadamore@1113 3110 if (token.kind == LBRACE) {
duke@1 3111 body = block();
duke@1 3112 }
duke@1 3113 }
duke@1 3114 }
jjg@482 3115
duke@1 3116 JCMethodDecl result =
duke@1 3117 toP(F.at(pos).MethodDef(mods, name, type, typarams,
jjg@722 3118 params, thrown,
duke@1 3119 body, defaultValue));
duke@1 3120 attach(result, dc);
duke@1 3121 return result;
duke@1 3122 }
duke@1 3123
jjg@722 3124 /** QualidentList = Qualident {"," Qualident}
duke@1 3125 */
duke@1 3126 List<JCExpression> qualidentList() {
duke@1 3127 ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>();
jjg@722 3128 ts.append(qualident());
mcimadamore@1113 3129 while (token.kind == COMMA) {
mcimadamore@1113 3130 nextToken();
jjg@722 3131 ts.append(qualident());
duke@1 3132 }
duke@1 3133 return ts.toList();
duke@1 3134 }
duke@1 3135
jjg@1326 3136 /**
jjg@1326 3137 * {@literal
jjg@1326 3138 * TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"]
jjg@1326 3139 * }
duke@1 3140 */
duke@1 3141 List<JCTypeParameter> typeParametersOpt() {
mcimadamore@1113 3142 if (token.kind == LT) {
duke@1 3143 checkGenerics();
duke@1 3144 ListBuffer<JCTypeParameter> typarams = new ListBuffer<JCTypeParameter>();
mcimadamore@1113 3145 nextToken();
duke@1 3146 typarams.append(typeParameter());
mcimadamore@1113 3147 while (token.kind == COMMA) {
mcimadamore@1113 3148 nextToken();
duke@1 3149 typarams.append(typeParameter());
duke@1 3150 }
duke@1 3151 accept(GT);
duke@1 3152 return typarams.toList();
duke@1 3153 } else {
duke@1 3154 return List.nil();
duke@1 3155 }
duke@1 3156 }
duke@1 3157
jjg@1326 3158 /**
jjg@1326 3159 * {@literal
jjg@1326 3160 * TypeParameter = TypeVariable [TypeParameterBound]
duke@1 3161 * TypeParameterBound = EXTENDS Type {"&" Type}
duke@1 3162 * TypeVariable = Ident
jjg@1326 3163 * }
duke@1 3164 */
duke@1 3165 JCTypeParameter typeParameter() {
mcimadamore@1113 3166 int pos = token.pos;
duke@1 3167 Name name = ident();
duke@1 3168 ListBuffer<JCExpression> bounds = new ListBuffer<JCExpression>();
mcimadamore@1113 3169 if (token.kind == EXTENDS) {
mcimadamore@1113 3170 nextToken();
jjg@111 3171 bounds.append(parseType());
mcimadamore@1113 3172 while (token.kind == AMP) {
mcimadamore@1113 3173 nextToken();
jjg@111 3174 bounds.append(parseType());
duke@1 3175 }
duke@1 3176 }
jjg@722 3177 return toP(F.at(pos).TypeParameter(name, bounds.toList()));
duke@1 3178 }
duke@1 3179
duke@1 3180 /** FormalParameters = "(" [ FormalParameterList ] ")"
duke@1 3181 * FormalParameterList = [ FormalParameterListNovarargs , ] LastFormalParameter
duke@1 3182 * FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter
duke@1 3183 */
duke@1 3184 List<JCVariableDecl> formalParameters() {
duke@1 3185 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
duke@1 3186 JCVariableDecl lastParam = null;
duke@1 3187 accept(LPAREN);
mcimadamore@1113 3188 if (token.kind != RPAREN) {
duke@1 3189 params.append(lastParam = formalParameter());
mcimadamore@1113 3190 while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
mcimadamore@1113 3191 nextToken();
duke@1 3192 params.append(lastParam = formalParameter());
duke@1 3193 }
duke@1 3194 }
duke@1 3195 accept(RPAREN);
duke@1 3196 return params.toList();
duke@1 3197 }
duke@1 3198
mcimadamore@1144 3199 List<JCVariableDecl> implicitParameters(boolean hasParens) {
mcimadamore@1144 3200 if (hasParens) {
mcimadamore@1144 3201 accept(LPAREN);
mcimadamore@1144 3202 }
mcimadamore@1144 3203 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
mcimadamore@1144 3204 if (token.kind != RPAREN && token.kind != ARROW) {
mcimadamore@1144 3205 params.append(implicitParameter());
mcimadamore@1144 3206 while (token.kind == COMMA) {
mcimadamore@1144 3207 nextToken();
mcimadamore@1144 3208 params.append(implicitParameter());
mcimadamore@1144 3209 }
mcimadamore@1144 3210 }
mcimadamore@1144 3211 if (hasParens) {
mcimadamore@1144 3212 accept(RPAREN);
mcimadamore@1144 3213 }
mcimadamore@1144 3214 return params.toList();
mcimadamore@1144 3215 }
mcimadamore@1144 3216
duke@1 3217 JCModifiers optFinal(long flags) {
duke@1 3218 JCModifiers mods = modifiersOpt();
duke@1 3219 checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED));
duke@1 3220 mods.flags |= flags;
duke@1 3221 return mods;
duke@1 3222 }
duke@1 3223
duke@1 3224 /** FormalParameter = { FINAL | '@' Annotation } Type VariableDeclaratorId
duke@1 3225 * LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter
duke@1 3226 */
ksrini@1074 3227 protected JCVariableDecl formalParameter() {
duke@1 3228 JCModifiers mods = optFinal(Flags.PARAMETER);
jjg@111 3229 JCExpression type = parseType();
mcimadamore@1113 3230 if (token.kind == ELLIPSIS) {
duke@1 3231 checkVarargs();
duke@1 3232 mods.flags |= Flags.VARARGS;
mcimadamore@1113 3233 type = to(F.at(token.pos).TypeArray(type));
mcimadamore@1113 3234 nextToken();
duke@1 3235 }
duke@1 3236 return variableDeclaratorId(mods, type);
duke@1 3237 }
duke@1 3238
mcimadamore@1144 3239 protected JCVariableDecl implicitParameter() {
mcimadamore@1144 3240 JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
mcimadamore@1144 3241 return variableDeclaratorId(mods, null);
mcimadamore@1144 3242 }
mcimadamore@1144 3243
duke@1 3244 /* ---------- auxiliary methods -------------- */
duke@1 3245
jjg@726 3246 void error(int pos, String key, Object ... args) {
jjg@726 3247 log.error(DiagnosticFlag.SYNTAX, pos, key, args);
jjg@726 3248 }
jjg@726 3249
ksrini@1074 3250 void error(DiagnosticPosition pos, String key, Object ... args) {
ksrini@1074 3251 log.error(DiagnosticFlag.SYNTAX, pos, key, args);
ksrini@1074 3252 }
ksrini@1074 3253
jjg@726 3254 void warning(int pos, String key, Object ... args) {
jjg@726 3255 log.warning(pos, key, args);
jjg@726 3256 }
jjg@726 3257
duke@1 3258 /** Check that given tree is a legal expression statement.
duke@1 3259 */
duke@1 3260 protected JCExpression checkExprStat(JCExpression t) {
mcimadamore@1433 3261 if (!TreeInfo.isExpressionStatement(t)) {
ksrini@1074 3262 JCExpression ret = F.at(t.pos).Erroneous(List.<JCTree>of(t));
ksrini@1074 3263 error(ret, "not.stmt");
ksrini@1074 3264 return ret;
mcimadamore@1433 3265 } else {
mcimadamore@1433 3266 return t;
duke@1 3267 }
duke@1 3268 }
duke@1 3269
duke@1 3270 /** Return precedence of operator represented by token,
duke@1 3271 * -1 if token is not a binary operator. @see TreeInfo.opPrec
duke@1 3272 */
mcimadamore@1113 3273 static int prec(TokenKind token) {
jjg@1127 3274 JCTree.Tag oc = optag(token);
jjg@1127 3275 return (oc != NO_TAG) ? TreeInfo.opPrec(oc) : -1;
duke@1 3276 }
duke@1 3277
jjg@516 3278 /**
jjg@516 3279 * Return the lesser of two positions, making allowance for either one
jjg@516 3280 * being unset.
jjg@516 3281 */
jjg@516 3282 static int earlier(int pos1, int pos2) {
jjg@516 3283 if (pos1 == Position.NOPOS)
jjg@516 3284 return pos2;
jjg@516 3285 if (pos2 == Position.NOPOS)
jjg@516 3286 return pos1;
jjg@516 3287 return (pos1 < pos2 ? pos1 : pos2);
jjg@516 3288 }
jjg@516 3289
duke@1 3290 /** Return operation tag of binary operator represented by token,
jjg@1127 3291 * No_TAG if token is not a binary operator.
duke@1 3292 */
jjg@1127 3293 static JCTree.Tag optag(TokenKind token) {
duke@1 3294 switch (token) {
duke@1 3295 case BARBAR:
jjg@1127 3296 return OR;
duke@1 3297 case AMPAMP:
jjg@1127 3298 return AND;
duke@1 3299 case BAR:
jjg@1127 3300 return BITOR;
duke@1 3301 case BAREQ:
jjg@1127 3302 return BITOR_ASG;
duke@1 3303 case CARET:
jjg@1127 3304 return BITXOR;
duke@1 3305 case CARETEQ:
jjg@1127 3306 return BITXOR_ASG;
duke@1 3307 case AMP:
jjg@1127 3308 return BITAND;
duke@1 3309 case AMPEQ:
jjg@1127 3310 return BITAND_ASG;
duke@1 3311 case EQEQ:
jjg@1127 3312 return JCTree.Tag.EQ;
duke@1 3313 case BANGEQ:
jjg@1127 3314 return NE;
duke@1 3315 case LT:
jjg@1127 3316 return JCTree.Tag.LT;
duke@1 3317 case GT:
jjg@1127 3318 return JCTree.Tag.GT;
duke@1 3319 case LTEQ:
jjg@1127 3320 return LE;
duke@1 3321 case GTEQ:
jjg@1127 3322 return GE;
duke@1 3323 case LTLT:
jjg@1127 3324 return SL;
duke@1 3325 case LTLTEQ:
jjg@1127 3326 return SL_ASG;
duke@1 3327 case GTGT:
jjg@1127 3328 return SR;
duke@1 3329 case GTGTEQ:
jjg@1127 3330 return SR_ASG;
duke@1 3331 case GTGTGT:
jjg@1127 3332 return USR;
duke@1 3333 case GTGTGTEQ:
jjg@1127 3334 return USR_ASG;
duke@1 3335 case PLUS:
jjg@1127 3336 return JCTree.Tag.PLUS;
duke@1 3337 case PLUSEQ:
jjg@1127 3338 return PLUS_ASG;
duke@1 3339 case SUB:
jjg@1127 3340 return MINUS;
duke@1 3341 case SUBEQ:
jjg@1127 3342 return MINUS_ASG;
duke@1 3343 case STAR:
jjg@1127 3344 return MUL;
duke@1 3345 case STAREQ:
jjg@1127 3346 return MUL_ASG;
duke@1 3347 case SLASH:
jjg@1127 3348 return DIV;
duke@1 3349 case SLASHEQ:
jjg@1127 3350 return DIV_ASG;
duke@1 3351 case PERCENT:
jjg@1127 3352 return MOD;
duke@1 3353 case PERCENTEQ:
jjg@1127 3354 return MOD_ASG;
duke@1 3355 case INSTANCEOF:
jjg@1127 3356 return TYPETEST;
duke@1 3357 default:
jjg@1127 3358 return NO_TAG;
duke@1 3359 }
duke@1 3360 }
duke@1 3361
duke@1 3362 /** Return operation tag of unary operator represented by token,
jjg@1127 3363 * No_TAG if token is not a binary operator.
duke@1 3364 */
jjg@1127 3365 static JCTree.Tag unoptag(TokenKind token) {
duke@1 3366 switch (token) {
duke@1 3367 case PLUS:
jjg@1127 3368 return POS;
duke@1 3369 case SUB:
jjg@1127 3370 return NEG;
duke@1 3371 case BANG:
jjg@1127 3372 return NOT;
duke@1 3373 case TILDE:
jjg@1127 3374 return COMPL;
duke@1 3375 case PLUSPLUS:
jjg@1127 3376 return PREINC;
duke@1 3377 case SUBSUB:
jjg@1127 3378 return PREDEC;
duke@1 3379 default:
jjg@1127 3380 return NO_TAG;
duke@1 3381 }
duke@1 3382 }
duke@1 3383
duke@1 3384 /** Return type tag of basic type represented by token,
jjg@1374 3385 * NONE if token is not a basic type identifier.
duke@1 3386 */
jjg@1374 3387 static TypeTag typetag(TokenKind token) {
duke@1 3388 switch (token) {
duke@1 3389 case BYTE:
jjg@1374 3390 return TypeTag.BYTE;
duke@1 3391 case CHAR:
jjg@1374 3392 return TypeTag.CHAR;
duke@1 3393 case SHORT:
jjg@1374 3394 return TypeTag.SHORT;
duke@1 3395 case INT:
jjg@1374 3396 return TypeTag.INT;
duke@1 3397 case LONG:
jjg@1374 3398 return TypeTag.LONG;
duke@1 3399 case FLOAT:
jjg@1374 3400 return TypeTag.FLOAT;
duke@1 3401 case DOUBLE:
jjg@1374 3402 return TypeTag.DOUBLE;
duke@1 3403 case BOOLEAN:
jjg@1374 3404 return TypeTag.BOOLEAN;
duke@1 3405 default:
jjg@1374 3406 return TypeTag.NONE;
duke@1 3407 }
duke@1 3408 }
duke@1 3409
duke@1 3410 void checkGenerics() {
duke@1 3411 if (!allowGenerics) {
mcimadamore@1113 3412 error(token.pos, "generics.not.supported.in.source", source.name);
duke@1 3413 allowGenerics = true;
duke@1 3414 }
duke@1 3415 }
duke@1 3416 void checkVarargs() {
duke@1 3417 if (!allowVarargs) {
mcimadamore@1113 3418 error(token.pos, "varargs.not.supported.in.source", source.name);
duke@1 3419 allowVarargs = true;
duke@1 3420 }
duke@1 3421 }
duke@1 3422 void checkForeach() {
duke@1 3423 if (!allowForeach) {
mcimadamore@1113 3424 error(token.pos, "foreach.not.supported.in.source", source.name);
duke@1 3425 allowForeach = true;
duke@1 3426 }
duke@1 3427 }
duke@1 3428 void checkStaticImports() {
duke@1 3429 if (!allowStaticImport) {
mcimadamore@1113 3430 error(token.pos, "static.import.not.supported.in.source", source.name);
duke@1 3431 allowStaticImport = true;
duke@1 3432 }
duke@1 3433 }
duke@1 3434 void checkAnnotations() {
duke@1 3435 if (!allowAnnotations) {
mcimadamore@1113 3436 error(token.pos, "annotations.not.supported.in.source", source.name);
duke@1 3437 allowAnnotations = true;
duke@1 3438 }
duke@1 3439 }
mcimadamore@537 3440 void checkDiamond() {
mcimadamore@537 3441 if (!allowDiamond) {
mcimadamore@1113 3442 error(token.pos, "diamond.not.supported.in.source", source.name);
mcimadamore@537 3443 allowDiamond = true;
mcimadamore@537 3444 }
mcimadamore@537 3445 }
mcimadamore@550 3446 void checkMulticatch() {
mcimadamore@550 3447 if (!allowMulticatch) {
mcimadamore@1113 3448 error(token.pos, "multicatch.not.supported.in.source", source.name);
mcimadamore@550 3449 allowMulticatch = true;
darcy@609 3450 }
darcy@609 3451 }
mcimadamore@743 3452 void checkTryWithResources() {
darcy@609 3453 if (!allowTWR) {
mcimadamore@1113 3454 error(token.pos, "try.with.resources.not.supported.in.source", source.name);
darcy@609 3455 allowTWR = true;
darcy@609 3456 }
mcimadamore@550 3457 }
mcimadamore@1144 3458 void checkLambda() {
mcimadamore@1144 3459 if (!allowLambda) {
mcimadamore@1144 3460 log.error(token.pos, "lambda.not.supported.in.source", source.name);
mcimadamore@1144 3461 allowLambda = true;
mcimadamore@1144 3462 }
mcimadamore@1144 3463 }
mcimadamore@1145 3464 void checkMethodReferences() {
mcimadamore@1145 3465 if (!allowMethodReferences) {
mcimadamore@1145 3466 log.error(token.pos, "method.references.not.supported.in.source", source.name);
mcimadamore@1145 3467 allowMethodReferences = true;
mcimadamore@1145 3468 }
mcimadamore@1145 3469 }
mcimadamore@1366 3470 void checkDefaultMethods() {
mcimadamore@1366 3471 if (!allowDefaultMethods) {
mcimadamore@1366 3472 log.error(token.pos, "default.methods.not.supported.in.source", source.name);
mcimadamore@1366 3473 allowDefaultMethods = true;
mcimadamore@1366 3474 }
mcimadamore@1366 3475 }
mcimadamore@1436 3476 void checkIntersectionTypesInCast() {
mcimadamore@1436 3477 if (!allowIntersectionTypesInCast) {
mcimadamore@1436 3478 log.error(token.pos, "intersection.types.in.cast.not.supported.in.source", source.name);
mcimadamore@1436 3479 allowIntersectionTypesInCast = true;
mcimadamore@1436 3480 }
mcimadamore@1436 3481 }
ksrini@1138 3482
ksrini@1138 3483 /*
ksrini@1138 3484 * a functional source tree and end position mappings
ksrini@1138 3485 */
ksrini@1138 3486 protected class SimpleEndPosTable extends AbstractEndPosTable {
ksrini@1138 3487
ksrini@1138 3488 private final Map<JCTree, Integer> endPosMap;
ksrini@1138 3489
ksrini@1138 3490 SimpleEndPosTable() {
ksrini@1138 3491 endPosMap = new HashMap<JCTree, Integer>();
ksrini@1138 3492 }
ksrini@1138 3493
ksrini@1138 3494 protected void storeEnd(JCTree tree, int endpos) {
ksrini@1138 3495 endPosMap.put(tree, errorEndPos > endpos ? errorEndPos : endpos);
ksrini@1138 3496 }
ksrini@1138 3497
ksrini@1138 3498 protected <T extends JCTree> T to(T t) {
ksrini@1138 3499 storeEnd(t, token.endPos);
ksrini@1138 3500 return t;
ksrini@1138 3501 }
ksrini@1138 3502
ksrini@1138 3503 protected <T extends JCTree> T toP(T t) {
ksrini@1138 3504 storeEnd(t, S.prevToken().endPos);
ksrini@1138 3505 return t;
ksrini@1138 3506 }
ksrini@1138 3507
ksrini@1138 3508 public int getEndPos(JCTree tree) {
ksrini@1138 3509 Integer value = endPosMap.get(tree);
ksrini@1138 3510 return (value == null) ? Position.NOPOS : value;
ksrini@1138 3511 }
ksrini@1138 3512
ksrini@1138 3513 public int replaceTree(JCTree oldTree, JCTree newTree) {
ksrini@1138 3514 Integer pos = endPosMap.remove(oldTree);
ksrini@1138 3515 if (pos != null) {
ksrini@1138 3516 endPosMap.put(newTree, pos);
ksrini@1138 3517 return pos;
ksrini@1138 3518 }
ksrini@1138 3519 return Position.NOPOS;
ksrini@1138 3520 }
ksrini@1138 3521 }
ksrini@1138 3522
ksrini@1138 3523 /*
ksrini@1138 3524 * a default skeletal implementation without any mapping overhead.
ksrini@1138 3525 */
ksrini@1138 3526 protected class EmptyEndPosTable extends AbstractEndPosTable {
ksrini@1138 3527
ksrini@1138 3528 protected void storeEnd(JCTree tree, int endpos) { /* empty */ }
ksrini@1138 3529
ksrini@1138 3530 protected <T extends JCTree> T to(T t) {
ksrini@1138 3531 return t;
ksrini@1138 3532 }
ksrini@1138 3533
ksrini@1138 3534 protected <T extends JCTree> T toP(T t) {
ksrini@1138 3535 return t;
ksrini@1138 3536 }
ksrini@1138 3537
ksrini@1138 3538 public int getEndPos(JCTree tree) {
ksrini@1138 3539 return Position.NOPOS;
ksrini@1138 3540 }
ksrini@1138 3541
ksrini@1138 3542 public int replaceTree(JCTree oldTree, JCTree newTree) {
ksrini@1138 3543 return Position.NOPOS;
ksrini@1138 3544 }
ksrini@1138 3545
ksrini@1138 3546 }
ksrini@1138 3547
ksrini@1138 3548 protected abstract class AbstractEndPosTable implements EndPosTable {
ksrini@1138 3549
ksrini@1138 3550 /**
ksrini@1138 3551 * Store the last error position.
ksrini@1138 3552 */
ksrini@1138 3553 protected int errorEndPos;
ksrini@1138 3554
ksrini@1138 3555 /**
ksrini@1138 3556 * Store ending position for a tree, the value of which is the greater
ksrini@1138 3557 * of last error position and the given ending position.
ksrini@1138 3558 * @param tree The tree.
ksrini@1138 3559 * @param endpos The ending position to associate with the tree.
ksrini@1138 3560 */
ksrini@1138 3561 protected abstract void storeEnd(JCTree tree, int endpos);
ksrini@1138 3562
ksrini@1138 3563 /**
ksrini@1138 3564 * Store current token's ending position for a tree, the value of which
ksrini@1138 3565 * will be the greater of last error position and the ending position of
ksrini@1138 3566 * the current token.
ksrini@1138 3567 * @param t The tree.
ksrini@1138 3568 */
ksrini@1138 3569 protected abstract <T extends JCTree> T to(T t);
ksrini@1138 3570
ksrini@1138 3571 /**
ksrini@1138 3572 * Store current token's ending position for a tree, the value of which
ksrini@1138 3573 * will be the greater of last error position and the ending position of
ksrini@1138 3574 * the previous token.
ksrini@1138 3575 * @param t The tree.
ksrini@1138 3576 */
ksrini@1138 3577 protected abstract <T extends JCTree> T toP(T t);
ksrini@1138 3578
ksrini@1138 3579 /**
ksrini@1138 3580 * Set the error position during the parsing phases, the value of which
ksrini@1138 3581 * will be set only if it is greater than the last stored error position.
ksrini@1138 3582 * @param errPos The error position
ksrini@1138 3583 */
ksrini@1138 3584 protected void setErrorEndPos(int errPos) {
ksrini@1138 3585 if (errPos > errorEndPos) {
ksrini@1138 3586 errorEndPos = errPos;
ksrini@1138 3587 }
ksrini@1138 3588 }
ksrini@1138 3589 }
duke@1 3590 }

mercurial