duke@1: /*
ksrini@1249: * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1: *
duke@1: * This code is free software; you can redistribute it and/or modify it
duke@1: * under the terms of the GNU General Public License version 2 only, as
ohair@554: * published by the Free Software Foundation. Oracle designates this
duke@1: * particular file as subject to the "Classpath" exception as provided
ohair@554: * by Oracle in the LICENSE file that accompanied this code.
duke@1: *
duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1: * version 2 for more details (a copy is included in the LICENSE file that
duke@1: * accompanied this code).
duke@1: *
duke@1: * You should have received a copy of the GNU General Public License version
duke@1: * 2 along with this work; if not, write to the Free Software Foundation,
duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1: *
ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554: * or visit www.oracle.com if you need additional information or have any
ohair@554: * questions.
duke@1: */
duke@1:
duke@1: package com.sun.tools.javac.parser;
duke@1:
duke@1: import java.util.*;
duke@1:
mcimadamore@1145: import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
mcimadamore@1145:
ksrini@1074: import com.sun.tools.javac.code.*;
mcimadamore@1113: import com.sun.tools.javac.parser.Tokens.*;
mcimadamore@1125: import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
duke@1: import com.sun.tools.javac.tree.*;
ksrini@1074: import com.sun.tools.javac.tree.JCTree.*;
duke@1: import com.sun.tools.javac.util.*;
jjg@726: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
ksrini@1074: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
duke@1: import com.sun.tools.javac.util.List;
ksrini@1074:
jjg@1127: import static com.sun.tools.javac.parser.Tokens.TokenKind.*;
jjg@1127: import static com.sun.tools.javac.parser.Tokens.TokenKind.ASSERT;
jjg@1127: import static com.sun.tools.javac.parser.Tokens.TokenKind.CASE;
jjg@1127: import static com.sun.tools.javac.parser.Tokens.TokenKind.CATCH;
jjg@1127: import static com.sun.tools.javac.parser.Tokens.TokenKind.EQ;
jjg@1127: import static com.sun.tools.javac.parser.Tokens.TokenKind.GT;
jjg@1127: import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
jjg@1127: import static com.sun.tools.javac.parser.Tokens.TokenKind.LT;
duke@1: import static com.sun.tools.javac.util.ListBuffer.lb;
jjg@1127: import static com.sun.tools.javac.tree.JCTree.Tag.*;
duke@1:
duke@1: /** The parser maps a token sequence into an abstract syntax
duke@1: * tree. It operates by recursive descent, with code derived
duke@1: * systematically from an LL(1) grammar. For efficiency reasons, an
duke@1: * operator precedence scheme is used for parsing binary operation
duke@1: * expressions.
duke@1: *
jjg@581: *
This is NOT part of any supported API.
jjg@581: * If you write code that depends on this, you do so at your own risk.
duke@1: * This code and its internal interfaces are subject to change or
duke@1: * deletion without notice.
duke@1: */
jjg@111: public class JavacParser implements Parser {
duke@1:
duke@1: /** The number of precedence levels of infix operators.
duke@1: */
duke@1: private static final int infixPrecedenceLevels = 10;
duke@1:
duke@1: /** The scanner used for lexical analysis.
duke@1: */
ksrini@1062: protected Lexer S;
duke@1:
duke@1: /** The factory to be used for abstract syntax tree construction.
duke@1: */
duke@1: protected TreeMaker F;
duke@1:
duke@1: /** The log to be used for error diagnostics.
duke@1: */
duke@1: private Log log;
duke@1:
duke@1: /** The Source language setting. */
duke@1: private Source source;
duke@1:
duke@1: /** The name table. */
jjg@113: private Names names;
duke@1:
ksrini@1138: /** End position mappings container */
ksrini@1138: private final AbstractEndPosTable endPosTable;
ksrini@1138:
duke@1: /** Construct a parser from a given scanner, tree factory and log.
duke@1: */
jjg@111: protected JavacParser(ParserFactory fac,
duke@1: Lexer S,
jjg@111: boolean keepDocComments,
ksrini@1138: boolean keepLineMap,
ksrini@1138: boolean keepEndPositions) {
duke@1: this.S = S;
mcimadamore@1113: nextToken(); // prime the pump
duke@1: this.F = fac.F;
duke@1: this.log = fac.log;
duke@1: this.names = fac.names;
duke@1: this.source = fac.source;
duke@1: this.allowGenerics = source.allowGenerics();
duke@1: this.allowVarargs = source.allowVarargs();
duke@1: this.allowAsserts = source.allowAsserts();
duke@1: this.allowEnums = source.allowEnums();
duke@1: this.allowForeach = source.allowForeach();
duke@1: this.allowStaticImport = source.allowStaticImport();
duke@1: this.allowAnnotations = source.allowAnnotations();
darcy@609: this.allowTWR = source.allowTryWithResources();
mcimadamore@537: this.allowDiamond = source.allowDiamond();
mcimadamore@550: this.allowMulticatch = source.allowMulticatch();
ksrini@1062: this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true);
mcimadamore@1144: this.allowLambda = source.allowLambda() &&
mcimadamore@1297: fac.options.isSet("allowLambda"); //pre-lambda guard
mcimadamore@1145: this.allowMethodReferences = source.allowMethodReferences() &&
mcimadamore@1297: fac.options.isSet("allowMethodReferences"); //pre-lambda guard
duke@1: this.keepDocComments = keepDocComments;
jjg@1280: docComments = newDocCommentTable(keepDocComments);
jjg@111: this.keepLineMap = keepLineMap;
duke@1: this.errorTree = F.Erroneous();
ksrini@1138: endPosTable = newEndPosTable(keepEndPositions);
duke@1: }
duke@1:
ksrini@1138: protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
ksrini@1138: return keepEndPositions
ksrini@1138: ? new SimpleEndPosTable()
ksrini@1138: : new EmptyEndPosTable();
ksrini@1138: }
jjg@1280:
jjg@1280: protected DocCommentTable newDocCommentTable(boolean keepDocComments) {
jjg@1280: return keepDocComments ? new SimpleDocCommentTable() : null;
jjg@1280: }
jjg@1280:
duke@1: /** Switch: Should generics be recognized?
duke@1: */
duke@1: boolean allowGenerics;
duke@1:
mcimadamore@537: /** Switch: Should diamond operator be recognized?
mcimadamore@537: */
mcimadamore@537: boolean allowDiamond;
mcimadamore@537:
mcimadamore@550: /** Switch: Should multicatch clause be accepted?
mcimadamore@550: */
mcimadamore@550: boolean allowMulticatch;
mcimadamore@550:
duke@1: /** Switch: Should varargs be recognized?
duke@1: */
duke@1: boolean allowVarargs;
duke@1:
duke@1: /** Switch: should we recognize assert statements, or just give a warning?
duke@1: */
duke@1: boolean allowAsserts;
duke@1:
duke@1: /** Switch: should we recognize enums, or just give a warning?
duke@1: */
duke@1: boolean allowEnums;
duke@1:
duke@1: /** Switch: should we recognize foreach?
duke@1: */
duke@1: boolean allowForeach;
duke@1:
duke@1: /** Switch: should we recognize foreach?
duke@1: */
duke@1: boolean allowStaticImport;
duke@1:
duke@1: /** Switch: should we recognize annotations?
duke@1: */
duke@1: boolean allowAnnotations;
duke@1:
darcy@840: /** Switch: should we recognize try-with-resources?
darcy@609: */
darcy@609: boolean allowTWR;
darcy@609:
ksrini@1062: /** Switch: should we fold strings?
ksrini@1062: */
ksrini@1062: boolean allowStringFolding;
ksrini@1062:
mcimadamore@1144: /** Switch: should we recognize lambda expressions?
mcimadamore@1144: */
mcimadamore@1144: boolean allowLambda;
mcimadamore@1144:
mcimadamore@1145: /** Switch: should we allow method/constructor references?
mcimadamore@1145: */
mcimadamore@1145: boolean allowMethodReferences;
mcimadamore@1145:
duke@1: /** Switch: should we keep docComments?
duke@1: */
duke@1: boolean keepDocComments;
duke@1:
jjg@111: /** Switch: should we keep line table?
jjg@111: */
jjg@111: boolean keepLineMap;
jjg@111:
duke@1: /** When terms are parsed, the mode determines which is expected:
duke@1: * mode = EXPR : an expression
duke@1: * mode = TYPE : a type
duke@1: * mode = NOPARAMS : no parameters allowed for type
duke@1: * mode = TYPEARG : type argument
duke@1: */
mcimadamore@537: static final int EXPR = 0x1;
mcimadamore@537: static final int TYPE = 0x2;
mcimadamore@537: static final int NOPARAMS = 0x4;
mcimadamore@537: static final int TYPEARG = 0x8;
mcimadamore@537: static final int DIAMOND = 0x10;
duke@1:
duke@1: /** The current mode.
duke@1: */
duke@1: private int mode = 0;
duke@1:
duke@1: /** The mode of the term that was parsed last.
duke@1: */
duke@1: private int lastmode = 0;
duke@1:
mcimadamore@1113: /* ---------- token management -------------- */
mcimadamore@1113:
mcimadamore@1113: protected Token token;
mcimadamore@1113:
mcimadamore@1113: protected void nextToken() {
mcimadamore@1113: S.nextToken();
mcimadamore@1113: token = S.token();
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1144: protected boolean peekToken(TokenKind tk) {
mcimadamore@1144: return S.token(1).kind == tk;
mcimadamore@1144: }
mcimadamore@1144:
mcimadamore@1144: protected boolean peekToken(TokenKind tk1, TokenKind tk2) {
mcimadamore@1144: return S.token(1).kind == tk1 &&
mcimadamore@1144: S.token(2).kind == tk2;
mcimadamore@1144: }
mcimadamore@1144:
mcimadamore@1144: protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) {
mcimadamore@1144: return S.token(1).kind == tk1 &&
mcimadamore@1144: S.token(2).kind == tk2 &&
mcimadamore@1144: S.token(3).kind == tk3;
mcimadamore@1144: }
mcimadamore@1144:
mcimadamore@1144: protected boolean peekToken(TokenKind... kinds) {
mcimadamore@1144: for (int lookahead = 0 ; lookahead < kinds.length ; lookahead++) {
mcimadamore@1144: if (S.token(lookahead + 1).kind != kinds[lookahead]) {
mcimadamore@1144: return false;
mcimadamore@1144: }
mcimadamore@1144: }
mcimadamore@1144: return true;
mcimadamore@1144: }
mcimadamore@1144:
mcimadamore@1113: /* ---------- error recovery -------------- */
duke@1:
duke@1: private JCErroneous errorTree;
duke@1:
duke@1: /** Skip forward until a suitable stop token is found.
duke@1: */
duke@1: private void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) {
duke@1: while (true) {
mcimadamore@1113: switch (token.kind) {
duke@1: case SEMI:
mcimadamore@1113: nextToken();
duke@1: return;
duke@1: case PUBLIC:
duke@1: case FINAL:
duke@1: case ABSTRACT:
duke@1: case MONKEYS_AT:
duke@1: case EOF:
duke@1: case CLASS:
duke@1: case INTERFACE:
duke@1: case ENUM:
duke@1: return;
duke@1: case IMPORT:
duke@1: if (stopAtImport)
duke@1: return;
duke@1: break;
duke@1: case LBRACE:
duke@1: case RBRACE:
duke@1: case PRIVATE:
duke@1: case PROTECTED:
duke@1: case STATIC:
duke@1: case TRANSIENT:
duke@1: case NATIVE:
duke@1: case VOLATILE:
duke@1: case SYNCHRONIZED:
duke@1: case STRICTFP:
duke@1: case LT:
duke@1: case BYTE:
duke@1: case SHORT:
duke@1: case CHAR:
duke@1: case INT:
duke@1: case LONG:
duke@1: case FLOAT:
duke@1: case DOUBLE:
duke@1: case BOOLEAN:
duke@1: case VOID:
duke@1: if (stopAtMemberDecl)
duke@1: return;
duke@1: break;
duke@1: case IDENTIFIER:
duke@1: if (stopAtIdentifier)
duke@1: return;
duke@1: break;
duke@1: case CASE:
duke@1: case DEFAULT:
duke@1: case IF:
duke@1: case FOR:
duke@1: case WHILE:
duke@1: case DO:
duke@1: case TRY:
duke@1: case SWITCH:
duke@1: case RETURN:
duke@1: case THROW:
duke@1: case BREAK:
duke@1: case CONTINUE:
duke@1: case ELSE:
duke@1: case FINALLY:
duke@1: case CATCH:
duke@1: if (stopAtStatement)
duke@1: return;
duke@1: break;
duke@1: }
mcimadamore@1113: nextToken();
duke@1: }
duke@1: }
duke@1:
mcimadamore@1113: private JCErroneous syntaxError(int pos, String key, TokenKind... args) {
ksrini@1074: return syntaxError(pos, List.nil(), key, args);
duke@1: }
duke@1:
mcimadamore@1113: private JCErroneous syntaxError(int pos, List errs, String key, TokenKind... args) {
duke@1: setErrorEndPos(pos);
ksrini@1074: JCErroneous err = F.at(pos).Erroneous(errs);
ksrini@1074: reportSyntaxError(err, key, (Object[])args);
ksrini@1074: if (errs != null) {
ksrini@1074: JCTree last = errs.last();
ksrini@1074: if (last != null)
ksrini@1074: storeEnd(last, pos);
ksrini@1074: }
ksrini@1074: return toP(err);
duke@1: }
duke@1:
duke@1: private int errorPos = Position.NOPOS;
ksrini@1074:
duke@1: /**
ksrini@1074: * Report a syntax using the given the position parameter and arguments,
ksrini@1074: * unless one was already reported at the same position.
duke@1: */
mcimadamore@80: private void reportSyntaxError(int pos, String key, Object... args) {
ksrini@1074: JCDiagnostic.DiagnosticPosition diag = new JCDiagnostic.SimpleDiagnosticPosition(pos);
ksrini@1074: reportSyntaxError(diag, key, args);
ksrini@1074: }
ksrini@1074:
ksrini@1074: /**
ksrini@1074: * Report a syntax error using the given DiagnosticPosition object and
ksrini@1074: * arguments, unless one was already reported at the same position.
ksrini@1074: */
ksrini@1074: private void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, String key, Object... args) {
ksrini@1074: int pos = diagPos.getPreferredPosition();
duke@1: if (pos > S.errPos() || pos == Position.NOPOS) {
mcimadamore@1113: if (token.kind == EOF) {
ksrini@1074: error(diagPos, "premature.eof");
ksrini@1074: } else {
ksrini@1074: error(diagPos, key, args);
ksrini@1074: }
duke@1: }
duke@1: S.errPos(pos);
mcimadamore@1113: if (token.pos == errorPos)
mcimadamore@1113: nextToken(); // guarantee progress
mcimadamore@1113: errorPos = token.pos;
duke@1: }
duke@1:
duke@1:
duke@1: /** Generate a syntax error at current position unless one was already
duke@1: * reported at the same position.
duke@1: */
duke@1: private JCErroneous syntaxError(String key) {
mcimadamore@1113: return syntaxError(token.pos, key);
duke@1: }
duke@1:
duke@1: /** Generate a syntax error at current position unless one was
duke@1: * already reported at the same position.
duke@1: */
mcimadamore@1113: private JCErroneous syntaxError(String key, TokenKind arg) {
mcimadamore@1113: return syntaxError(token.pos, key, arg);
duke@1: }
duke@1:
duke@1: /** If next input token matches given token, skip it, otherwise report
duke@1: * an error.
duke@1: */
mcimadamore@1113: public void accept(TokenKind tk) {
mcimadamore@1113: if (token.kind == tk) {
mcimadamore@1113: nextToken();
duke@1: } else {
mcimadamore@1113: setErrorEndPos(token.pos);
mcimadamore@1113: reportSyntaxError(S.prevToken().endPos, "expected", tk);
duke@1: }
duke@1: }
duke@1:
duke@1: /** Report an illegal start of expression/type error at given position.
duke@1: */
duke@1: JCExpression illegal(int pos) {
ksrini@1074: setErrorEndPos(pos);
duke@1: if ((mode & EXPR) != 0)
duke@1: return syntaxError(pos, "illegal.start.of.expr");
duke@1: else
duke@1: return syntaxError(pos, "illegal.start.of.type");
duke@1:
duke@1: }
duke@1:
duke@1: /** Report an illegal start of expression/type error at current position.
duke@1: */
duke@1: JCExpression illegal() {
mcimadamore@1113: return illegal(token.pos);
duke@1: }
duke@1:
duke@1: /** Diagnose a modifier flag from the set, if any. */
duke@1: void checkNoMods(long mods) {
duke@1: if (mods != 0) {
duke@1: long lowestMod = mods & -mods;
mcimadamore@1113: error(token.pos, "mod.not.allowed.here",
mcimadamore@80: Flags.asFlagSet(lowestMod));
duke@1: }
duke@1: }
duke@1:
duke@1: /* ---------- doc comments --------- */
duke@1:
jjg@1280: /** A table to store all documentation comments
duke@1: * indexed by the tree nodes they refer to.
duke@1: * defined only if option flag keepDocComment is set.
duke@1: */
jjg@1280: private final DocCommentTable docComments;
duke@1:
duke@1: /** Make an entry into docComments hashtable,
duke@1: * provided flag keepDocComments is set and given doc comment is non-null.
duke@1: * @param tree The tree to be used as index in the hashtable
duke@1: * @param dc The doc comment to associate with the tree, or null.
duke@1: */
jjg@1280: void attach(JCTree tree, Comment dc) {
duke@1: if (keepDocComments && dc != null) {
duke@1: // System.out.println("doc comment = ");System.out.println(dc);//DEBUG
jjg@1280: docComments.putComment(tree, dc);
duke@1: }
duke@1: }
duke@1:
duke@1: /* -------- source positions ------- */
duke@1:
duke@1: private void setErrorEndPos(int errPos) {
ksrini@1138: endPosTable.setErrorEndPos(errPos);
duke@1: }
duke@1:
ksrini@1138: private void storeEnd(JCTree tree, int endpos) {
ksrini@1138: endPosTable.storeEnd(tree, endpos);
duke@1: }
duke@1:
ksrini@1138: private T to(T t) {
ksrini@1138: return endPosTable.to(t);
ksrini@1138: }
duke@1:
ksrini@1138: private T toP(T t) {
ksrini@1138: return endPosTable.toP(t);
ksrini@1138: }
duke@1:
duke@1: /** Get the start position for a tree node. The start position is
duke@1: * defined to be the position of the first character of the first
duke@1: * token of the node's source text.
duke@1: * @param tree The tree node
duke@1: */
duke@1: public int getStartPos(JCTree tree) {
duke@1: return TreeInfo.getStartPos(tree);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get the end position for a tree node. The end position is
duke@1: * defined to be the position of the last character of the last
duke@1: * token of the node's source text. Returns Position.NOPOS if end
duke@1: * positions are not generated or the position is otherwise not
duke@1: * found.
duke@1: * @param tree The tree node
duke@1: */
duke@1: public int getEndPos(JCTree tree) {
ksrini@1138: return endPosTable.getEndPos(tree);
duke@1: }
duke@1:
duke@1:
duke@1:
duke@1: /* ---------- parsing -------------- */
duke@1:
duke@1: /**
duke@1: * Ident = IDENTIFIER
duke@1: */
duke@1: Name ident() {
mcimadamore@1113: if (token.kind == IDENTIFIER) {
mcimadamore@1113: Name name = token.name();
mcimadamore@1113: nextToken();
duke@1: return name;
mcimadamore@1113: } else if (token.kind == ASSERT) {
duke@1: if (allowAsserts) {
mcimadamore@1113: error(token.pos, "assert.as.identifier");
mcimadamore@1113: nextToken();
duke@1: return names.error;
duke@1: } else {
mcimadamore@1113: warning(token.pos, "assert.as.identifier");
mcimadamore@1113: Name name = token.name();
mcimadamore@1113: nextToken();
duke@1: return name;
duke@1: }
mcimadamore@1113: } else if (token.kind == ENUM) {
duke@1: if (allowEnums) {
mcimadamore@1113: error(token.pos, "enum.as.identifier");
mcimadamore@1113: nextToken();
duke@1: return names.error;
duke@1: } else {
mcimadamore@1113: warning(token.pos, "enum.as.identifier");
mcimadamore@1113: Name name = token.name();
mcimadamore@1113: nextToken();
duke@1: return name;
duke@1: }
duke@1: } else {
duke@1: accept(IDENTIFIER);
duke@1: return names.error;
duke@1: }
duke@1: }
duke@1:
duke@1: /**
duke@1: * Qualident = Ident { DOT Ident }
duke@1: */
duke@1: public JCExpression qualident() {
mcimadamore@1113: JCExpression t = toP(F.at(token.pos).Ident(ident()));
mcimadamore@1113: while (token.kind == DOT) {
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: nextToken();
duke@1: t = toP(F.at(pos).Select(t, ident()));
duke@1: }
duke@1: return t;
duke@1: }
duke@1:
ksrini@1074: JCExpression literal(Name prefix) {
mcimadamore@1113: return literal(prefix, token.pos);
ksrini@1074: }
ksrini@1074:
duke@1: /**
duke@1: * Literal =
duke@1: * INTLITERAL
duke@1: * | LONGLITERAL
duke@1: * | FLOATLITERAL
duke@1: * | DOUBLELITERAL
duke@1: * | CHARLITERAL
duke@1: * | STRINGLITERAL
duke@1: * | TRUE
duke@1: * | FALSE
duke@1: * | NULL
duke@1: */
ksrini@1074: JCExpression literal(Name prefix, int pos) {
duke@1: JCExpression t = errorTree;
mcimadamore@1113: switch (token.kind) {
duke@1: case INTLITERAL:
duke@1: try {
duke@1: t = F.at(pos).Literal(
duke@1: TypeTags.INT,
mcimadamore@1113: Convert.string2int(strval(prefix), token.radix()));
duke@1: } catch (NumberFormatException ex) {
mcimadamore@1113: error(token.pos, "int.number.too.large", strval(prefix));
duke@1: }
duke@1: break;
duke@1: case LONGLITERAL:
duke@1: try {
duke@1: t = F.at(pos).Literal(
duke@1: TypeTags.LONG,
mcimadamore@1113: new Long(Convert.string2long(strval(prefix), token.radix())));
duke@1: } catch (NumberFormatException ex) {
mcimadamore@1113: error(token.pos, "int.number.too.large", strval(prefix));
duke@1: }
duke@1: break;
duke@1: case FLOATLITERAL: {
mcimadamore@1113: String proper = token.radix() == 16 ?
mcimadamore@1113: ("0x"+ token.stringVal()) :
mcimadamore@1113: token.stringVal();
duke@1: Float n;
duke@1: try {
duke@1: n = Float.valueOf(proper);
duke@1: } catch (NumberFormatException ex) {
jjg@788: // error already reported in scanner
duke@1: n = Float.NaN;
duke@1: }
duke@1: if (n.floatValue() == 0.0f && !isZero(proper))
mcimadamore@1113: error(token.pos, "fp.number.too.small");
duke@1: else if (n.floatValue() == Float.POSITIVE_INFINITY)
mcimadamore@1113: error(token.pos, "fp.number.too.large");
duke@1: else
duke@1: t = F.at(pos).Literal(TypeTags.FLOAT, n);
duke@1: break;
duke@1: }
duke@1: case DOUBLELITERAL: {
mcimadamore@1113: String proper = token.radix() == 16 ?
mcimadamore@1113: ("0x"+ token.stringVal()) :
mcimadamore@1113: token.stringVal();
duke@1: Double n;
duke@1: try {
duke@1: n = Double.valueOf(proper);
duke@1: } catch (NumberFormatException ex) {
duke@1: // error already reported in scanner
duke@1: n = Double.NaN;
duke@1: }
duke@1: if (n.doubleValue() == 0.0d && !isZero(proper))
mcimadamore@1113: error(token.pos, "fp.number.too.small");
duke@1: else if (n.doubleValue() == Double.POSITIVE_INFINITY)
mcimadamore@1113: error(token.pos, "fp.number.too.large");
duke@1: else
duke@1: t = F.at(pos).Literal(TypeTags.DOUBLE, n);
duke@1: break;
duke@1: }
duke@1: case CHARLITERAL:
duke@1: t = F.at(pos).Literal(
duke@1: TypeTags.CHAR,
mcimadamore@1113: token.stringVal().charAt(0) + 0);
duke@1: break;
duke@1: case STRINGLITERAL:
duke@1: t = F.at(pos).Literal(
duke@1: TypeTags.CLASS,
mcimadamore@1113: token.stringVal());
duke@1: break;
duke@1: case TRUE: case FALSE:
duke@1: t = F.at(pos).Literal(
duke@1: TypeTags.BOOLEAN,
mcimadamore@1113: (token.kind == TRUE ? 1 : 0));
duke@1: break;
duke@1: case NULL:
duke@1: t = F.at(pos).Literal(
duke@1: TypeTags.BOT,
duke@1: null);
duke@1: break;
duke@1: default:
jjg@816: Assert.error();
duke@1: }
duke@1: if (t == errorTree)
duke@1: t = F.at(pos).Erroneous();
mcimadamore@1113: storeEnd(t, token.endPos);
mcimadamore@1113: nextToken();
duke@1: return t;
duke@1: }
duke@1: //where
duke@1: boolean isZero(String s) {
duke@1: char[] cs = s.toCharArray();
jjg@408: int base = ((cs.length > 1 && Character.toLowerCase(cs[1]) == 'x') ? 16 : 10);
duke@1: int i = ((base==16) ? 2 : 0);
duke@1: while (i < cs.length && (cs[i] == '0' || cs[i] == '.')) i++;
duke@1: return !(i < cs.length && (Character.digit(cs[i], base) > 0));
duke@1: }
duke@1:
duke@1: String strval(Name prefix) {
mcimadamore@1113: String s = token.stringVal();
jjg@113: return prefix.isEmpty() ? s : prefix + s;
duke@1: }
duke@1:
duke@1: /** terms can be either expressions or types.
duke@1: */
jjg@111: public JCExpression parseExpression() {
duke@1: return term(EXPR);
duke@1: }
duke@1:
jjg@111: public JCExpression parseType() {
duke@1: return term(TYPE);
duke@1: }
duke@1:
duke@1: JCExpression term(int newmode) {
duke@1: int prevmode = mode;
duke@1: mode = newmode;
duke@1: JCExpression t = term();
duke@1: lastmode = mode;
duke@1: mode = prevmode;
duke@1: return t;
duke@1: }
duke@1:
duke@1: /**
jjg@1326: * {@literal
duke@1: * Expression = Expression1 [ExpressionRest]
duke@1: * ExpressionRest = [AssignmentOperator Expression1]
duke@1: * AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" |
duke@1: * "&=" | "|=" | "^=" |
duke@1: * "%=" | "<<=" | ">>=" | ">>>="
duke@1: * Type = Type1
duke@1: * TypeNoParams = TypeNoParams1
duke@1: * StatementExpression = Expression
duke@1: * ConstantExpression = Expression
jjg@1326: * }
duke@1: */
duke@1: JCExpression term() {
duke@1: JCExpression t = term1();
duke@1: if ((mode & EXPR) != 0 &&
mcimadamore@1113: token.kind == EQ || PLUSEQ.compareTo(token.kind) <= 0 && token.kind.compareTo(GTGTGTEQ) <= 0)
duke@1: return termRest(t);
duke@1: else
duke@1: return t;
duke@1: }
duke@1:
duke@1: JCExpression termRest(JCExpression t) {
mcimadamore@1113: switch (token.kind) {
duke@1: case EQ: {
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: nextToken();
duke@1: mode = EXPR;
duke@1: JCExpression t1 = term();
duke@1: return toP(F.at(pos).Assign(t, t1));
duke@1: }
duke@1: case PLUSEQ:
duke@1: case SUBEQ:
duke@1: case STAREQ:
duke@1: case SLASHEQ:
duke@1: case PERCENTEQ:
duke@1: case AMPEQ:
duke@1: case BAREQ:
duke@1: case CARETEQ:
duke@1: case LTLTEQ:
duke@1: case GTGTEQ:
duke@1: case GTGTGTEQ:
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: TokenKind tk = token.kind;
mcimadamore@1113: nextToken();
duke@1: mode = EXPR;
duke@1: JCExpression t1 = term();
mcimadamore@1113: return F.at(pos).Assignop(optag(tk), t, t1);
duke@1: default:
duke@1: return t;
duke@1: }
duke@1: }
duke@1:
duke@1: /** Expression1 = Expression2 [Expression1Rest]
duke@1: * Type1 = Type2
duke@1: * TypeNoParams1 = TypeNoParams2
duke@1: */
duke@1: JCExpression term1() {
duke@1: JCExpression t = term2();
mcimadamore@1113: if ((mode & EXPR) != 0 && token.kind == QUES) {
duke@1: mode = EXPR;
duke@1: return term1Rest(t);
duke@1: } else {
duke@1: return t;
duke@1: }
duke@1: }
duke@1:
duke@1: /** Expression1Rest = ["?" Expression ":" Expression1]
duke@1: */
duke@1: JCExpression term1Rest(JCExpression t) {
mcimadamore@1113: if (token.kind == QUES) {
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: nextToken();
duke@1: JCExpression t1 = term();
duke@1: accept(COLON);
duke@1: JCExpression t2 = term1();
duke@1: return F.at(pos).Conditional(t, t1, t2);
duke@1: } else {
duke@1: return t;
duke@1: }
duke@1: }
duke@1:
duke@1: /** Expression2 = Expression3 [Expression2Rest]
duke@1: * Type2 = Type3
duke@1: * TypeNoParams2 = TypeNoParams3
duke@1: */
duke@1: JCExpression term2() {
duke@1: JCExpression t = term3();
mcimadamore@1113: if ((mode & EXPR) != 0 && prec(token.kind) >= TreeInfo.orPrec) {
duke@1: mode = EXPR;
duke@1: return term2Rest(t, TreeInfo.orPrec);
duke@1: } else {
duke@1: return t;
duke@1: }
duke@1: }
duke@1:
duke@1: /* Expression2Rest = {infixop Expression3}
duke@1: * | Expression3 instanceof Type
duke@1: * infixop = "||"
duke@1: * | "&&"
duke@1: * | "|"
duke@1: * | "^"
duke@1: * | "&"
duke@1: * | "==" | "!="
duke@1: * | "<" | ">" | "<=" | ">="
duke@1: * | "<<" | ">>" | ">>>"
duke@1: * | "+" | "-"
duke@1: * | "*" | "/" | "%"
duke@1: */
duke@1: JCExpression term2Rest(JCExpression t, int minprec) {
duke@1: List savedOd = odStackSupply.elems;
duke@1: JCExpression[] odStack = newOdStack();
duke@1: List savedOp = opStackSupply.elems;
duke@1: Token[] opStack = newOpStack();
mcimadamore@1113:
duke@1: // optimization, was odStack = new Tree[...]; opStack = new Tree[...];
duke@1: int top = 0;
duke@1: odStack[0] = t;
mcimadamore@1113: int startPos = token.pos;
mcimadamore@1113: Token topOp = Tokens.DUMMY;
mcimadamore@1113: while (prec(token.kind) >= minprec) {
duke@1: opStack[top] = topOp;
duke@1: top++;
mcimadamore@1113: topOp = token;
mcimadamore@1113: nextToken();
mcimadamore@1165: odStack[top] = (topOp.kind == INSTANCEOF) ? parseType() : term3();
mcimadamore@1113: while (top > 0 && prec(topOp.kind) >= prec(token.kind)) {
mcimadamore@1113: odStack[top-1] = makeOp(topOp.pos, topOp.kind, odStack[top-1],
duke@1: odStack[top]);
duke@1: top--;
duke@1: topOp = opStack[top];
duke@1: }
duke@1: }
jjg@816: Assert.check(top == 0);
duke@1: t = odStack[0];
duke@1:
jjg@1127: if (t.hasTag(JCTree.Tag.PLUS)) {
duke@1: StringBuffer buf = foldStrings(t);
duke@1: if (buf != null) {
duke@1: t = toP(F.at(startPos).Literal(TypeTags.CLASS, buf.toString()));
duke@1: }
duke@1: }
duke@1:
duke@1: odStackSupply.elems = savedOd; // optimization
duke@1: opStackSupply.elems = savedOp; // optimization
duke@1: return t;
duke@1: }
duke@1: //where
duke@1: /** Construct a binary or type test node.
duke@1: */
duke@1: private JCExpression makeOp(int pos,
mcimadamore@1113: TokenKind topOp,
duke@1: JCExpression od1,
duke@1: JCExpression od2)
duke@1: {
duke@1: if (topOp == INSTANCEOF) {
duke@1: return F.at(pos).TypeTest(od1, od2);
duke@1: } else {
duke@1: return F.at(pos).Binary(optag(topOp), od1, od2);
duke@1: }
duke@1: }
duke@1: /** If tree is a concatenation of string literals, replace it
duke@1: * by a single literal representing the concatenated string.
duke@1: */
duke@1: protected StringBuffer foldStrings(JCTree tree) {
ksrini@1062: if (!allowStringFolding)
ksrini@1062: return null;
duke@1: List buf = List.nil();
duke@1: while (true) {
jjg@1127: if (tree.hasTag(LITERAL)) {
duke@1: JCLiteral lit = (JCLiteral) tree;
duke@1: if (lit.typetag == TypeTags.CLASS) {
duke@1: StringBuffer sbuf =
duke@1: new StringBuffer((String)lit.value);
duke@1: while (buf.nonEmpty()) {
duke@1: sbuf.append(buf.head);
duke@1: buf = buf.tail;
duke@1: }
duke@1: return sbuf;
duke@1: }
jjg@1127: } else if (tree.hasTag(JCTree.Tag.PLUS)) {
duke@1: JCBinary op = (JCBinary)tree;
jjg@1127: if (op.rhs.hasTag(LITERAL)) {
duke@1: JCLiteral lit = (JCLiteral) op.rhs;
duke@1: if (lit.typetag == TypeTags.CLASS) {
duke@1: buf = buf.prepend((String) lit.value);
duke@1: tree = op.lhs;
duke@1: continue;
duke@1: }
duke@1: }
duke@1: }
duke@1: return null;
duke@1: }
duke@1: }
duke@1:
duke@1: /** optimization: To save allocating a new operand/operator stack
duke@1: * for every binary operation, we use supplys.
duke@1: */
duke@1: ListBuffer odStackSupply = new ListBuffer();
duke@1: ListBuffer opStackSupply = new ListBuffer();
duke@1:
duke@1: private JCExpression[] newOdStack() {
duke@1: if (odStackSupply.elems == odStackSupply.last)
duke@1: odStackSupply.append(new JCExpression[infixPrecedenceLevels + 1]);
duke@1: JCExpression[] odStack = odStackSupply.elems.head;
duke@1: odStackSupply.elems = odStackSupply.elems.tail;
duke@1: return odStack;
duke@1: }
duke@1:
duke@1: private Token[] newOpStack() {
duke@1: if (opStackSupply.elems == opStackSupply.last)
duke@1: opStackSupply.append(new Token[infixPrecedenceLevels + 1]);
duke@1: Token[] opStack = opStackSupply.elems.head;
duke@1: opStackSupply.elems = opStackSupply.elems.tail;
duke@1: return opStack;
duke@1: }
duke@1:
jjg@1326: /**
jjg@1326: * Expression3 = PrefixOp Expression3
duke@1: * | "(" Expr | TypeNoParams ")" Expression3
duke@1: * | Primary {Selector} {PostfixOp}
jjg@1326: *
jjg@1326: * {@literal
duke@1: * Primary = "(" Expression ")"
duke@1: * | Literal
duke@1: * | [TypeArguments] THIS [Arguments]
duke@1: * | [TypeArguments] SUPER SuperSuffix
duke@1: * | NEW [TypeArguments] Creator
mcimadamore@1144: * | "(" Arguments ")" "->" ( Expression | Block )
mcimadamore@1144: * | Ident "->" ( Expression | Block )
jjg@722: * | Ident { "." Ident }
mcimadamore@1145: * | Expression3 MemberReferenceSuffix
jjg@722: * [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
duke@1: * | Arguments
duke@1: * | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
duke@1: * ]
duke@1: * | BasicType BracketsOpt "." CLASS
jjg@1326: * }
jjg@1326: *
duke@1: * PrefixOp = "++" | "--" | "!" | "~" | "+" | "-"
duke@1: * PostfixOp = "++" | "--"
duke@1: * Type3 = Ident { "." Ident } [TypeArguments] {TypeSelector} BracketsOpt
duke@1: * | BasicType
duke@1: * TypeNoParams3 = Ident { "." Ident } BracketsOpt
duke@1: * Selector = "." [TypeArguments] Ident [Arguments]
duke@1: * | "." THIS
duke@1: * | "." [TypeArguments] SUPER SuperSuffix
duke@1: * | "." NEW [TypeArguments] InnerCreator
duke@1: * | "[" Expression "]"
duke@1: * TypeSelector = "." Ident [TypeArguments]
duke@1: * SuperSuffix = Arguments | "." Ident [Arguments]
duke@1: */
duke@1: protected JCExpression term3() {
mcimadamore@1113: int pos = token.pos;
duke@1: JCExpression t;
duke@1: List typeArgs = typeArgumentsOpt(EXPR);
mcimadamore@1113: switch (token.kind) {
duke@1: case QUES:
duke@1: if ((mode & TYPE) != 0 && (mode & (TYPEARG|NOPARAMS)) == TYPEARG) {
duke@1: mode = TYPE;
duke@1: return typeArgument();
duke@1: } else
duke@1: return illegal();
duke@1: case PLUSPLUS: case SUBSUB: case BANG: case TILDE: case PLUS: case SUB:
duke@1: if (typeArgs == null && (mode & EXPR) != 0) {
mcimadamore@1113: TokenKind tk = token.kind;
mcimadamore@1113: nextToken();
duke@1: mode = EXPR;
mcimadamore@1113: if (tk == SUB &&
mcimadamore@1113: (token.kind == INTLITERAL || token.kind == LONGLITERAL) &&
mcimadamore@1113: token.radix() == 10) {
duke@1: mode = EXPR;
ksrini@1074: t = literal(names.hyphen, pos);
duke@1: } else {
mcimadamore@1165: t = term3();
mcimadamore@1113: return F.at(pos).Unary(unoptag(tk), t);
duke@1: }
duke@1: } else return illegal();
duke@1: break;
duke@1: case LPAREN:
duke@1: if (typeArgs == null && (mode & EXPR) != 0) {
mcimadamore@1144: if (peekToken(FINAL) ||
mcimadamore@1144: peekToken(RPAREN) ||
mcimadamore@1144: peekToken(IDENTIFIER, COMMA) ||
mcimadamore@1144: peekToken(IDENTIFIER, RPAREN, ARROW)) {
mcimadamore@1144: //implicit n-ary lambda
mcimadamore@1144: t = lambdaExpressionOrStatement(true, peekToken(FINAL), pos);
mcimadamore@1144: break;
mcimadamore@1144: } else {
mcimadamore@1113: nextToken();
mcimadamore@1165: mode = EXPR | TYPE | NOPARAMS;
mcimadamore@1165: t = term3();
mcimadamore@1144: if ((mode & TYPE) != 0 && token.kind == LT) {
mcimadamore@1144: // Could be a cast to a parameterized type
mcimadamore@1144: JCTree.Tag op = JCTree.Tag.LT;
mcimadamore@1144: int pos1 = token.pos;
mcimadamore@1144: nextToken();
mcimadamore@1144: mode &= (EXPR | TYPE);
mcimadamore@1144: mode |= TYPEARG;
mcimadamore@1144: JCExpression t1 = term3();
mcimadamore@1144: if ((mode & TYPE) != 0 &&
mcimadamore@1144: (token.kind == COMMA || token.kind == GT)) {
mcimadamore@1144: mode = TYPE;
mcimadamore@1144: ListBuffer args = new ListBuffer();
mcimadamore@1144: args.append(t1);
mcimadamore@1144: while (token.kind == COMMA) {
mcimadamore@1144: nextToken();
mcimadamore@1144: args.append(typeArgument());
mcimadamore@1144: }
mcimadamore@1144: accept(GT);
mcimadamore@1144: t = toP(F.at(pos1).TypeApply(t, args.toList()));
mcimadamore@1144: checkGenerics();
mcimadamore@1144: mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type
mcimadamore@1144: t = term3Rest(t, typeArgs);
mcimadamore@1144: if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) {
mcimadamore@1144: //explicit lambda (w/ generic type)
mcimadamore@1144: mode = EXPR;
mcimadamore@1144: JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
mcimadamore@1144: if (token.kind == ELLIPSIS) {
mcimadamore@1144: mods.flags = Flags.VARARGS;
mcimadamore@1144: t = to(F.at(token.pos).TypeArray(t));
mcimadamore@1144: nextToken();
mcimadamore@1144: }
mcimadamore@1144: t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
mcimadamore@1144: break;
mcimadamore@1144: }
mcimadamore@1241: } else if ((mode & EXPR) != 0) {
mcimadamore@1144: mode = EXPR;
mcimadamore@1144: JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
mcimadamore@1144: t = F.at(pos1).Binary(op, t, e);
mcimadamore@1144: t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
mcimadamore@1241: } else {
mcimadamore@1241: accept(GT);
mcimadamore@1144: }
mcimadamore@1144: } else if ((mode & TYPE) != 0 &&
mcimadamore@1144: (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) {
mcimadamore@1144: //explicit lambda (w/ non-generic type)
mcimadamore@1144: mode = EXPR;
mcimadamore@1144: JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
mcimadamore@1144: if (token.kind == ELLIPSIS) {
mcimadamore@1144: mods.flags = Flags.VARARGS;
mcimadamore@1144: t = to(F.at(token.pos).TypeArray(t));
mcimadamore@1113: nextToken();
duke@1: }
mcimadamore@1144: t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
mcimadamore@1144: break;
mcimadamore@1144: } else {
duke@1: t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
duke@1: }
mcimadamore@185: }
mcimadamore@1144:
duke@1: accept(RPAREN);
duke@1: lastmode = mode;
duke@1: mode = EXPR;
duke@1: if ((lastmode & EXPR) == 0) {
mcimadamore@1165: JCExpression t1 = term3();
duke@1: return F.at(pos).TypeCast(t, t1);
duke@1: } else if ((lastmode & TYPE) != 0) {
mcimadamore@1113: switch (token.kind) {
duke@1: /*case PLUSPLUS: case SUBSUB: */
duke@1: case BANG: case TILDE:
duke@1: case LPAREN: case THIS: case SUPER:
duke@1: case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
duke@1: case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
duke@1: case TRUE: case FALSE: case NULL:
mcimadamore@1144: case NEW: case IDENTIFIER: case ASSERT: case ENUM:
duke@1: case BYTE: case SHORT: case CHAR: case INT:
duke@1: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
mcimadamore@1165: JCExpression t1 = term3();
duke@1: return F.at(pos).TypeCast(t, t1);
duke@1: }
duke@1: }
mcimadamore@1144: } else {
mcimadamore@1144: return illegal();
mcimadamore@1144: }
duke@1: t = toP(F.at(pos).Parens(t));
duke@1: break;
duke@1: case THIS:
duke@1: if ((mode & EXPR) != 0) {
duke@1: mode = EXPR;
duke@1: t = to(F.at(pos).Ident(names._this));
mcimadamore@1113: nextToken();
duke@1: if (typeArgs == null)
duke@1: t = argumentsOpt(null, t);
duke@1: else
duke@1: t = arguments(typeArgs, t);
duke@1: typeArgs = null;
duke@1: } else return illegal();
duke@1: break;
duke@1: case SUPER:
duke@1: if ((mode & EXPR) != 0) {
duke@1: mode = EXPR;
jjg@482: t = to(F.at(pos).Ident(names._super));
jjg@482: t = superSuffix(typeArgs, t);
duke@1: typeArgs = null;
duke@1: } else return illegal();
duke@1: break;
duke@1: case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL:
duke@1: case CHARLITERAL: case STRINGLITERAL:
duke@1: case TRUE: case FALSE: case NULL:
duke@1: if (typeArgs == null && (mode & EXPR) != 0) {
duke@1: mode = EXPR;
duke@1: t = literal(names.empty);
duke@1: } else return illegal();
duke@1: break;
duke@1: case NEW:
duke@1: if (typeArgs != null) return illegal();
duke@1: if ((mode & EXPR) != 0) {
duke@1: mode = EXPR;
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == LT) typeArgs = typeArguments(false);
duke@1: t = creator(pos, typeArgs);
duke@1: typeArgs = null;
duke@1: } else return illegal();
duke@1: break;
duke@1: case IDENTIFIER: case ASSERT: case ENUM:
duke@1: if (typeArgs != null) return illegal();
mcimadamore@1144: if ((mode & EXPR) != 0 && peekToken(ARROW)) {
mcimadamore@1144: t = lambdaExpressionOrStatement(false, false, pos);
mcimadamore@1144: } else {
mcimadamore@1144: t = toP(F.at(token.pos).Ident(ident()));
mcimadamore@1144: loop: while (true) {
mcimadamore@1144: pos = token.pos;
mcimadamore@1144: switch (token.kind) {
mcimadamore@1144: case LBRACKET:
mcimadamore@1113: nextToken();
mcimadamore@1144: if (token.kind == RBRACKET) {
mcimadamore@1144: nextToken();
mcimadamore@1144: t = bracketsOpt(t);
mcimadamore@1144: t = toP(F.at(pos).TypeArray(t));
mcimadamore@1144: t = bracketsSuffix(t);
mcimadamore@1144: } else {
mcimadamore@1144: if ((mode & EXPR) != 0) {
mcimadamore@1144: mode = EXPR;
mcimadamore@1144: JCExpression t1 = term();
mcimadamore@1144: t = to(F.at(pos).Indexed(t, t1));
mcimadamore@1144: }
mcimadamore@1144: accept(RBRACKET);
mcimadamore@1144: }
mcimadamore@1144: break loop;
mcimadamore@1144: case LPAREN:
duke@1: if ((mode & EXPR) != 0) {
duke@1: mode = EXPR;
mcimadamore@1144: t = arguments(typeArgs, t);
mcimadamore@1144: typeArgs = null;
duke@1: }
mcimadamore@1144: break loop;
mcimadamore@1144: case DOT:
mcimadamore@1144: nextToken();
mcimadamore@1144: int oldmode = mode;
mcimadamore@1144: mode &= ~NOPARAMS;
mcimadamore@1144: typeArgs = typeArgumentsOpt(EXPR);
mcimadamore@1144: mode = oldmode;
mcimadamore@1144: if ((mode & EXPR) != 0) {
mcimadamore@1144: switch (token.kind) {
mcimadamore@1144: case CLASS:
mcimadamore@1144: if (typeArgs != null) return illegal();
mcimadamore@1144: mode = EXPR;
mcimadamore@1144: t = to(F.at(pos).Select(t, names._class));
mcimadamore@1144: nextToken();
mcimadamore@1144: break loop;
mcimadamore@1144: case THIS:
mcimadamore@1144: if (typeArgs != null) return illegal();
mcimadamore@1144: mode = EXPR;
mcimadamore@1144: t = to(F.at(pos).Select(t, names._this));
mcimadamore@1144: nextToken();
mcimadamore@1144: break loop;
mcimadamore@1144: case SUPER:
mcimadamore@1144: mode = EXPR;
mcimadamore@1144: t = to(F.at(pos).Select(t, names._super));
mcimadamore@1144: t = superSuffix(typeArgs, t);
mcimadamore@1144: typeArgs = null;
mcimadamore@1144: break loop;
mcimadamore@1144: case NEW:
mcimadamore@1144: if (typeArgs != null) return illegal();
mcimadamore@1144: mode = EXPR;
mcimadamore@1144: int pos1 = token.pos;
mcimadamore@1144: nextToken();
mcimadamore@1144: if (token.kind == LT) typeArgs = typeArguments(false);
mcimadamore@1144: t = innerCreator(pos1, typeArgs, t);
mcimadamore@1144: typeArgs = null;
mcimadamore@1144: break loop;
mcimadamore@1144: }
mcimadamore@1144: }
mcimadamore@1144: // typeArgs saved for next loop iteration.
mcimadamore@1144: t = toP(F.at(pos).Select(t, ident()));
mcimadamore@1144: break;
mcimadamore@1165: case LT:
mcimadamore@1165: if ((mode & TYPE) == 0 && isUnboundMemberRef()) {
mcimadamore@1165: //this is an unbound method reference whose qualifier
mcimadamore@1165: //is a generic type i.e. A#m
mcimadamore@1165: int pos1 = token.pos;
mcimadamore@1165: accept(LT);
mcimadamore@1165: ListBuffer args = new ListBuffer();
mcimadamore@1165: args.append(typeArgument());
mcimadamore@1165: while (token.kind == COMMA) {
mcimadamore@1165: nextToken();
mcimadamore@1165: args.append(typeArgument());
mcimadamore@1165: }
mcimadamore@1165: accept(GT);
mcimadamore@1165: t = toP(F.at(pos1).TypeApply(t, args.toList()));
mcimadamore@1165: checkGenerics();
mcimadamore@1165: while (token.kind == DOT) {
mcimadamore@1165: nextToken();
mcimadamore@1165: mode = TYPE;
mcimadamore@1165: t = toP(F.at(token.pos).Select(t, ident()));
mcimadamore@1165: t = typeArgumentsOpt(t);
mcimadamore@1165: }
mcimadamore@1165: if (token.kind != HASH) {
mcimadamore@1165: //method reference expected here
mcimadamore@1165: t = illegal();
mcimadamore@1165: }
mcimadamore@1165: mode = EXPR;
mcimadamore@1165: return term3Rest(t, typeArgs);
mcimadamore@1165: }
mcimadamore@1165: break loop;
mcimadamore@1144: default:
mcimadamore@1144: break loop;
duke@1: }
duke@1: }
duke@1: }
duke@1: if (typeArgs != null) illegal();
duke@1: t = typeArgumentsOpt(t);
duke@1: break;
duke@1: case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
duke@1: case DOUBLE: case BOOLEAN:
duke@1: if (typeArgs != null) illegal();
duke@1: t = bracketsSuffix(bracketsOpt(basicType()));
duke@1: break;
duke@1: case VOID:
duke@1: if (typeArgs != null) illegal();
duke@1: if ((mode & EXPR) != 0) {
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == DOT) {
duke@1: JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTags.VOID));
duke@1: t = bracketsSuffix(ti);
duke@1: } else {
duke@1: return illegal(pos);
duke@1: }
duke@1: } else {
jrose@267: // Support the corner case of myMethodHandle.invoke() by passing
jrose@267: // a void type (like other primitive types) to the next phase.
jrose@267: // The error will be reported in Attr.attribTypes or Attr.visitApply.
jrose@267: JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTags.VOID));
mcimadamore@1113: nextToken();
jrose@267: return ti;
jrose@267: //return illegal();
duke@1: }
duke@1: break;
duke@1: default:
duke@1: return illegal();
duke@1: }
mcimadamore@1144: return term3Rest(t, typeArgs);
mcimadamore@1144: }
mcimadamore@1144:
mcimadamore@1144: JCExpression term3Rest(JCExpression t, List typeArgs) {
duke@1: if (typeArgs != null) illegal();
duke@1: while (true) {
mcimadamore@1113: int pos1 = token.pos;
mcimadamore@1113: if (token.kind == LBRACKET) {
mcimadamore@1113: nextToken();
duke@1: if ((mode & TYPE) != 0) {
duke@1: int oldmode = mode;
duke@1: mode = TYPE;
mcimadamore@1113: if (token.kind == RBRACKET) {
mcimadamore@1113: nextToken();
jjg@722: t = bracketsOpt(t);
duke@1: t = toP(F.at(pos1).TypeArray(t));
duke@1: return t;
duke@1: }
duke@1: mode = oldmode;
duke@1: }
duke@1: if ((mode & EXPR) != 0) {
duke@1: mode = EXPR;
duke@1: JCExpression t1 = term();
duke@1: t = to(F.at(pos1).Indexed(t, t1));
duke@1: }
duke@1: accept(RBRACKET);
mcimadamore@1113: } else if (token.kind == DOT) {
mcimadamore@1113: nextToken();
duke@1: typeArgs = typeArgumentsOpt(EXPR);
mcimadamore@1113: if (token.kind == SUPER && (mode & EXPR) != 0) {
duke@1: mode = EXPR;
duke@1: t = to(F.at(pos1).Select(t, names._super));
mcimadamore@1113: nextToken();
duke@1: t = arguments(typeArgs, t);
duke@1: typeArgs = null;
mcimadamore@1113: } else if (token.kind == NEW && (mode & EXPR) != 0) {
duke@1: if (typeArgs != null) return illegal();
duke@1: mode = EXPR;
mcimadamore@1113: int pos2 = token.pos;
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == LT) typeArgs = typeArguments(false);
duke@1: t = innerCreator(pos2, typeArgs, t);
duke@1: typeArgs = null;
duke@1: } else {
duke@1: t = toP(F.at(pos1).Select(t, ident()));
duke@1: t = argumentsOpt(typeArgs, typeArgumentsOpt(t));
duke@1: typeArgs = null;
duke@1: }
mcimadamore@1145: } else if ((mode & EXPR) != 0 && token.kind == HASH) {
mcimadamore@1145: mode = EXPR;
mcimadamore@1145: if (typeArgs != null) return illegal();
mcimadamore@1145: accept(HASH);
mcimadamore@1145: t = memberReferenceSuffix(pos1, t);
duke@1: } else {
duke@1: break;
duke@1: }
duke@1: }
mcimadamore@1113: while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && (mode & EXPR) != 0) {
duke@1: mode = EXPR;
mcimadamore@1113: t = to(F.at(token.pos).Unary(
jjg@1127: token.kind == PLUSPLUS ? POSTINC : POSTDEC, t));
mcimadamore@1113: nextToken();
duke@1: }
duke@1: return toP(t);
duke@1: }
duke@1:
mcimadamore@1165: /**
mcimadamore@1165: * If we see an identifier followed by a '<' it could be an unbound
mcimadamore@1165: * method reference or a binary expression. To disambiguate, look for a
mcimadamore@1165: * matching '>' and see if the subsequent terminal is either '.' or '#'.
mcimadamore@1165: */
mcimadamore@1165: @SuppressWarnings("fallthrough")
mcimadamore@1165: boolean isUnboundMemberRef() {
mcimadamore@1165: int pos = 0, depth = 0;
mcimadamore@1165: for (Token t = S.token(pos) ; ; t = S.token(++pos)) {
mcimadamore@1165: switch (t.kind) {
mcimadamore@1165: case IDENTIFIER: case QUES: case EXTENDS: case SUPER:
mcimadamore@1165: case DOT: case RBRACKET: case LBRACKET: case COMMA:
mcimadamore@1165: case BYTE: case SHORT: case INT: case LONG: case FLOAT:
mcimadamore@1165: case DOUBLE: case BOOLEAN: case CHAR:
mcimadamore@1165: break;
mcimadamore@1165: case LT:
mcimadamore@1165: depth++; break;
mcimadamore@1165: case GTGTGT:
mcimadamore@1165: depth--;
mcimadamore@1165: case GTGT:
mcimadamore@1165: depth--;
mcimadamore@1165: case GT:
mcimadamore@1165: depth--;
mcimadamore@1165: if (depth == 0) {
mcimadamore@1165: return
mcimadamore@1165: S.token(pos + 1).kind == TokenKind.DOT ||
mcimadamore@1165: S.token(pos + 1).kind == TokenKind.HASH;
mcimadamore@1165: }
mcimadamore@1165: break;
mcimadamore@1165: default:
mcimadamore@1165: return false;
mcimadamore@1165: }
mcimadamore@1165: }
mcimadamore@1165: }
mcimadamore@1165:
mcimadamore@1144: JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
mcimadamore@1144: ListBuffer params = new ListBuffer();
mcimadamore@1144: params.append(firstParam);
mcimadamore@1144: JCVariableDecl lastParam = firstParam;
mcimadamore@1144: while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
mcimadamore@1144: nextToken();
mcimadamore@1144: params.append(lastParam = formalParameter());
mcimadamore@1144: }
mcimadamore@1144: accept(RPAREN);
mcimadamore@1144: return lambdaExpressionOrStatementRest(params.toList(), pos);
mcimadamore@1144: }
mcimadamore@1144:
mcimadamore@1144: JCExpression lambdaExpressionOrStatement(boolean hasParens, boolean explicitParams, int pos) {
mcimadamore@1144: List params = explicitParams ?
mcimadamore@1144: formalParameters() :
mcimadamore@1144: implicitParameters(hasParens);
mcimadamore@1144:
mcimadamore@1144: return lambdaExpressionOrStatementRest(params, pos);
mcimadamore@1144: }
mcimadamore@1144:
mcimadamore@1144: JCExpression lambdaExpressionOrStatementRest(List args, int pos) {
mcimadamore@1144: if (token.kind != ARROW) {
mcimadamore@1144: //better error recovery
mcimadamore@1144: return F.at(pos).Erroneous(args);
mcimadamore@1144: }
mcimadamore@1144:
mcimadamore@1144: checkLambda();
mcimadamore@1144: accept(ARROW);
mcimadamore@1144:
mcimadamore@1144: return token.kind == LBRACE ?
mcimadamore@1144: lambdaStatement(args, pos, pos) :
mcimadamore@1144: lambdaExpression(args, pos);
mcimadamore@1144: }
mcimadamore@1144:
mcimadamore@1144: JCExpression lambdaStatement(List args, int pos, int pos2) {
mcimadamore@1144: JCBlock block = block(pos2, 0);
mcimadamore@1144: return toP(F.at(pos).Lambda(args, block));
mcimadamore@1144: }
mcimadamore@1144:
mcimadamore@1144: JCExpression lambdaExpression(List args, int pos) {
mcimadamore@1144: JCTree expr = parseExpression();
mcimadamore@1144: return toP(F.at(pos).Lambda(args, expr));
mcimadamore@1144: }
mcimadamore@1144:
duke@1: /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments]
duke@1: */
duke@1: JCExpression superSuffix(List typeArgs, JCExpression t) {
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == LPAREN || typeArgs != null) {
duke@1: t = arguments(typeArgs, t);
mcimadamore@1145: } else if (token.kind == HASH) {
mcimadamore@1145: if (typeArgs != null) return illegal();
mcimadamore@1145: t = memberReferenceSuffix(t);
duke@1: } else {
mcimadamore@1113: int pos = token.pos;
duke@1: accept(DOT);
mcimadamore@1113: typeArgs = (token.kind == LT) ? typeArguments(false) : null;
duke@1: t = toP(F.at(pos).Select(t, ident()));
duke@1: t = argumentsOpt(typeArgs, t);
duke@1: }
duke@1: return t;
duke@1: }
duke@1:
duke@1: /** BasicType = BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE | BOOLEAN
duke@1: */
duke@1: JCPrimitiveTypeTree basicType() {
mcimadamore@1113: JCPrimitiveTypeTree t = to(F.at(token.pos).TypeIdent(typetag(token.kind)));
mcimadamore@1113: nextToken();
duke@1: return t;
duke@1: }
duke@1:
duke@1: /** ArgumentsOpt = [ Arguments ]
duke@1: */
duke@1: JCExpression argumentsOpt(List typeArgs, JCExpression t) {
mcimadamore@1113: if ((mode & EXPR) != 0 && token.kind == LPAREN || typeArgs != null) {
duke@1: mode = EXPR;
duke@1: return arguments(typeArgs, t);
duke@1: } else {
duke@1: return t;
duke@1: }
duke@1: }
duke@1:
duke@1: /** Arguments = "(" [Expression { COMMA Expression }] ")"
duke@1: */
duke@1: List arguments() {
duke@1: ListBuffer args = lb();
mcimadamore@1113: if (token.kind == LPAREN) {
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind != RPAREN) {
jjg@111: args.append(parseExpression());
mcimadamore@1113: while (token.kind == COMMA) {
mcimadamore@1113: nextToken();
jjg@111: args.append(parseExpression());
duke@1: }
duke@1: }
duke@1: accept(RPAREN);
duke@1: } else {
mcimadamore@1113: syntaxError(token.pos, "expected", LPAREN);
duke@1: }
duke@1: return args.toList();
duke@1: }
duke@1:
duke@1: JCMethodInvocation arguments(List typeArgs, JCExpression t) {
mcimadamore@1113: int pos = token.pos;
duke@1: List args = arguments();
duke@1: return toP(F.at(pos).Apply(typeArgs, t, args));
duke@1: }
duke@1:
duke@1: /** TypeArgumentsOpt = [ TypeArguments ]
duke@1: */
duke@1: JCExpression typeArgumentsOpt(JCExpression t) {
mcimadamore@1113: if (token.kind == LT &&
duke@1: (mode & TYPE) != 0 &&
duke@1: (mode & NOPARAMS) == 0) {
duke@1: mode = TYPE;
duke@1: checkGenerics();
mcimadamore@948: return typeArguments(t, false);
duke@1: } else {
duke@1: return t;
duke@1: }
duke@1: }
duke@1: List typeArgumentsOpt() {
duke@1: return typeArgumentsOpt(TYPE);
duke@1: }
duke@1:
duke@1: List typeArgumentsOpt(int useMode) {
mcimadamore@1113: if (token.kind == LT) {
duke@1: checkGenerics();
duke@1: if ((mode & useMode) == 0 ||
duke@1: (mode & NOPARAMS) != 0) {
duke@1: illegal();
duke@1: }
duke@1: mode = useMode;
mcimadamore@948: return typeArguments(false);
duke@1: }
duke@1: return null;
duke@1: }
duke@1:
jjg@1326: /**
jjg@1326: * {@literal
jjg@1326: * TypeArguments = "<" TypeArgument {"," TypeArgument} ">"
jjg@1326: * }
duke@1: */
mcimadamore@948: List typeArguments(boolean diamondAllowed) {
mcimadamore@1113: if (token.kind == LT) {
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == GT && diamondAllowed) {
mcimadamore@537: checkDiamond();
mcimadamore@948: mode |= DIAMOND;
mcimadamore@1113: nextToken();
mcimadamore@537: return List.nil();
mcimadamore@948: } else {
mcimadamore@948: ListBuffer args = ListBuffer.lb();
jjg@111: args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
mcimadamore@1113: while (token.kind == COMMA) {
mcimadamore@1113: nextToken();
mcimadamore@948: args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
mcimadamore@948: }
mcimadamore@1113: switch (token.kind) {
mcimadamore@1113:
mcimadamore@1113: case GTGTGTEQ: case GTGTEQ: case GTEQ:
mcimadamore@1113: case GTGTGT: case GTGT:
mcimadamore@1113: token = S.split();
mcimadamore@948: break;
ksrini@1074: case GT:
mcimadamore@1113: nextToken();
ksrini@1074: break;
mcimadamore@948: default:
mcimadamore@1113: args.append(syntaxError(token.pos, "expected", GT));
mcimadamore@948: break;
mcimadamore@948: }
mcimadamore@948: return args.toList();
duke@1: }
duke@1: } else {
mcimadamore@1113: return List.of(syntaxError(token.pos, "expected", LT));
duke@1: }
duke@1: }
duke@1:
jjg@1326: /**
jjg@1326: * {@literal
jjg@1326: * TypeArgument = Type
jjg@722: * | "?"
jjg@722: * | "?" EXTENDS Type {"&" Type}
jjg@722: * | "?" SUPER Type
jjg@1326: * }
duke@1: */
duke@1: JCExpression typeArgument() {
mcimadamore@1113: if (token.kind != QUES) return parseType();
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == EXTENDS) {
jjg@482: TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.EXTENDS));
mcimadamore@1113: nextToken();
jjg@482: JCExpression bound = parseType();
jjg@722: return F.at(pos).Wildcard(t, bound);
mcimadamore@1113: } else if (token.kind == SUPER) {
jjg@482: TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.SUPER));
mcimadamore@1113: nextToken();
jjg@482: JCExpression bound = parseType();
jjg@722: return F.at(pos).Wildcard(t, bound);
mcimadamore@1113: } else if (token.kind == IDENTIFIER) {
duke@1: //error recovery
duke@1: TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
duke@1: JCExpression wc = toP(F.at(pos).Wildcard(t, null));
mcimadamore@1113: JCIdent id = toP(F.at(token.pos).Ident(ident()));
ksrini@1074: JCErroneous err = F.at(pos).Erroneous(List.of(wc, id));
ksrini@1074: reportSyntaxError(err, "expected3", GT, EXTENDS, SUPER);
ksrini@1074: return err;
duke@1: } else {
jjg@482: TypeBoundKind t = toP(F.at(pos).TypeBoundKind(BoundKind.UNBOUND));
jjg@722: return toP(F.at(pos).Wildcard(t, null));
duke@1: }
duke@1: }
duke@1:
mcimadamore@948: JCTypeApply typeArguments(JCExpression t, boolean diamondAllowed) {
mcimadamore@1113: int pos = token.pos;
mcimadamore@948: List args = typeArguments(diamondAllowed);
duke@1: return toP(F.at(pos).TypeApply(t, args));
duke@1: }
duke@1:
jjg@722: /** BracketsOpt = {"[" "]"}
duke@1: */
jjg@722: private JCExpression bracketsOpt(JCExpression t) {
mcimadamore@1113: if (token.kind == LBRACKET) {
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: nextToken();
jjg@722: t = bracketsOptCont(t, pos);
jjg@722: F.at(pos);
duke@1: }
duke@1: return t;
duke@1: }
duke@1:
jjg@722: private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos) {
duke@1: accept(RBRACKET);
jjg@722: t = bracketsOpt(t);
duke@1: return toP(F.at(pos).TypeArray(t));
duke@1: }
duke@1:
duke@1: /** BracketsSuffixExpr = "." CLASS
duke@1: * BracketsSuffixType =
duke@1: */
duke@1: JCExpression bracketsSuffix(JCExpression t) {
mcimadamore@1113: if ((mode & EXPR) != 0 && token.kind == DOT) {
duke@1: mode = EXPR;
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: nextToken();
duke@1: accept(CLASS);
ksrini@1138: if (token.pos == endPosTable.errorEndPos) {
duke@1: // error recovery
duke@1: Name name = null;
mcimadamore@1113: if (token.kind == IDENTIFIER) {
mcimadamore@1113: name = token.name();
mcimadamore@1113: nextToken();
duke@1: } else {
duke@1: name = names.error;
duke@1: }
duke@1: t = F.at(pos).Erroneous(List.of(toP(F.at(pos).Select(t, name))));
duke@1: } else {
duke@1: t = toP(F.at(pos).Select(t, names._class));
duke@1: }
duke@1: } else if ((mode & TYPE) != 0) {
duke@1: mode = TYPE;
duke@1: } else {
mcimadamore@1113: syntaxError(token.pos, "dot.class.expected");
duke@1: }
duke@1: return t;
duke@1: }
duke@1:
mcimadamore@1145: /**
mcimadamore@1145: * MemberReferenceSuffix = "#" [TypeArguments] Ident
mcimadamore@1145: * | "#" [TypeArguments] "new"
mcimadamore@1145: */
mcimadamore@1145: JCExpression memberReferenceSuffix(JCExpression t) {
mcimadamore@1145: int pos1 = token.pos;
mcimadamore@1145: accept(HASH);
mcimadamore@1145: return memberReferenceSuffix(pos1, t);
mcimadamore@1145: }
mcimadamore@1145:
mcimadamore@1145: JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
mcimadamore@1145: checkMethodReferences();
mcimadamore@1145: mode = EXPR;
mcimadamore@1145: List typeArgs = null;
mcimadamore@1145: if (token.kind == LT) {
mcimadamore@1145: typeArgs = typeArguments(false);
mcimadamore@1145: }
mcimadamore@1145: Name refName = null;
mcimadamore@1145: ReferenceMode refMode = null;
mcimadamore@1145: if (token.kind == NEW) {
mcimadamore@1145: refMode = ReferenceMode.NEW;
mcimadamore@1145: refName = names.init;
mcimadamore@1145: nextToken();
mcimadamore@1145: } else {
mcimadamore@1145: refMode = ReferenceMode.INVOKE;
mcimadamore@1145: refName = ident();
mcimadamore@1145: }
mcimadamore@1145: return toP(F.at(t.getStartPosition()).Reference(refMode, refName, t, typeArgs));
mcimadamore@1145: }
mcimadamore@1145:
jjg@722: /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
duke@1: */
duke@1: JCExpression creator(int newpos, List typeArgs) {
mcimadamore@1113: switch (token.kind) {
duke@1: case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
duke@1: case DOUBLE: case BOOLEAN:
jjg@722: if (typeArgs == null)
jjg@722: return arrayCreatorRest(newpos, basicType());
duke@1: break;
duke@1: default:
duke@1: }
duke@1: JCExpression t = qualident();
duke@1: int oldmode = mode;
mcimadamore@948: mode = TYPE;
mcimadamore@948: boolean diamondFound = false;
mcimadamore@1061: int lastTypeargsPos = -1;
mcimadamore@1113: if (token.kind == LT) {
duke@1: checkGenerics();
mcimadamore@1113: lastTypeargsPos = token.pos;
mcimadamore@948: t = typeArguments(t, true);
mcimadamore@948: diamondFound = (mode & DIAMOND) != 0;
duke@1: }
mcimadamore@1113: while (token.kind == DOT) {
mcimadamore@948: if (diamondFound) {
mcimadamore@948: //cannot select after a diamond
ksrini@1074: illegal();
mcimadamore@948: }
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: nextToken();
duke@1: t = toP(F.at(pos).Select(t, ident()));
mcimadamore@1113: if (token.kind == LT) {
mcimadamore@1113: lastTypeargsPos = token.pos;
duke@1: checkGenerics();
mcimadamore@948: t = typeArguments(t, true);
mcimadamore@948: diamondFound = (mode & DIAMOND) != 0;
duke@1: }
duke@1: }
duke@1: mode = oldmode;
mcimadamore@1113: if (token.kind == LBRACKET) {
duke@1: JCExpression e = arrayCreatorRest(newpos, t);
mcimadamore@1061: if (diamondFound) {
mcimadamore@1061: reportSyntaxError(lastTypeargsPos, "cannot.create.array.with.diamond");
mcimadamore@1061: return toP(F.at(newpos).Erroneous(List.of(e)));
mcimadamore@1061: }
mcimadamore@1061: else if (typeArgs != null) {
duke@1: int pos = newpos;
duke@1: if (!typeArgs.isEmpty() && typeArgs.head.pos != Position.NOPOS) {
duke@1: // note: this should always happen but we should
duke@1: // not rely on this as the parser is continuously
duke@1: // modified to improve error recovery.
duke@1: pos = typeArgs.head.pos;
duke@1: }
mcimadamore@1113: setErrorEndPos(S.prevToken().endPos);
ksrini@1074: JCErroneous err = F.at(pos).Erroneous(typeArgs.prepend(e));
ksrini@1074: reportSyntaxError(err, "cannot.create.array.with.type.arguments");
ksrini@1074: return toP(err);
duke@1: }
duke@1: return e;
mcimadamore@1113: } else if (token.kind == LPAREN) {
jjg@722: return classCreatorRest(newpos, null, typeArgs, t);
duke@1: } else {
mcimadamore@1113: setErrorEndPos(token.pos);
mcimadamore@1113: reportSyntaxError(token.pos, "expected2", LPAREN, LBRACKET);
duke@1: t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.nil(), null));
duke@1: return toP(F.at(newpos).Erroneous(List.of(t)));
duke@1: }
duke@1: }
duke@1:
duke@1: /** InnerCreator = Ident [TypeArguments] ClassCreatorRest
duke@1: */
duke@1: JCExpression innerCreator(int newpos, List typeArgs, JCExpression encl) {
mcimadamore@1113: JCExpression t = toP(F.at(token.pos).Ident(ident()));
mcimadamore@1113: if (token.kind == LT) {
mcimadamore@537: int oldmode = mode;
duke@1: checkGenerics();
mcimadamore@948: t = typeArguments(t, true);
mcimadamore@537: mode = oldmode;
duke@1: }
duke@1: return classCreatorRest(newpos, encl, typeArgs, t);
duke@1: }
duke@1:
jjg@722: /** ArrayCreatorRest = "[" ( "]" BracketsOpt ArrayInitializer
jjg@722: * | Expression "]" {"[" Expression "]"} BracketsOpt )
duke@1: */
duke@1: JCExpression arrayCreatorRest(int newpos, JCExpression elemtype) {
duke@1: accept(LBRACKET);
mcimadamore@1113: if (token.kind == RBRACKET) {
duke@1: accept(RBRACKET);
jjg@722: elemtype = bracketsOpt(elemtype);
mcimadamore@1113: if (token.kind == LBRACE) {
jjg@722: return arrayInitializer(newpos, elemtype);
duke@1: } else {
ksrini@1074: JCExpression t = toP(F.at(newpos).NewArray(elemtype, List.nil(), null));
mcimadamore@1113: return syntaxError(token.pos, List.of(t), "array.dimension.missing");
duke@1: }
duke@1: } else {
duke@1: ListBuffer dims = new ListBuffer();
jjg@111: dims.append(parseExpression());
duke@1: accept(RBRACKET);
mcimadamore@1113: while (token.kind == LBRACKET) {
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == RBRACKET) {
jjg@722: elemtype = bracketsOptCont(elemtype, pos);
duke@1: } else {
jjg@722: dims.append(parseExpression());
jjg@722: accept(RBRACKET);
duke@1: }
duke@1: }
jjg@722: return toP(F.at(newpos).NewArray(elemtype, dims.toList(), null));
duke@1: }
duke@1: }
duke@1:
duke@1: /** ClassCreatorRest = Arguments [ClassBody]
duke@1: */
jjg@308: JCNewClass classCreatorRest(int newpos,
duke@1: JCExpression encl,
duke@1: List typeArgs,
duke@1: JCExpression t)
duke@1: {
duke@1: List args = arguments();
duke@1: JCClassDecl body = null;
mcimadamore@1113: if (token.kind == LBRACE) {
mcimadamore@1113: int pos = token.pos;
duke@1: List defs = classOrInterfaceBody(names.empty, false);
duke@1: JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
duke@1: body = toP(F.at(pos).AnonymousClassDef(mods, defs));
duke@1: }
duke@1: return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
duke@1: }
duke@1:
duke@1: /** ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}"
duke@1: */
duke@1: JCExpression arrayInitializer(int newpos, JCExpression t) {
duke@1: accept(LBRACE);
duke@1: ListBuffer elems = new ListBuffer();
mcimadamore@1113: if (token.kind == COMMA) {
mcimadamore@1113: nextToken();
mcimadamore@1113: } else if (token.kind != RBRACE) {
duke@1: elems.append(variableInitializer());
mcimadamore@1113: while (token.kind == COMMA) {
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == RBRACE) break;
duke@1: elems.append(variableInitializer());
duke@1: }
duke@1: }
duke@1: accept(RBRACE);
duke@1: return toP(F.at(newpos).NewArray(t, List.nil(), elems.toList()));
duke@1: }
duke@1:
duke@1: /** VariableInitializer = ArrayInitializer | Expression
duke@1: */
duke@1: public JCExpression variableInitializer() {
mcimadamore@1113: return token.kind == LBRACE ? arrayInitializer(token.pos, null) : parseExpression();
duke@1: }
duke@1:
duke@1: /** ParExpression = "(" Expression ")"
duke@1: */
duke@1: JCExpression parExpression() {
ksrini@1138: int pos = token.pos;
duke@1: accept(LPAREN);
jjg@111: JCExpression t = parseExpression();
duke@1: accept(RPAREN);
ksrini@1138: return toP(F.at(pos).Parens(t));
duke@1: }
duke@1:
duke@1: /** Block = "{" BlockStatements "}"
duke@1: */
duke@1: JCBlock block(int pos, long flags) {
duke@1: accept(LBRACE);
duke@1: List stats = blockStatements();
duke@1: JCBlock t = F.at(pos).Block(flags, stats);
mcimadamore@1113: while (token.kind == CASE || token.kind == DEFAULT) {
mcimadamore@1113: syntaxError("orphaned", token.kind);
duke@1: switchBlockStatementGroups();
duke@1: }
duke@1: // the Block node has a field "endpos" for first char of last token, which is
duke@1: // usually but not necessarily the last char of the last token.
mcimadamore@1113: t.endpos = token.pos;
duke@1: accept(RBRACE);
duke@1: return toP(t);
duke@1: }
duke@1:
duke@1: public JCBlock block() {
mcimadamore@1113: return block(token.pos, 0);
duke@1: }
duke@1:
duke@1: /** BlockStatements = { BlockStatement }
duke@1: * BlockStatement = LocalVariableDeclarationStatement
duke@1: * | ClassOrInterfaceOrEnumDeclaration
duke@1: * | [Ident ":"] Statement
duke@1: * LocalVariableDeclarationStatement
duke@1: * = { FINAL | '@' Annotation } Type VariableDeclarators ";"
duke@1: */
duke@1: @SuppressWarnings("fallthrough")
duke@1: List blockStatements() {
ksrini@1249: //todo: skip to anchor on error(?)
duke@1: ListBuffer stats = new ListBuffer();
duke@1: while (true) {
ksrini@1249: List stat = blockStatement();
ksrini@1249: if (stat.isEmpty()) {
duke@1: return stats.toList();
ksrini@1249: } else {
ksrini@1249: if (token.pos <= endPosTable.errorEndPos) {
ksrini@1249: skip(false, true, true, true);
ksrini@1249: }
ksrini@1249: stats.addAll(stat);
ksrini@1249: }
ksrini@1249: }
ksrini@1249: }
ksrini@1249:
ksrini@1249: /*
ksrini@1249: * This method parses a statement treating it as a block, relaxing the
ksrini@1249: * JLS restrictions, allows us to parse more faulty code, doing so
ksrini@1249: * enables us to provide better and accurate diagnostics to the user.
ksrini@1249: */
ksrini@1249: JCStatement parseStatementAsBlock() {
ksrini@1249: int pos = token.pos;
ksrini@1249: List stats = blockStatement();
ksrini@1249: if (stats.isEmpty()) {
ksrini@1249: JCErroneous e = F.at(pos).Erroneous();
ksrini@1249: error(e, "illegal.start.of.stmt");
ksrini@1249: return F.at(pos).Exec(e);
ksrini@1249: } else {
ksrini@1249: JCStatement first = stats.head;
ksrini@1249: String error = null;
ksrini@1249: switch (first.getTag()) {
ksrini@1249: case CLASSDEF:
ksrini@1249: error = "class.not.allowed";
duke@1: break;
ksrini@1249: case VARDEF:
ksrini@1249: error = "variable.not.allowed";
duke@1: break;
duke@1: }
ksrini@1249: if (error != null) {
ksrini@1249: error(first, error);
ksrini@1249: List blist = List.of(F.at(first.pos).Block(0, stats));
ksrini@1249: return toP(F.at(pos).Exec(F.at(first.pos).Erroneous(blist)));
duke@1: }
ksrini@1249: return first;
ksrini@1249: }
ksrini@1249: }
ksrini@1249:
ksrini@1249: @SuppressWarnings("fallthrough")
ksrini@1249: List blockStatement() {
ksrini@1249: //todo: skip to anchor on error(?)
ksrini@1249: int pos = token.pos;
ksrini@1249: switch (token.kind) {
ksrini@1249: case RBRACE: case CASE: case DEFAULT: case EOF:
ksrini@1249: return List.nil();
ksrini@1249: case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY:
ksrini@1249: case SWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK:
ksrini@1249: case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH:
ksrini@1249: return List.of(parseStatement());
ksrini@1249: case MONKEYS_AT:
ksrini@1249: case FINAL: {
jjg@1280: Comment dc = token.comment(CommentStyle.JAVADOC);
ksrini@1249: JCModifiers mods = modifiersOpt();
ksrini@1249: if (token.kind == INTERFACE ||
ksrini@1249: token.kind == CLASS ||
ksrini@1249: allowEnums && token.kind == ENUM) {
ksrini@1249: return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
ksrini@1249: } else {
ksrini@1249: JCExpression t = parseType();
ksrini@1249: ListBuffer stats =
ksrini@1249: variableDeclarators(mods, t, new ListBuffer());
ksrini@1249: // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
ksrini@1249: storeEnd(stats.elems.last(), token.endPos);
ksrini@1249: accept(SEMI);
ksrini@1249: return stats.toList();
duke@1: }
ksrini@1249: }
ksrini@1249: case ABSTRACT: case STRICTFP: {
jjg@1280: Comment dc = token.comment(CommentStyle.JAVADOC);
ksrini@1249: JCModifiers mods = modifiersOpt();
ksrini@1249: return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
ksrini@1249: }
ksrini@1249: case INTERFACE:
ksrini@1249: case CLASS:
jjg@1280: Comment dc = token.comment(CommentStyle.JAVADOC);
ksrini@1249: return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
ksrini@1249: case ENUM:
ksrini@1249: case ASSERT:
ksrini@1249: if (allowEnums && token.kind == ENUM) {
ksrini@1249: error(token.pos, "local.enum");
ksrini@1249: dc = token.comment(CommentStyle.JAVADOC);
ksrini@1249: return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
ksrini@1249: } else if (allowAsserts && token.kind == ASSERT) {
ksrini@1249: return List.of(parseStatement());
ksrini@1249: }
ksrini@1249: /* fall through to default */
ksrini@1249: default:
ksrini@1249: Token prevToken = token;
ksrini@1249: JCExpression t = term(EXPR | TYPE);
ksrini@1249: if (token.kind == COLON && t.hasTag(IDENT)) {
ksrini@1249: nextToken();
ksrini@1249: JCStatement stat = parseStatement();
ksrini@1249: return List.of(F.at(pos).Labelled(prevToken.name(), stat));
ksrini@1249: } else if ((lastmode & TYPE) != 0 &&
ksrini@1249: (token.kind == IDENTIFIER ||
ksrini@1249: token.kind == ASSERT ||
ksrini@1249: token.kind == ENUM)) {
ksrini@1249: pos = token.pos;
ksrini@1249: JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
ksrini@1249: F.at(pos);
ksrini@1249: ListBuffer stats =
ksrini@1249: variableDeclarators(mods, t, new ListBuffer());
ksrini@1249: // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
ksrini@1249: storeEnd(stats.elems.last(), token.endPos);
ksrini@1249: accept(SEMI);
duke@1: return stats.toList();
ksrini@1249: } else {
ksrini@1249: // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
ksrini@1249: JCExpressionStatement expr = to(F.at(pos).Exec(checkExprStat(t)));
ksrini@1249: accept(SEMI);
ksrini@1249: return List.of(expr);
duke@1: }
duke@1: }
duke@1: }
duke@1:
duke@1: /** Statement =
duke@1: * Block
duke@1: * | IF ParExpression Statement [ELSE Statement]
duke@1: * | FOR "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement
duke@1: * | FOR "(" FormalParameter : Expression ")" Statement
duke@1: * | WHILE ParExpression Statement
duke@1: * | DO Statement WHILE ParExpression ";"
duke@1: * | TRY Block ( Catches | [Catches] FinallyPart )
darcy@850: * | TRY "(" ResourceSpecification ";"opt ")" Block [Catches] [FinallyPart]
duke@1: * | SWITCH ParExpression "{" SwitchBlockStatementGroups "}"
duke@1: * | SYNCHRONIZED ParExpression Block
duke@1: * | RETURN [Expression] ";"
duke@1: * | THROW Expression ";"
duke@1: * | BREAK [Ident] ";"
duke@1: * | CONTINUE [Ident] ";"
duke@1: * | ASSERT Expression [ ":" Expression ] ";"
duke@1: * | ";"
duke@1: * | ExpressionStatement
duke@1: * | Ident ":" Statement
duke@1: */
duke@1: @SuppressWarnings("fallthrough")
jjg@111: public JCStatement parseStatement() {
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: switch (token.kind) {
duke@1: case LBRACE:
duke@1: return block();
duke@1: case IF: {
mcimadamore@1113: nextToken();
duke@1: JCExpression cond = parExpression();
ksrini@1249: JCStatement thenpart = parseStatementAsBlock();
duke@1: JCStatement elsepart = null;
mcimadamore@1113: if (token.kind == ELSE) {
mcimadamore@1113: nextToken();
ksrini@1249: elsepart = parseStatementAsBlock();
duke@1: }
duke@1: return F.at(pos).If(cond, thenpart, elsepart);
duke@1: }
duke@1: case FOR: {
mcimadamore@1113: nextToken();
duke@1: accept(LPAREN);
mcimadamore@1113: List inits = token.kind == SEMI ? List.nil() : forInit();
duke@1: if (inits.length() == 1 &&
jjg@1127: inits.head.hasTag(VARDEF) &&
duke@1: ((JCVariableDecl) inits.head).init == null &&
mcimadamore@1113: token.kind == COLON) {
duke@1: checkForeach();
duke@1: JCVariableDecl var = (JCVariableDecl)inits.head;
duke@1: accept(COLON);
jjg@111: JCExpression expr = parseExpression();
duke@1: accept(RPAREN);
ksrini@1249: JCStatement body = parseStatementAsBlock();
duke@1: return F.at(pos).ForeachLoop(var, expr, body);
duke@1: } else {
duke@1: accept(SEMI);
mcimadamore@1113: JCExpression cond = token.kind == SEMI ? null : parseExpression();
duke@1: accept(SEMI);
mcimadamore@1113: List steps = token.kind == RPAREN ? List.nil() : forUpdate();
duke@1: accept(RPAREN);
ksrini@1249: JCStatement body = parseStatementAsBlock();
duke@1: return F.at(pos).ForLoop(inits, cond, steps, body);
duke@1: }
duke@1: }
duke@1: case WHILE: {
mcimadamore@1113: nextToken();
duke@1: JCExpression cond = parExpression();
ksrini@1249: JCStatement body = parseStatementAsBlock();
duke@1: return F.at(pos).WhileLoop(cond, body);
duke@1: }
duke@1: case DO: {
mcimadamore@1113: nextToken();
ksrini@1249: JCStatement body = parseStatementAsBlock();
duke@1: accept(WHILE);
duke@1: JCExpression cond = parExpression();
duke@1: JCDoWhileLoop t = to(F.at(pos).DoLoop(body, cond));
duke@1: accept(SEMI);
duke@1: return t;
duke@1: }
duke@1: case TRY: {
mcimadamore@1113: nextToken();
darcy@609: List resources = List.nil();
mcimadamore@1113: if (token.kind == LPAREN) {
mcimadamore@743: checkTryWithResources();
mcimadamore@1113: nextToken();
darcy@609: resources = resources();
darcy@609: accept(RPAREN);
darcy@609: }
duke@1: JCBlock body = block();
duke@1: ListBuffer catchers = new ListBuffer();
duke@1: JCBlock finalizer = null;
mcimadamore@1113: if (token.kind == CATCH || token.kind == FINALLY) {
mcimadamore@1113: while (token.kind == CATCH) catchers.append(catchClause());
mcimadamore@1113: if (token.kind == FINALLY) {
mcimadamore@1113: nextToken();
duke@1: finalizer = block();
duke@1: }
duke@1: } else {
darcy@609: if (allowTWR) {
darcy@609: if (resources.isEmpty())
jjg@726: error(pos, "try.without.catch.finally.or.resource.decls");
darcy@609: } else
jjg@726: error(pos, "try.without.catch.or.finally");
duke@1: }
darcy@609: return F.at(pos).Try(resources, body, catchers.toList(), finalizer);
duke@1: }
duke@1: case SWITCH: {
mcimadamore@1113: nextToken();
duke@1: JCExpression selector = parExpression();
duke@1: accept(LBRACE);
duke@1: List cases = switchBlockStatementGroups();
duke@1: JCSwitch t = to(F.at(pos).Switch(selector, cases));
duke@1: accept(RBRACE);
duke@1: return t;
duke@1: }
duke@1: case SYNCHRONIZED: {
mcimadamore@1113: nextToken();
duke@1: JCExpression lock = parExpression();
duke@1: JCBlock body = block();
duke@1: return F.at(pos).Synchronized(lock, body);
duke@1: }
duke@1: case RETURN: {
mcimadamore@1113: nextToken();
mcimadamore@1113: JCExpression result = token.kind == SEMI ? null : parseExpression();
duke@1: JCReturn t = to(F.at(pos).Return(result));
duke@1: accept(SEMI);
duke@1: return t;
duke@1: }
duke@1: case THROW: {
mcimadamore@1113: nextToken();
jjg@111: JCExpression exc = parseExpression();
duke@1: JCThrow t = to(F.at(pos).Throw(exc));
duke@1: accept(SEMI);
duke@1: return t;
duke@1: }
duke@1: case BREAK: {
mcimadamore@1113: nextToken();
mcimadamore@1113: Name label = (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM) ? ident() : null;
duke@1: JCBreak t = to(F.at(pos).Break(label));
duke@1: accept(SEMI);
duke@1: return t;
duke@1: }
duke@1: case CONTINUE: {
mcimadamore@1113: nextToken();
mcimadamore@1113: Name label = (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM) ? ident() : null;
duke@1: JCContinue t = to(F.at(pos).Continue(label));
duke@1: accept(SEMI);
duke@1: return t;
duke@1: }
duke@1: case SEMI:
mcimadamore@1113: nextToken();
duke@1: return toP(F.at(pos).Skip());
duke@1: case ELSE:
duke@1: return toP(F.Exec(syntaxError("else.without.if")));
duke@1: case FINALLY:
duke@1: return toP(F.Exec(syntaxError("finally.without.try")));
duke@1: case CATCH:
duke@1: return toP(F.Exec(syntaxError("catch.without.try")));
duke@1: case ASSERT: {
mcimadamore@1113: if (allowAsserts && token.kind == ASSERT) {
mcimadamore@1113: nextToken();
jjg@111: JCExpression assertion = parseExpression();
duke@1: JCExpression message = null;
mcimadamore@1113: if (token.kind == COLON) {
mcimadamore@1113: nextToken();
jjg@111: message = parseExpression();
duke@1: }
duke@1: JCAssert t = to(F.at(pos).Assert(assertion, message));
duke@1: accept(SEMI);
duke@1: return t;
duke@1: }
duke@1: /* else fall through to default case */
duke@1: }
duke@1: case ENUM:
duke@1: default:
mcimadamore@1113: Token prevToken = token;
jjg@111: JCExpression expr = parseExpression();
jjg@1127: if (token.kind == COLON && expr.hasTag(IDENT)) {
mcimadamore@1113: nextToken();
jjg@111: JCStatement stat = parseStatement();
mcimadamore@1113: return F.at(pos).Labelled(prevToken.name(), stat);
duke@1: } else {
duke@1: // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
duke@1: JCExpressionStatement stat = to(F.at(pos).Exec(checkExprStat(expr)));
duke@1: accept(SEMI);
duke@1: return stat;
duke@1: }
duke@1: }
duke@1: }
duke@1:
duke@1: /** CatchClause = CATCH "(" FormalParameter ")" Block
duke@1: */
ksrini@1074: protected JCCatch catchClause() {
mcimadamore@1113: int pos = token.pos;
duke@1: accept(CATCH);
duke@1: accept(LPAREN);
mcimadamore@550: JCModifiers mods = optFinal(Flags.PARAMETER);
mcimadamore@550: List catchTypes = catchTypes();
mcimadamore@550: JCExpression paramType = catchTypes.size() > 1 ?
darcy@969: toP(F.at(catchTypes.head.getStartPosition()).TypeUnion(catchTypes)) :
mcimadamore@550: catchTypes.head;
mcimadamore@550: JCVariableDecl formal = variableDeclaratorId(mods, paramType);
duke@1: accept(RPAREN);
duke@1: JCBlock body = block();
duke@1: return F.at(pos).Catch(formal, body);
duke@1: }
duke@1:
mcimadamore@550: List catchTypes() {
mcimadamore@550: ListBuffer catchTypes = ListBuffer.lb();
mcimadamore@550: catchTypes.add(parseType());
mcimadamore@1113: while (token.kind == BAR) {
mcimadamore@550: checkMulticatch();
mcimadamore@1113: nextToken();
mcimadamore@550: catchTypes.add(qualident());
mcimadamore@550: }
mcimadamore@550: return catchTypes.toList();
mcimadamore@550: }
mcimadamore@550:
duke@1: /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup }
duke@1: * SwitchBlockStatementGroup = SwitchLabel BlockStatements
duke@1: * SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":"
duke@1: */
duke@1: List switchBlockStatementGroups() {
duke@1: ListBuffer cases = new ListBuffer();
duke@1: while (true) {
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: switch (token.kind) {
ksrini@1346: case CASE:
ksrini@1346: case DEFAULT:
ksrini@1346: cases.append(switchBlockStatementGroup());
duke@1: break;
duke@1: case RBRACE: case EOF:
duke@1: return cases.toList();
duke@1: default:
mcimadamore@1113: nextToken(); // to ensure progress
duke@1: syntaxError(pos, "expected3",
mcimadamore@80: CASE, DEFAULT, RBRACE);
duke@1: }
duke@1: }
duke@1: }
duke@1:
ksrini@1346: protected JCCase switchBlockStatementGroup() {
ksrini@1346: int pos = token.pos;
ksrini@1346: List stats;
ksrini@1346: JCCase c;
ksrini@1346: switch (token.kind) {
ksrini@1346: case CASE:
ksrini@1346: nextToken();
ksrini@1346: JCExpression pat = parseExpression();
ksrini@1346: accept(COLON);
ksrini@1346: stats = blockStatements();
ksrini@1346: c = F.at(pos).Case(pat, stats);
ksrini@1346: if (stats.isEmpty())
ksrini@1346: storeEnd(c, S.prevToken().endPos);
ksrini@1346: return c;
ksrini@1346: case DEFAULT:
ksrini@1346: nextToken();
ksrini@1346: accept(COLON);
ksrini@1346: stats = blockStatements();
ksrini@1346: c = F.at(pos).Case(null, stats);
ksrini@1346: if (stats.isEmpty())
ksrini@1346: storeEnd(c, S.prevToken().endPos);
ksrini@1346: return c;
ksrini@1346: }
ksrini@1346: throw new AssertionError("should not reach here");
ksrini@1346: }
ksrini@1346:
duke@1: /** MoreStatementExpressions = { COMMA StatementExpression }
duke@1: */
duke@1: > T moreStatementExpressions(int pos,
duke@1: JCExpression first,
duke@1: T stats) {
duke@1: // This Exec is a "StatementExpression"; it subsumes no terminating token
duke@1: stats.append(toP(F.at(pos).Exec(checkExprStat(first))));
mcimadamore@1113: while (token.kind == COMMA) {
mcimadamore@1113: nextToken();
mcimadamore@1113: pos = token.pos;
jjg@111: JCExpression t = parseExpression();
duke@1: // This Exec is a "StatementExpression"; it subsumes no terminating token
duke@1: stats.append(toP(F.at(pos).Exec(checkExprStat(t))));
duke@1: }
duke@1: return stats;
duke@1: }
duke@1:
duke@1: /** ForInit = StatementExpression MoreStatementExpressions
duke@1: * | { FINAL | '@' Annotation } Type VariableDeclarators
duke@1: */
duke@1: List forInit() {
duke@1: ListBuffer stats = lb();
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: if (token.kind == FINAL || token.kind == MONKEYS_AT) {
jjg@111: return variableDeclarators(optFinal(0), parseType(), stats).toList();
duke@1: } else {
duke@1: JCExpression t = term(EXPR | TYPE);
duke@1: if ((lastmode & TYPE) != 0 &&
ksrini@1259: (token.kind == IDENTIFIER || token.kind == ASSERT ||
ksrini@1259: token.kind == ENUM)) {
duke@1: return variableDeclarators(modifiersOpt(), t, stats).toList();
ksrini@1259: } else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
ksrini@1259: error(pos, "bad.initializer", "for-loop");
ksrini@1259: return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
ksrini@1259: } else {
duke@1: return moreStatementExpressions(pos, t, stats).toList();
ksrini@1259: }
duke@1: }
duke@1: }
duke@1:
duke@1: /** ForUpdate = StatementExpression MoreStatementExpressions
duke@1: */
duke@1: List forUpdate() {
mcimadamore@1113: return moreStatementExpressions(token.pos,
jjg@111: parseExpression(),
duke@1: new ListBuffer()).toList();
duke@1: }
duke@1:
duke@1: /** AnnotationsOpt = { '@' Annotation }
duke@1: */
jjg@722: List annotationsOpt() {
mcimadamore@1113: if (token.kind != MONKEYS_AT) return List.nil(); // optimization
duke@1: ListBuffer buf = new ListBuffer();
mcimadamore@1113: while (token.kind == MONKEYS_AT) {
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: nextToken();
jjg@722: buf.append(annotation(pos));
duke@1: }
jjg@722: return buf.toList();
duke@1: }
duke@1:
duke@1: /** ModifiersOpt = { Modifier }
duke@1: * Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL
duke@1: * | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@"
duke@1: * | "@" Annotation
duke@1: */
duke@1: JCModifiers modifiersOpt() {
duke@1: return modifiersOpt(null);
duke@1: }
ksrini@1074: protected JCModifiers modifiersOpt(JCModifiers partial) {
jjg@482: long flags;
jjg@482: ListBuffer annotations = new ListBuffer();
jjg@482: int pos;
jjg@482: if (partial == null) {
jjg@482: flags = 0;
mcimadamore@1113: pos = token.pos;
jjg@482: } else {
jjg@482: flags = partial.flags;
jjg@482: annotations.appendList(partial.annotations);
jjg@482: pos = partial.pos;
jjg@482: }
mcimadamore@1125: if (token.deprecatedFlag()) {
duke@1: flags |= Flags.DEPRECATED;
duke@1: }
duke@1: int lastPos = Position.NOPOS;
duke@1: loop:
duke@1: while (true) {
duke@1: long flag;
mcimadamore@1113: switch (token.kind) {
duke@1: case PRIVATE : flag = Flags.PRIVATE; break;
duke@1: case PROTECTED : flag = Flags.PROTECTED; break;
duke@1: case PUBLIC : flag = Flags.PUBLIC; break;
duke@1: case STATIC : flag = Flags.STATIC; break;
duke@1: case TRANSIENT : flag = Flags.TRANSIENT; break;
duke@1: case FINAL : flag = Flags.FINAL; break;
duke@1: case ABSTRACT : flag = Flags.ABSTRACT; break;
duke@1: case NATIVE : flag = Flags.NATIVE; break;
duke@1: case VOLATILE : flag = Flags.VOLATILE; break;
duke@1: case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break;
duke@1: case STRICTFP : flag = Flags.STRICTFP; break;
duke@1: case MONKEYS_AT : flag = Flags.ANNOTATION; break;
mcimadamore@1113: case ERROR : flag = 0; nextToken(); break;
duke@1: default: break loop;
duke@1: }
mcimadamore@1113: if ((flags & flag) != 0) error(token.pos, "repeated.modifier");
mcimadamore@1113: lastPos = token.pos;
mcimadamore@1113: nextToken();
duke@1: if (flag == Flags.ANNOTATION) {
duke@1: checkAnnotations();
mcimadamore@1113: if (token.kind != INTERFACE) {
jjg@722: JCAnnotation ann = annotation(lastPos);
jjg@482: // if first modifier is an annotation, set pos to annotation's.
jjg@482: if (flags == 0 && annotations.isEmpty())
jjg@482: pos = ann.pos;
jjg@482: annotations.append(ann);
jjg@482: lastPos = ann.pos;
duke@1: flag = 0;
duke@1: }
duke@1: }
duke@1: flags |= flag;
duke@1: }
mcimadamore@1113: switch (token.kind) {
duke@1: case ENUM: flags |= Flags.ENUM; break;
duke@1: case INTERFACE: flags |= Flags.INTERFACE; break;
duke@1: default: break;
duke@1: }
duke@1:
duke@1: /* A modifiers tree with no modifier tokens or annotations
duke@1: * has no text position. */
jjg@613: if ((flags & (Flags.ModifierFlags | Flags.ANNOTATION)) == 0 && annotations.isEmpty())
duke@1: pos = Position.NOPOS;
duke@1:
duke@1: JCModifiers mods = F.at(pos).Modifiers(flags, annotations.toList());
duke@1: if (pos != Position.NOPOS)
mcimadamore@1113: storeEnd(mods, S.prevToken().endPos);
duke@1: return mods;
duke@1: }
duke@1:
duke@1: /** Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ]
duke@1: * @param pos position of "@" token
duke@1: */
jjg@722: JCAnnotation annotation(int pos) {
duke@1: // accept(AT); // AT consumed by caller
duke@1: checkAnnotations();
duke@1: JCTree ident = qualident();
duke@1: List fieldValues = annotationFieldValuesOpt();
jjg@722: JCAnnotation ann = F.at(pos).Annotation(ident, fieldValues);
mcimadamore@1113: storeEnd(ann, S.prevToken().endPos);
duke@1: return ann;
duke@1: }
duke@1:
duke@1: List annotationFieldValuesOpt() {
mcimadamore@1113: return (token.kind == LPAREN) ? annotationFieldValues() : List.nil();
duke@1: }
duke@1:
duke@1: /** AnnotationFieldValues = "(" [ AnnotationFieldValue { "," AnnotationFieldValue } ] ")" */
duke@1: List annotationFieldValues() {
duke@1: accept(LPAREN);
duke@1: ListBuffer buf = new ListBuffer();
mcimadamore@1113: if (token.kind != RPAREN) {
duke@1: buf.append(annotationFieldValue());
mcimadamore@1113: while (token.kind == COMMA) {
mcimadamore@1113: nextToken();
duke@1: buf.append(annotationFieldValue());
duke@1: }
duke@1: }
duke@1: accept(RPAREN);
duke@1: return buf.toList();
duke@1: }
duke@1:
duke@1: /** AnnotationFieldValue = AnnotationValue
duke@1: * | Identifier "=" AnnotationValue
duke@1: */
duke@1: JCExpression annotationFieldValue() {
mcimadamore@1113: if (token.kind == IDENTIFIER) {
duke@1: mode = EXPR;
duke@1: JCExpression t1 = term1();
jjg@1127: if (t1.hasTag(IDENT) && token.kind == EQ) {
mcimadamore@1113: int pos = token.pos;
duke@1: accept(EQ);
jjg@482: JCExpression v = annotationValue();
jjg@482: return toP(F.at(pos).Assign(t1, v));
duke@1: } else {
duke@1: return t1;
duke@1: }
duke@1: }
duke@1: return annotationValue();
duke@1: }
duke@1:
duke@1: /* AnnotationValue = ConditionalExpression
duke@1: * | Annotation
darcy@417: * | "{" [ AnnotationValue { "," AnnotationValue } ] [","] "}"
duke@1: */
duke@1: JCExpression annotationValue() {
duke@1: int pos;
mcimadamore@1113: switch (token.kind) {
duke@1: case MONKEYS_AT:
mcimadamore@1113: pos = token.pos;
mcimadamore@1113: nextToken();
jjg@722: return annotation(pos);
duke@1: case LBRACE:
mcimadamore@1113: pos = token.pos;
duke@1: accept(LBRACE);
duke@1: ListBuffer buf = new ListBuffer();
mcimadamore@1113: if (token.kind != RBRACE) {
duke@1: buf.append(annotationValue());
mcimadamore@1113: while (token.kind == COMMA) {
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == RBRACE) break;
duke@1: buf.append(annotationValue());
duke@1: }
duke@1: }
duke@1: accept(RBRACE);
duke@1: return toP(F.at(pos).NewArray(null, List.nil(), buf.toList()));
duke@1: default:
duke@1: mode = EXPR;
duke@1: return term1();
duke@1: }
duke@1: }
duke@1:
duke@1: /** VariableDeclarators = VariableDeclarator { "," VariableDeclarator }
duke@1: */
duke@1: public > T variableDeclarators(JCModifiers mods,
duke@1: JCExpression type,
duke@1: T vdefs)
duke@1: {
mcimadamore@1113: return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs);
duke@1: }
duke@1:
duke@1: /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
duke@1: * ConstantDeclaratorsRest = ConstantDeclaratorRest { "," ConstantDeclarator }
duke@1: *
duke@1: * @param reqInit Is an initializer always required?
duke@1: * @param dc The documentation comment for the variable declarations, or null.
duke@1: */
duke@1: > T variableDeclaratorsRest(int pos,
duke@1: JCModifiers mods,
duke@1: JCExpression type,
duke@1: Name name,
duke@1: boolean reqInit,
jjg@1280: Comment dc,
duke@1: T vdefs)
duke@1: {
duke@1: vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc));
mcimadamore@1113: while (token.kind == COMMA) {
duke@1: // All but last of multiple declarators subsume a comma
mcimadamore@1113: storeEnd((JCTree)vdefs.elems.last(), token.endPos);
mcimadamore@1113: nextToken();
duke@1: vdefs.append(variableDeclarator(mods, type, reqInit, dc));
duke@1: }
duke@1: return vdefs;
duke@1: }
duke@1:
duke@1: /** VariableDeclarator = Ident VariableDeclaratorRest
duke@1: * ConstantDeclarator = Ident ConstantDeclaratorRest
duke@1: */
jjg@1280: JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
mcimadamore@1113: return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
duke@1: }
duke@1:
duke@1: /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
duke@1: * ConstantDeclaratorRest = BracketsOpt "=" VariableInitializer
duke@1: *
duke@1: * @param reqInit Is an initializer always required?
duke@1: * @param dc The documentation comment for the variable declarations, or null.
duke@1: */
duke@1: JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
jjg@1280: boolean reqInit, Comment dc) {
duke@1: type = bracketsOpt(type);
duke@1: JCExpression init = null;
mcimadamore@1113: if (token.kind == EQ) {
mcimadamore@1113: nextToken();
duke@1: init = variableInitializer();
duke@1: }
mcimadamore@1113: else if (reqInit) syntaxError(token.pos, "expected", EQ);
duke@1: JCVariableDecl result =
duke@1: toP(F.at(pos).VarDef(mods, name, type, init));
duke@1: attach(result, dc);
duke@1: return result;
duke@1: }
duke@1:
duke@1: /** VariableDeclaratorId = Ident BracketsOpt
duke@1: */
duke@1: JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
mcimadamore@1113: int pos = token.pos;
duke@1: Name name = ident();
mcimadamore@831: if ((mods.flags & Flags.VARARGS) != 0 &&
mcimadamore@1113: token.kind == LBRACKET) {
mcimadamore@1113: log.error(token.pos, "varargs.and.old.array.syntax");
mcimadamore@831: }
mcimadamore@831: type = bracketsOpt(type);
duke@1: return toP(F.at(pos).VarDef(mods, name, type, null));
duke@1: }
duke@1:
darcy@609: /** Resources = Resource { ";" Resources }
darcy@609: */
darcy@609: List resources() {
darcy@609: ListBuffer defs = new ListBuffer();
darcy@609: defs.append(resource());
mcimadamore@1113: while (token.kind == SEMI) {
darcy@850: // All but last of multiple declarators must subsume a semicolon
mcimadamore@1113: storeEnd(defs.elems.last(), token.endPos);
mcimadamore@1113: int semiColonPos = token.pos;
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == RPAREN) { // Optional trailing semicolon
darcy@840: // after last resource
darcy@840: break;
darcy@840: }
darcy@609: defs.append(resource());
darcy@609: }
darcy@609: return defs.toList();
darcy@609: }
darcy@609:
darcy@840: /** Resource = VariableModifiersOpt Type VariableDeclaratorId = Expression
darcy@609: */
ksrini@1074: protected JCTree resource() {
ksrini@1074: JCModifiers optFinal = optFinal(Flags.FINAL);
ksrini@1074: JCExpression type = parseType();
mcimadamore@1113: int pos = token.pos;
ksrini@1074: Name ident = ident();
ksrini@1074: return variableDeclaratorRest(pos, optFinal, type, ident, true, null);
darcy@609: }
darcy@609:
duke@1: /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration}
duke@1: */
jjg@111: public JCTree.JCCompilationUnit parseCompilationUnit() {
mcimadamore@1113: Token firstToken = token;
duke@1: JCExpression pid = null;
duke@1: JCModifiers mods = null;
mcimadamore@1113: boolean consumedToplevelDoc = false;
mcimadamore@1113: boolean seenImport = false;
mcimadamore@1113: boolean seenPackage = false;
duke@1: List packageAnnotations = List.nil();
mcimadamore@1113: if (token.kind == MONKEYS_AT)
duke@1: mods = modifiersOpt();
duke@1:
mcimadamore@1113: if (token.kind == PACKAGE) {
mcimadamore@1113: seenPackage = true;
duke@1: if (mods != null) {
duke@1: checkNoMods(mods.flags);
duke@1: packageAnnotations = mods.annotations;
duke@1: mods = null;
duke@1: }
mcimadamore@1113: nextToken();
duke@1: pid = qualident();
duke@1: accept(SEMI);
duke@1: }
duke@1: ListBuffer defs = new ListBuffer();
jjg@111: boolean checkForImports = true;
mcimadamore@1113: boolean firstTypeDecl = true;
mcimadamore@1113: while (token.kind != EOF) {
ksrini@1138: if (token.pos <= endPosTable.errorEndPos) {
duke@1: // error recovery
duke@1: skip(checkForImports, false, false, false);
mcimadamore@1113: if (token.kind == EOF)
duke@1: break;
duke@1: }
mcimadamore@1113: if (checkForImports && mods == null && token.kind == IMPORT) {
mcimadamore@1113: seenImport = true;
duke@1: defs.append(importDeclaration());
duke@1: } else {
jjg@1280: Comment docComment = token.comment(CommentStyle.JAVADOC);
mcimadamore@1113: if (firstTypeDecl && !seenImport && !seenPackage) {
mcimadamore@1125: docComment = firstToken.comment(CommentStyle.JAVADOC);
mcimadamore@1113: consumedToplevelDoc = true;
jjg@695: }
mcimadamore@1113: JCTree def = typeDeclaration(mods, docComment);
duke@1: if (def instanceof JCExpressionStatement)
duke@1: def = ((JCExpressionStatement)def).expr;
duke@1: defs.append(def);
duke@1: if (def instanceof JCClassDecl)
duke@1: checkForImports = false;
duke@1: mods = null;
mcimadamore@1113: firstTypeDecl = false;
duke@1: }
duke@1: }
mcimadamore@1113: JCTree.JCCompilationUnit toplevel = F.at(firstToken.pos).TopLevel(packageAnnotations, pid, defs.toList());
mcimadamore@1113: if (!consumedToplevelDoc)
mcimadamore@1125: attach(toplevel, firstToken.comment(CommentStyle.JAVADOC));
duke@1: if (defs.elems.isEmpty())
mcimadamore@1113: storeEnd(toplevel, S.prevToken().endPos);
jjg@111: if (keepDocComments)
jjg@111: toplevel.docComments = docComments;
jjg@111: if (keepLineMap)
jjg@111: toplevel.lineMap = S.getLineMap();
ksrini@1138: toplevel.endPositions = this.endPosTable;
duke@1: return toplevel;
duke@1: }
duke@1:
duke@1: /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";"
duke@1: */
duke@1: JCTree importDeclaration() {
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: nextToken();
duke@1: boolean importStatic = false;
mcimadamore@1113: if (token.kind == STATIC) {
duke@1: checkStaticImports();
duke@1: importStatic = true;
mcimadamore@1113: nextToken();
duke@1: }
mcimadamore@1113: JCExpression pid = toP(F.at(token.pos).Ident(ident()));
duke@1: do {
mcimadamore@1113: int pos1 = token.pos;
duke@1: accept(DOT);
mcimadamore@1113: if (token.kind == STAR) {
duke@1: pid = to(F.at(pos1).Select(pid, names.asterisk));
mcimadamore@1113: nextToken();
duke@1: break;
duke@1: } else {
duke@1: pid = toP(F.at(pos1).Select(pid, ident()));
duke@1: }
mcimadamore@1113: } while (token.kind == DOT);
duke@1: accept(SEMI);
duke@1: return toP(F.at(pos).Import(pid, importStatic));
duke@1: }
duke@1:
duke@1: /** TypeDeclaration = ClassOrInterfaceOrEnumDeclaration
duke@1: * | ";"
duke@1: */
jjg@1280: JCTree typeDeclaration(JCModifiers mods, Comment docComment) {
mcimadamore@1113: int pos = token.pos;
mcimadamore@1113: if (mods == null && token.kind == SEMI) {
mcimadamore@1113: nextToken();
duke@1: return toP(F.at(pos).Skip());
duke@1: } else {
mcimadamore@1113: return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment);
duke@1: }
duke@1: }
duke@1:
duke@1: /** ClassOrInterfaceOrEnumDeclaration = ModifiersOpt
duke@1: * (ClassDeclaration | InterfaceDeclaration | EnumDeclaration)
duke@1: * @param mods Any modifiers starting the class or interface declaration
duke@1: * @param dc The documentation comment for the class, or null.
duke@1: */
jjg@1280: JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
mcimadamore@1113: if (token.kind == CLASS) {
duke@1: return classDeclaration(mods, dc);
mcimadamore@1113: } else if (token.kind == INTERFACE) {
duke@1: return interfaceDeclaration(mods, dc);
duke@1: } else if (allowEnums) {
mcimadamore@1113: if (token.kind == ENUM) {
duke@1: return enumDeclaration(mods, dc);
duke@1: } else {
mcimadamore@1113: int pos = token.pos;
duke@1: List errs;
mcimadamore@1113: if (token.kind == IDENTIFIER) {
duke@1: errs = List.of(mods, toP(F.at(pos).Ident(ident())));
mcimadamore@1113: setErrorEndPos(token.pos);
duke@1: } else {
duke@1: errs = List.of(mods);
duke@1: }
duke@1: return toP(F.Exec(syntaxError(pos, errs, "expected3",
mcimadamore@80: CLASS, INTERFACE, ENUM)));
duke@1: }
duke@1: } else {
mcimadamore@1113: if (token.kind == ENUM) {
mcimadamore@1113: error(token.pos, "enums.not.supported.in.source", source.name);
duke@1: allowEnums = true;
duke@1: return enumDeclaration(mods, dc);
duke@1: }
mcimadamore@1113: int pos = token.pos;
duke@1: List errs;
mcimadamore@1113: if (token.kind == IDENTIFIER) {
duke@1: errs = List.of(mods, toP(F.at(pos).Ident(ident())));
mcimadamore@1113: setErrorEndPos(token.pos);
duke@1: } else {
duke@1: errs = List.of(mods);
duke@1: }
duke@1: return toP(F.Exec(syntaxError(pos, errs, "expected2",
mcimadamore@80: CLASS, INTERFACE)));
duke@1: }
duke@1: }
duke@1:
duke@1: /** ClassDeclaration = CLASS Ident TypeParametersOpt [EXTENDS Type]
duke@1: * [IMPLEMENTS TypeList] ClassBody
duke@1: * @param mods The modifiers starting the class declaration
duke@1: * @param dc The documentation comment for the class, or null.
duke@1: */
jjg@1280: protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
mcimadamore@1113: int pos = token.pos;
duke@1: accept(CLASS);
duke@1: Name name = ident();
duke@1:
duke@1: List typarams = typeParametersOpt();
duke@1:
jjg@904: JCExpression extending = null;
mcimadamore@1113: if (token.kind == EXTENDS) {
mcimadamore@1113: nextToken();
jjg@111: extending = parseType();
duke@1: }
duke@1: List implementing = List.nil();
mcimadamore@1113: if (token.kind == IMPLEMENTS) {
mcimadamore@1113: nextToken();
duke@1: implementing = typeList();
duke@1: }
duke@1: List defs = classOrInterfaceBody(name, false);
duke@1: JCClassDecl result = toP(F.at(pos).ClassDef(
duke@1: mods, name, typarams, extending, implementing, defs));
duke@1: attach(result, dc);
duke@1: return result;
duke@1: }
duke@1:
duke@1: /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
duke@1: * [EXTENDS TypeList] InterfaceBody
duke@1: * @param mods The modifiers starting the interface declaration
duke@1: * @param dc The documentation comment for the interface, or null.
duke@1: */
jjg@1280: protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
mcimadamore@1113: int pos = token.pos;
duke@1: accept(INTERFACE);
duke@1: Name name = ident();
duke@1:
duke@1: List typarams = typeParametersOpt();
duke@1:
duke@1: List extending = List.nil();
mcimadamore@1113: if (token.kind == EXTENDS) {
mcimadamore@1113: nextToken();
duke@1: extending = typeList();
duke@1: }
duke@1: List defs = classOrInterfaceBody(name, true);
duke@1: JCClassDecl result = toP(F.at(pos).ClassDef(
duke@1: mods, name, typarams, null, extending, defs));
duke@1: attach(result, dc);
duke@1: return result;
duke@1: }
duke@1:
duke@1: /** EnumDeclaration = ENUM Ident [IMPLEMENTS TypeList] EnumBody
duke@1: * @param mods The modifiers starting the enum declaration
duke@1: * @param dc The documentation comment for the enum, or null.
duke@1: */
jjg@1280: protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
mcimadamore@1113: int pos = token.pos;
duke@1: accept(ENUM);
duke@1: Name name = ident();
duke@1:
duke@1: List implementing = List.nil();
mcimadamore@1113: if (token.kind == IMPLEMENTS) {
mcimadamore@1113: nextToken();
duke@1: implementing = typeList();
duke@1: }
duke@1:
duke@1: List defs = enumBody(name);
jjg@482: mods.flags |= Flags.ENUM;
duke@1: JCClassDecl result = toP(F.at(pos).
jjg@482: ClassDef(mods, name, List.nil(),
duke@1: null, implementing, defs));
duke@1: attach(result, dc);
duke@1: return result;
duke@1: }
duke@1:
duke@1: /** EnumBody = "{" { EnumeratorDeclarationList } [","]
duke@1: * [ ";" {ClassBodyDeclaration} ] "}"
duke@1: */
duke@1: List enumBody(Name enumName) {
duke@1: accept(LBRACE);
duke@1: ListBuffer defs = new ListBuffer();
mcimadamore@1113: if (token.kind == COMMA) {
mcimadamore@1113: nextToken();
mcimadamore@1113: } else if (token.kind != RBRACE && token.kind != SEMI) {
duke@1: defs.append(enumeratorDeclaration(enumName));
mcimadamore@1113: while (token.kind == COMMA) {
mcimadamore@1113: nextToken();
mcimadamore@1113: if (token.kind == RBRACE || token.kind == SEMI) break;
duke@1: defs.append(enumeratorDeclaration(enumName));
duke@1: }
mcimadamore@1113: if (token.kind != SEMI && token.kind != RBRACE) {
mcimadamore@1113: defs.append(syntaxError(token.pos, "expected3",
mcimadamore@80: COMMA, RBRACE, SEMI));
mcimadamore@1113: nextToken();
duke@1: }
duke@1: }
mcimadamore@1113: if (token.kind == SEMI) {
mcimadamore@1113: nextToken();
mcimadamore@1113: while (token.kind != RBRACE && token.kind != EOF) {
duke@1: defs.appendList(classOrInterfaceBodyDeclaration(enumName,
duke@1: false));
ksrini@1138: if (token.pos <= endPosTable.errorEndPos) {
duke@1: // error recovery
duke@1: skip(false, true, true, false);
duke@1: }
duke@1: }
duke@1: }
duke@1: accept(RBRACE);
duke@1: return defs.toList();
duke@1: }
duke@1:
duke@1: /** EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ]
duke@1: */
duke@1: JCTree enumeratorDeclaration(Name enumName) {
jjg@1280: Comment dc = token.comment(CommentStyle.JAVADOC);
duke@1: int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM;
mcimadamore@1125: if (token.deprecatedFlag()) {
duke@1: flags |= Flags.DEPRECATED;
duke@1: }
mcimadamore@1113: int pos = token.pos;
jjg@722: List annotations = annotationsOpt();
duke@1: JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations);
duke@1: List typeArgs = typeArgumentsOpt();
mcimadamore@1113: int identPos = token.pos;
duke@1: Name name = ident();
mcimadamore@1113: int createPos = token.pos;
mcimadamore@1113: List args = (token.kind == LPAREN)
duke@1: ? arguments() : List.nil();
duke@1: JCClassDecl body = null;
mcimadamore@1113: if (token.kind == LBRACE) {
duke@1: JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC);
duke@1: List defs = classOrInterfaceBody(names.empty, false);
duke@1: body = toP(F.at(identPos).AnonymousClassDef(mods1, defs));
duke@1: }
duke@1: if (args.isEmpty() && body == null)
jjg@469: createPos = identPos;
jjg@469: JCIdent ident = F.at(identPos).Ident(enumName);
duke@1: JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body);
jjg@469: if (createPos != identPos)
mcimadamore@1113: storeEnd(create, S.prevToken().endPos);
jjg@469: ident = F.at(identPos).Ident(enumName);
duke@1: JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create));
duke@1: attach(result, dc);
duke@1: return result;
duke@1: }
duke@1:
duke@1: /** TypeList = Type {"," Type}
duke@1: */
duke@1: List typeList() {
duke@1: ListBuffer ts = new ListBuffer();
jjg@111: ts.append(parseType());
mcimadamore@1113: while (token.kind == COMMA) {
mcimadamore@1113: nextToken();
jjg@111: ts.append(parseType());
duke@1: }
duke@1: return ts.toList();
duke@1: }
duke@1:
duke@1: /** ClassBody = "{" {ClassBodyDeclaration} "}"
duke@1: * InterfaceBody = "{" {InterfaceBodyDeclaration} "}"
duke@1: */
duke@1: List classOrInterfaceBody(Name className, boolean isInterface) {
duke@1: accept(LBRACE);
ksrini@1138: if (token.pos <= endPosTable.errorEndPos) {
duke@1: // error recovery
duke@1: skip(false, true, false, false);
mcimadamore@1113: if (token.kind == LBRACE)
mcimadamore@1113: nextToken();
duke@1: }
duke@1: ListBuffer defs = new ListBuffer();
mcimadamore@1113: while (token.kind != RBRACE && token.kind != EOF) {
duke@1: defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface));
ksrini@1138: if (token.pos <= endPosTable.errorEndPos) {
duke@1: // error recovery
duke@1: skip(false, true, true, false);
duke@1: }
duke@1: }
duke@1: accept(RBRACE);
duke@1: return defs.toList();
duke@1: }
duke@1:
duke@1: /** ClassBodyDeclaration =
duke@1: * ";"
duke@1: * | [STATIC] Block
duke@1: * | ModifiersOpt
duke@1: * ( Type Ident
duke@1: * ( VariableDeclaratorsRest ";" | MethodDeclaratorRest )
duke@1: * | VOID Ident MethodDeclaratorRest
duke@1: * | TypeParameters (Type | VOID) Ident MethodDeclaratorRest
duke@1: * | Ident ConstructorDeclaratorRest
duke@1: * | TypeParameters Ident ConstructorDeclaratorRest
duke@1: * | ClassOrInterfaceOrEnumDeclaration
duke@1: * )
duke@1: * InterfaceBodyDeclaration =
duke@1: * ";"
duke@1: * | ModifiersOpt Type Ident
duke@1: * ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" )
duke@1: */
ksrini@1074: protected List classOrInterfaceBodyDeclaration(Name className, boolean isInterface) {
mcimadamore@1113: if (token.kind == SEMI) {
mcimadamore@1113: nextToken();
jjg@667: return List.nil();
duke@1: } else {
jjg@1280: Comment dc = token.comment(CommentStyle.JAVADOC);
mcimadamore@1113: int pos = token.pos;
duke@1: JCModifiers mods = modifiersOpt();
mcimadamore@1113: if (token.kind == CLASS ||
mcimadamore@1113: token.kind == INTERFACE ||
mcimadamore@1113: allowEnums && token.kind == ENUM) {
duke@1: return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
mcimadamore@1113: } else if (token.kind == LBRACE && !isInterface &&
duke@1: (mods.flags & Flags.StandardFlags & ~Flags.STATIC) == 0 &&
duke@1: mods.annotations.isEmpty()) {
duke@1: return List.of(block(pos, mods.flags));
duke@1: } else {
mcimadamore@1113: pos = token.pos;
duke@1: List typarams = typeParametersOpt();
jjg@817: // if there are type parameters but no modifiers, save the start
jjg@817: // position of the method in the modifiers.
jjg@817: if (typarams.nonEmpty() && mods.pos == Position.NOPOS) {
jjg@817: mods.pos = pos;
jjg@817: storeEnd(mods, pos);
jjg@817: }
mcimadamore@1113: Token tk = token;
mcimadamore@1113: pos = token.pos;
duke@1: JCExpression type;
mcimadamore@1113: boolean isVoid = token.kind == VOID;
duke@1: if (isVoid) {
duke@1: type = to(F.at(pos).TypeIdent(TypeTags.VOID));
mcimadamore@1113: nextToken();
duke@1: } else {
jjg@722: type = parseType();
duke@1: }
jjg@1127: if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
mcimadamore@1113: if (isInterface || tk.name() != className)
jjg@726: error(pos, "invalid.meth.decl.ret.type.req");
duke@1: return List.of(methodDeclaratorRest(
duke@1: pos, mods, null, names.init, typarams,
duke@1: isInterface, true, dc));
duke@1: } else {
mcimadamore@1113: pos = token.pos;
mcimadamore@1113: Name name = ident();
mcimadamore@1113: if (token.kind == LPAREN) {
duke@1: return List.of(methodDeclaratorRest(
duke@1: pos, mods, type, name, typarams,
duke@1: isInterface, isVoid, dc));
duke@1: } else if (!isVoid && typarams.isEmpty()) {
duke@1: List defs =
duke@1: variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
duke@1: new ListBuffer()).toList();
mcimadamore@1113: storeEnd(defs.last(), token.endPos);
duke@1: accept(SEMI);
duke@1: return defs;
duke@1: } else {
mcimadamore@1113: pos = token.pos;
duke@1: List err = isVoid
duke@1: ? List.of(toP(F.at(pos).MethodDef(mods, name, type, typarams,
duke@1: List.nil(), List.nil(), null, null)))
duke@1: : null;
mcimadamore@1113: return List.of(syntaxError(token.pos, err, "expected", LPAREN));
duke@1: }
duke@1: }
duke@1: }
duke@1: }
duke@1: }
duke@1:
duke@1: /** MethodDeclaratorRest =
jjg@722: * FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
duke@1: * VoidMethodDeclaratorRest =
jjg@722: * FormalParameters [Throws TypeList] ( MethodBody | ";")
duke@1: * InterfaceMethodDeclaratorRest =
jjg@722: * FormalParameters BracketsOpt [THROWS TypeList] ";"
duke@1: * VoidInterfaceMethodDeclaratorRest =
jjg@722: * FormalParameters [THROWS TypeList] ";"
duke@1: * ConstructorDeclaratorRest =
jjg@722: * "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody
duke@1: */
ksrini@1148: protected JCTree methodDeclaratorRest(int pos,
duke@1: JCModifiers mods,
duke@1: JCExpression type,
duke@1: Name name,
duke@1: List typarams,
duke@1: boolean isInterface, boolean isVoid,
jjg@1280: Comment dc) {
duke@1: List params = formalParameters();
jjg@722: if (!isVoid) type = bracketsOpt(type);
duke@1: List thrown = List.nil();
mcimadamore@1113: if (token.kind == THROWS) {
mcimadamore@1113: nextToken();
duke@1: thrown = qualidentList();
duke@1: }
duke@1: JCBlock body = null;
duke@1: JCExpression defaultValue;
mcimadamore@1113: if (token.kind == LBRACE) {
duke@1: body = block();
duke@1: defaultValue = null;
duke@1: } else {
mcimadamore@1113: if (token.kind == DEFAULT) {
duke@1: accept(DEFAULT);
duke@1: defaultValue = annotationValue();
duke@1: } else {
duke@1: defaultValue = null;
duke@1: }
duke@1: accept(SEMI);
ksrini@1138: if (token.pos <= endPosTable.errorEndPos) {
duke@1: // error recovery
duke@1: skip(false, true, false, false);
mcimadamore@1113: if (token.kind == LBRACE) {
duke@1: body = block();
duke@1: }
duke@1: }
duke@1: }
jjg@482:
duke@1: JCMethodDecl result =
duke@1: toP(F.at(pos).MethodDef(mods, name, type, typarams,
jjg@722: params, thrown,
duke@1: body, defaultValue));
duke@1: attach(result, dc);
duke@1: return result;
duke@1: }
duke@1:
jjg@722: /** QualidentList = Qualident {"," Qualident}
duke@1: */
duke@1: List qualidentList() {
duke@1: ListBuffer ts = new ListBuffer();
jjg@722: ts.append(qualident());
mcimadamore@1113: while (token.kind == COMMA) {
mcimadamore@1113: nextToken();
jjg@722: ts.append(qualident());
duke@1: }
duke@1: return ts.toList();
duke@1: }
duke@1:
jjg@1326: /**
jjg@1326: * {@literal
jjg@1326: * TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"]
jjg@1326: * }
duke@1: */
duke@1: List typeParametersOpt() {
mcimadamore@1113: if (token.kind == LT) {
duke@1: checkGenerics();
duke@1: ListBuffer typarams = new ListBuffer();
mcimadamore@1113: nextToken();
duke@1: typarams.append(typeParameter());
mcimadamore@1113: while (token.kind == COMMA) {
mcimadamore@1113: nextToken();
duke@1: typarams.append(typeParameter());
duke@1: }
duke@1: accept(GT);
duke@1: return typarams.toList();
duke@1: } else {
duke@1: return List.nil();
duke@1: }
duke@1: }
duke@1:
jjg@1326: /**
jjg@1326: * {@literal
jjg@1326: * TypeParameter = TypeVariable [TypeParameterBound]
duke@1: * TypeParameterBound = EXTENDS Type {"&" Type}
duke@1: * TypeVariable = Ident
jjg@1326: * }
duke@1: */
duke@1: JCTypeParameter typeParameter() {
mcimadamore@1113: int pos = token.pos;
duke@1: Name name = ident();
duke@1: ListBuffer bounds = new ListBuffer();
mcimadamore@1113: if (token.kind == EXTENDS) {
mcimadamore@1113: nextToken();
jjg@111: bounds.append(parseType());
mcimadamore@1113: while (token.kind == AMP) {
mcimadamore@1113: nextToken();
jjg@111: bounds.append(parseType());
duke@1: }
duke@1: }
jjg@722: return toP(F.at(pos).TypeParameter(name, bounds.toList()));
duke@1: }
duke@1:
duke@1: /** FormalParameters = "(" [ FormalParameterList ] ")"
duke@1: * FormalParameterList = [ FormalParameterListNovarargs , ] LastFormalParameter
duke@1: * FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter
duke@1: */
duke@1: List formalParameters() {
duke@1: ListBuffer params = new ListBuffer();
duke@1: JCVariableDecl lastParam = null;
duke@1: accept(LPAREN);
mcimadamore@1113: if (token.kind != RPAREN) {
duke@1: params.append(lastParam = formalParameter());
mcimadamore@1113: while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
mcimadamore@1113: nextToken();
duke@1: params.append(lastParam = formalParameter());
duke@1: }
duke@1: }
duke@1: accept(RPAREN);
duke@1: return params.toList();
duke@1: }
duke@1:
mcimadamore@1144: List implicitParameters(boolean hasParens) {
mcimadamore@1144: if (hasParens) {
mcimadamore@1144: accept(LPAREN);
mcimadamore@1144: }
mcimadamore@1144: ListBuffer params = new ListBuffer();
mcimadamore@1144: if (token.kind != RPAREN && token.kind != ARROW) {
mcimadamore@1144: params.append(implicitParameter());
mcimadamore@1144: while (token.kind == COMMA) {
mcimadamore@1144: nextToken();
mcimadamore@1144: params.append(implicitParameter());
mcimadamore@1144: }
mcimadamore@1144: }
mcimadamore@1144: if (hasParens) {
mcimadamore@1144: accept(RPAREN);
mcimadamore@1144: }
mcimadamore@1144: return params.toList();
mcimadamore@1144: }
mcimadamore@1144:
duke@1: JCModifiers optFinal(long flags) {
duke@1: JCModifiers mods = modifiersOpt();
duke@1: checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED));
duke@1: mods.flags |= flags;
duke@1: return mods;
duke@1: }
duke@1:
duke@1: /** FormalParameter = { FINAL | '@' Annotation } Type VariableDeclaratorId
duke@1: * LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter
duke@1: */
ksrini@1074: protected JCVariableDecl formalParameter() {
duke@1: JCModifiers mods = optFinal(Flags.PARAMETER);
jjg@111: JCExpression type = parseType();
mcimadamore@1113: if (token.kind == ELLIPSIS) {
duke@1: checkVarargs();
duke@1: mods.flags |= Flags.VARARGS;
mcimadamore@1113: type = to(F.at(token.pos).TypeArray(type));
mcimadamore@1113: nextToken();
duke@1: }
duke@1: return variableDeclaratorId(mods, type);
duke@1: }
duke@1:
mcimadamore@1144: protected JCVariableDecl implicitParameter() {
mcimadamore@1144: JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
mcimadamore@1144: return variableDeclaratorId(mods, null);
mcimadamore@1144: }
mcimadamore@1144:
duke@1: /* ---------- auxiliary methods -------------- */
duke@1:
jjg@726: void error(int pos, String key, Object ... args) {
jjg@726: log.error(DiagnosticFlag.SYNTAX, pos, key, args);
jjg@726: }
jjg@726:
ksrini@1074: void error(DiagnosticPosition pos, String key, Object ... args) {
ksrini@1074: log.error(DiagnosticFlag.SYNTAX, pos, key, args);
ksrini@1074: }
ksrini@1074:
jjg@726: void warning(int pos, String key, Object ... args) {
jjg@726: log.warning(pos, key, args);
jjg@726: }
jjg@726:
duke@1: /** Check that given tree is a legal expression statement.
duke@1: */
duke@1: protected JCExpression checkExprStat(JCExpression t) {
duke@1: switch(t.getTag()) {
jjg@1127: case PREINC: case PREDEC:
jjg@1127: case POSTINC: case POSTDEC:
jjg@1127: case ASSIGN:
jjg@1127: case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
jjg@1127: case SL_ASG: case SR_ASG: case USR_ASG:
jjg@1127: case PLUS_ASG: case MINUS_ASG:
jjg@1127: case MUL_ASG: case DIV_ASG: case MOD_ASG:
jjg@1127: case APPLY: case NEWCLASS:
jjg@1127: case ERRONEOUS:
duke@1: return t;
duke@1: default:
ksrini@1074: JCExpression ret = F.at(t.pos).Erroneous(List.of(t));
ksrini@1074: error(ret, "not.stmt");
ksrini@1074: return ret;
duke@1: }
duke@1: }
duke@1:
duke@1: /** Return precedence of operator represented by token,
duke@1: * -1 if token is not a binary operator. @see TreeInfo.opPrec
duke@1: */
mcimadamore@1113: static int prec(TokenKind token) {
jjg@1127: JCTree.Tag oc = optag(token);
jjg@1127: return (oc != NO_TAG) ? TreeInfo.opPrec(oc) : -1;
duke@1: }
duke@1:
jjg@516: /**
jjg@516: * Return the lesser of two positions, making allowance for either one
jjg@516: * being unset.
jjg@516: */
jjg@516: static int earlier(int pos1, int pos2) {
jjg@516: if (pos1 == Position.NOPOS)
jjg@516: return pos2;
jjg@516: if (pos2 == Position.NOPOS)
jjg@516: return pos1;
jjg@516: return (pos1 < pos2 ? pos1 : pos2);
jjg@516: }
jjg@516:
duke@1: /** Return operation tag of binary operator represented by token,
jjg@1127: * No_TAG if token is not a binary operator.
duke@1: */
jjg@1127: static JCTree.Tag optag(TokenKind token) {
duke@1: switch (token) {
duke@1: case BARBAR:
jjg@1127: return OR;
duke@1: case AMPAMP:
jjg@1127: return AND;
duke@1: case BAR:
jjg@1127: return BITOR;
duke@1: case BAREQ:
jjg@1127: return BITOR_ASG;
duke@1: case CARET:
jjg@1127: return BITXOR;
duke@1: case CARETEQ:
jjg@1127: return BITXOR_ASG;
duke@1: case AMP:
jjg@1127: return BITAND;
duke@1: case AMPEQ:
jjg@1127: return BITAND_ASG;
duke@1: case EQEQ:
jjg@1127: return JCTree.Tag.EQ;
duke@1: case BANGEQ:
jjg@1127: return NE;
duke@1: case LT:
jjg@1127: return JCTree.Tag.LT;
duke@1: case GT:
jjg@1127: return JCTree.Tag.GT;
duke@1: case LTEQ:
jjg@1127: return LE;
duke@1: case GTEQ:
jjg@1127: return GE;
duke@1: case LTLT:
jjg@1127: return SL;
duke@1: case LTLTEQ:
jjg@1127: return SL_ASG;
duke@1: case GTGT:
jjg@1127: return SR;
duke@1: case GTGTEQ:
jjg@1127: return SR_ASG;
duke@1: case GTGTGT:
jjg@1127: return USR;
duke@1: case GTGTGTEQ:
jjg@1127: return USR_ASG;
duke@1: case PLUS:
jjg@1127: return JCTree.Tag.PLUS;
duke@1: case PLUSEQ:
jjg@1127: return PLUS_ASG;
duke@1: case SUB:
jjg@1127: return MINUS;
duke@1: case SUBEQ:
jjg@1127: return MINUS_ASG;
duke@1: case STAR:
jjg@1127: return MUL;
duke@1: case STAREQ:
jjg@1127: return MUL_ASG;
duke@1: case SLASH:
jjg@1127: return DIV;
duke@1: case SLASHEQ:
jjg@1127: return DIV_ASG;
duke@1: case PERCENT:
jjg@1127: return MOD;
duke@1: case PERCENTEQ:
jjg@1127: return MOD_ASG;
duke@1: case INSTANCEOF:
jjg@1127: return TYPETEST;
duke@1: default:
jjg@1127: return NO_TAG;
duke@1: }
duke@1: }
duke@1:
duke@1: /** Return operation tag of unary operator represented by token,
jjg@1127: * No_TAG if token is not a binary operator.
duke@1: */
jjg@1127: static JCTree.Tag unoptag(TokenKind token) {
duke@1: switch (token) {
duke@1: case PLUS:
jjg@1127: return POS;
duke@1: case SUB:
jjg@1127: return NEG;
duke@1: case BANG:
jjg@1127: return NOT;
duke@1: case TILDE:
jjg@1127: return COMPL;
duke@1: case PLUSPLUS:
jjg@1127: return PREINC;
duke@1: case SUBSUB:
jjg@1127: return PREDEC;
duke@1: default:
jjg@1127: return NO_TAG;
duke@1: }
duke@1: }
duke@1:
duke@1: /** Return type tag of basic type represented by token,
duke@1: * -1 if token is not a basic type identifier.
duke@1: */
mcimadamore@1113: static int typetag(TokenKind token) {
duke@1: switch (token) {
duke@1: case BYTE:
duke@1: return TypeTags.BYTE;
duke@1: case CHAR:
duke@1: return TypeTags.CHAR;
duke@1: case SHORT:
duke@1: return TypeTags.SHORT;
duke@1: case INT:
duke@1: return TypeTags.INT;
duke@1: case LONG:
duke@1: return TypeTags.LONG;
duke@1: case FLOAT:
duke@1: return TypeTags.FLOAT;
duke@1: case DOUBLE:
duke@1: return TypeTags.DOUBLE;
duke@1: case BOOLEAN:
duke@1: return TypeTags.BOOLEAN;
duke@1: default:
duke@1: return -1;
duke@1: }
duke@1: }
duke@1:
duke@1: void checkGenerics() {
duke@1: if (!allowGenerics) {
mcimadamore@1113: error(token.pos, "generics.not.supported.in.source", source.name);
duke@1: allowGenerics = true;
duke@1: }
duke@1: }
duke@1: void checkVarargs() {
duke@1: if (!allowVarargs) {
mcimadamore@1113: error(token.pos, "varargs.not.supported.in.source", source.name);
duke@1: allowVarargs = true;
duke@1: }
duke@1: }
duke@1: void checkForeach() {
duke@1: if (!allowForeach) {
mcimadamore@1113: error(token.pos, "foreach.not.supported.in.source", source.name);
duke@1: allowForeach = true;
duke@1: }
duke@1: }
duke@1: void checkStaticImports() {
duke@1: if (!allowStaticImport) {
mcimadamore@1113: error(token.pos, "static.import.not.supported.in.source", source.name);
duke@1: allowStaticImport = true;
duke@1: }
duke@1: }
duke@1: void checkAnnotations() {
duke@1: if (!allowAnnotations) {
mcimadamore@1113: error(token.pos, "annotations.not.supported.in.source", source.name);
duke@1: allowAnnotations = true;
duke@1: }
duke@1: }
mcimadamore@537: void checkDiamond() {
mcimadamore@537: if (!allowDiamond) {
mcimadamore@1113: error(token.pos, "diamond.not.supported.in.source", source.name);
mcimadamore@537: allowDiamond = true;
mcimadamore@537: }
mcimadamore@537: }
mcimadamore@550: void checkMulticatch() {
mcimadamore@550: if (!allowMulticatch) {
mcimadamore@1113: error(token.pos, "multicatch.not.supported.in.source", source.name);
mcimadamore@550: allowMulticatch = true;
darcy@609: }
darcy@609: }
mcimadamore@743: void checkTryWithResources() {
darcy@609: if (!allowTWR) {
mcimadamore@1113: error(token.pos, "try.with.resources.not.supported.in.source", source.name);
darcy@609: allowTWR = true;
darcy@609: }
mcimadamore@550: }
mcimadamore@1144: void checkLambda() {
mcimadamore@1144: if (!allowLambda) {
mcimadamore@1144: log.error(token.pos, "lambda.not.supported.in.source", source.name);
mcimadamore@1144: allowLambda = true;
mcimadamore@1144: }
mcimadamore@1144: }
mcimadamore@1145: void checkMethodReferences() {
mcimadamore@1145: if (!allowMethodReferences) {
mcimadamore@1145: log.error(token.pos, "method.references.not.supported.in.source", source.name);
mcimadamore@1145: allowMethodReferences = true;
mcimadamore@1145: }
mcimadamore@1145: }
ksrini@1138:
ksrini@1138: /*
ksrini@1138: * a functional source tree and end position mappings
ksrini@1138: */
ksrini@1138: protected class SimpleEndPosTable extends AbstractEndPosTable {
ksrini@1138:
ksrini@1138: private final Map endPosMap;
ksrini@1138:
ksrini@1138: SimpleEndPosTable() {
ksrini@1138: endPosMap = new HashMap();
ksrini@1138: }
ksrini@1138:
ksrini@1138: protected void storeEnd(JCTree tree, int endpos) {
ksrini@1138: endPosMap.put(tree, errorEndPos > endpos ? errorEndPos : endpos);
ksrini@1138: }
ksrini@1138:
ksrini@1138: protected T to(T t) {
ksrini@1138: storeEnd(t, token.endPos);
ksrini@1138: return t;
ksrini@1138: }
ksrini@1138:
ksrini@1138: protected T toP(T t) {
ksrini@1138: storeEnd(t, S.prevToken().endPos);
ksrini@1138: return t;
ksrini@1138: }
ksrini@1138:
ksrini@1138: public int getEndPos(JCTree tree) {
ksrini@1138: Integer value = endPosMap.get(tree);
ksrini@1138: return (value == null) ? Position.NOPOS : value;
ksrini@1138: }
ksrini@1138:
ksrini@1138: public int replaceTree(JCTree oldTree, JCTree newTree) {
ksrini@1138: Integer pos = endPosMap.remove(oldTree);
ksrini@1138: if (pos != null) {
ksrini@1138: endPosMap.put(newTree, pos);
ksrini@1138: return pos;
ksrini@1138: }
ksrini@1138: return Position.NOPOS;
ksrini@1138: }
ksrini@1138: }
ksrini@1138:
ksrini@1138: /*
ksrini@1138: * a default skeletal implementation without any mapping overhead.
ksrini@1138: */
ksrini@1138: protected class EmptyEndPosTable extends AbstractEndPosTable {
ksrini@1138:
ksrini@1138: protected void storeEnd(JCTree tree, int endpos) { /* empty */ }
ksrini@1138:
ksrini@1138: protected T to(T t) {
ksrini@1138: return t;
ksrini@1138: }
ksrini@1138:
ksrini@1138: protected T toP(T t) {
ksrini@1138: return t;
ksrini@1138: }
ksrini@1138:
ksrini@1138: public int getEndPos(JCTree tree) {
ksrini@1138: return Position.NOPOS;
ksrini@1138: }
ksrini@1138:
ksrini@1138: public int replaceTree(JCTree oldTree, JCTree newTree) {
ksrini@1138: return Position.NOPOS;
ksrini@1138: }
ksrini@1138:
ksrini@1138: }
ksrini@1138:
ksrini@1138: protected abstract class AbstractEndPosTable implements EndPosTable {
ksrini@1138:
ksrini@1138: /**
ksrini@1138: * Store the last error position.
ksrini@1138: */
ksrini@1138: protected int errorEndPos;
ksrini@1138:
ksrini@1138: /**
ksrini@1138: * Store ending position for a tree, the value of which is the greater
ksrini@1138: * of last error position and the given ending position.
ksrini@1138: * @param tree The tree.
ksrini@1138: * @param endpos The ending position to associate with the tree.
ksrini@1138: */
ksrini@1138: protected abstract void storeEnd(JCTree tree, int endpos);
ksrini@1138:
ksrini@1138: /**
ksrini@1138: * Store current token's ending position for a tree, the value of which
ksrini@1138: * will be the greater of last error position and the ending position of
ksrini@1138: * the current token.
ksrini@1138: * @param t The tree.
ksrini@1138: */
ksrini@1138: protected abstract T to(T t);
ksrini@1138:
ksrini@1138: /**
ksrini@1138: * Store current token's ending position for a tree, the value of which
ksrini@1138: * will be the greater of last error position and the ending position of
ksrini@1138: * the previous token.
ksrini@1138: * @param t The tree.
ksrini@1138: */
ksrini@1138: protected abstract T toP(T t);
ksrini@1138:
ksrini@1138: /**
ksrini@1138: * Set the error position during the parsing phases, the value of which
ksrini@1138: * will be set only if it is greater than the last stored error position.
ksrini@1138: * @param errPos The error position
ksrini@1138: */
ksrini@1138: protected void setErrorEndPos(int errPos) {
ksrini@1138: if (errPos > errorEndPos) {
ksrini@1138: errorEndPos = errPos;
ksrini@1138: }
ksrini@1138: }
ksrini@1138: }
duke@1: }