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

Thu, 04 Oct 2012 13:04:53 +0100

author
mcimadamore
date
Thu, 04 Oct 2012 13:04:53 +0100
changeset 1347
1408af4cd8b0
parent 1346
20e4a54b1629
child 1348
573ceb23beeb
permissions
-rw-r--r--

7177387: Add target-typing support in method context
Summary: Add support for deferred types and speculative attribution
Reviewed-by: jjg, dlsmith

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

mercurial