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

Thu, 25 Oct 2012 11:09:36 -0700

author
jjg
date
Thu, 25 Oct 2012 11:09:36 -0700
changeset 1374
c002fdee76fd
parent 1366
12cf6bfd8c05
child 1400
19d6ba779759
permissions
-rw-r--r--

7200915: convert TypeTags from a series of small ints to an enum
Reviewed-by: jjg, mcimadamore
Contributed-by: vicente.romero@oracle.com

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

mercurial