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

Mon, 25 Mar 2013 16:55:14 -0700

author
mfang
date
Mon, 25 Mar 2013 16:55:14 -0700
changeset 1658
fdf30b225e1c
parent 1583
186023614cd3
child 1680
3f3cc8d3f13c
permissions
-rw-r--r--

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

mercurial