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

Mon, 14 Nov 2011 15:11:10 -0800

author
ksrini
date
Mon, 14 Nov 2011 15:11:10 -0800
changeset 1138
7375d4979bd3
parent 1127
ca49d50318dc
child 1144
9448fe783fd2
permissions
-rw-r--r--

7106166: (javac) re-factor EndPos parser
Reviewed-by: jjg

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

mercurial