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

Fri, 30 Nov 2012 15:14:36 +0000

author
mcimadamore
date
Fri, 30 Nov 2012 15:14:36 +0000
changeset 1435
9b26c96f5138
parent 1433
4f9853659bf1
child 1436
f6f1fd261f57
permissions
-rw-r--r--

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

mercurial