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

Mon, 21 Jan 2013 20:19:53 +0000

author
mcimadamore
date
Mon, 21 Jan 2013 20:19:53 +0000
changeset 1513
cf84b07a82db
parent 1511
c7c41a044e7c
child 1521
71f35e4b93a5
permissions
-rw-r--r--

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

mercurial