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; jjg@1409: import static com.sun.tools.javac.tree.JCTree.Tag.*; duke@1: import static com.sun.tools.javac.util.ListBuffer.lb; 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: vromero@1400: interface ErrorRecoveryAction { vromero@1400: JCTree doRecover(JavacParser parser); vromero@1400: } vromero@1400: vromero@1400: enum BasicErrorRecoveryAction implements ErrorRecoveryAction { vromero@1400: BLOCK_STMT {public JCTree doRecover(JavacParser parser) { return parser.parseStatementAsBlock(); }}, vromero@1400: CATCH_CLAUSE {public JCTree doRecover(JavacParser parser) { return parser.catchClause(); }} vromero@1400: } vromero@1400: 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@1415: this.allowLambda = source.allowLambda(); mcimadamore@1415: this.allowMethodReferences = source.allowMethodReferences(); mcimadamore@1415: this.allowDefaultMethods = source.allowDefaultMethods(); mcimadamore@1513: this.allowStaticInterfaceMethods = source.allowStaticInterfaceMethods(); mcimadamore@1511: this.allowIntersectionTypesInCast = source.allowIntersectionTypesInCast(); duke@1: this.keepDocComments = keepDocComments; jjg@1409: docComments = newDocCommentTable(keepDocComments, fac); 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@1409: protected DocCommentTable newDocCommentTable(boolean keepDocComments, ParserFactory fac) { jjg@1409: return keepDocComments ? new LazyDocCommentTable(fac) : 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: mcimadamore@1366: /** Switch: should we allow default methods in interfaces? mcimadamore@1366: */ mcimadamore@1366: boolean allowDefaultMethods; mcimadamore@1366: mcimadamore@1513: /** Switch: should we allow static methods in interfaces? mcimadamore@1513: */ mcimadamore@1513: boolean allowStaticInterfaceMethods; mcimadamore@1513: mcimadamore@1436: /** Switch: should we allow intersection types in cast? mcimadamore@1436: */ mcimadamore@1436: boolean allowIntersectionTypesInCast; mcimadamore@1436: 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: jjg@1409: public Token token() { jjg@1409: return token; jjg@1409: } jjg@1409: jjg@1409: public void nextToken() { mcimadamore@1113: S.nextToken(); mcimadamore@1113: token = S.token(); mcimadamore@1113: } mcimadamore@1113: mcimadamore@1503: protected boolean peekToken(Filter tk) { mcimadamore@1436: return peekToken(0, tk); mcimadamore@1436: } mcimadamore@1436: mcimadamore@1503: protected boolean peekToken(int lookahead, Filter tk) { mcimadamore@1503: return tk.accepts(S.token(lookahead + 1).kind); mcimadamore@1144: } mcimadamore@1144: mcimadamore@1503: protected boolean peekToken(Filter tk1, Filter tk2) { mcimadamore@1436: return peekToken(0, tk1, tk2); mcimadamore@1436: } mcimadamore@1436: mcimadamore@1503: protected boolean peekToken(int lookahead, Filter tk1, Filter tk2) { mcimadamore@1503: return tk1.accepts(S.token(lookahead + 1).kind) && mcimadamore@1503: tk2.accepts(S.token(lookahead + 2).kind); mcimadamore@1144: } mcimadamore@1144: mcimadamore@1503: protected boolean peekToken(Filter tk1, Filter tk2, Filter tk3) { mcimadamore@1436: return peekToken(0, tk1, tk2, tk3); mcimadamore@1436: } mcimadamore@1436: mcimadamore@1503: protected boolean peekToken(int lookahead, Filter tk1, Filter tk2, Filter tk3) { mcimadamore@1503: return tk1.accepts(S.token(lookahead + 1).kind) && mcimadamore@1503: tk2.accepts(S.token(lookahead + 2).kind) && mcimadamore@1503: tk3.accepts(S.token(lookahead + 3).kind); mcimadamore@1144: } mcimadamore@1144: mcimadamore@1503: @SuppressWarnings("unchecked") mcimadamore@1503: protected boolean peekToken(Filter... kinds) { mcimadamore@1436: return peekToken(0, kinds); mcimadamore@1436: } mcimadamore@1436: mcimadamore@1503: @SuppressWarnings("unchecked") mcimadamore@1503: protected boolean peekToken(int lookahead, Filter... kinds) { mcimadamore@1436: for (; lookahead < kinds.length ; lookahead++) { mcimadamore@1503: if (!kinds[lookahead].accepts(S.token(lookahead + 1).kind)) { 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; mcimadamore@1503: case UNDERSCORE: 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: } mcimadamore@1503: } else if (token.kind == UNDERSCORE) { mcimadamore@1503: warning(token.pos, "underscore.as.identifier"); mcimadamore@1503: Name name = token.name(); mcimadamore@1503: nextToken(); mcimadamore@1503: return name; duke@1: } else { duke@1: accept(IDENTIFIER); duke@1: return names.error; duke@1: } mcimadamore@1503: } 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( jjg@1374: TypeTag.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( jjg@1374: TypeTag.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 jjg@1374: t = F.at(pos).Literal(TypeTag.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 jjg@1374: t = F.at(pos).Literal(TypeTag.DOUBLE, n); duke@1: break; duke@1: } duke@1: case CHARLITERAL: duke@1: t = F.at(pos).Literal( jjg@1374: TypeTag.CHAR, mcimadamore@1113: token.stringVal().charAt(0) + 0); duke@1: break; duke@1: case STRINGLITERAL: duke@1: t = F.at(pos).Literal( jjg@1374: TypeTag.CLASS, mcimadamore@1113: token.stringVal()); duke@1: break; duke@1: case TRUE: case FALSE: duke@1: t = F.at(pos).Literal( jjg@1374: TypeTag.BOOLEAN, mcimadamore@1113: (token.kind == TRUE ? 1 : 0)); duke@1: break; duke@1: case NULL: duke@1: t = F.at(pos).Literal( jjg@1374: TypeTag.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: JCExpression[] odStack = newOdStack(); 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)) { jjg@1362: StringBuilder buf = foldStrings(t); duke@1: if (buf != null) { jjg@1374: t = toP(F.at(startPos).Literal(TypeTag.CLASS, buf.toString())); duke@1: } duke@1: } duke@1: jlahoda@1444: odStackSupply.add(odStack); jlahoda@1444: opStackSupply.add(opStack); 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: */ jjg@1362: protected StringBuilder 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; jjg@1374: if (lit.typetag == TypeTag.CLASS) { jjg@1362: StringBuilder sbuf = jjg@1362: new StringBuilder((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; jjg@1374: if (lit.typetag == TypeTag.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: */ jlahoda@1444: ArrayList odStackSupply = new ArrayList(); jlahoda@1444: ArrayList opStackSupply = new ArrayList(); duke@1: duke@1: private JCExpression[] newOdStack() { jlahoda@1444: if (odStackSupply.isEmpty()) jlahoda@1444: return new JCExpression[infixPrecedenceLevels + 1]; jlahoda@1444: return odStackSupply.remove(odStackSupply.size() - 1); duke@1: } duke@1: duke@1: private Token[] newOpStack() { jlahoda@1444: if (opStackSupply.isEmpty()) jlahoda@1444: return new Token[infixPrecedenceLevels + 1]; jlahoda@1444: return opStackSupply.remove(opStackSupply.size() - 1); 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@1436: ParensResult pres = analyzeParens(); mcimadamore@1436: switch (pres) { mcimadamore@1436: case CAST: mcimadamore@1436: accept(LPAREN); mcimadamore@1436: mode = TYPE; mcimadamore@1436: int pos1 = pos; mcimadamore@1436: List targets = List.of(t = term3()); mcimadamore@1436: while (token.kind == AMP) { mcimadamore@1436: checkIntersectionTypesInCast(); mcimadamore@1436: accept(AMP); mcimadamore@1436: targets = targets.prepend(term3()); mcimadamore@1436: } mcimadamore@1436: if (targets.length() > 1) { mcimadamore@1436: t = toP(F.at(pos1).TypeIntersection(targets.reverse())); mcimadamore@1436: } mcimadamore@1436: accept(RPAREN); mcimadamore@1436: mode = EXPR; mcimadamore@1436: JCExpression t1 = term3(); mcimadamore@1436: return F.at(pos).TypeCast(t, t1); mcimadamore@1436: case IMPLICIT_LAMBDA: mcimadamore@1436: case EXPLICIT_LAMBDA: mcimadamore@1436: t = lambdaExpressionOrStatement(true, pres == ParensResult.EXPLICIT_LAMBDA, pos); mcimadamore@1436: break; mcimadamore@1436: default: //PARENS mcimadamore@1436: accept(LPAREN); mcimadamore@1144: mode = EXPR; mcimadamore@1436: t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec))); mcimadamore@1436: accept(RPAREN); mcimadamore@1436: t = toP(F.at(pos).Parens(t)); mcimadamore@1144: break; duke@1: } mcimadamore@1144: } else { mcimadamore@1144: return illegal(); mcimadamore@1144: } 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; mcimadamore@1503: case UNDERSCORE: 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@1352: //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@1352: t = bracketsOpt(t); mcimadamore@1352: if (token.kind != COLCOL) { 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) { jjg@1374: JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTag.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. jjg@1374: JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTag.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)); mcimadamore@1352: if (token.kind == COLCOL) { mcimadamore@1352: mode = EXPR; mcimadamore@1352: continue; mcimadamore@1352: } 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@1352: } else if ((mode & EXPR) != 0 && token.kind == COLCOL) { mcimadamore@1145: mode = EXPR; mcimadamore@1145: if (typeArgs != null) return illegal(); mcimadamore@1352: accept(COLCOL); 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@1503: case IDENTIFIER: case UNDERSCORE: 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@1352: TokenKind nextKind = S.token(pos + 1).kind; mcimadamore@1165: return mcimadamore@1352: nextKind == TokenKind.DOT || mcimadamore@1352: nextKind == TokenKind.LBRACKET || mcimadamore@1352: nextKind == TokenKind.COLCOL; mcimadamore@1165: } mcimadamore@1165: break; mcimadamore@1165: default: mcimadamore@1165: return false; mcimadamore@1165: } mcimadamore@1165: } mcimadamore@1165: } mcimadamore@1165: mcimadamore@1436: /** mcimadamore@1436: * If we see an identifier followed by a '<' it could be an unbound mcimadamore@1436: * method reference or a binary expression. To disambiguate, look for a mcimadamore@1436: * matching '>' and see if the subsequent terminal is either '.' or '#'. mcimadamore@1436: */ mcimadamore@1436: @SuppressWarnings("fallthrough") mcimadamore@1436: ParensResult analyzeParens() { mcimadamore@1436: int depth = 0; mcimadamore@1436: boolean type = false; mcimadamore@1436: for (int lookahead = 0 ; ; lookahead++) { mcimadamore@1436: TokenKind tk = S.token(lookahead).kind; mcimadamore@1436: switch (tk) { mcimadamore@1436: case EXTENDS: case SUPER: case COMMA: mcimadamore@1436: type = true; mcimadamore@1436: case QUES: case DOT: case AMP: mcimadamore@1436: //skip mcimadamore@1436: break; mcimadamore@1436: case BYTE: case SHORT: case INT: case LONG: case FLOAT: mcimadamore@1436: case DOUBLE: case BOOLEAN: case CHAR: mcimadamore@1436: if (peekToken(lookahead, RPAREN)) { mcimadamore@1436: //Type, ')' -> cast mcimadamore@1436: return ParensResult.CAST; mcimadamore@1503: } else if (peekToken(lookahead, LAX_IDENTIFIER)) { mcimadamore@1503: //Type, Identifier/'_'/'assert'/'enum' -> explicit lambda mcimadamore@1436: return ParensResult.EXPLICIT_LAMBDA; mcimadamore@1436: } mcimadamore@1436: break; mcimadamore@1436: case LPAREN: mcimadamore@1436: if (lookahead != 0) { mcimadamore@1436: // '(' in a non-starting position -> parens mcimadamore@1436: return ParensResult.PARENS; mcimadamore@1436: } else if (peekToken(lookahead, RPAREN)) { mcimadamore@1436: // '(', ')' -> explicit lambda mcimadamore@1436: return ParensResult.EXPLICIT_LAMBDA; mcimadamore@1436: } mcimadamore@1436: break; mcimadamore@1436: case RPAREN: mcimadamore@1436: // if we have seen something that looks like a type, mcimadamore@1436: // then it's a cast expression mcimadamore@1436: if (type) return ParensResult.CAST; mcimadamore@1436: // otherwise, disambiguate cast vs. parenthesized expression mcimadamore@1436: // based on subsequent token. mcimadamore@1436: switch (S.token(lookahead + 1).kind) { mcimadamore@1436: /*case PLUSPLUS: case SUBSUB: */ mcimadamore@1436: case BANG: case TILDE: mcimadamore@1436: case LPAREN: case THIS: case SUPER: mcimadamore@1436: case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: mcimadamore@1436: case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL: mcimadamore@1436: case TRUE: case FALSE: case NULL: mcimadamore@1503: case NEW: case IDENTIFIER: case ASSERT: case ENUM: case UNDERSCORE: mcimadamore@1436: case BYTE: case SHORT: case CHAR: case INT: mcimadamore@1436: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: mcimadamore@1436: return ParensResult.CAST; mcimadamore@1436: default: mcimadamore@1436: return ParensResult.PARENS; mcimadamore@1436: } mcimadamore@1503: case UNDERSCORE: mcimadamore@1503: case ASSERT: mcimadamore@1503: case ENUM: mcimadamore@1436: case IDENTIFIER: mcimadamore@1503: if (peekToken(lookahead, LAX_IDENTIFIER)) { mcimadamore@1503: // Identifier, Identifier/'_'/'assert'/'enum' -> explicit lambda mcimadamore@1436: return ParensResult.EXPLICIT_LAMBDA; mcimadamore@1436: } else if (peekToken(lookahead, RPAREN, ARROW)) { mcimadamore@1436: // Identifier, ')' '->' -> implicit lambda mcimadamore@1436: return ParensResult.IMPLICIT_LAMBDA; mcimadamore@1436: } mcimadamore@1436: break; mcimadamore@1436: case FINAL: mcimadamore@1436: case ELLIPSIS: mcimadamore@1436: case MONKEYS_AT: mcimadamore@1436: //those can only appear in explicit lambdas mcimadamore@1436: return ParensResult.EXPLICIT_LAMBDA; mcimadamore@1436: case LBRACKET: mcimadamore@1503: if (peekToken(lookahead, RBRACKET, LAX_IDENTIFIER)) { mcimadamore@1503: // '[', ']', Identifier/'_'/'assert'/'enum' -> explicit lambda mcimadamore@1436: return ParensResult.EXPLICIT_LAMBDA; mcimadamore@1436: } else if (peekToken(lookahead, RBRACKET, RPAREN) || mcimadamore@1436: peekToken(lookahead, RBRACKET, AMP)) { mcimadamore@1436: // '[', ']', ')' -> cast mcimadamore@1436: // '[', ']', '&' -> cast (intersection type) mcimadamore@1436: return ParensResult.CAST; mcimadamore@1436: } else if (peekToken(lookahead, RBRACKET)) { mcimadamore@1436: //consume the ']' and skip mcimadamore@1436: type = true; mcimadamore@1436: lookahead++; mcimadamore@1436: break; mcimadamore@1436: } else { mcimadamore@1436: return ParensResult.PARENS; mcimadamore@1436: } mcimadamore@1436: case LT: mcimadamore@1436: depth++; break; mcimadamore@1436: case GTGTGT: mcimadamore@1436: depth--; mcimadamore@1436: case GTGT: mcimadamore@1436: depth--; mcimadamore@1436: case GT: mcimadamore@1436: depth--; mcimadamore@1436: if (depth == 0) { mcimadamore@1436: if (peekToken(lookahead, RPAREN) || mcimadamore@1436: peekToken(lookahead, AMP)) { mcimadamore@1436: // '>', ')' -> cast mcimadamore@1436: // '>', '&' -> cast mcimadamore@1436: return ParensResult.CAST; mcimadamore@1503: } else if (peekToken(lookahead, LAX_IDENTIFIER, COMMA) || mcimadamore@1503: peekToken(lookahead, LAX_IDENTIFIER, RPAREN, ARROW) || mcimadamore@1436: peekToken(lookahead, ELLIPSIS)) { mcimadamore@1503: // '>', Identifier/'_'/'assert'/'enum', ',' -> explicit lambda mcimadamore@1503: // '>', Identifier/'_'/'assert'/'enum', ')', '->' -> explicit lambda mcimadamore@1436: // '>', '...' -> explicit lambda mcimadamore@1436: return ParensResult.EXPLICIT_LAMBDA; mcimadamore@1436: } mcimadamore@1436: //it looks a type, but could still be (i) a cast to generic type, mcimadamore@1436: //(ii) an unbound method reference or (iii) an explicit lambda mcimadamore@1436: type = true; mcimadamore@1436: break; mcimadamore@1436: } else if (depth < 0) { mcimadamore@1436: //unbalanced '<', '>' - not a generic type mcimadamore@1436: return ParensResult.PARENS; mcimadamore@1436: } mcimadamore@1436: break; mcimadamore@1436: default: mcimadamore@1436: //this includes EOF mcimadamore@1436: return ParensResult.PARENS; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: mcimadamore@1503: /** Accepts all identifier-like tokens */ mcimadamore@1503: Filter LAX_IDENTIFIER = new Filter() { mcimadamore@1503: public boolean accepts(TokenKind t) { mcimadamore@1503: return t == IDENTIFIER || t == UNDERSCORE || t == ASSERT || t == ENUM; mcimadamore@1503: } mcimadamore@1503: }; mcimadamore@1503: mcimadamore@1436: enum ParensResult { mcimadamore@1436: CAST, mcimadamore@1436: EXPLICIT_LAMBDA, mcimadamore@1436: IMPLICIT_LAMBDA, mcimadamore@1436: PARENS; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1144: JCExpression lambdaExpressionOrStatement(boolean hasParens, boolean explicitParams, int pos) { mcimadamore@1144: List params = explicitParams ? mcimadamore@1503: formalParameters(true) : 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: 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@1352: } else if (token.kind == COLCOL) { 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@1503: } else if (LAX_IDENTIFIER.accepts(token.kind)) { 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@1503: if (LAX_IDENTIFIER.accepts(token.kind)) { 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) { mcimadamore@1352: if (token.kind != COLCOL) { mcimadamore@1352: mode = TYPE; mcimadamore@1352: } mcimadamore@1352: } else if (token.kind != COLCOL) { mcimadamore@1113: syntaxError(token.pos, "dot.class.expected"); duke@1: } duke@1: return t; duke@1: } duke@1: mcimadamore@1145: /** mcimadamore@1352: * MemberReferenceSuffix = "::" [TypeArguments] Ident mcimadamore@1352: * | "::" [TypeArguments] "new" mcimadamore@1145: */ mcimadamore@1145: JCExpression memberReferenceSuffix(JCExpression t) { mcimadamore@1145: int pos1 = token.pos; mcimadamore@1352: accept(COLCOL); 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 jlahoda@1444: storeEnd(stats.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)); mcimadamore@1503: } else if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) { 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 jlahoda@1444: storeEnd(stats.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@1503: Name label = LAX_IDENTIFIER.accepts(token.kind) ? 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@1503: Name label = LAX_IDENTIFIER.accepts(token.kind) ? 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: vromero@1400: int elsePos = token.pos; vromero@1400: nextToken(); vromero@1400: return doRecover(elsePos, BasicErrorRecoveryAction.BLOCK_STMT, "else.without.if"); duke@1: case FINALLY: vromero@1400: int finallyPos = token.pos; vromero@1400: nextToken(); vromero@1400: return doRecover(finallyPos, BasicErrorRecoveryAction.BLOCK_STMT, "finally.without.try"); duke@1: case CATCH: vromero@1400: return doRecover(token.pos, BasicErrorRecoveryAction.CATCH_CLAUSE, "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: vromero@1400: private JCStatement doRecover(int startPos, ErrorRecoveryAction action, String key) { vromero@1400: int errPos = S.errPos(); vromero@1400: JCTree stm = action.doRecover(this); vromero@1400: S.errPos(errPos); vromero@1400: return toP(F.Exec(syntaxError(startPos, List.of(stm), key))); vromero@1400: } vromero@1400: 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); mcimadamore@1503: if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) { 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@1366: case DEFAULT : checkDefaultMethods(); flag = Flags.DEFAULT; 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 jlahoda@1444: storeEnd((JCTree)vdefs.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@1503: return variableDeclaratorId(mods, type, false); mcimadamore@1503: } mcimadamore@1503: //where mcimadamore@1503: JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, boolean lambdaParameter) { mcimadamore@1113: int pos = token.pos; mcimadamore@1503: Name name; mcimadamore@1503: if (lambdaParameter && token.kind == UNDERSCORE) { mcimadamore@1503: syntaxError(pos, "expected", IDENTIFIER); mcimadamore@1503: name = token.name(); mcimadamore@1503: } else { mcimadamore@1503: name = ident(); mcimadamore@1503: } 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 jlahoda@1444: storeEnd(defs.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)); jlahoda@1444: if (defs.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@1503: if (LAX_IDENTIFIER.accepts(token.kind)) { 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@1503: if (LAX_IDENTIFIER.accepts(token.kind)) { 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) { jjg@1374: type = to(F.at(pos).TypeIdent(TypeTag.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) { mcimadamore@1513: if (isInterface && (mods.flags & Flags.STATIC) != 0) { mcimadamore@1513: checkStaticInterfaceMethods(); mcimadamore@1513: } 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() { mcimadamore@1503: return formalParameters(false); mcimadamore@1503: } mcimadamore@1503: List formalParameters(boolean lambdaParameters) { duke@1: ListBuffer params = new ListBuffer(); duke@1: JCVariableDecl lastParam = null; duke@1: accept(LPAREN); mcimadamore@1113: if (token.kind != RPAREN) { mcimadamore@1503: params.append(lastParam = formalParameter(lambdaParameters)); mcimadamore@1113: while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) { mcimadamore@1113: nextToken(); mcimadamore@1503: params.append(lastParam = formalParameter(lambdaParameters)); 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() { mcimadamore@1503: return formalParameter(false); mcimadamore@1503: } mcimadamore@1503: protected JCVariableDecl formalParameter(boolean lambdaParameter) { 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: } mcimadamore@1503: return variableDeclaratorId(mods, type, lambdaParameter); duke@1: } duke@1: mcimadamore@1144: protected JCVariableDecl implicitParameter() { mcimadamore@1144: JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER); mcimadamore@1503: return variableDeclaratorId(mods, null, true); 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) { mcimadamore@1433: if (!TreeInfo.isExpressionStatement(t)) { ksrini@1074: JCExpression ret = F.at(t.pos).Erroneous(List.of(t)); ksrini@1074: error(ret, "not.stmt"); ksrini@1074: return ret; mcimadamore@1433: } else { mcimadamore@1433: return t; 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, jjg@1374: * NONE if token is not a basic type identifier. duke@1: */ jjg@1374: static TypeTag typetag(TokenKind token) { duke@1: switch (token) { duke@1: case BYTE: jjg@1374: return TypeTag.BYTE; duke@1: case CHAR: jjg@1374: return TypeTag.CHAR; duke@1: case SHORT: jjg@1374: return TypeTag.SHORT; duke@1: case INT: jjg@1374: return TypeTag.INT; duke@1: case LONG: jjg@1374: return TypeTag.LONG; duke@1: case FLOAT: jjg@1374: return TypeTag.FLOAT; duke@1: case DOUBLE: jjg@1374: return TypeTag.DOUBLE; duke@1: case BOOLEAN: jjg@1374: return TypeTag.BOOLEAN; duke@1: default: jjg@1374: return TypeTag.NONE; 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: } mcimadamore@1366: void checkDefaultMethods() { mcimadamore@1366: if (!allowDefaultMethods) { mcimadamore@1366: log.error(token.pos, "default.methods.not.supported.in.source", source.name); mcimadamore@1366: allowDefaultMethods = true; mcimadamore@1366: } mcimadamore@1366: } mcimadamore@1436: void checkIntersectionTypesInCast() { mcimadamore@1436: if (!allowIntersectionTypesInCast) { mcimadamore@1436: log.error(token.pos, "intersection.types.in.cast.not.supported.in.source", source.name); mcimadamore@1436: allowIntersectionTypesInCast = true; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1513: void checkStaticInterfaceMethods() { mcimadamore@1513: if (!allowStaticInterfaceMethods) { mcimadamore@1513: log.error(token.pos, "static.intf.methods.not.supported.in.source", source.name); mcimadamore@1513: allowStaticInterfaceMethods = true; mcimadamore@1513: } mcimadamore@1513: } 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: }