duke@1: /* jjg@816: * Copyright (c) 1999, 2011, 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: duke@1: import com.sun.tools.javac.tree.*; duke@1: import com.sun.tools.javac.code.*; duke@1: import com.sun.tools.javac.util.*; jjg@726: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; duke@1: import com.sun.tools.javac.util.List; duke@1: import static com.sun.tools.javac.util.ListBuffer.lb; duke@1: duke@1: import com.sun.tools.javac.tree.JCTree.*; duke@1: duke@1: import static com.sun.tools.javac.parser.Token.*; 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: */ duke@1: private 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 keyword table. */ duke@1: private Keywords keywords; 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: 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, jjg@111: boolean keepLineMap) { duke@1: this.S = S; duke@1: S.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.keywords = fac.keywords; 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(); duke@1: this.keepDocComments = keepDocComments; jjg@111: if (keepDocComments) jjg@111: docComments = new HashMap(); jjg@111: this.keepLineMap = keepLineMap; duke@1: this.errorTree = F.Erroneous(); duke@1: } duke@1: 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: 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: duke@1: /* ---------- 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) { duke@1: switch (S.token()) { duke@1: case SEMI: duke@1: S.nextToken(); duke@1: return; duke@1: case PUBLIC: duke@1: case FINAL: duke@1: case ABSTRACT: duke@1: case MONKEYS_AT: duke@1: case EOF: duke@1: case CLASS: duke@1: case INTERFACE: duke@1: case ENUM: duke@1: return; duke@1: case IMPORT: duke@1: if (stopAtImport) duke@1: return; duke@1: break; duke@1: case LBRACE: duke@1: case RBRACE: duke@1: case PRIVATE: duke@1: case PROTECTED: duke@1: case STATIC: duke@1: case TRANSIENT: duke@1: case NATIVE: duke@1: case VOLATILE: duke@1: case SYNCHRONIZED: duke@1: case STRICTFP: duke@1: case LT: duke@1: case BYTE: duke@1: case SHORT: duke@1: case CHAR: duke@1: case INT: duke@1: case LONG: duke@1: case FLOAT: duke@1: case DOUBLE: duke@1: case BOOLEAN: duke@1: case VOID: duke@1: if (stopAtMemberDecl) duke@1: return; duke@1: break; duke@1: case IDENTIFIER: duke@1: if (stopAtIdentifier) duke@1: return; duke@1: break; duke@1: case CASE: duke@1: case DEFAULT: duke@1: case IF: duke@1: case FOR: duke@1: case WHILE: duke@1: case DO: duke@1: case TRY: duke@1: case SWITCH: duke@1: case RETURN: duke@1: case THROW: duke@1: case BREAK: duke@1: case CONTINUE: duke@1: case ELSE: duke@1: case FINALLY: duke@1: case CATCH: duke@1: if (stopAtStatement) duke@1: return; duke@1: break; duke@1: } duke@1: S.nextToken(); duke@1: } duke@1: } duke@1: mcimadamore@80: private JCErroneous syntaxError(int pos, String key, Token... args) { mcimadamore@80: return syntaxError(pos, null, key, args); duke@1: } duke@1: mcimadamore@80: private JCErroneous syntaxError(int pos, List errs, String key, Token... args) { duke@1: setErrorEndPos(pos); mcimadamore@80: reportSyntaxError(pos, key, (Object[])args); duke@1: return toP(F.at(pos).Erroneous(errs)); duke@1: } duke@1: duke@1: private int errorPos = Position.NOPOS; duke@1: /** duke@1: * Report a syntax error at given position using the given duke@1: * argument unless one was already reported at the same position. duke@1: */ mcimadamore@80: private void reportSyntaxError(int pos, String key, Object... args) { duke@1: if (pos > S.errPos() || pos == Position.NOPOS) { duke@1: if (S.token() == EOF) jjg@726: error(pos, "premature.eof"); duke@1: else jjg@726: error(pos, key, args); duke@1: } duke@1: S.errPos(pos); duke@1: if (S.pos() == errorPos) duke@1: S.nextToken(); // guarantee progress duke@1: errorPos = S.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) { duke@1: return syntaxError(S.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@80: private JCErroneous syntaxError(String key, Token arg) { duke@1: return syntaxError(S.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: */ duke@1: public void accept(Token token) { duke@1: if (S.token() == token) { duke@1: S.nextToken(); duke@1: } else { duke@1: setErrorEndPos(S.pos()); mcimadamore@80: reportSyntaxError(S.prevEndPos(), "expected", token); 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) { duke@1: setErrorEndPos(S.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() { duke@1: return illegal(S.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; jjg@726: error(S.pos(), "mod.not.allowed.here", mcimadamore@80: Flags.asFlagSet(lowestMod)); duke@1: } duke@1: } duke@1: duke@1: /* ---------- doc comments --------- */ duke@1: duke@1: /** A hashtable 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: */ duke@1: Map 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: */ duke@1: void attach(JCTree tree, String dc) { duke@1: if (keepDocComments && dc != null) { duke@1: // System.out.println("doc comment = ");System.out.println(dc);//DEBUG duke@1: docComments.put(tree, dc); duke@1: } duke@1: } duke@1: duke@1: /* -------- source positions ------- */ duke@1: duke@1: private int errorEndPos = -1; duke@1: duke@1: private void setErrorEndPos(int errPos) { duke@1: if (errPos > errorEndPos) duke@1: errorEndPos = errPos; duke@1: } duke@1: duke@1: protected int getErrorEndPos() { duke@1: return errorEndPos; duke@1: } duke@1: duke@1: /** duke@1: * Store ending position for a tree. duke@1: * @param tree The tree. duke@1: * @param endpos The ending position to associate with the tree. duke@1: */ duke@1: protected void storeEnd(JCTree tree, int endpos) {} duke@1: duke@1: /** duke@1: * Store ending position for a tree. The ending position should duke@1: * be the ending position of the current token. duke@1: * @param t The tree. duke@1: */ duke@1: protected T to(T t) { return t; } duke@1: duke@1: /** duke@1: * Store ending position for a tree. The ending position should duke@1: * be greater of the ending position of the previous token and errorEndPos. duke@1: * @param t The tree. duke@1: */ duke@1: protected T toP(T t) { return t; } 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) { duke@1: return Position.NOPOS; 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() { duke@1: if (S.token() == IDENTIFIER) { duke@1: Name name = S.name(); duke@1: S.nextToken(); duke@1: return name; duke@1: } else if (S.token() == ASSERT) { duke@1: if (allowAsserts) { jjg@726: error(S.pos(), "assert.as.identifier"); duke@1: S.nextToken(); duke@1: return names.error; duke@1: } else { jjg@726: warning(S.pos(), "assert.as.identifier"); duke@1: Name name = S.name(); duke@1: S.nextToken(); duke@1: return name; duke@1: } duke@1: } else if (S.token() == ENUM) { duke@1: if (allowEnums) { jjg@726: error(S.pos(), "enum.as.identifier"); duke@1: S.nextToken(); duke@1: return names.error; duke@1: } else { jjg@726: warning(S.pos(), "enum.as.identifier"); duke@1: Name name = S.name(); duke@1: S.nextToken(); duke@1: return name; duke@1: } duke@1: } else { duke@1: accept(IDENTIFIER); duke@1: return names.error; duke@1: } duke@1: } duke@1: duke@1: /** duke@1: * Qualident = Ident { DOT Ident } duke@1: */ duke@1: public JCExpression qualident() { duke@1: JCExpression t = toP(F.at(S.pos()).Ident(ident())); duke@1: while (S.token() == DOT) { duke@1: int pos = S.pos(); duke@1: S.nextToken(); duke@1: t = toP(F.at(pos).Select(t, ident())); duke@1: } duke@1: return t; duke@1: } duke@1: 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: */ duke@1: JCExpression literal(Name prefix) { duke@1: int pos = S.pos(); duke@1: JCExpression t = errorTree; duke@1: switch (S.token()) { duke@1: case INTLITERAL: duke@1: try { duke@1: t = F.at(pos).Literal( duke@1: TypeTags.INT, duke@1: Convert.string2int(strval(prefix), S.radix())); duke@1: } catch (NumberFormatException ex) { jjg@726: error(S.pos(), "int.number.too.large", strval(prefix)); duke@1: } duke@1: break; duke@1: case LONGLITERAL: duke@1: try { duke@1: t = F.at(pos).Literal( duke@1: TypeTags.LONG, duke@1: new Long(Convert.string2long(strval(prefix), S.radix()))); duke@1: } catch (NumberFormatException ex) { jjg@726: error(S.pos(), "int.number.too.large", strval(prefix)); duke@1: } duke@1: break; duke@1: case FLOATLITERAL: { duke@1: String proper = (S.radix() == 16 ? ("0x"+ S.stringVal()) : S.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)) jjg@726: error(S.pos(), "fp.number.too.small"); duke@1: else if (n.floatValue() == Float.POSITIVE_INFINITY) jjg@726: error(S.pos(), "fp.number.too.large"); duke@1: else duke@1: t = F.at(pos).Literal(TypeTags.FLOAT, n); duke@1: break; duke@1: } duke@1: case DOUBLELITERAL: { duke@1: String proper = (S.radix() == 16 ? ("0x"+ S.stringVal()) : S.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)) jjg@726: error(S.pos(), "fp.number.too.small"); duke@1: else if (n.doubleValue() == Double.POSITIVE_INFINITY) jjg@726: error(S.pos(), "fp.number.too.large"); duke@1: else duke@1: t = F.at(pos).Literal(TypeTags.DOUBLE, n); duke@1: break; duke@1: } duke@1: case CHARLITERAL: duke@1: t = F.at(pos).Literal( duke@1: TypeTags.CHAR, duke@1: S.stringVal().charAt(0) + 0); duke@1: break; duke@1: case STRINGLITERAL: duke@1: t = F.at(pos).Literal( duke@1: TypeTags.CLASS, duke@1: S.stringVal()); duke@1: break; duke@1: case TRUE: case FALSE: duke@1: t = F.at(pos).Literal( duke@1: TypeTags.BOOLEAN, duke@1: (S.token() == TRUE ? 1 : 0)); duke@1: break; duke@1: case NULL: duke@1: t = F.at(pos).Literal( duke@1: TypeTags.BOT, duke@1: null); duke@1: break; duke@1: default: jjg@816: Assert.error(); duke@1: } duke@1: if (t == errorTree) duke@1: t = F.at(pos).Erroneous(); duke@1: storeEnd(t, S.endPos()); duke@1: S.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) { duke@1: String s = S.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: /** 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 duke@1: */ duke@1: JCExpression term() { duke@1: JCExpression t = term1(); duke@1: if ((mode & EXPR) != 0 && duke@1: S.token() == EQ || PLUSEQ.compareTo(S.token()) <= 0 && S.token().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) { duke@1: switch (S.token()) { duke@1: case EQ: { duke@1: int pos = S.pos(); duke@1: S.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: duke@1: int pos = S.pos(); duke@1: Token token = S.token(); duke@1: S.nextToken(); duke@1: mode = EXPR; duke@1: JCExpression t1 = term(); duke@1: return F.at(pos).Assignop(optag(token), 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(); duke@1: if ((mode & EXPR) != 0 && S.token() == 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) { duke@1: if (S.token() == QUES) { duke@1: int pos = S.pos(); duke@1: S.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(); duke@1: if ((mode & EXPR) != 0 && prec(S.token()) >= TreeInfo.orPrec) { duke@1: mode = EXPR; duke@1: return term2Rest(t, TreeInfo.orPrec); duke@1: } else { duke@1: return t; duke@1: } duke@1: } duke@1: duke@1: /* Expression2Rest = {infixop Expression3} duke@1: * | Expression3 instanceof Type duke@1: * infixop = "||" duke@1: * | "&&" duke@1: * | "|" duke@1: * | "^" duke@1: * | "&" duke@1: * | "==" | "!=" duke@1: * | "<" | ">" | "<=" | ">=" duke@1: * | "<<" | ">>" | ">>>" duke@1: * | "+" | "-" duke@1: * | "*" | "/" | "%" duke@1: */ duke@1: JCExpression term2Rest(JCExpression t, int minprec) { duke@1: List savedOd = odStackSupply.elems; duke@1: JCExpression[] odStack = newOdStack(); duke@1: List savedOp = opStackSupply.elems; duke@1: Token[] opStack = newOpStack(); jjg@482: List savedPos = posStackSupply.elems; jjg@482: int[] posStack = newPosStack(); duke@1: // optimization, was odStack = new Tree[...]; opStack = new Tree[...]; duke@1: int top = 0; duke@1: odStack[0] = t; duke@1: int startPos = S.pos(); duke@1: Token topOp = ERROR; jjg@482: int topOpPos = Position.NOPOS; duke@1: while (prec(S.token()) >= minprec) { jjg@482: posStack[top] = topOpPos; duke@1: opStack[top] = topOp; duke@1: top++; duke@1: topOp = S.token(); jjg@482: topOpPos = S.pos(); duke@1: S.nextToken(); jjg@482: odStack[top] = (topOp == INSTANCEOF) ? parseType() : term3(); duke@1: while (top > 0 && prec(topOp) >= prec(S.token())) { jjg@482: odStack[top-1] = makeOp(topOpPos, topOp, odStack[top-1], duke@1: odStack[top]); duke@1: top--; duke@1: topOp = opStack[top]; jjg@482: topOpPos = posStack[top]; duke@1: } duke@1: } jjg@816: Assert.check(top == 0); duke@1: t = odStack[0]; duke@1: duke@1: if (t.getTag() == JCTree.PLUS) { duke@1: StringBuffer buf = foldStrings(t); duke@1: if (buf != null) { duke@1: t = toP(F.at(startPos).Literal(TypeTags.CLASS, buf.toString())); duke@1: } duke@1: } duke@1: duke@1: odStackSupply.elems = savedOd; // optimization duke@1: opStackSupply.elems = savedOp; // optimization jjg@482: posStackSupply.elems = savedPos; // optimization duke@1: return t; duke@1: } duke@1: //where duke@1: /** Construct a binary or type test node. duke@1: */ duke@1: private JCExpression makeOp(int pos, duke@1: Token topOp, duke@1: JCExpression od1, duke@1: JCExpression od2) duke@1: { duke@1: if (topOp == INSTANCEOF) { duke@1: return F.at(pos).TypeTest(od1, od2); duke@1: } else { duke@1: return F.at(pos).Binary(optag(topOp), od1, od2); duke@1: } duke@1: } duke@1: /** If tree is a concatenation of string literals, replace it duke@1: * by a single literal representing the concatenated string. duke@1: */ duke@1: protected StringBuffer foldStrings(JCTree tree) { duke@1: List buf = List.nil(); duke@1: while (true) { duke@1: if (tree.getTag() == JCTree.LITERAL) { duke@1: JCLiteral lit = (JCLiteral) tree; duke@1: if (lit.typetag == TypeTags.CLASS) { duke@1: StringBuffer sbuf = duke@1: new StringBuffer((String)lit.value); duke@1: while (buf.nonEmpty()) { duke@1: sbuf.append(buf.head); duke@1: buf = buf.tail; duke@1: } duke@1: return sbuf; duke@1: } duke@1: } else if (tree.getTag() == JCTree.PLUS) { duke@1: JCBinary op = (JCBinary)tree; duke@1: if (op.rhs.getTag() == JCTree.LITERAL) { duke@1: JCLiteral lit = (JCLiteral) op.rhs; duke@1: if (lit.typetag == TypeTags.CLASS) { duke@1: buf = buf.prepend((String) lit.value); duke@1: tree = op.lhs; duke@1: continue; duke@1: } duke@1: } duke@1: } duke@1: return null; duke@1: } duke@1: } duke@1: duke@1: /** optimization: To save allocating a new operand/operator stack duke@1: * for every binary operation, we use supplys. duke@1: */ duke@1: ListBuffer odStackSupply = new ListBuffer(); duke@1: ListBuffer opStackSupply = new ListBuffer(); jjg@482: ListBuffer posStackSupply = new ListBuffer(); duke@1: duke@1: private JCExpression[] newOdStack() { duke@1: if (odStackSupply.elems == odStackSupply.last) duke@1: odStackSupply.append(new JCExpression[infixPrecedenceLevels + 1]); duke@1: JCExpression[] odStack = odStackSupply.elems.head; duke@1: odStackSupply.elems = odStackSupply.elems.tail; duke@1: return odStack; duke@1: } duke@1: duke@1: private Token[] newOpStack() { duke@1: if (opStackSupply.elems == opStackSupply.last) duke@1: opStackSupply.append(new Token[infixPrecedenceLevels + 1]); duke@1: Token[] opStack = opStackSupply.elems.head; duke@1: opStackSupply.elems = opStackSupply.elems.tail; duke@1: return opStack; duke@1: } duke@1: jjg@482: private int[] newPosStack() { jjg@482: if (posStackSupply.elems == posStackSupply.last) jjg@482: posStackSupply.append(new int[infixPrecedenceLevels + 1]); jjg@482: int[] posStack = posStackSupply.elems.head; jjg@482: posStackSupply.elems = posStackSupply.elems.tail; jjg@482: return posStack; jjg@482: } jjg@482: duke@1: /** Expression3 = PrefixOp Expression3 duke@1: * | "(" Expr | TypeNoParams ")" Expression3 duke@1: * | Primary {Selector} {PostfixOp} duke@1: * Primary = "(" Expression ")" duke@1: * | Literal duke@1: * | [TypeArguments] THIS [Arguments] duke@1: * | [TypeArguments] SUPER SuperSuffix duke@1: * | NEW [TypeArguments] Creator jjg@722: * | Ident { "." Ident } 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 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() { duke@1: int pos = S.pos(); duke@1: JCExpression t; duke@1: List typeArgs = typeArgumentsOpt(EXPR); duke@1: switch (S.token()) { 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) { duke@1: Token token = S.token(); duke@1: S.nextToken(); duke@1: mode = EXPR; duke@1: if (token == SUB && duke@1: (S.token() == INTLITERAL || S.token() == LONGLITERAL) && duke@1: S.radix() == 10) { duke@1: mode = EXPR; duke@1: t = literal(names.hyphen); duke@1: } else { duke@1: t = term3(); duke@1: return F.at(pos).Unary(unoptag(token), t); duke@1: } duke@1: } else return illegal(); duke@1: break; duke@1: case LPAREN: duke@1: if (typeArgs == null && (mode & EXPR) != 0) { duke@1: S.nextToken(); duke@1: mode = EXPR | TYPE | NOPARAMS; duke@1: t = term3(); duke@1: if ((mode & TYPE) != 0 && S.token() == LT) { duke@1: // Could be a cast to a parameterized type duke@1: int op = JCTree.LT; duke@1: int pos1 = S.pos(); duke@1: S.nextToken(); duke@1: mode &= (EXPR | TYPE); duke@1: mode |= TYPEARG; duke@1: JCExpression t1 = term3(); duke@1: if ((mode & TYPE) != 0 && duke@1: (S.token() == COMMA || S.token() == GT)) { duke@1: mode = TYPE; duke@1: ListBuffer args = new ListBuffer(); duke@1: args.append(t1); duke@1: while (S.token() == COMMA) { duke@1: S.nextToken(); duke@1: args.append(typeArgument()); duke@1: } duke@1: accept(GT); jjg@482: t = toP(F.at(pos1).TypeApply(t, args.toList())); duke@1: checkGenerics(); mcimadamore@185: while (S.token() == DOT) { mcimadamore@185: S.nextToken(); mcimadamore@185: mode = TYPE; mcimadamore@185: t = toP(F.at(S.pos()).Select(t, ident())); mcimadamore@185: t = typeArgumentsOpt(t); mcimadamore@185: } mcimadamore@195: t = bracketsOpt(toP(t)); duke@1: } else if ((mode & EXPR) != 0) { duke@1: mode = EXPR; jjg@482: JCExpression e = term2Rest(t1, TreeInfo.shiftPrec); jjg@482: t = F.at(pos1).Binary(op, t, e); duke@1: t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec))); duke@1: } else { duke@1: accept(GT); duke@1: } mcimadamore@185: } mcimadamore@185: else { duke@1: t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec))); duke@1: } duke@1: accept(RPAREN); duke@1: lastmode = mode; duke@1: mode = EXPR; duke@1: if ((lastmode & EXPR) == 0) { duke@1: JCExpression t1 = term3(); duke@1: return F.at(pos).TypeCast(t, t1); duke@1: } else if ((lastmode & TYPE) != 0) { duke@1: switch (S.token()) { duke@1: /*case PLUSPLUS: case SUBSUB: */ duke@1: case BANG: case TILDE: duke@1: case LPAREN: case THIS: case SUPER: duke@1: case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: duke@1: case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL: duke@1: case TRUE: case FALSE: case NULL: duke@1: case NEW: case IDENTIFIER: case ASSERT: case ENUM: duke@1: case BYTE: case SHORT: case CHAR: case INT: duke@1: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: duke@1: JCExpression t1 = term3(); duke@1: return F.at(pos).TypeCast(t, t1); duke@1: } duke@1: } duke@1: } else return illegal(); duke@1: t = toP(F.at(pos).Parens(t)); duke@1: break; duke@1: case THIS: duke@1: if ((mode & EXPR) != 0) { duke@1: mode = EXPR; duke@1: t = to(F.at(pos).Ident(names._this)); duke@1: S.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; duke@1: S.nextToken(); mcimadamore@948: if (S.token() == LT) typeArgs = typeArguments(false); duke@1: t = creator(pos, typeArgs); duke@1: typeArgs = null; duke@1: } else return illegal(); duke@1: break; duke@1: case IDENTIFIER: case ASSERT: case ENUM: duke@1: if (typeArgs != null) return illegal(); duke@1: t = toP(F.at(S.pos()).Ident(ident())); duke@1: loop: while (true) { duke@1: pos = S.pos(); duke@1: switch (S.token()) { duke@1: case LBRACKET: duke@1: S.nextToken(); duke@1: if (S.token() == RBRACKET) { duke@1: S.nextToken(); jjg@722: t = bracketsOpt(t); duke@1: t = toP(F.at(pos).TypeArray(t)); duke@1: t = bracketsSuffix(t); duke@1: } else { duke@1: if ((mode & EXPR) != 0) { duke@1: mode = EXPR; duke@1: JCExpression t1 = term(); duke@1: t = to(F.at(pos).Indexed(t, t1)); duke@1: } duke@1: accept(RBRACKET); duke@1: } duke@1: break loop; duke@1: case LPAREN: duke@1: if ((mode & EXPR) != 0) { duke@1: mode = EXPR; duke@1: t = arguments(typeArgs, t); duke@1: typeArgs = null; duke@1: } duke@1: break loop; duke@1: case DOT: duke@1: S.nextToken(); mcimadamore@26: int oldmode = mode; mcimadamore@26: mode &= ~NOPARAMS; duke@1: typeArgs = typeArgumentsOpt(EXPR); mcimadamore@26: mode = oldmode; duke@1: if ((mode & EXPR) != 0) { duke@1: switch (S.token()) { duke@1: case CLASS: duke@1: if (typeArgs != null) return illegal(); duke@1: mode = EXPR; duke@1: t = to(F.at(pos).Select(t, names._class)); duke@1: S.nextToken(); duke@1: break loop; duke@1: case THIS: duke@1: if (typeArgs != null) return illegal(); duke@1: mode = EXPR; duke@1: t = to(F.at(pos).Select(t, names._this)); duke@1: S.nextToken(); duke@1: break loop; duke@1: case SUPER: duke@1: mode = EXPR; duke@1: t = to(F.at(pos).Select(t, names._super)); duke@1: t = superSuffix(typeArgs, t); duke@1: typeArgs = null; duke@1: break loop; duke@1: case NEW: duke@1: if (typeArgs != null) return illegal(); duke@1: mode = EXPR; duke@1: int pos1 = S.pos(); duke@1: S.nextToken(); mcimadamore@948: if (S.token() == LT) typeArgs = typeArguments(false); duke@1: t = innerCreator(pos1, typeArgs, t); duke@1: typeArgs = null; duke@1: break loop; duke@1: } duke@1: } duke@1: // typeArgs saved for next loop iteration. duke@1: t = toP(F.at(pos).Select(t, ident())); duke@1: break; duke@1: default: duke@1: break loop; 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) { duke@1: S.nextToken(); duke@1: if (S.token() == DOT) { duke@1: JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTags.VOID)); duke@1: t = bracketsSuffix(ti); duke@1: } else { duke@1: return illegal(pos); duke@1: } duke@1: } else { jrose@267: // Support the corner case of myMethodHandle.invoke() by passing jrose@267: // a void type (like other primitive types) to the next phase. jrose@267: // The error will be reported in Attr.attribTypes or Attr.visitApply. jrose@267: JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTags.VOID)); jrose@267: S.nextToken(); jrose@267: return ti; jrose@267: //return illegal(); duke@1: } duke@1: break; duke@1: default: duke@1: return illegal(); duke@1: } duke@1: if (typeArgs != null) illegal(); duke@1: while (true) { duke@1: int pos1 = S.pos(); duke@1: if (S.token() == LBRACKET) { duke@1: S.nextToken(); duke@1: if ((mode & TYPE) != 0) { duke@1: int oldmode = mode; duke@1: mode = TYPE; duke@1: if (S.token() == RBRACKET) { duke@1: S.nextToken(); jjg@722: t = bracketsOpt(t); duke@1: t = toP(F.at(pos1).TypeArray(t)); duke@1: return t; duke@1: } duke@1: mode = oldmode; duke@1: } duke@1: if ((mode & EXPR) != 0) { duke@1: mode = EXPR; duke@1: JCExpression t1 = term(); duke@1: t = to(F.at(pos1).Indexed(t, t1)); duke@1: } duke@1: accept(RBRACKET); duke@1: } else if (S.token() == DOT) { duke@1: S.nextToken(); duke@1: typeArgs = typeArgumentsOpt(EXPR); duke@1: if (S.token() == SUPER && (mode & EXPR) != 0) { duke@1: mode = EXPR; duke@1: t = to(F.at(pos1).Select(t, names._super)); duke@1: S.nextToken(); duke@1: t = arguments(typeArgs, t); duke@1: typeArgs = null; duke@1: } else if (S.token() == NEW && (mode & EXPR) != 0) { duke@1: if (typeArgs != null) return illegal(); duke@1: mode = EXPR; duke@1: int pos2 = S.pos(); duke@1: S.nextToken(); mcimadamore@948: if (S.token() == 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: } duke@1: } else { duke@1: break; duke@1: } duke@1: } duke@1: while ((S.token() == PLUSPLUS || S.token() == SUBSUB) && (mode & EXPR) != 0) { duke@1: mode = EXPR; duke@1: t = to(F.at(S.pos()).Unary( duke@1: S.token() == PLUSPLUS ? JCTree.POSTINC : JCTree.POSTDEC, t)); duke@1: S.nextToken(); duke@1: } duke@1: return toP(t); duke@1: } duke@1: duke@1: /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments] duke@1: */ duke@1: JCExpression superSuffix(List typeArgs, JCExpression t) { duke@1: S.nextToken(); duke@1: if (S.token() == LPAREN || typeArgs != null) { duke@1: t = arguments(typeArgs, t); duke@1: } else { duke@1: int pos = S.pos(); duke@1: accept(DOT); mcimadamore@948: typeArgs = (S.token() == 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() { duke@1: JCPrimitiveTypeTree t = to(F.at(S.pos()).TypeIdent(typetag(S.token()))); duke@1: S.nextToken(); duke@1: return t; duke@1: } duke@1: duke@1: /** ArgumentsOpt = [ Arguments ] duke@1: */ duke@1: JCExpression argumentsOpt(List typeArgs, JCExpression t) { duke@1: if ((mode & EXPR) != 0 && S.token() == 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(); duke@1: if (S.token() == LPAREN) { duke@1: S.nextToken(); duke@1: if (S.token() != RPAREN) { jjg@111: args.append(parseExpression()); duke@1: while (S.token() == COMMA) { duke@1: S.nextToken(); jjg@111: args.append(parseExpression()); duke@1: } duke@1: } duke@1: accept(RPAREN); duke@1: } else { mcimadamore@80: syntaxError(S.pos(), "expected", LPAREN); duke@1: } duke@1: return args.toList(); duke@1: } duke@1: duke@1: JCMethodInvocation arguments(List typeArgs, JCExpression t) { duke@1: int pos = S.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) { duke@1: if (S.token() == 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) { duke@1: if (S.token() == 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: duke@1: /** TypeArguments = "<" TypeArgument {"," TypeArgument} ">" duke@1: */ mcimadamore@948: List typeArguments(boolean diamondAllowed) { duke@1: if (S.token() == LT) { duke@1: S.nextToken(); mcimadamore@948: if (S.token() == GT && diamondAllowed) { mcimadamore@537: checkDiamond(); mcimadamore@948: mode |= DIAMOND; mcimadamore@537: S.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@948: while (S.token() == COMMA) { mcimadamore@948: S.nextToken(); mcimadamore@948: args.append(((mode & EXPR) == 0) ? typeArgument() : parseType()); mcimadamore@948: } mcimadamore@948: switch (S.token()) { mcimadamore@948: case GTGTGTEQ: mcimadamore@948: S.token(GTGTEQ); mcimadamore@948: break; mcimadamore@948: case GTGTEQ: mcimadamore@948: S.token(GTEQ); mcimadamore@948: break; mcimadamore@948: case GTEQ: mcimadamore@948: S.token(EQ); mcimadamore@948: break; mcimadamore@948: case GTGTGT: mcimadamore@948: S.token(GTGT); mcimadamore@948: break; mcimadamore@948: case GTGT: mcimadamore@948: S.token(GT); mcimadamore@948: break; mcimadamore@948: default: mcimadamore@948: accept(GT); mcimadamore@948: break; mcimadamore@948: } mcimadamore@948: return args.toList(); duke@1: } duke@1: } else { mcimadamore@80: syntaxError(S.pos(), "expected", LT); mcimadamore@948: return List.nil(); duke@1: } duke@1: } duke@1: duke@1: /** TypeArgument = Type jjg@722: * | "?" jjg@722: * | "?" EXTENDS Type {"&" Type} jjg@722: * | "?" SUPER Type duke@1: */ duke@1: JCExpression typeArgument() { jjg@722: if (S.token() != QUES) return parseType(); duke@1: int pos = S.pos(); duke@1: S.nextToken(); duke@1: if (S.token() == EXTENDS) { jjg@482: TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.EXTENDS)); duke@1: S.nextToken(); jjg@482: JCExpression bound = parseType(); jjg@722: return F.at(pos).Wildcard(t, bound); duke@1: } else if (S.token() == SUPER) { jjg@482: TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.SUPER)); duke@1: S.nextToken(); jjg@482: JCExpression bound = parseType(); jjg@722: return F.at(pos).Wildcard(t, bound); duke@1: } else if (S.token() == IDENTIFIER) { duke@1: //error recovery duke@1: reportSyntaxError(S.prevEndPos(), "expected3", mcimadamore@80: GT, EXTENDS, SUPER); duke@1: TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND); duke@1: JCExpression wc = toP(F.at(pos).Wildcard(t, null)); duke@1: JCIdent id = toP(F.at(S.pos()).Ident(ident())); jjg@722: return F.at(pos).Erroneous(List.of(wc, id)); 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) { duke@1: int pos = S.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) { duke@1: if (S.token() == LBRACKET) { duke@1: int pos = S.pos(); duke@1: S.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) { duke@1: if ((mode & EXPR) != 0 && S.token() == DOT) { duke@1: mode = EXPR; duke@1: int pos = S.pos(); duke@1: S.nextToken(); duke@1: accept(CLASS); duke@1: if (S.pos() == errorEndPos) { duke@1: // error recovery duke@1: Name name = null; duke@1: if (S.token() == IDENTIFIER) { duke@1: name = S.name(); duke@1: S.nextToken(); duke@1: } else { duke@1: name = names.error; duke@1: } duke@1: t = F.at(pos).Erroneous(List.of(toP(F.at(pos).Select(t, name)))); duke@1: } else { duke@1: t = toP(F.at(pos).Select(t, names._class)); duke@1: } duke@1: } else if ((mode & TYPE) != 0) { duke@1: mode = TYPE; duke@1: } else { duke@1: syntaxError(S.pos(), "dot.class.expected"); duke@1: } duke@1: return t; duke@1: } duke@1: jjg@722: /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest ) duke@1: */ duke@1: JCExpression creator(int newpos, List typeArgs) { duke@1: switch (S.token()) { 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; duke@1: if (S.token() == LT) { duke@1: checkGenerics(); mcimadamore@948: t = typeArguments(t, true); mcimadamore@948: diamondFound = (mode & DIAMOND) != 0; duke@1: } duke@1: while (S.token() == DOT) { mcimadamore@948: if (diamondFound) { mcimadamore@948: //cannot select after a diamond mcimadamore@948: illegal(S.pos()); mcimadamore@948: } duke@1: int pos = S.pos(); duke@1: S.nextToken(); duke@1: t = toP(F.at(pos).Select(t, ident())); duke@1: if (S.token() == LT) { duke@1: checkGenerics(); mcimadamore@948: t = typeArguments(t, true); mcimadamore@948: diamondFound = (mode & DIAMOND) != 0; duke@1: } duke@1: } duke@1: mode = oldmode; jjg@722: if (S.token() == LBRACKET) { duke@1: JCExpression e = arrayCreatorRest(newpos, t); duke@1: 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: } duke@1: setErrorEndPos(S.prevEndPos()); duke@1: reportSyntaxError(pos, "cannot.create.array.with.type.arguments"); duke@1: return toP(F.at(newpos).Erroneous(typeArgs.prepend(e))); duke@1: } duke@1: return e; duke@1: } else if (S.token() == LPAREN) { jjg@722: return classCreatorRest(newpos, null, typeArgs, t); duke@1: } else { duke@1: reportSyntaxError(S.pos(), "expected2", mcimadamore@80: 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) { duke@1: JCExpression t = toP(F.at(S.pos()).Ident(ident())); duke@1: if (S.token() == 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); duke@1: if (S.token() == RBRACKET) { duke@1: accept(RBRACKET); jjg@722: elemtype = bracketsOpt(elemtype); duke@1: if (S.token() == LBRACE) { jjg@722: return arrayInitializer(newpos, elemtype); duke@1: } else { duke@1: return syntaxError(S.pos(), "array.dimension.missing"); duke@1: } duke@1: } else { duke@1: ListBuffer dims = new ListBuffer(); jjg@111: dims.append(parseExpression()); duke@1: accept(RBRACKET); jjg@722: while (S.token() == LBRACKET) { duke@1: int pos = S.pos(); duke@1: S.nextToken(); duke@1: if (S.token() == 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; duke@1: if (S.token() == LBRACE) { duke@1: int pos = S.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(); duke@1: if (S.token() == COMMA) { duke@1: S.nextToken(); duke@1: } else if (S.token() != RBRACE) { duke@1: elems.append(variableInitializer()); duke@1: while (S.token() == COMMA) { duke@1: S.nextToken(); duke@1: if (S.token() == 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() { jjg@111: return S.token() == LBRACE ? arrayInitializer(S.pos(), null) : parseExpression(); duke@1: } duke@1: duke@1: /** ParExpression = "(" Expression ")" duke@1: */ duke@1: JCExpression parExpression() { duke@1: accept(LPAREN); jjg@111: JCExpression t = parseExpression(); duke@1: accept(RPAREN); duke@1: return 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); duke@1: while (S.token() == CASE || S.token() == DEFAULT) { mcimadamore@80: syntaxError("orphaned", S.token()); 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. duke@1: t.endpos = S.pos(); duke@1: accept(RBRACE); duke@1: return toP(t); duke@1: } duke@1: duke@1: public JCBlock block() { duke@1: return block(S.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() { duke@1: //todo: skip to anchor on error(?) duke@1: int lastErrPos = -1; duke@1: ListBuffer stats = new ListBuffer(); duke@1: while (true) { duke@1: int pos = S.pos(); duke@1: switch (S.token()) { duke@1: case RBRACE: case CASE: case DEFAULT: case EOF: duke@1: return stats.toList(); duke@1: case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY: duke@1: case SWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK: duke@1: case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH: jjg@111: stats.append(parseStatement()); duke@1: break; duke@1: case MONKEYS_AT: duke@1: case FINAL: { duke@1: String dc = S.docComment(); duke@1: JCModifiers mods = modifiersOpt(); duke@1: if (S.token() == INTERFACE || duke@1: S.token() == CLASS || duke@1: allowEnums && S.token() == ENUM) { duke@1: stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); duke@1: } else { jjg@111: JCExpression t = parseType(); duke@1: stats.appendList(variableDeclarators(mods, t, duke@1: new ListBuffer())); duke@1: // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon duke@1: storeEnd(stats.elems.last(), S.endPos()); duke@1: accept(SEMI); duke@1: } duke@1: break; duke@1: } duke@1: case ABSTRACT: case STRICTFP: { duke@1: String dc = S.docComment(); duke@1: JCModifiers mods = modifiersOpt(); duke@1: stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); duke@1: break; duke@1: } duke@1: case INTERFACE: duke@1: case CLASS: duke@1: stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), duke@1: S.docComment())); duke@1: break; duke@1: case ENUM: duke@1: case ASSERT: duke@1: if (allowEnums && S.token() == ENUM) { jjg@726: error(S.pos(), "local.enum"); duke@1: stats. duke@1: append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), duke@1: S.docComment())); duke@1: break; duke@1: } else if (allowAsserts && S.token() == ASSERT) { jjg@111: stats.append(parseStatement()); duke@1: break; duke@1: } duke@1: /* fall through to default */ duke@1: default: duke@1: Name name = S.name(); duke@1: JCExpression t = term(EXPR | TYPE); duke@1: if (S.token() == COLON && t.getTag() == JCTree.IDENT) { duke@1: S.nextToken(); jjg@111: JCStatement stat = parseStatement(); duke@1: stats.append(F.at(pos).Labelled(name, stat)); duke@1: } else if ((lastmode & TYPE) != 0 && duke@1: (S.token() == IDENTIFIER || duke@1: S.token() == ASSERT || duke@1: S.token() == ENUM)) { duke@1: pos = S.pos(); duke@1: JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); duke@1: F.at(pos); duke@1: stats.appendList(variableDeclarators(mods, t, duke@1: new ListBuffer())); duke@1: // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon duke@1: storeEnd(stats.elems.last(), S.endPos()); duke@1: accept(SEMI); duke@1: } else { duke@1: // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon duke@1: stats.append(to(F.at(pos).Exec(checkExprStat(t)))); duke@1: accept(SEMI); duke@1: } duke@1: } duke@1: duke@1: // error recovery duke@1: if (S.pos() == lastErrPos) duke@1: return stats.toList(); duke@1: if (S.pos() <= errorEndPos) { duke@1: skip(false, true, true, true); duke@1: lastErrPos = S.pos(); duke@1: } duke@1: duke@1: // ensure no dangling /** @deprecated */ active duke@1: S.resetDeprecatedFlag(); 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() { duke@1: int pos = S.pos(); duke@1: switch (S.token()) { duke@1: case LBRACE: duke@1: return block(); duke@1: case IF: { duke@1: S.nextToken(); duke@1: JCExpression cond = parExpression(); jjg@111: JCStatement thenpart = parseStatement(); duke@1: JCStatement elsepart = null; duke@1: if (S.token() == ELSE) { duke@1: S.nextToken(); jjg@111: elsepart = parseStatement(); duke@1: } duke@1: return F.at(pos).If(cond, thenpart, elsepart); duke@1: } duke@1: case FOR: { duke@1: S.nextToken(); duke@1: accept(LPAREN); duke@1: List inits = S.token() == SEMI ? List.nil() : forInit(); duke@1: if (inits.length() == 1 && duke@1: inits.head.getTag() == JCTree.VARDEF && duke@1: ((JCVariableDecl) inits.head).init == null && duke@1: S.token() == COLON) { duke@1: checkForeach(); duke@1: JCVariableDecl var = (JCVariableDecl)inits.head; duke@1: accept(COLON); jjg@111: JCExpression expr = parseExpression(); duke@1: accept(RPAREN); jjg@111: JCStatement body = parseStatement(); duke@1: return F.at(pos).ForeachLoop(var, expr, body); duke@1: } else { duke@1: accept(SEMI); jjg@111: JCExpression cond = S.token() == SEMI ? null : parseExpression(); duke@1: accept(SEMI); duke@1: List steps = S.token() == RPAREN ? List.nil() : forUpdate(); duke@1: accept(RPAREN); jjg@111: JCStatement body = parseStatement(); duke@1: return F.at(pos).ForLoop(inits, cond, steps, body); duke@1: } duke@1: } duke@1: case WHILE: { duke@1: S.nextToken(); duke@1: JCExpression cond = parExpression(); jjg@111: JCStatement body = parseStatement(); duke@1: return F.at(pos).WhileLoop(cond, body); duke@1: } duke@1: case DO: { duke@1: S.nextToken(); jjg@111: JCStatement body = parseStatement(); 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: { duke@1: S.nextToken(); darcy@609: List resources = List.nil(); darcy@609: if (S.token() == LPAREN) { mcimadamore@743: checkTryWithResources(); darcy@609: S.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; duke@1: if (S.token() == CATCH || S.token() == FINALLY) { duke@1: while (S.token() == CATCH) catchers.append(catchClause()); duke@1: if (S.token() == FINALLY) { duke@1: S.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: { duke@1: S.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: { duke@1: S.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: { duke@1: S.nextToken(); jjg@111: JCExpression result = S.token() == 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: { duke@1: S.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: { duke@1: S.nextToken(); duke@1: Name label = (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM) ? ident() : null; duke@1: JCBreak t = to(F.at(pos).Break(label)); duke@1: accept(SEMI); duke@1: return t; duke@1: } duke@1: case CONTINUE: { duke@1: S.nextToken(); duke@1: Name label = (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM) ? ident() : null; duke@1: JCContinue t = to(F.at(pos).Continue(label)); duke@1: accept(SEMI); duke@1: return t; duke@1: } duke@1: case SEMI: duke@1: S.nextToken(); duke@1: return toP(F.at(pos).Skip()); duke@1: case ELSE: duke@1: return toP(F.Exec(syntaxError("else.without.if"))); duke@1: case FINALLY: duke@1: return toP(F.Exec(syntaxError("finally.without.try"))); duke@1: case CATCH: duke@1: return toP(F.Exec(syntaxError("catch.without.try"))); duke@1: case ASSERT: { duke@1: if (allowAsserts && S.token() == ASSERT) { duke@1: S.nextToken(); jjg@111: JCExpression assertion = parseExpression(); duke@1: JCExpression message = null; duke@1: if (S.token() == COLON) { duke@1: S.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: duke@1: Name name = S.name(); jjg@111: JCExpression expr = parseExpression(); duke@1: if (S.token() == COLON && expr.getTag() == JCTree.IDENT) { duke@1: S.nextToken(); jjg@111: JCStatement stat = parseStatement(); duke@1: return F.at(pos).Labelled(name, stat); duke@1: } else { duke@1: // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon duke@1: JCExpressionStatement stat = to(F.at(pos).Exec(checkExprStat(expr))); duke@1: accept(SEMI); duke@1: return stat; duke@1: } duke@1: } duke@1: } duke@1: duke@1: /** CatchClause = CATCH "(" FormalParameter ")" Block duke@1: */ duke@1: JCCatch catchClause() { duke@1: int pos = S.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@550: while (S.token() == BAR) { mcimadamore@550: checkMulticatch(); mcimadamore@550: S.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) { duke@1: int pos = S.pos(); duke@1: switch (S.token()) { duke@1: case CASE: { duke@1: S.nextToken(); jjg@111: JCExpression pat = parseExpression(); duke@1: accept(COLON); duke@1: List stats = blockStatements(); duke@1: JCCase c = F.at(pos).Case(pat, stats); duke@1: if (stats.isEmpty()) duke@1: storeEnd(c, S.prevEndPos()); duke@1: cases.append(c); duke@1: break; duke@1: } duke@1: case DEFAULT: { duke@1: S.nextToken(); duke@1: accept(COLON); duke@1: List stats = blockStatements(); duke@1: JCCase c = F.at(pos).Case(null, stats); duke@1: if (stats.isEmpty()) duke@1: storeEnd(c, S.prevEndPos()); duke@1: cases.append(c); duke@1: break; duke@1: } duke@1: case RBRACE: case EOF: duke@1: return cases.toList(); duke@1: default: duke@1: S.nextToken(); // to ensure progress duke@1: syntaxError(pos, "expected3", mcimadamore@80: CASE, DEFAULT, RBRACE); duke@1: } duke@1: } duke@1: } duke@1: 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)))); duke@1: while (S.token() == COMMA) { duke@1: S.nextToken(); duke@1: pos = S.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(); duke@1: int pos = S.pos(); duke@1: if (S.token() == FINAL || S.token() == MONKEYS_AT) { jjg@111: return variableDeclarators(optFinal(0), parseType(), stats).toList(); duke@1: } else { duke@1: JCExpression t = term(EXPR | TYPE); duke@1: if ((lastmode & TYPE) != 0 && duke@1: (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM)) duke@1: return variableDeclarators(modifiersOpt(), t, stats).toList(); duke@1: else duke@1: return moreStatementExpressions(pos, t, stats).toList(); duke@1: } duke@1: } duke@1: duke@1: /** ForUpdate = StatementExpression MoreStatementExpressions duke@1: */ duke@1: List forUpdate() { duke@1: return moreStatementExpressions(S.pos(), jjg@111: parseExpression(), duke@1: new ListBuffer()).toList(); duke@1: } duke@1: duke@1: /** AnnotationsOpt = { '@' Annotation } duke@1: */ jjg@722: List annotationsOpt() { duke@1: if (S.token() != MONKEYS_AT) return List.nil(); // optimization duke@1: ListBuffer buf = new ListBuffer(); duke@1: while (S.token() == MONKEYS_AT) { duke@1: int pos = S.pos(); duke@1: S.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: } duke@1: 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; jjg@482: pos = S.pos(); jjg@482: } else { jjg@482: flags = partial.flags; jjg@482: annotations.appendList(partial.annotations); jjg@482: pos = partial.pos; jjg@482: } duke@1: if (S.deprecatedFlag()) { duke@1: flags |= Flags.DEPRECATED; duke@1: S.resetDeprecatedFlag(); duke@1: } duke@1: int lastPos = Position.NOPOS; duke@1: loop: duke@1: while (true) { duke@1: long flag; duke@1: switch (S.token()) { 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; duke@1: default: break loop; duke@1: } jjg@726: if ((flags & flag) != 0) error(S.pos(), "repeated.modifier"); duke@1: lastPos = S.pos(); duke@1: S.nextToken(); duke@1: if (flag == Flags.ANNOTATION) { duke@1: checkAnnotations(); duke@1: if (S.token() != 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: } duke@1: switch (S.token()) { 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) duke@1: storeEnd(mods, S.prevEndPos()); 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); duke@1: storeEnd(ann, S.prevEndPos()); duke@1: return ann; duke@1: } duke@1: duke@1: List annotationFieldValuesOpt() { duke@1: return (S.token() == 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(); duke@1: if (S.token() != RPAREN) { duke@1: buf.append(annotationFieldValue()); duke@1: while (S.token() == COMMA) { duke@1: S.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() { duke@1: if (S.token() == IDENTIFIER) { duke@1: mode = EXPR; duke@1: JCExpression t1 = term1(); duke@1: if (t1.getTag() == JCTree.IDENT && S.token() == EQ) { duke@1: int pos = S.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; duke@1: switch (S.token()) { duke@1: case MONKEYS_AT: duke@1: pos = S.pos(); duke@1: S.nextToken(); jjg@722: return annotation(pos); duke@1: case LBRACE: duke@1: pos = S.pos(); duke@1: accept(LBRACE); duke@1: ListBuffer buf = new ListBuffer(); duke@1: if (S.token() != RBRACE) { duke@1: buf.append(annotationValue()); duke@1: while (S.token() == COMMA) { duke@1: S.nextToken(); darcy@417: if (S.token() == 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: { duke@1: return variableDeclaratorsRest(S.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, duke@1: String dc, duke@1: T vdefs) duke@1: { duke@1: vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc)); duke@1: while (S.token() == COMMA) { duke@1: // All but last of multiple declarators subsume a comma duke@1: storeEnd((JCTree)vdefs.elems.last(), S.endPos()); duke@1: S.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: */ duke@1: JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, String dc) { duke@1: return variableDeclaratorRest(S.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, duke@1: boolean reqInit, String dc) { duke@1: type = bracketsOpt(type); duke@1: JCExpression init = null; duke@1: if (S.token() == EQ) { duke@1: S.nextToken(); duke@1: init = variableInitializer(); duke@1: } mcimadamore@80: else if (reqInit) syntaxError(S.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) { duke@1: int pos = S.pos(); duke@1: Name name = ident(); mcimadamore@831: if ((mods.flags & Flags.VARARGS) != 0 && mcimadamore@831: S.token() == LBRACKET) { mcimadamore@831: log.error(S.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()); darcy@609: while (S.token() == SEMI) { darcy@850: // All but last of multiple declarators must subsume a semicolon darcy@609: storeEnd(defs.elems.last(), S.endPos()); darcy@840: int semiColonPos = S.pos(); darcy@609: S.nextToken(); darcy@850: if (S.token() == 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: */ darcy@609: JCTree resource() { darcy@840: return variableDeclaratorRest(S.pos(), optFinal(Flags.FINAL), darcy@840: parseType(), ident(), true, null); darcy@609: } darcy@609: duke@1: /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration} duke@1: */ jjg@111: public JCTree.JCCompilationUnit parseCompilationUnit() { duke@1: int pos = S.pos(); duke@1: JCExpression pid = null; duke@1: String dc = S.docComment(); duke@1: JCModifiers mods = null; duke@1: List packageAnnotations = List.nil(); duke@1: if (S.token() == MONKEYS_AT) duke@1: mods = modifiersOpt(); duke@1: duke@1: if (S.token() == PACKAGE) { duke@1: if (mods != null) { duke@1: checkNoMods(mods.flags); duke@1: packageAnnotations = mods.annotations; duke@1: mods = null; duke@1: } duke@1: S.nextToken(); duke@1: pid = qualident(); duke@1: accept(SEMI); duke@1: } duke@1: ListBuffer defs = new ListBuffer(); jjg@111: boolean checkForImports = true; duke@1: while (S.token() != EOF) { duke@1: if (S.pos() <= errorEndPos) { duke@1: // error recovery duke@1: skip(checkForImports, false, false, false); duke@1: if (S.token() == EOF) duke@1: break; duke@1: } duke@1: if (checkForImports && mods == null && S.token() == IMPORT) { duke@1: defs.append(importDeclaration()); duke@1: } else { duke@1: JCTree def = typeDeclaration(mods); jjg@695: if (keepDocComments && dc != null && docComments.get(def) == dc) { jjg@695: // If the first type declaration has consumed the first doc jjg@695: // comment, then don't use it for the top level comment as well. jjg@695: dc = null; jjg@695: } 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; duke@1: } duke@1: } duke@1: JCTree.JCCompilationUnit toplevel = F.at(pos).TopLevel(packageAnnotations, pid, defs.toList()); duke@1: attach(toplevel, dc); duke@1: if (defs.elems.isEmpty()) duke@1: storeEnd(toplevel, S.prevEndPos()); jjg@111: if (keepDocComments) jjg@111: toplevel.docComments = docComments; jjg@111: if (keepLineMap) jjg@111: toplevel.lineMap = S.getLineMap(); duke@1: return toplevel; duke@1: } duke@1: duke@1: /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";" duke@1: */ duke@1: JCTree importDeclaration() { duke@1: int pos = S.pos(); duke@1: S.nextToken(); duke@1: boolean importStatic = false; duke@1: if (S.token() == STATIC) { duke@1: checkStaticImports(); duke@1: importStatic = true; duke@1: S.nextToken(); duke@1: } duke@1: JCExpression pid = toP(F.at(S.pos()).Ident(ident())); duke@1: do { duke@1: int pos1 = S.pos(); duke@1: accept(DOT); duke@1: if (S.token() == STAR) { duke@1: pid = to(F.at(pos1).Select(pid, names.asterisk)); duke@1: S.nextToken(); duke@1: break; duke@1: } else { duke@1: pid = toP(F.at(pos1).Select(pid, ident())); duke@1: } duke@1: } while (S.token() == 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: */ duke@1: JCTree typeDeclaration(JCModifiers mods) { duke@1: int pos = S.pos(); duke@1: if (mods == null && S.token() == SEMI) { duke@1: S.nextToken(); duke@1: return toP(F.at(pos).Skip()); duke@1: } else { duke@1: String dc = S.docComment(); duke@1: return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), dc); 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: */ duke@1: JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, String dc) { duke@1: if (S.token() == CLASS) { duke@1: return classDeclaration(mods, dc); duke@1: } else if (S.token() == INTERFACE) { duke@1: return interfaceDeclaration(mods, dc); duke@1: } else if (allowEnums) { duke@1: if (S.token() == ENUM) { duke@1: return enumDeclaration(mods, dc); duke@1: } else { duke@1: int pos = S.pos(); duke@1: List errs; duke@1: if (S.token() == IDENTIFIER) { duke@1: errs = List.of(mods, toP(F.at(pos).Ident(ident()))); duke@1: setErrorEndPos(S.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 { duke@1: if (S.token() == ENUM) { jjg@726: error(S.pos(), "enums.not.supported.in.source", source.name); duke@1: allowEnums = true; duke@1: return enumDeclaration(mods, dc); duke@1: } duke@1: int pos = S.pos(); duke@1: List errs; duke@1: if (S.token() == IDENTIFIER) { duke@1: errs = List.of(mods, toP(F.at(pos).Ident(ident()))); duke@1: setErrorEndPos(S.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: */ duke@1: JCClassDecl classDeclaration(JCModifiers mods, String dc) { duke@1: int pos = S.pos(); duke@1: accept(CLASS); duke@1: Name name = ident(); duke@1: duke@1: List typarams = typeParametersOpt(); duke@1: jjg@904: JCExpression extending = null; duke@1: if (S.token() == EXTENDS) { duke@1: S.nextToken(); jjg@111: extending = parseType(); duke@1: } duke@1: List implementing = List.nil(); duke@1: if (S.token() == IMPLEMENTS) { duke@1: S.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: */ duke@1: JCClassDecl interfaceDeclaration(JCModifiers mods, String dc) { duke@1: int pos = S.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(); duke@1: if (S.token() == EXTENDS) { duke@1: S.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: */ duke@1: JCClassDecl enumDeclaration(JCModifiers mods, String dc) { duke@1: int pos = S.pos(); duke@1: accept(ENUM); duke@1: Name name = ident(); duke@1: duke@1: List implementing = List.nil(); duke@1: if (S.token() == IMPLEMENTS) { duke@1: S.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(); duke@1: if (S.token() == COMMA) { duke@1: S.nextToken(); duke@1: } else if (S.token() != RBRACE && S.token() != SEMI) { duke@1: defs.append(enumeratorDeclaration(enumName)); duke@1: while (S.token() == COMMA) { duke@1: S.nextToken(); duke@1: if (S.token() == RBRACE || S.token() == SEMI) break; duke@1: defs.append(enumeratorDeclaration(enumName)); duke@1: } duke@1: if (S.token() != SEMI && S.token() != RBRACE) { duke@1: defs.append(syntaxError(S.pos(), "expected3", mcimadamore@80: COMMA, RBRACE, SEMI)); duke@1: S.nextToken(); duke@1: } duke@1: } duke@1: if (S.token() == SEMI) { duke@1: S.nextToken(); duke@1: while (S.token() != RBRACE && S.token() != EOF) { duke@1: defs.appendList(classOrInterfaceBodyDeclaration(enumName, duke@1: false)); duke@1: if (S.pos() <= 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) { duke@1: String dc = S.docComment(); duke@1: int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM; duke@1: if (S.deprecatedFlag()) { duke@1: flags |= Flags.DEPRECATED; duke@1: S.resetDeprecatedFlag(); duke@1: } duke@1: int pos = S.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(); duke@1: int identPos = S.pos(); duke@1: Name name = ident(); duke@1: int createPos = S.pos(); duke@1: List args = (S.token() == LPAREN) duke@1: ? arguments() : List.nil(); duke@1: JCClassDecl body = null; duke@1: if (S.token() == 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) duke@1: storeEnd(create, S.prevEndPos()); 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()); duke@1: while (S.token() == COMMA) { duke@1: S.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); duke@1: if (S.pos() <= errorEndPos) { duke@1: // error recovery duke@1: skip(false, true, false, false); duke@1: if (S.token() == LBRACE) duke@1: S.nextToken(); duke@1: } duke@1: ListBuffer defs = new ListBuffer(); duke@1: while (S.token() != RBRACE && S.token() != EOF) { duke@1: defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface)); duke@1: if (S.pos() <= 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: */ duke@1: List classOrInterfaceBodyDeclaration(Name className, boolean isInterface) { duke@1: if (S.token() == SEMI) { duke@1: S.nextToken(); jjg@667: return List.nil(); duke@1: } else { duke@1: String dc = S.docComment(); duke@1: int pos = S.pos(); duke@1: JCModifiers mods = modifiersOpt(); duke@1: if (S.token() == CLASS || duke@1: S.token() == INTERFACE || duke@1: allowEnums && S.token() == ENUM) { duke@1: return List.of(classOrInterfaceOrEnumDeclaration(mods, dc)); duke@1: } else if (S.token() == 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 { duke@1: pos = S.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: } duke@1: Name name = S.name(); duke@1: pos = S.pos(); duke@1: JCExpression type; duke@1: boolean isVoid = S.token() == VOID; duke@1: if (isVoid) { duke@1: type = to(F.at(pos).TypeIdent(TypeTags.VOID)); duke@1: S.nextToken(); duke@1: } else { jjg@722: type = parseType(); duke@1: } duke@1: if (S.token() == LPAREN && !isInterface && type.getTag() == JCTree.IDENT) { duke@1: if (isInterface || 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 { duke@1: pos = S.pos(); duke@1: name = ident(); duke@1: if (S.token() == 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(); duke@1: storeEnd(defs.last(), S.endPos()); duke@1: accept(SEMI); duke@1: return defs; duke@1: } else { duke@1: pos = S.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@80: return List.of(syntaxError(S.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: */ duke@1: 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, duke@1: String dc) { duke@1: List params = formalParameters(); jjg@722: if (!isVoid) type = bracketsOpt(type); duke@1: List thrown = List.nil(); duke@1: if (S.token() == THROWS) { duke@1: S.nextToken(); duke@1: thrown = qualidentList(); duke@1: } duke@1: JCBlock body = null; duke@1: JCExpression defaultValue; duke@1: if (S.token() == LBRACE) { duke@1: body = block(); duke@1: defaultValue = null; duke@1: } else { duke@1: if (S.token() == DEFAULT) { duke@1: accept(DEFAULT); duke@1: defaultValue = annotationValue(); duke@1: } else { duke@1: defaultValue = null; duke@1: } duke@1: accept(SEMI); duke@1: if (S.pos() <= errorEndPos) { duke@1: // error recovery duke@1: skip(false, true, false, false); duke@1: if (S.token() == 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()); duke@1: while (S.token() == COMMA) { duke@1: S.nextToken(); jjg@722: ts.append(qualident()); duke@1: } duke@1: return ts.toList(); duke@1: } duke@1: duke@1: /** TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"] duke@1: */ duke@1: List typeParametersOpt() { duke@1: if (S.token() == LT) { duke@1: checkGenerics(); duke@1: ListBuffer typarams = new ListBuffer(); duke@1: S.nextToken(); duke@1: typarams.append(typeParameter()); duke@1: while (S.token() == COMMA) { duke@1: S.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@722: /** TypeParameter = TypeVariable [TypeParameterBound] duke@1: * TypeParameterBound = EXTENDS Type {"&" Type} duke@1: * TypeVariable = Ident duke@1: */ duke@1: JCTypeParameter typeParameter() { duke@1: int pos = S.pos(); duke@1: Name name = ident(); duke@1: ListBuffer bounds = new ListBuffer(); duke@1: if (S.token() == EXTENDS) { duke@1: S.nextToken(); jjg@111: bounds.append(parseType()); duke@1: while (S.token() == AMP) { duke@1: S.nextToken(); jjg@111: bounds.append(parseType()); duke@1: } duke@1: } jjg@722: return toP(F.at(pos).TypeParameter(name, bounds.toList())); duke@1: } duke@1: duke@1: /** FormalParameters = "(" [ FormalParameterList ] ")" duke@1: * FormalParameterList = [ FormalParameterListNovarargs , ] LastFormalParameter duke@1: * FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter duke@1: */ duke@1: List formalParameters() { duke@1: ListBuffer params = new ListBuffer(); duke@1: JCVariableDecl lastParam = null; duke@1: accept(LPAREN); duke@1: if (S.token() != RPAREN) { duke@1: params.append(lastParam = formalParameter()); duke@1: while ((lastParam.mods.flags & Flags.VARARGS) == 0 && S.token() == COMMA) { duke@1: S.nextToken(); duke@1: params.append(lastParam = formalParameter()); duke@1: } duke@1: } duke@1: accept(RPAREN); duke@1: return params.toList(); duke@1: } duke@1: 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: */ duke@1: JCVariableDecl formalParameter() { duke@1: JCModifiers mods = optFinal(Flags.PARAMETER); jjg@111: JCExpression type = parseType(); duke@1: if (S.token() == ELLIPSIS) { duke@1: checkVarargs(); duke@1: mods.flags |= Flags.VARARGS; duke@1: type = to(F.at(S.pos()).TypeArray(type)); duke@1: S.nextToken(); duke@1: } duke@1: return variableDeclaratorId(mods, type); duke@1: } duke@1: 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: jjg@726: void warning(int pos, String key, Object ... args) { jjg@726: log.warning(pos, key, args); jjg@726: } jjg@726: duke@1: /** Check that given tree is a legal expression statement. duke@1: */ duke@1: protected JCExpression checkExprStat(JCExpression t) { duke@1: switch(t.getTag()) { duke@1: case JCTree.PREINC: case JCTree.PREDEC: duke@1: case JCTree.POSTINC: case JCTree.POSTDEC: duke@1: case JCTree.ASSIGN: duke@1: case JCTree.BITOR_ASG: case JCTree.BITXOR_ASG: case JCTree.BITAND_ASG: duke@1: case JCTree.SL_ASG: case JCTree.SR_ASG: case JCTree.USR_ASG: duke@1: case JCTree.PLUS_ASG: case JCTree.MINUS_ASG: duke@1: case JCTree.MUL_ASG: case JCTree.DIV_ASG: case JCTree.MOD_ASG: duke@1: case JCTree.APPLY: case JCTree.NEWCLASS: duke@1: case JCTree.ERRONEOUS: duke@1: return t; duke@1: default: jjg@726: error(t.pos, "not.stmt"); duke@1: return F.at(t.pos).Erroneous(List.of(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: */ duke@1: static int prec(Token token) { duke@1: int oc = optag(token); duke@1: return (oc >= 0) ? 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, duke@1: * -1 if token is not a binary operator. duke@1: */ duke@1: static int optag(Token token) { duke@1: switch (token) { duke@1: case BARBAR: duke@1: return JCTree.OR; duke@1: case AMPAMP: duke@1: return JCTree.AND; duke@1: case BAR: duke@1: return JCTree.BITOR; duke@1: case BAREQ: duke@1: return JCTree.BITOR_ASG; duke@1: case CARET: duke@1: return JCTree.BITXOR; duke@1: case CARETEQ: duke@1: return JCTree.BITXOR_ASG; duke@1: case AMP: duke@1: return JCTree.BITAND; duke@1: case AMPEQ: duke@1: return JCTree.BITAND_ASG; duke@1: case EQEQ: duke@1: return JCTree.EQ; duke@1: case BANGEQ: duke@1: return JCTree.NE; duke@1: case LT: duke@1: return JCTree.LT; duke@1: case GT: duke@1: return JCTree.GT; duke@1: case LTEQ: duke@1: return JCTree.LE; duke@1: case GTEQ: duke@1: return JCTree.GE; duke@1: case LTLT: duke@1: return JCTree.SL; duke@1: case LTLTEQ: duke@1: return JCTree.SL_ASG; duke@1: case GTGT: duke@1: return JCTree.SR; duke@1: case GTGTEQ: duke@1: return JCTree.SR_ASG; duke@1: case GTGTGT: duke@1: return JCTree.USR; duke@1: case GTGTGTEQ: duke@1: return JCTree.USR_ASG; duke@1: case PLUS: duke@1: return JCTree.PLUS; duke@1: case PLUSEQ: duke@1: return JCTree.PLUS_ASG; duke@1: case SUB: duke@1: return JCTree.MINUS; duke@1: case SUBEQ: duke@1: return JCTree.MINUS_ASG; duke@1: case STAR: duke@1: return JCTree.MUL; duke@1: case STAREQ: duke@1: return JCTree.MUL_ASG; duke@1: case SLASH: duke@1: return JCTree.DIV; duke@1: case SLASHEQ: duke@1: return JCTree.DIV_ASG; duke@1: case PERCENT: duke@1: return JCTree.MOD; duke@1: case PERCENTEQ: duke@1: return JCTree.MOD_ASG; duke@1: case INSTANCEOF: duke@1: return JCTree.TYPETEST; duke@1: default: duke@1: return -1; duke@1: } duke@1: } duke@1: duke@1: /** Return operation tag of unary operator represented by token, duke@1: * -1 if token is not a binary operator. duke@1: */ duke@1: static int unoptag(Token token) { duke@1: switch (token) { duke@1: case PLUS: duke@1: return JCTree.POS; duke@1: case SUB: duke@1: return JCTree.NEG; duke@1: case BANG: duke@1: return JCTree.NOT; duke@1: case TILDE: duke@1: return JCTree.COMPL; duke@1: case PLUSPLUS: duke@1: return JCTree.PREINC; duke@1: case SUBSUB: duke@1: return JCTree.PREDEC; duke@1: default: duke@1: return -1; duke@1: } duke@1: } duke@1: duke@1: /** Return type tag of basic type represented by token, duke@1: * -1 if token is not a basic type identifier. duke@1: */ duke@1: static int typetag(Token token) { duke@1: switch (token) { duke@1: case BYTE: duke@1: return TypeTags.BYTE; duke@1: case CHAR: duke@1: return TypeTags.CHAR; duke@1: case SHORT: duke@1: return TypeTags.SHORT; duke@1: case INT: duke@1: return TypeTags.INT; duke@1: case LONG: duke@1: return TypeTags.LONG; duke@1: case FLOAT: duke@1: return TypeTags.FLOAT; duke@1: case DOUBLE: duke@1: return TypeTags.DOUBLE; duke@1: case BOOLEAN: duke@1: return TypeTags.BOOLEAN; duke@1: default: duke@1: return -1; duke@1: } duke@1: } duke@1: duke@1: void checkGenerics() { duke@1: if (!allowGenerics) { jjg@726: error(S.pos(), "generics.not.supported.in.source", source.name); duke@1: allowGenerics = true; duke@1: } duke@1: } duke@1: void checkVarargs() { duke@1: if (!allowVarargs) { jjg@726: error(S.pos(), "varargs.not.supported.in.source", source.name); duke@1: allowVarargs = true; duke@1: } duke@1: } duke@1: void checkForeach() { duke@1: if (!allowForeach) { jjg@726: error(S.pos(), "foreach.not.supported.in.source", source.name); duke@1: allowForeach = true; duke@1: } duke@1: } duke@1: void checkStaticImports() { duke@1: if (!allowStaticImport) { jjg@726: error(S.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) { jjg@726: error(S.pos(), "annotations.not.supported.in.source", source.name); duke@1: allowAnnotations = true; duke@1: } duke@1: } mcimadamore@537: void checkDiamond() { mcimadamore@537: if (!allowDiamond) { jjg@726: error(S.pos(), "diamond.not.supported.in.source", source.name); mcimadamore@537: allowDiamond = true; mcimadamore@537: } mcimadamore@537: } mcimadamore@550: void checkMulticatch() { mcimadamore@550: if (!allowMulticatch) { jjg@726: error(S.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@743: error(S.pos(), "try.with.resources.not.supported.in.source", source.name); darcy@609: allowTWR = true; darcy@609: } mcimadamore@550: } duke@1: }