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

Mon, 03 Jun 2013 17:09:26 -0700

author
jjg
date
Mon, 03 Jun 2013 17:09:26 -0700
changeset 1796
242bcad5be74
parent 1778
58329d9f6b68
child 1852
bf020de5a6db
permissions
-rw-r--r--

8006615: [doclint] move remaining messages into resource bundle
Reviewed-by: mcimadamore, vromero

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

mercurial