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

Fri, 09 May 2014 20:33:21 -0700

author
mfang
date
Fri, 09 May 2014 20:33:21 -0700
changeset 2388
0add97444be9
parent 2355
4f7d19235357
child 2372
7daae506441f
permissions
-rw-r--r--

8041424: 8u20 l10n resource file translation update 1
Reviewed-by: naoto, yhuang

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

mercurial