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

Fri, 04 Nov 2011 12:36:40 +0000

author
mcimadamore
date
Fri, 04 Nov 2011 12:36:40 +0000
changeset 1125
56830d5cb5bb
parent 1113
d346ab55031b
child 1127
ca49d50318dc
permissions
-rw-r--r--

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

mercurial