duke@1: /*
duke@1: * Copyright 1999-2006 Sun Microsystems, Inc. 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
duke@1: * published by the Free Software Foundation. Sun designates this
duke@1: * particular file as subject to the "Classpath" exception as provided
duke@1: * by Sun 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: *
duke@1: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@1: * CA 95054 USA or visit www.sun.com if you need additional information or
duke@1: * have any 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.*;
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: *
duke@1: *
This is NOT part of any API supported by Sun Microsystems. If
duke@1: * 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: */
duke@1: public class Parser {
duke@1:
duke@1: /** A factory for creating parsers. */
duke@1: public static class Factory {
duke@1: /** The context key for the parser factory. */
duke@1: protected static final Context.Key parserFactoryKey =
duke@1: new Context.Key();
duke@1:
duke@1: /** Get the Factory instance for this context. */
duke@1: public static Factory instance(Context context) {
duke@1: Factory instance = context.get(parserFactoryKey);
duke@1: if (instance == null)
duke@1: instance = new Factory(context);
duke@1: return instance;
duke@1: }
duke@1:
duke@1: final TreeMaker F;
duke@1: final Log log;
duke@1: final Keywords keywords;
duke@1: final Source source;
duke@1: final Name.Table names;
duke@1: final Options options;
duke@1:
duke@1: /** Create a new parser factory. */
duke@1: protected Factory(Context context) {
duke@1: context.put(parserFactoryKey, this);
duke@1: this.F = TreeMaker.instance(context);
duke@1: this.log = Log.instance(context);
duke@1: this.names = Name.Table.instance(context);
duke@1: this.keywords = Keywords.instance(context);
duke@1: this.source = Source.instance(context);
duke@1: this.options = Options.instance(context);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Create a new Parser.
duke@1: * @param S Lexer for getting tokens while parsing
duke@1: * @param keepDocComments true if javadoc comments should be kept
duke@1: * @param genEndPos true if end positions should be generated
duke@1: */
duke@1: public Parser newParser(Lexer S, boolean keepDocComments, boolean genEndPos) {
duke@1: if (!genEndPos)
duke@1: return new Parser(this, S, keepDocComments);
duke@1: else
duke@1: return new EndPosParser(this, S, keepDocComments);
duke@1: }
duke@1: }
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. */
duke@1: private Name.Table names;
duke@1:
duke@1: /** Construct a parser from a given scanner, tree factory and log.
duke@1: */
duke@1: protected Parser(Factory fac,
duke@1: Lexer S,
duke@1: boolean keepDocComments) {
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: Options options = fac.options;
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();
duke@1: this.keepDocComments = keepDocComments;
duke@1: if (keepDocComments) docComments = new HashMap();
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:
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:
duke@1: /** Switch: should we keep docComments?
duke@1: */
duke@1: boolean keepDocComments;
duke@1:
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: */
duke@1: static final int EXPR = 1;
duke@1: static final int TYPE = 2;
duke@1: static final int NOPARAMS = 4;
duke@1: static final int TYPEARG = 8;
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:
duke@1: private JCErroneous syntaxError(int pos, String key, Object... arg) {
duke@1: return syntaxError(pos, null, key, arg);
duke@1: }
duke@1:
duke@1: private JCErroneous syntaxError(int pos, List errs, String key, Object... arg) {
duke@1: setErrorEndPos(pos);
duke@1: reportSyntaxError(pos, key, arg);
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: */
duke@1: private void reportSyntaxError(int pos, String key, Object... arg) {
duke@1: if (pos > S.errPos() || pos == Position.NOPOS) {
duke@1: if (S.token() == EOF)
duke@1: log.error(pos, "premature.eof");
duke@1: else
duke@1: log.error(pos, key, arg);
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: */
duke@1: private JCErroneous syntaxError(String key, String 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());
duke@1: reportSyntaxError(S.prevEndPos(), "expected", keywords.token2string(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;
duke@1: log.error(S.pos(), "mod.not.allowed.here",
duke@1: Flags.toString(lowestMod).trim());
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) {
duke@1: log.error(S.pos(), "assert.as.identifier");
duke@1: S.nextToken();
duke@1: return names.error;
duke@1: } else {
duke@1: log.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) {
duke@1: log.error(S.pos(), "enum.as.identifier");
duke@1: S.nextToken();
duke@1: return names.error;
duke@1: } else {
duke@1: log.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) {
duke@1: log.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) {
duke@1: log.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) {
duke@1: // error already repoted in scanner
duke@1: n = Float.NaN;
duke@1: }
duke@1: if (n.floatValue() == 0.0f && !isZero(proper))
duke@1: log.error(S.pos(), "fp.number.too.small");
duke@1: else if (n.floatValue() == Float.POSITIVE_INFINITY)
duke@1: log.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))
duke@1: log.error(S.pos(), "fp.number.too.small");
duke@1: else if (n.doubleValue() == Double.POSITIVE_INFINITY)
duke@1: log.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:
duke@1: assert false;
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();
duke@1: int base = ((Character.toLowerCase(s.charAt(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();
duke@1: return (prefix.len == 0) ? s : prefix + s;
duke@1: }
duke@1:
duke@1: /** terms can be either expressions or types.
duke@1: */
duke@1: public JCExpression expression() {
duke@1: return term(EXPR);
duke@1: }
duke@1:
duke@1: public JCExpression type() {
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();
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;
duke@1: while (prec(S.token()) >= minprec) {
duke@1: opStack[top] = topOp;
duke@1: top++;
duke@1: topOp = S.token();
duke@1: int pos = S.pos();
duke@1: S.nextToken();
duke@1: odStack[top] = topOp == INSTANCEOF ? type() : term3();
duke@1: while (top > 0 && prec(topOp) >= prec(S.token())) {
duke@1: odStack[top-1] = makeOp(pos, topOp, odStack[top-1],
duke@1: odStack[top]);
duke@1: top--;
duke@1: topOp = opStack[top];
duke@1: }
duke@1: }
duke@1: assert 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
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();
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:
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
duke@1: * | Ident { "." Ident }
duke@1: * [ "[" ( "]" 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);
duke@1: t = F.at(pos1).TypeApply(t, args.toList());
duke@1: checkGenerics();
duke@1: t = bracketsOpt(toP(t));
duke@1: } else if ((mode & EXPR) != 0) {
duke@1: mode = EXPR;
duke@1: t = F.at(pos1).Binary(op, t, term2Rest(t1, TreeInfo.shiftPrec));
duke@1: t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
duke@1: } else {
duke@1: accept(GT);
duke@1: }
duke@1: } 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;
duke@1: t = to(superSuffix(typeArgs, F.at(pos).Ident(names._super)));
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();
duke@1: if (S.token() == LT) typeArgs = typeArguments();
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();
duke@1: 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();
duke@1: typeArgs = typeArgumentsOpt(EXPR);
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();
duke@1: if (S.token() == LT) typeArgs = typeArguments();
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 {
duke@1: 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();
duke@1: 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();
duke@1: if (S.token() == LT) typeArgs = typeArguments();
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);
duke@1: typeArgs = (S.token() == LT) ? typeArguments() : 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) {
duke@1: args.append(expression());
duke@1: while (S.token() == COMMA) {
duke@1: S.nextToken();
duke@1: args.append(expression());
duke@1: }
duke@1: }
duke@1: accept(RPAREN);
duke@1: } else {
duke@1: syntaxError(S.pos(), "expected", keywords.token2string(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();
duke@1: return typeArguments(t);
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;
duke@1: return typeArguments();
duke@1: }
duke@1: return null;
duke@1: }
duke@1:
duke@1: /** TypeArguments = "<" TypeArgument {"," TypeArgument} ">"
duke@1: */
duke@1: List typeArguments() {
duke@1: ListBuffer args = lb();
duke@1: if (S.token() == LT) {
duke@1: S.nextToken();
duke@1: args.append(((mode & EXPR) == 0) ? typeArgument() : type());
duke@1: while (S.token() == COMMA) {
duke@1: S.nextToken();
duke@1: args.append(((mode & EXPR) == 0) ? typeArgument() : type());
duke@1: }
duke@1: switch (S.token()) {
duke@1: case GTGTGTEQ:
duke@1: S.token(GTGTEQ);
duke@1: break;
duke@1: case GTGTEQ:
duke@1: S.token(GTEQ);
duke@1: break;
duke@1: case GTEQ:
duke@1: S.token(EQ);
duke@1: break;
duke@1: case GTGTGT:
duke@1: S.token(GTGT);
duke@1: break;
duke@1: case GTGT:
duke@1: S.token(GT);
duke@1: break;
duke@1: default:
duke@1: accept(GT);
duke@1: break;
duke@1: }
duke@1: } else {
duke@1: syntaxError(S.pos(), "expected", keywords.token2string(LT));
duke@1: }
duke@1: return args.toList();
duke@1: }
duke@1:
duke@1: /** TypeArgument = Type
duke@1: * | "?"
duke@1: * | "?" EXTENDS Type {"&" Type}
duke@1: * | "?" SUPER Type
duke@1: */
duke@1: JCExpression typeArgument() {
duke@1: if (S.token() != QUES) return type();
duke@1: int pos = S.pos();
duke@1: S.nextToken();
duke@1: if (S.token() == EXTENDS) {
duke@1: TypeBoundKind t = to(F.at(S.pos()).TypeBoundKind(BoundKind.EXTENDS));
duke@1: S.nextToken();
duke@1: return F.at(pos).Wildcard(t, type());
duke@1: } else if (S.token() == SUPER) {
duke@1: TypeBoundKind t = to(F.at(S.pos()).TypeBoundKind(BoundKind.SUPER));
duke@1: S.nextToken();
duke@1: return F.at(pos).Wildcard(t, type());
duke@1: } else if (S.token() == IDENTIFIER) {
duke@1: //error recovery
duke@1: reportSyntaxError(S.prevEndPos(), "expected3",
duke@1: keywords.token2string(GT),
duke@1: keywords.token2string(EXTENDS),
duke@1: keywords.token2string(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()));
duke@1: return F.at(pos).Erroneous(List.of(wc, id));
duke@1: } else {
duke@1: TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
duke@1: return toP(F.at(pos).Wildcard(t, null));
duke@1: }
duke@1: }
duke@1:
duke@1: JCTypeApply typeArguments(JCExpression t) {
duke@1: int pos = S.pos();
duke@1: List args = typeArguments();
duke@1: return toP(F.at(pos).TypeApply(t, args));
duke@1: }
duke@1:
duke@1: /** BracketsOpt = {"[" "]"}
duke@1: */
duke@1: private JCExpression bracketsOpt(JCExpression t) {
duke@1: if (S.token() == LBRACKET) {
duke@1: int pos = S.pos();
duke@1: S.nextToken();
duke@1: t = bracketsOptCont(t, pos);
duke@1: F.at(pos);
duke@1: }
duke@1: return t;
duke@1: }
duke@1:
duke@1: private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos) {
duke@1: accept(RBRACKET);
duke@1: 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:
duke@1: /** 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:
duke@1: if (typeArgs == null)
duke@1: return arrayCreatorRest(newpos, basicType());
duke@1: break;
duke@1: default:
duke@1: }
duke@1: JCExpression t = qualident();
duke@1: int oldmode = mode;
duke@1: mode = TYPE;
duke@1: if (S.token() == LT) {
duke@1: checkGenerics();
duke@1: t = typeArguments(t);
duke@1: }
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: if (S.token() == LT) {
duke@1: checkGenerics();
duke@1: t = typeArguments(t);
duke@1: }
duke@1: }
duke@1: mode = oldmode;
duke@1: 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) {
duke@1: return classCreatorRest(newpos, null, typeArgs, t);
duke@1: } else {
duke@1: reportSyntaxError(S.pos(), "expected2",
duke@1: keywords.token2string(LPAREN),
duke@1: keywords.token2string(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) {
duke@1: checkGenerics();
duke@1: t = typeArguments(t);
duke@1: }
duke@1: return classCreatorRest(newpos, encl, typeArgs, t);
duke@1: }
duke@1:
duke@1: /** ArrayCreatorRest = "[" ( "]" BracketsOpt ArrayInitializer
duke@1: * | 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);
duke@1: elemtype = bracketsOpt(elemtype);
duke@1: if (S.token() == LBRACE) {
duke@1: 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();
duke@1: dims.append(expression());
duke@1: accept(RBRACKET);
duke@1: while (S.token() == LBRACKET) {
duke@1: int pos = S.pos();
duke@1: S.nextToken();
duke@1: if (S.token() == RBRACKET) {
duke@1: elemtype = bracketsOptCont(elemtype, pos);
duke@1: } else {
duke@1: dims.append(expression());
duke@1: accept(RBRACKET);
duke@1: }
duke@1: }
duke@1: return toP(F.at(newpos).NewArray(elemtype, dims.toList(), null));
duke@1: }
duke@1: }
duke@1:
duke@1: /** ClassCreatorRest = Arguments [ClassBody]
duke@1: */
duke@1: JCExpression 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() {
duke@1: return S.token() == LBRACE ? arrayInitializer(S.pos(), null) : expression();
duke@1: }
duke@1:
duke@1: /** ParExpression = "(" Expression ")"
duke@1: */
duke@1: JCExpression parExpression() {
duke@1: accept(LPAREN);
duke@1: JCExpression t = expression();
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) {
duke@1: syntaxError("orphaned", keywords.token2string(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:
duke@1: stats.append(statement());
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 {
duke@1: JCExpression t = type();
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) {
duke@1: log.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) {
duke@1: stats.append(statement());
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();
duke@1: JCStatement stat = statement();
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 )
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")
duke@1: public JCStatement statement() {
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();
duke@1: JCStatement thenpart = statement();
duke@1: JCStatement elsepart = null;
duke@1: if (S.token() == ELSE) {
duke@1: S.nextToken();
duke@1: elsepart = statement();
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);
duke@1: JCExpression expr = expression();
duke@1: accept(RPAREN);
duke@1: JCStatement body = statement();
duke@1: return F.at(pos).ForeachLoop(var, expr, body);
duke@1: } else {
duke@1: accept(SEMI);
duke@1: JCExpression cond = S.token() == SEMI ? null : expression();
duke@1: accept(SEMI);
duke@1: List steps = S.token() == RPAREN ? List.nil() : forUpdate();
duke@1: accept(RPAREN);
duke@1: JCStatement body = statement();
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();
duke@1: JCStatement body = statement();
duke@1: return F.at(pos).WhileLoop(cond, body);
duke@1: }
duke@1: case DO: {
duke@1: S.nextToken();
duke@1: JCStatement body = statement();
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();
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 {
duke@1: log.error(pos, "try.without.catch.or.finally");
duke@1: }
duke@1: return F.at(pos).Try(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();
duke@1: JCExpression result = S.token() == SEMI ? null : expression();
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();
duke@1: JCExpression exc = expression();
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();
duke@1: JCExpression assertion = expression();
duke@1: JCExpression message = null;
duke@1: if (S.token() == COLON) {
duke@1: S.nextToken();
duke@1: message = expression();
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();
duke@1: JCExpression expr = expression();
duke@1: if (S.token() == COLON && expr.getTag() == JCTree.IDENT) {
duke@1: S.nextToken();
duke@1: JCStatement stat = statement();
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);
duke@1: JCVariableDecl formal =
duke@1: variableDeclaratorId(optFinal(Flags.PARAMETER),
duke@1: qualident());
duke@1: accept(RPAREN);
duke@1: JCBlock body = block();
duke@1: return F.at(pos).Catch(formal, body);
duke@1: }
duke@1:
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();
duke@1: JCExpression pat = expression();
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",
duke@1: keywords.token2string(CASE),
duke@1: keywords.token2string(DEFAULT),
duke@1: keywords.token2string(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();
duke@1: JCExpression t = expression();
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) {
duke@1: return variableDeclarators(optFinal(0), type(), 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(),
duke@1: expression(),
duke@1: new ListBuffer()).toList();
duke@1: }
duke@1:
duke@1: /** AnnotationsOpt = { '@' Annotation }
duke@1: */
duke@1: 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();
duke@1: buf.append(annotation(pos));
duke@1: }
duke@1: 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) {
duke@1: long flags = (partial == null) ? 0 : partial.flags;
duke@1: if (S.deprecatedFlag()) {
duke@1: flags |= Flags.DEPRECATED;
duke@1: S.resetDeprecatedFlag();
duke@1: }
duke@1: ListBuffer annotations = new ListBuffer();
duke@1: if (partial != null) annotations.appendList(partial.annotations);
duke@1: int pos = S.pos();
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: }
duke@1: if ((flags & flag) != 0) log.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) {
duke@1: JCAnnotation ann = annotation(lastPos);
duke@1: // if first modifier is an annotation, set pos to annotation's.
duke@1: if (flags == 0 && annotations.isEmpty())
duke@1: pos = ann.pos;
duke@1: annotations.append(ann);
duke@1: 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. */
duke@1: if (flags == 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: */
duke@1: 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();
duke@1: 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);
duke@1: return toP(F.at(pos).Assign(t1, annotationValue()));
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
duke@1: * | "{" [ 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();
duke@1: 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();
duke@1: if (S.token() == RPAREN) 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: }
duke@1: else if (reqInit) syntaxError(S.pos(), "expected", keywords.token2string(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();
duke@1: if ((mods.flags & Flags.VARARGS) == 0)
duke@1: type = bracketsOpt(type);
duke@1: return toP(F.at(pos).VarDef(mods, name, type, null));
duke@1: }
duke@1:
duke@1: /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration}
duke@1: */
duke@1: public JCTree.JCCompilationUnit compilationUnit() {
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();
duke@1: 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);
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());
duke@1: if (keepDocComments) toplevel.docComments = docComments;
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",
duke@1: keywords.token2string(CLASS),
duke@1: keywords.token2string(INTERFACE),
duke@1: keywords.token2string(ENUM))));
duke@1: }
duke@1: } else {
duke@1: if (S.token() == ENUM) {
duke@1: log.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",
duke@1: keywords.token2string(CLASS),
duke@1: keywords.token2string(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:
duke@1: JCTree extending = null;
duke@1: if (S.token() == EXTENDS) {
duke@1: S.nextToken();
duke@1: extending = type();
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);
duke@1: JCModifiers newMods =
duke@1: F.at(mods.pos).Modifiers(mods.flags|Flags.ENUM, mods.annotations);
duke@1: JCClassDecl result = toP(F.at(pos).
duke@1: ClassDef(newMods, 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",
duke@1: keywords.token2string(COMMA),
duke@1: keywords.token2string(RBRACE),
duke@1: keywords.token2string(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();
duke@1: 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)
duke@1: createPos = Position.NOPOS;
duke@1: JCIdent ident = F.at(Position.NOPOS).Ident(enumName);
duke@1: JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body);
duke@1: if (createPos != Position.NOPOS)
duke@1: storeEnd(create, S.prevEndPos());
duke@1: ident = F.at(Position.NOPOS).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();
duke@1: ts.append(type());
duke@1: while (S.token() == COMMA) {
duke@1: S.nextToken();
duke@1: ts.append(type());
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();
duke@1: return List.of(F.at(Position.NOPOS).Block(0, 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();
duke@1: // Hack alert: if there are type arguments but no Modifiers, the start
duke@1: // position will be lost unless we set the Modifiers position. There
duke@1: // should be an AST node for type parameters (BugId 5005090).
duke@1: if (typarams.length() > 0 && mods.pos == Position.NOPOS) {
duke@1: mods.pos = pos;
duke@1: }
duke@1: Token token = S.token();
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 {
duke@1: type = type();
duke@1: }
duke@1: if (S.token() == LPAREN && !isInterface && type.getTag() == JCTree.IDENT) {
duke@1: if (isInterface || name != className)
duke@1: log.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;
duke@1: return List.of(syntaxError(S.pos(), err, "expected", keywords.token2string(LPAREN)));
duke@1: }
duke@1: }
duke@1: }
duke@1: }
duke@1: }
duke@1:
duke@1: /** MethodDeclaratorRest =
duke@1: * FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
duke@1: * VoidMethodDeclaratorRest =
duke@1: * FormalParameters [Throws TypeList] ( MethodBody | ";")
duke@1: * InterfaceMethodDeclaratorRest =
duke@1: * FormalParameters BracketsOpt [THROWS TypeList] ";"
duke@1: * VoidInterfaceMethodDeclaratorRest =
duke@1: * FormalParameters [THROWS TypeList] ";"
duke@1: * ConstructorDeclaratorRest =
duke@1: * "(" 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();
duke@1: 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: }
duke@1: JCMethodDecl result =
duke@1: toP(F.at(pos).MethodDef(mods, name, type, typarams,
duke@1: params, thrown,
duke@1: body, defaultValue));
duke@1: attach(result, dc);
duke@1: return result;
duke@1: }
duke@1:
duke@1: /** QualidentList = Qualident {"," Qualident}
duke@1: */
duke@1: List qualidentList() {
duke@1: ListBuffer ts = new ListBuffer();
duke@1: ts.append(qualident());
duke@1: while (S.token() == COMMA) {
duke@1: S.nextToken();
duke@1: 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:
duke@1: /** 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();
duke@1: bounds.append(type());
duke@1: while (S.token() == AMP) {
duke@1: S.nextToken();
duke@1: bounds.append(type());
duke@1: }
duke@1: }
duke@1: 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);
duke@1: JCExpression type = type();
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:
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:
duke@1: log.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:
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) {
duke@1: log.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) {
duke@1: log.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) {
duke@1: log.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) {
duke@1: log.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) {
duke@1: log.error(S.pos(), "annotations.not.supported.in.source", source.name);
duke@1: allowAnnotations = true;
duke@1: }
duke@1: }
duke@1: }