author | jjg |
Tue, 09 Sep 2008 10:40:50 -0700 | |
changeset 1258 | 1cf37d8837d1 |
parent 1257 | 873b053bf757 |
child 1259 | 61142e0aeb3f |
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Tue Sep 09 10:28:21 2008 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Tue Sep 09 10:40:50 2008 -0700 @@ -27,6 +27,7 @@ import java.io.File; import java.io.IOException; +import java.nio.CharBuffer; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; @@ -45,7 +46,7 @@ import com.sun.tools.javac.main.*; import com.sun.tools.javac.model.*; import com.sun.tools.javac.parser.Parser; -import com.sun.tools.javac.parser.Scanner; +import com.sun.tools.javac.parser.ParserFactory; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.*; @@ -93,6 +94,9 @@ args.getClass(); context.getClass(); fileObjects.getClass(); + + // force the use of the scanner that captures Javadoc comments + com.sun.tools.javac.parser.DocCommentScanner.Factory.preRegister(context); } JavacTaskImpl(JavacTool tool, @@ -166,8 +170,6 @@ if (!filenames.isEmpty()) throw new IllegalArgumentException("Malformed arguments " + filenames.toString(" ")); compiler = JavaCompiler.instance(context); - // force the use of the scanner that captures Javadoc comments - com.sun.tools.javac.parser.DocCommentScanner.Factory.preRegister(context); compiler.keepComments = true; compiler.genEndPos = true; // NOTE: this value will be updated after annotation processing @@ -519,14 +521,12 @@ throw new IllegalArgumentException(); compiler = JavaCompiler.instance(context); JavaFileObject prev = compiler.log.useSource(null); - Scanner.Factory scannerFactory = Scanner.Factory.instance(context); - Parser.Factory parserFactory = Parser.Factory.instance(context); + ParserFactory parserFactory = ParserFactory.instance(context); Attr attr = Attr.instance(context); try { - Scanner scanner = scannerFactory.newScanner((expr+"\u0000").toCharArray(), - expr.length()); - Parser parser = parserFactory.newParser(scanner, false, false); - JCTree tree = parser.type(); + CharBuffer buf = CharBuffer.wrap((expr+"\u0000").toCharArray(), 0, expr.length()); + Parser parser = parserFactory.newParser(buf, false, false, false); + JCTree tree = parser.parseType(); return attr.attribType(tree, (Symbol.TypeSymbol)scope); } finally { compiler.log.useSource(prev);
--- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Sep 09 10:28:21 2008 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Sep 09 10:40:50 2008 -0700 @@ -276,7 +276,7 @@ /** Factory for parsers. */ - protected Parser.Factory parserFactory; + protected ParserFactory parserFactory; /** Optional listener for progress events */ @@ -320,7 +320,7 @@ todo = Todo.instance(context); fileManager = context.get(JavaFileManager.class); - parserFactory = Parser.Factory.instance(context); + parserFactory = ParserFactory.instance(context); try { // catch completion problems with predefineds @@ -510,10 +510,6 @@ return parseErrors; } - protected Scanner.Factory getScannerFactory() { - return Scanner.Factory.instance(context); - } - /** Try to open input stream with given name. * Report an error if this fails. * @param filename The file name of the input stream to be opened. @@ -545,13 +541,9 @@ taskListener.started(e); } int initialErrorCount = log.nerrors; - Scanner scanner = getScannerFactory().newScanner(content); - Parser parser = parserFactory.newParser(scanner, keepComments(), genEndPos); - tree = parser.compilationUnit(); + Parser parser = parserFactory.newParser(content, keepComments(), genEndPos, lineDebugInfo); + tree = parser.parseCompilationUnit(); parseErrors |= (log.nerrors > initialErrorCount); - if (lineDebugInfo) { - tree.lineMap = scanner.getLineMap(); - } if (verbose) { printVerbose("parsing.done", Long.toString(elapsed(msec))); }
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/EndPosParser.java Tue Sep 09 10:28:21 2008 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/EndPosParser.java Tue Sep 09 10:40:50 2008 -0700 @@ -41,10 +41,10 @@ * This code and its internal interfaces are subject to change or * deletion without notice.</b></p> */ -public class EndPosParser extends Parser { +public class EndPosParser extends JavacParser { - public EndPosParser(Factory fac, Lexer S, boolean keepDocComments) { - super(fac, S, keepDocComments); + public EndPosParser(ParserFactory fac, Lexer S, boolean keepDocComments, boolean keepLineMap) { + super(fac, S, keepDocComments, keepLineMap); this.S = S; endPositions = new HashMap<JCTree,Integer>(); } @@ -79,8 +79,8 @@ } @Override - public JCCompilationUnit compilationUnit() { - JCCompilationUnit t = super.compilationUnit(); + public JCCompilationUnit parseCompilationUnit() { + JCCompilationUnit t = super.parseCompilationUnit(); t.endPositions = endPositions; return t; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Tue Sep 09 10:40:50 2008 -0700 @@ -0,0 +1,2819 @@ +/* + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.javac.parser; + +import java.util.*; + +import com.sun.tools.javac.tree.*; +import com.sun.tools.javac.code.*; +import com.sun.tools.javac.util.*; +import com.sun.tools.javac.util.List; +import static com.sun.tools.javac.util.ListBuffer.lb; + +import com.sun.tools.javac.tree.JCTree.*; + +import static com.sun.tools.javac.parser.Token.*; + +/** The parser maps a token sequence into an abstract syntax + * tree. It operates by recursive descent, with code derived + * systematically from an LL(1) grammar. For efficiency reasons, an + * operator precedence scheme is used for parsing binary operation + * expressions. + * + * <p><b>This is NOT part of any API supported by Sun Microsystems. If + * you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public class JavacParser implements Parser { + + /** The number of precedence levels of infix operators. + */ + private static final int infixPrecedenceLevels = 10; + + /** The scanner used for lexical analysis. + */ + private Lexer S; + + /** The factory to be used for abstract syntax tree construction. + */ + protected TreeMaker F; + + /** The log to be used for error diagnostics. + */ + private Log log; + + /** The keyword table. */ + private Keywords keywords; + + /** The Source language setting. */ + private Source source; + + /** The name table. */ + private Name.Table names; + + /** Construct a parser from a given scanner, tree factory and log. + */ + protected JavacParser(ParserFactory fac, + Lexer S, + boolean keepDocComments, + boolean keepLineMap) { + this.S = S; + S.nextToken(); // prime the pump + this.F = fac.F; + this.log = fac.log; + this.names = fac.names; + this.keywords = fac.keywords; + this.source = fac.source; + this.allowGenerics = source.allowGenerics(); + this.allowVarargs = source.allowVarargs(); + this.allowAsserts = source.allowAsserts(); + this.allowEnums = source.allowEnums(); + this.allowForeach = source.allowForeach(); + this.allowStaticImport = source.allowStaticImport(); + this.allowAnnotations = source.allowAnnotations(); + this.keepDocComments = keepDocComments; + if (keepDocComments) + docComments = new HashMap<JCTree,String>(); + this.keepLineMap = keepLineMap; + this.errorTree = F.Erroneous(); + } + + /** Switch: Should generics be recognized? + */ + boolean allowGenerics; + + /** Switch: Should varargs be recognized? + */ + boolean allowVarargs; + + /** Switch: should we recognize assert statements, or just give a warning? + */ + boolean allowAsserts; + + /** Switch: should we recognize enums, or just give a warning? + */ + boolean allowEnums; + + /** Switch: should we recognize foreach? + */ + boolean allowForeach; + + /** Switch: should we recognize foreach? + */ + boolean allowStaticImport; + + /** Switch: should we recognize annotations? + */ + boolean allowAnnotations; + + /** Switch: should we keep docComments? + */ + boolean keepDocComments; + + /** Switch: should we keep line table? + */ + boolean keepLineMap; + + /** When terms are parsed, the mode determines which is expected: + * mode = EXPR : an expression + * mode = TYPE : a type + * mode = NOPARAMS : no parameters allowed for type + * mode = TYPEARG : type argument + */ + static final int EXPR = 1; + static final int TYPE = 2; + static final int NOPARAMS = 4; + static final int TYPEARG = 8; + + /** The current mode. + */ + private int mode = 0; + + /** The mode of the term that was parsed last. + */ + private int lastmode = 0; + +/* ---------- error recovery -------------- */ + + private JCErroneous errorTree; + + /** Skip forward until a suitable stop token is found. + */ + private void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) { + while (true) { + switch (S.token()) { + case SEMI: + S.nextToken(); + return; + case PUBLIC: + case FINAL: + case ABSTRACT: + case MONKEYS_AT: + case EOF: + case CLASS: + case INTERFACE: + case ENUM: + return; + case IMPORT: + if (stopAtImport) + return; + break; + case LBRACE: + case RBRACE: + case PRIVATE: + case PROTECTED: + case STATIC: + case TRANSIENT: + case NATIVE: + case VOLATILE: + case SYNCHRONIZED: + case STRICTFP: + case LT: + case BYTE: + case SHORT: + case CHAR: + case INT: + case LONG: + case FLOAT: + case DOUBLE: + case BOOLEAN: + case VOID: + if (stopAtMemberDecl) + return; + break; + case IDENTIFIER: + if (stopAtIdentifier) + return; + break; + case CASE: + case DEFAULT: + case IF: + case FOR: + case WHILE: + case DO: + case TRY: + case SWITCH: + case RETURN: + case THROW: + case BREAK: + case CONTINUE: + case ELSE: + case FINALLY: + case CATCH: + if (stopAtStatement) + return; + break; + } + S.nextToken(); + } + } + + private JCErroneous syntaxError(int pos, String key, Token... args) { + return syntaxError(pos, null, key, args); + } + + private JCErroneous syntaxError(int pos, List<JCTree> errs, String key, Token... args) { + setErrorEndPos(pos); + reportSyntaxError(pos, key, (Object[])args); + return toP(F.at(pos).Erroneous(errs)); + } + + private int errorPos = Position.NOPOS; + /** + * Report a syntax error at given position using the given + * argument unless one was already reported at the same position. + */ + private void reportSyntaxError(int pos, String key, Object... args) { + if (pos > S.errPos() || pos == Position.NOPOS) { + if (S.token() == EOF) + log.error(pos, "premature.eof"); + else + log.error(pos, key, args); + } + S.errPos(pos); + if (S.pos() == errorPos) + S.nextToken(); // guarantee progress + errorPos = S.pos(); + } + + + /** Generate a syntax error at current position unless one was already + * reported at the same position. + */ + private JCErroneous syntaxError(String key) { + return syntaxError(S.pos(), key); + } + + /** Generate a syntax error at current position unless one was + * already reported at the same position. + */ + private JCErroneous syntaxError(String key, Token arg) { + return syntaxError(S.pos(), key, arg); + } + + /** If next input token matches given token, skip it, otherwise report + * an error. + */ + public void accept(Token token) { + if (S.token() == token) { + S.nextToken(); + } else { + setErrorEndPos(S.pos()); + reportSyntaxError(S.prevEndPos(), "expected", token); + } + } + + /** Report an illegal start of expression/type error at given position. + */ + JCExpression illegal(int pos) { + setErrorEndPos(S.pos()); + if ((mode & EXPR) != 0) + return syntaxError(pos, "illegal.start.of.expr"); + else + return syntaxError(pos, "illegal.start.of.type"); + + } + + /** Report an illegal start of expression/type error at current position. + */ + JCExpression illegal() { + return illegal(S.pos()); + } + + /** Diagnose a modifier flag from the set, if any. */ + void checkNoMods(long mods) { + if (mods != 0) { + long lowestMod = mods & -mods; + log.error(S.pos(), "mod.not.allowed.here", + Flags.asFlagSet(lowestMod)); + } + } + +/* ---------- doc comments --------- */ + + /** A hashtable to store all documentation comments + * indexed by the tree nodes they refer to. + * defined only if option flag keepDocComment is set. + */ + Map<JCTree, String> docComments; + + /** Make an entry into docComments hashtable, + * provided flag keepDocComments is set and given doc comment is non-null. + * @param tree The tree to be used as index in the hashtable + * @param dc The doc comment to associate with the tree, or null. + */ + void attach(JCTree tree, String dc) { + if (keepDocComments && dc != null) { +// System.out.println("doc comment = ");System.out.println(dc);//DEBUG + docComments.put(tree, dc); + } + } + +/* -------- source positions ------- */ + + private int errorEndPos = -1; + + private void setErrorEndPos(int errPos) { + if (errPos > errorEndPos) + errorEndPos = errPos; + } + + protected int getErrorEndPos() { + return errorEndPos; + } + + /** + * Store ending position for a tree. + * @param tree The tree. + * @param endpos The ending position to associate with the tree. + */ + protected void storeEnd(JCTree tree, int endpos) {} + + /** + * Store ending position for a tree. The ending position should + * be the ending position of the current token. + * @param t The tree. + */ + protected <T extends JCTree> T to(T t) { return t; } + + /** + * Store ending position for a tree. The ending position should + * be greater of the ending position of the previous token and errorEndPos. + * @param t The tree. + */ + protected <T extends JCTree> T toP(T t) { return t; } + + /** Get the start position for a tree node. The start position is + * defined to be the position of the first character of the first + * token of the node's source text. + * @param tree The tree node + */ + public int getStartPos(JCTree tree) { + return TreeInfo.getStartPos(tree); + } + + /** + * Get the end position for a tree node. The end position is + * defined to be the position of the last character of the last + * token of the node's source text. Returns Position.NOPOS if end + * positions are not generated or the position is otherwise not + * found. + * @param tree The tree node + */ + public int getEndPos(JCTree tree) { + return Position.NOPOS; + } + + + +/* ---------- parsing -------------- */ + + /** + * Ident = IDENTIFIER + */ + Name ident() { + if (S.token() == IDENTIFIER) { + Name name = S.name(); + S.nextToken(); + return name; + } else if (S.token() == ASSERT) { + if (allowAsserts) { + log.error(S.pos(), "assert.as.identifier"); + S.nextToken(); + return names.error; + } else { + log.warning(S.pos(), "assert.as.identifier"); + Name name = S.name(); + S.nextToken(); + return name; + } + } else if (S.token() == ENUM) { + if (allowEnums) { + log.error(S.pos(), "enum.as.identifier"); + S.nextToken(); + return names.error; + } else { + log.warning(S.pos(), "enum.as.identifier"); + Name name = S.name(); + S.nextToken(); + return name; + } + } else { + accept(IDENTIFIER); + return names.error; + } +} + + /** + * Qualident = Ident { DOT Ident } + */ + public JCExpression qualident() { + JCExpression t = toP(F.at(S.pos()).Ident(ident())); + while (S.token() == DOT) { + int pos = S.pos(); + S.nextToken(); + t = toP(F.at(pos).Select(t, ident())); + } + return t; + } + + /** + * Literal = + * INTLITERAL + * | LONGLITERAL + * | FLOATLITERAL + * | DOUBLELITERAL + * | CHARLITERAL + * | STRINGLITERAL + * | TRUE + * | FALSE + * | NULL + */ + JCExpression literal(Name prefix) { + int pos = S.pos(); + JCExpression t = errorTree; + switch (S.token()) { + case INTLITERAL: + try { + t = F.at(pos).Literal( + TypeTags.INT, + Convert.string2int(strval(prefix), S.radix())); + } catch (NumberFormatException ex) { + log.error(S.pos(), "int.number.too.large", strval(prefix)); + } + break; + case LONGLITERAL: + try { + t = F.at(pos).Literal( + TypeTags.LONG, + new Long(Convert.string2long(strval(prefix), S.radix()))); + } catch (NumberFormatException ex) { + log.error(S.pos(), "int.number.too.large", strval(prefix)); + } + break; + case FLOATLITERAL: { + String proper = (S.radix() == 16 ? ("0x"+ S.stringVal()) : S.stringVal()); + Float n; + try { + n = Float.valueOf(proper); + } catch (NumberFormatException ex) { + // error already repoted in scanner + n = Float.NaN; + } + if (n.floatValue() == 0.0f && !isZero(proper)) + log.error(S.pos(), "fp.number.too.small"); + else if (n.floatValue() == Float.POSITIVE_INFINITY) + log.error(S.pos(), "fp.number.too.large"); + else + t = F.at(pos).Literal(TypeTags.FLOAT, n); + break; + } + case DOUBLELITERAL: { + String proper = (S.radix() == 16 ? ("0x"+ S.stringVal()) : S.stringVal()); + Double n; + try { + n = Double.valueOf(proper); + } catch (NumberFormatException ex) { + // error already reported in scanner + n = Double.NaN; + } + if (n.doubleValue() == 0.0d && !isZero(proper)) + log.error(S.pos(), "fp.number.too.small"); + else if (n.doubleValue() == Double.POSITIVE_INFINITY) + log.error(S.pos(), "fp.number.too.large"); + else + t = F.at(pos).Literal(TypeTags.DOUBLE, n); + break; + } + case CHARLITERAL: + t = F.at(pos).Literal( + TypeTags.CHAR, + S.stringVal().charAt(0) + 0); + break; + case STRINGLITERAL: + t = F.at(pos).Literal( + TypeTags.CLASS, + S.stringVal()); + break; + case TRUE: case FALSE: + t = F.at(pos).Literal( + TypeTags.BOOLEAN, + (S.token() == TRUE ? 1 : 0)); + break; + case NULL: + t = F.at(pos).Literal( + TypeTags.BOT, + null); + break; + default: + assert false; + } + if (t == errorTree) + t = F.at(pos).Erroneous(); + storeEnd(t, S.endPos()); + S.nextToken(); + return t; + } +//where + boolean isZero(String s) { + char[] cs = s.toCharArray(); + int base = ((Character.toLowerCase(s.charAt(1)) == 'x') ? 16 : 10); + int i = ((base==16) ? 2 : 0); + while (i < cs.length && (cs[i] == '0' || cs[i] == '.')) i++; + return !(i < cs.length && (Character.digit(cs[i], base) > 0)); + } + + String strval(Name prefix) { + String s = S.stringVal(); + return (prefix.len == 0) ? s : prefix + s; + } + + /** terms can be either expressions or types. + */ + public JCExpression parseExpression() { + return term(EXPR); + } + + public JCExpression parseType() { + return term(TYPE); + } + + JCExpression term(int newmode) { + int prevmode = mode; + mode = newmode; + JCExpression t = term(); + lastmode = mode; + mode = prevmode; + return t; + } + + /** + * Expression = Expression1 [ExpressionRest] + * ExpressionRest = [AssignmentOperator Expression1] + * AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | + * "&=" | "|=" | "^=" | + * "%=" | "<<=" | ">>=" | ">>>=" + * Type = Type1 + * TypeNoParams = TypeNoParams1 + * StatementExpression = Expression + * ConstantExpression = Expression + */ + JCExpression term() { + JCExpression t = term1(); + if ((mode & EXPR) != 0 && + S.token() == EQ || PLUSEQ.compareTo(S.token()) <= 0 && S.token().compareTo(GTGTGTEQ) <= 0) + return termRest(t); + else + return t; + } + + JCExpression termRest(JCExpression t) { + switch (S.token()) { + case EQ: { + int pos = S.pos(); + S.nextToken(); + mode = EXPR; + JCExpression t1 = term(); + return toP(F.at(pos).Assign(t, t1)); + } + case PLUSEQ: + case SUBEQ: + case STAREQ: + case SLASHEQ: + case PERCENTEQ: + case AMPEQ: + case BAREQ: + case CARETEQ: + case LTLTEQ: + case GTGTEQ: + case GTGTGTEQ: + int pos = S.pos(); + Token token = S.token(); + S.nextToken(); + mode = EXPR; + JCExpression t1 = term(); + return F.at(pos).Assignop(optag(token), t, t1); + default: + return t; + } + } + + /** Expression1 = Expression2 [Expression1Rest] + * Type1 = Type2 + * TypeNoParams1 = TypeNoParams2 + */ + JCExpression term1() { + JCExpression t = term2(); + if ((mode & EXPR) != 0 && S.token() == QUES) { + mode = EXPR; + return term1Rest(t); + } else { + return t; + } + } + + /** Expression1Rest = ["?" Expression ":" Expression1] + */ + JCExpression term1Rest(JCExpression t) { + if (S.token() == QUES) { + int pos = S.pos(); + S.nextToken(); + JCExpression t1 = term(); + accept(COLON); + JCExpression t2 = term1(); + return F.at(pos).Conditional(t, t1, t2); + } else { + return t; + } + } + + /** Expression2 = Expression3 [Expression2Rest] + * Type2 = Type3 + * TypeNoParams2 = TypeNoParams3 + */ + JCExpression term2() { + JCExpression t = term3(); + if ((mode & EXPR) != 0 && prec(S.token()) >= TreeInfo.orPrec) { + mode = EXPR; + return term2Rest(t, TreeInfo.orPrec); + } else { + return t; + } + } + + /* Expression2Rest = {infixop Expression3} + * | Expression3 instanceof Type + * infixop = "||" + * | "&&" + * | "|" + * | "^" + * | "&" + * | "==" | "!=" + * | "<" | ">" | "<=" | ">=" + * | "<<" | ">>" | ">>>" + * | "+" | "-" + * | "*" | "/" | "%" + */ + JCExpression term2Rest(JCExpression t, int minprec) { + List<JCExpression[]> savedOd = odStackSupply.elems; + JCExpression[] odStack = newOdStack(); + List<Token[]> savedOp = opStackSupply.elems; + Token[] opStack = newOpStack(); + // optimization, was odStack = new Tree[...]; opStack = new Tree[...]; + int top = 0; + odStack[0] = t; + int startPos = S.pos(); + Token topOp = ERROR; + while (prec(S.token()) >= minprec) { + opStack[top] = topOp; + top++; + topOp = S.token(); + int pos = S.pos(); + S.nextToken(); + odStack[top] = topOp == INSTANCEOF ? parseType() : term3(); + while (top > 0 && prec(topOp) >= prec(S.token())) { + odStack[top-1] = makeOp(pos, topOp, odStack[top-1], + odStack[top]); + top--; + topOp = opStack[top]; + } + } + assert top == 0; + t = odStack[0]; + + if (t.getTag() == JCTree.PLUS) { + StringBuffer buf = foldStrings(t); + if (buf != null) { + t = toP(F.at(startPos).Literal(TypeTags.CLASS, buf.toString())); + } + } + + odStackSupply.elems = savedOd; // optimization + opStackSupply.elems = savedOp; // optimization + return t; + } +//where + /** Construct a binary or type test node. + */ + private JCExpression makeOp(int pos, + Token topOp, + JCExpression od1, + JCExpression od2) + { + if (topOp == INSTANCEOF) { + return F.at(pos).TypeTest(od1, od2); + } else { + return F.at(pos).Binary(optag(topOp), od1, od2); + } + } + /** If tree is a concatenation of string literals, replace it + * by a single literal representing the concatenated string. + */ + protected StringBuffer foldStrings(JCTree tree) { + List<String> buf = List.nil(); + while (true) { + if (tree.getTag() == JCTree.LITERAL) { + JCLiteral lit = (JCLiteral) tree; + if (lit.typetag == TypeTags.CLASS) { + StringBuffer sbuf = + new StringBuffer((String)lit.value); + while (buf.nonEmpty()) { + sbuf.append(buf.head); + buf = buf.tail; + } + return sbuf; + } + } else if (tree.getTag() == JCTree.PLUS) { + JCBinary op = (JCBinary)tree; + if (op.rhs.getTag() == JCTree.LITERAL) { + JCLiteral lit = (JCLiteral) op.rhs; + if (lit.typetag == TypeTags.CLASS) { + buf = buf.prepend((String) lit.value); + tree = op.lhs; + continue; + } + } + } + return null; + } + } + + /** optimization: To save allocating a new operand/operator stack + * for every binary operation, we use supplys. + */ + ListBuffer<JCExpression[]> odStackSupply = new ListBuffer<JCExpression[]>(); + ListBuffer<Token[]> opStackSupply = new ListBuffer<Token[]>(); + + private JCExpression[] newOdStack() { + if (odStackSupply.elems == odStackSupply.last) + odStackSupply.append(new JCExpression[infixPrecedenceLevels + 1]); + JCExpression[] odStack = odStackSupply.elems.head; + odStackSupply.elems = odStackSupply.elems.tail; + return odStack; + } + + private Token[] newOpStack() { + if (opStackSupply.elems == opStackSupply.last) + opStackSupply.append(new Token[infixPrecedenceLevels + 1]); + Token[] opStack = opStackSupply.elems.head; + opStackSupply.elems = opStackSupply.elems.tail; + return opStack; + } + + /** Expression3 = PrefixOp Expression3 + * | "(" Expr | TypeNoParams ")" Expression3 + * | Primary {Selector} {PostfixOp} + * Primary = "(" Expression ")" + * | Literal + * | [TypeArguments] THIS [Arguments] + * | [TypeArguments] SUPER SuperSuffix + * | NEW [TypeArguments] Creator + * | Ident { "." Ident } + * [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" ) + * | Arguments + * | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator ) + * ] + * | BasicType BracketsOpt "." CLASS + * PrefixOp = "++" | "--" | "!" | "~" | "+" | "-" + * PostfixOp = "++" | "--" + * Type3 = Ident { "." Ident } [TypeArguments] {TypeSelector} BracketsOpt + * | BasicType + * TypeNoParams3 = Ident { "." Ident } BracketsOpt + * Selector = "." [TypeArguments] Ident [Arguments] + * | "." THIS + * | "." [TypeArguments] SUPER SuperSuffix + * | "." NEW [TypeArguments] InnerCreator + * | "[" Expression "]" + * TypeSelector = "." Ident [TypeArguments] + * SuperSuffix = Arguments | "." Ident [Arguments] + */ + protected JCExpression term3() { + int pos = S.pos(); + JCExpression t; + List<JCExpression> typeArgs = typeArgumentsOpt(EXPR); + switch (S.token()) { + case QUES: + if ((mode & TYPE) != 0 && (mode & (TYPEARG|NOPARAMS)) == TYPEARG) { + mode = TYPE; + return typeArgument(); + } else + return illegal(); + case PLUSPLUS: case SUBSUB: case BANG: case TILDE: case PLUS: case SUB: + if (typeArgs == null && (mode & EXPR) != 0) { + Token token = S.token(); + S.nextToken(); + mode = EXPR; + if (token == SUB && + (S.token() == INTLITERAL || S.token() == LONGLITERAL) && + S.radix() == 10) { + mode = EXPR; + t = literal(names.hyphen); + } else { + t = term3(); + return F.at(pos).Unary(unoptag(token), t); + } + } else return illegal(); + break; + case LPAREN: + if (typeArgs == null && (mode & EXPR) != 0) { + S.nextToken(); + mode = EXPR | TYPE | NOPARAMS; + t = term3(); + if ((mode & TYPE) != 0 && S.token() == LT) { + // Could be a cast to a parameterized type + int op = JCTree.LT; + int pos1 = S.pos(); + S.nextToken(); + mode &= (EXPR | TYPE); + mode |= TYPEARG; + JCExpression t1 = term3(); + if ((mode & TYPE) != 0 && + (S.token() == COMMA || S.token() == GT)) { + mode = TYPE; + ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); + args.append(t1); + while (S.token() == COMMA) { + S.nextToken(); + args.append(typeArgument()); + } + accept(GT); + t = F.at(pos1).TypeApply(t, args.toList()); + checkGenerics(); + t = bracketsOpt(toP(t)); + } else if ((mode & EXPR) != 0) { + mode = EXPR; + t = F.at(pos1).Binary(op, t, term2Rest(t1, TreeInfo.shiftPrec)); + t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec))); + } else { + accept(GT); + } + } else { + t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec))); + } + accept(RPAREN); + lastmode = mode; + mode = EXPR; + if ((lastmode & EXPR) == 0) { + JCExpression t1 = term3(); + return F.at(pos).TypeCast(t, t1); + } else if ((lastmode & TYPE) != 0) { + switch (S.token()) { + /*case PLUSPLUS: case SUBSUB: */ + case BANG: case TILDE: + case LPAREN: case THIS: case SUPER: + case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: + case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL: + case TRUE: case FALSE: case NULL: + case NEW: case IDENTIFIER: case ASSERT: case ENUM: + case BYTE: case SHORT: case CHAR: case INT: + case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: + JCExpression t1 = term3(); + return F.at(pos).TypeCast(t, t1); + } + } + } else return illegal(); + t = toP(F.at(pos).Parens(t)); + break; + case THIS: + if ((mode & EXPR) != 0) { + mode = EXPR; + t = to(F.at(pos).Ident(names._this)); + S.nextToken(); + if (typeArgs == null) + t = argumentsOpt(null, t); + else + t = arguments(typeArgs, t); + typeArgs = null; + } else return illegal(); + break; + case SUPER: + if ((mode & EXPR) != 0) { + mode = EXPR; + t = to(superSuffix(typeArgs, F.at(pos).Ident(names._super))); + typeArgs = null; + } else return illegal(); + break; + case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL: + case CHARLITERAL: case STRINGLITERAL: + case TRUE: case FALSE: case NULL: + if (typeArgs == null && (mode & EXPR) != 0) { + mode = EXPR; + t = literal(names.empty); + } else return illegal(); + break; + case NEW: + if (typeArgs != null) return illegal(); + if ((mode & EXPR) != 0) { + mode = EXPR; + S.nextToken(); + if (S.token() == LT) typeArgs = typeArguments(); + t = creator(pos, typeArgs); + typeArgs = null; + } else return illegal(); + break; + case IDENTIFIER: case ASSERT: case ENUM: + if (typeArgs != null) return illegal(); + t = toP(F.at(S.pos()).Ident(ident())); + loop: while (true) { + pos = S.pos(); + switch (S.token()) { + case LBRACKET: + S.nextToken(); + if (S.token() == RBRACKET) { + S.nextToken(); + t = bracketsOpt(t); + t = toP(F.at(pos).TypeArray(t)); + t = bracketsSuffix(t); + } else { + if ((mode & EXPR) != 0) { + mode = EXPR; + JCExpression t1 = term(); + t = to(F.at(pos).Indexed(t, t1)); + } + accept(RBRACKET); + } + break loop; + case LPAREN: + if ((mode & EXPR) != 0) { + mode = EXPR; + t = arguments(typeArgs, t); + typeArgs = null; + } + break loop; + case DOT: + S.nextToken(); + int oldmode = mode; + mode &= ~NOPARAMS; + typeArgs = typeArgumentsOpt(EXPR); + mode = oldmode; + if ((mode & EXPR) != 0) { + switch (S.token()) { + case CLASS: + if (typeArgs != null) return illegal(); + mode = EXPR; + t = to(F.at(pos).Select(t, names._class)); + S.nextToken(); + break loop; + case THIS: + if (typeArgs != null) return illegal(); + mode = EXPR; + t = to(F.at(pos).Select(t, names._this)); + S.nextToken(); + break loop; + case SUPER: + mode = EXPR; + t = to(F.at(pos).Select(t, names._super)); + t = superSuffix(typeArgs, t); + typeArgs = null; + break loop; + case NEW: + if (typeArgs != null) return illegal(); + mode = EXPR; + int pos1 = S.pos(); + S.nextToken(); + if (S.token() == LT) typeArgs = typeArguments(); + t = innerCreator(pos1, typeArgs, t); + typeArgs = null; + break loop; + } + } + // typeArgs saved for next loop iteration. + t = toP(F.at(pos).Select(t, ident())); + break; + default: + break loop; + } + } + if (typeArgs != null) illegal(); + t = typeArgumentsOpt(t); + break; + case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT: + case DOUBLE: case BOOLEAN: + if (typeArgs != null) illegal(); + t = bracketsSuffix(bracketsOpt(basicType())); + break; + case VOID: + if (typeArgs != null) illegal(); + if ((mode & EXPR) != 0) { + S.nextToken(); + if (S.token() == DOT) { + JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTags.VOID)); + t = bracketsSuffix(ti); + } else { + return illegal(pos); + } + } else { + return illegal(); + } + break; + default: + return illegal(); + } + if (typeArgs != null) illegal(); + while (true) { + int pos1 = S.pos(); + if (S.token() == LBRACKET) { + S.nextToken(); + if ((mode & TYPE) != 0) { + int oldmode = mode; + mode = TYPE; + if (S.token() == RBRACKET) { + S.nextToken(); + t = bracketsOpt(t); + t = toP(F.at(pos1).TypeArray(t)); + return t; + } + mode = oldmode; + } + if ((mode & EXPR) != 0) { + mode = EXPR; + JCExpression t1 = term(); + t = to(F.at(pos1).Indexed(t, t1)); + } + accept(RBRACKET); + } else if (S.token() == DOT) { + S.nextToken(); + typeArgs = typeArgumentsOpt(EXPR); + if (S.token() == SUPER && (mode & EXPR) != 0) { + mode = EXPR; + t = to(F.at(pos1).Select(t, names._super)); + S.nextToken(); + t = arguments(typeArgs, t); + typeArgs = null; + } else if (S.token() == NEW && (mode & EXPR) != 0) { + if (typeArgs != null) return illegal(); + mode = EXPR; + int pos2 = S.pos(); + S.nextToken(); + if (S.token() == LT) typeArgs = typeArguments(); + t = innerCreator(pos2, typeArgs, t); + typeArgs = null; + } else { + t = toP(F.at(pos1).Select(t, ident())); + t = argumentsOpt(typeArgs, typeArgumentsOpt(t)); + typeArgs = null; + } + } else { + break; + } + } + while ((S.token() == PLUSPLUS || S.token() == SUBSUB) && (mode & EXPR) != 0) { + mode = EXPR; + t = to(F.at(S.pos()).Unary( + S.token() == PLUSPLUS ? JCTree.POSTINC : JCTree.POSTDEC, t)); + S.nextToken(); + } + return toP(t); + } + + /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments] + */ + JCExpression superSuffix(List<JCExpression> typeArgs, JCExpression t) { + S.nextToken(); + if (S.token() == LPAREN || typeArgs != null) { + t = arguments(typeArgs, t); + } else { + int pos = S.pos(); + accept(DOT); + typeArgs = (S.token() == LT) ? typeArguments() : null; + t = toP(F.at(pos).Select(t, ident())); + t = argumentsOpt(typeArgs, t); + } + return t; + } + + /** BasicType = BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE | BOOLEAN + */ + JCPrimitiveTypeTree basicType() { + JCPrimitiveTypeTree t = to(F.at(S.pos()).TypeIdent(typetag(S.token()))); + S.nextToken(); + return t; + } + + /** ArgumentsOpt = [ Arguments ] + */ + JCExpression argumentsOpt(List<JCExpression> typeArgs, JCExpression t) { + if ((mode & EXPR) != 0 && S.token() == LPAREN || typeArgs != null) { + mode = EXPR; + return arguments(typeArgs, t); + } else { + return t; + } + } + + /** Arguments = "(" [Expression { COMMA Expression }] ")" + */ + List<JCExpression> arguments() { + ListBuffer<JCExpression> args = lb(); + if (S.token() == LPAREN) { + S.nextToken(); + if (S.token() != RPAREN) { + args.append(parseExpression()); + while (S.token() == COMMA) { + S.nextToken(); + args.append(parseExpression()); + } + } + accept(RPAREN); + } else { + syntaxError(S.pos(), "expected", LPAREN); + } + return args.toList(); + } + + JCMethodInvocation arguments(List<JCExpression> typeArgs, JCExpression t) { + int pos = S.pos(); + List<JCExpression> args = arguments(); + return toP(F.at(pos).Apply(typeArgs, t, args)); + } + + /** TypeArgumentsOpt = [ TypeArguments ] + */ + JCExpression typeArgumentsOpt(JCExpression t) { + if (S.token() == LT && + (mode & TYPE) != 0 && + (mode & NOPARAMS) == 0) { + mode = TYPE; + checkGenerics(); + return typeArguments(t); + } else { + return t; + } + } + List<JCExpression> typeArgumentsOpt() { + return typeArgumentsOpt(TYPE); + } + + List<JCExpression> typeArgumentsOpt(int useMode) { + if (S.token() == LT) { + checkGenerics(); + if ((mode & useMode) == 0 || + (mode & NOPARAMS) != 0) { + illegal(); + } + mode = useMode; + return typeArguments(); + } + return null; + } + + /** TypeArguments = "<" TypeArgument {"," TypeArgument} ">" + */ + List<JCExpression> typeArguments() { + ListBuffer<JCExpression> args = lb(); + if (S.token() == LT) { + S.nextToken(); + args.append(((mode & EXPR) == 0) ? typeArgument() : parseType()); + while (S.token() == COMMA) { + S.nextToken(); + args.append(((mode & EXPR) == 0) ? typeArgument() : parseType()); + } + switch (S.token()) { + case GTGTGTEQ: + S.token(GTGTEQ); + break; + case GTGTEQ: + S.token(GTEQ); + break; + case GTEQ: + S.token(EQ); + break; + case GTGTGT: + S.token(GTGT); + break; + case GTGT: + S.token(GT); + break; + default: + accept(GT); + break; + } + } else { + syntaxError(S.pos(), "expected", LT); + } + return args.toList(); + } + + /** TypeArgument = Type + * | "?" + * | "?" EXTENDS Type {"&" Type} + * | "?" SUPER Type + */ + JCExpression typeArgument() { + if (S.token() != QUES) return parseType(); + int pos = S.pos(); + S.nextToken(); + if (S.token() == EXTENDS) { + TypeBoundKind t = to(F.at(S.pos()).TypeBoundKind(BoundKind.EXTENDS)); + S.nextToken(); + return F.at(pos).Wildcard(t, parseType()); + } else if (S.token() == SUPER) { + TypeBoundKind t = to(F.at(S.pos()).TypeBoundKind(BoundKind.SUPER)); + S.nextToken(); + return F.at(pos).Wildcard(t, parseType()); + } else if (S.token() == IDENTIFIER) { + //error recovery + reportSyntaxError(S.prevEndPos(), "expected3", + GT, EXTENDS, SUPER); + TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND); + JCExpression wc = toP(F.at(pos).Wildcard(t, null)); + JCIdent id = toP(F.at(S.pos()).Ident(ident())); + return F.at(pos).Erroneous(List.<JCTree>of(wc, id)); + } else { + TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND); + return toP(F.at(pos).Wildcard(t, null)); + } + } + + JCTypeApply typeArguments(JCExpression t) { + int pos = S.pos(); + List<JCExpression> args = typeArguments(); + return toP(F.at(pos).TypeApply(t, args)); + } + + /** BracketsOpt = {"[" "]"} + */ + private JCExpression bracketsOpt(JCExpression t) { + if (S.token() == LBRACKET) { + int pos = S.pos(); + S.nextToken(); + t = bracketsOptCont(t, pos); + F.at(pos); + } + return t; + } + + private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos) { + accept(RBRACKET); + t = bracketsOpt(t); + return toP(F.at(pos).TypeArray(t)); + } + + /** BracketsSuffixExpr = "." CLASS + * BracketsSuffixType = + */ + JCExpression bracketsSuffix(JCExpression t) { + if ((mode & EXPR) != 0 && S.token() == DOT) { + mode = EXPR; + int pos = S.pos(); + S.nextToken(); + accept(CLASS); + if (S.pos() == errorEndPos) { + // error recovery + Name name = null; + if (S.token() == IDENTIFIER) { + name = S.name(); + S.nextToken(); + } else { + name = names.error; + } + t = F.at(pos).Erroneous(List.<JCTree>of(toP(F.at(pos).Select(t, name)))); + } else { + t = toP(F.at(pos).Select(t, names._class)); + } + } else if ((mode & TYPE) != 0) { + mode = TYPE; + } else { + syntaxError(S.pos(), "dot.class.expected"); + } + return t; + } + + /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest ) + */ + JCExpression creator(int newpos, List<JCExpression> typeArgs) { + switch (S.token()) { + case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT: + case DOUBLE: case BOOLEAN: + if (typeArgs == null) + return arrayCreatorRest(newpos, basicType()); + break; + default: + } + JCExpression t = qualident(); + int oldmode = mode; + mode = TYPE; + if (S.token() == LT) { + checkGenerics(); + t = typeArguments(t); + } + while (S.token() == DOT) { + int pos = S.pos(); + S.nextToken(); + t = toP(F.at(pos).Select(t, ident())); + if (S.token() == LT) { + checkGenerics(); + t = typeArguments(t); + } + } + mode = oldmode; + if (S.token() == LBRACKET) { + JCExpression e = arrayCreatorRest(newpos, t); + if (typeArgs != null) { + int pos = newpos; + if (!typeArgs.isEmpty() && typeArgs.head.pos != Position.NOPOS) { + // note: this should always happen but we should + // not rely on this as the parser is continuously + // modified to improve error recovery. + pos = typeArgs.head.pos; + } + setErrorEndPos(S.prevEndPos()); + reportSyntaxError(pos, "cannot.create.array.with.type.arguments"); + return toP(F.at(newpos).Erroneous(typeArgs.prepend(e))); + } + return e; + } else if (S.token() == LPAREN) { + return classCreatorRest(newpos, null, typeArgs, t); + } else { + reportSyntaxError(S.pos(), "expected2", + LPAREN, LBRACKET); + t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.<JCExpression>nil(), null)); + return toP(F.at(newpos).Erroneous(List.<JCTree>of(t))); + } + } + + /** InnerCreator = Ident [TypeArguments] ClassCreatorRest + */ + JCExpression innerCreator(int newpos, List<JCExpression> typeArgs, JCExpression encl) { + JCExpression t = toP(F.at(S.pos()).Ident(ident())); + if (S.token() == LT) { + checkGenerics(); + t = typeArguments(t); + } + return classCreatorRest(newpos, encl, typeArgs, t); + } + + /** ArrayCreatorRest = "[" ( "]" BracketsOpt ArrayInitializer + * | Expression "]" {"[" Expression "]"} BracketsOpt ) + */ + JCExpression arrayCreatorRest(int newpos, JCExpression elemtype) { + accept(LBRACKET); + if (S.token() == RBRACKET) { + accept(RBRACKET); + elemtype = bracketsOpt(elemtype); + if (S.token() == LBRACE) { + return arrayInitializer(newpos, elemtype); + } else { + return syntaxError(S.pos(), "array.dimension.missing"); + } + } else { + ListBuffer<JCExpression> dims = new ListBuffer<JCExpression>(); + dims.append(parseExpression()); + accept(RBRACKET); + while (S.token() == LBRACKET) { + int pos = S.pos(); + S.nextToken(); + if (S.token() == RBRACKET) { + elemtype = bracketsOptCont(elemtype, pos); + } else { + dims.append(parseExpression()); + accept(RBRACKET); + } + } + return toP(F.at(newpos).NewArray(elemtype, dims.toList(), null)); + } + } + + /** ClassCreatorRest = Arguments [ClassBody] + */ + JCExpression classCreatorRest(int newpos, + JCExpression encl, + List<JCExpression> typeArgs, + JCExpression t) + { + List<JCExpression> args = arguments(); + JCClassDecl body = null; + if (S.token() == LBRACE) { + int pos = S.pos(); + List<JCTree> defs = classOrInterfaceBody(names.empty, false); + JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); + body = toP(F.at(pos).AnonymousClassDef(mods, defs)); + } + return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body)); + } + + /** ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}" + */ + JCExpression arrayInitializer(int newpos, JCExpression t) { + accept(LBRACE); + ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>(); + if (S.token() == COMMA) { + S.nextToken(); + } else if (S.token() != RBRACE) { + elems.append(variableInitializer()); + while (S.token() == COMMA) { + S.nextToken(); + if (S.token() == RBRACE) break; + elems.append(variableInitializer()); + } + } + accept(RBRACE); + return toP(F.at(newpos).NewArray(t, List.<JCExpression>nil(), elems.toList())); + } + + /** VariableInitializer = ArrayInitializer | Expression + */ + public JCExpression variableInitializer() { + return S.token() == LBRACE ? arrayInitializer(S.pos(), null) : parseExpression(); + } + + /** ParExpression = "(" Expression ")" + */ + JCExpression parExpression() { + accept(LPAREN); + JCExpression t = parseExpression(); + accept(RPAREN); + return t; + } + + /** Block = "{" BlockStatements "}" + */ + JCBlock block(int pos, long flags) { + accept(LBRACE); + List<JCStatement> stats = blockStatements(); + JCBlock t = F.at(pos).Block(flags, stats); + while (S.token() == CASE || S.token() == DEFAULT) { + syntaxError("orphaned", S.token()); + switchBlockStatementGroups(); + } + // the Block node has a field "endpos" for first char of last token, which is + // usually but not necessarily the last char of the last token. + t.endpos = S.pos(); + accept(RBRACE); + return toP(t); + } + + public JCBlock block() { + return block(S.pos(), 0); + } + + /** BlockStatements = { BlockStatement } + * BlockStatement = LocalVariableDeclarationStatement + * | ClassOrInterfaceOrEnumDeclaration + * | [Ident ":"] Statement + * LocalVariableDeclarationStatement + * = { FINAL | '@' Annotation } Type VariableDeclarators ";" + */ + @SuppressWarnings("fallthrough") + List<JCStatement> blockStatements() { +//todo: skip to anchor on error(?) + int lastErrPos = -1; + ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>(); + while (true) { + int pos = S.pos(); + switch (S.token()) { + case RBRACE: case CASE: case DEFAULT: case EOF: + return stats.toList(); + case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY: + case SWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK: + case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH: + stats.append(parseStatement()); + break; + case MONKEYS_AT: + case FINAL: { + String dc = S.docComment(); + JCModifiers mods = modifiersOpt(); + if (S.token() == INTERFACE || + S.token() == CLASS || + allowEnums && S.token() == ENUM) { + stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); + } else { + JCExpression t = parseType(); + stats.appendList(variableDeclarators(mods, t, + new ListBuffer<JCStatement>())); + // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon + storeEnd(stats.elems.last(), S.endPos()); + accept(SEMI); + } + break; + } + case ABSTRACT: case STRICTFP: { + String dc = S.docComment(); + JCModifiers mods = modifiersOpt(); + stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); + break; + } + case INTERFACE: + case CLASS: + stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), + S.docComment())); + break; + case ENUM: + case ASSERT: + if (allowEnums && S.token() == ENUM) { + log.error(S.pos(), "local.enum"); + stats. + append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), + S.docComment())); + break; + } else if (allowAsserts && S.token() == ASSERT) { + stats.append(parseStatement()); + break; + } + /* fall through to default */ + default: + Name name = S.name(); + JCExpression t = term(EXPR | TYPE); + if (S.token() == COLON && t.getTag() == JCTree.IDENT) { + S.nextToken(); + JCStatement stat = parseStatement(); + stats.append(F.at(pos).Labelled(name, stat)); + } else if ((lastmode & TYPE) != 0 && + (S.token() == IDENTIFIER || + S.token() == ASSERT || + S.token() == ENUM)) { + pos = S.pos(); + JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); + F.at(pos); + stats.appendList(variableDeclarators(mods, t, + new ListBuffer<JCStatement>())); + // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon + storeEnd(stats.elems.last(), S.endPos()); + accept(SEMI); + } else { + // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon + stats.append(to(F.at(pos).Exec(checkExprStat(t)))); + accept(SEMI); + } + } + + // error recovery + if (S.pos() == lastErrPos) + return stats.toList(); + if (S.pos() <= errorEndPos) { + skip(false, true, true, true); + lastErrPos = S.pos(); + } + + // ensure no dangling /** @deprecated */ active + S.resetDeprecatedFlag(); + } + } + + /** Statement = + * Block + * | IF ParExpression Statement [ELSE Statement] + * | FOR "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement + * | FOR "(" FormalParameter : Expression ")" Statement + * | WHILE ParExpression Statement + * | DO Statement WHILE ParExpression ";" + * | TRY Block ( Catches | [Catches] FinallyPart ) + * | SWITCH ParExpression "{" SwitchBlockStatementGroups "}" + * | SYNCHRONIZED ParExpression Block + * | RETURN [Expression] ";" + * | THROW Expression ";" + * | BREAK [Ident] ";" + * | CONTINUE [Ident] ";" + * | ASSERT Expression [ ":" Expression ] ";" + * | ";" + * | ExpressionStatement + * | Ident ":" Statement + */ + @SuppressWarnings("fallthrough") + public JCStatement parseStatement() { + int pos = S.pos(); + switch (S.token()) { + case LBRACE: + return block(); + case IF: { + S.nextToken(); + JCExpression cond = parExpression(); + JCStatement thenpart = parseStatement(); + JCStatement elsepart = null; + if (S.token() == ELSE) { + S.nextToken(); + elsepart = parseStatement(); + } + return F.at(pos).If(cond, thenpart, elsepart); + } + case FOR: { + S.nextToken(); + accept(LPAREN); + List<JCStatement> inits = S.token() == SEMI ? List.<JCStatement>nil() : forInit(); + if (inits.length() == 1 && + inits.head.getTag() == JCTree.VARDEF && + ((JCVariableDecl) inits.head).init == null && + S.token() == COLON) { + checkForeach(); + JCVariableDecl var = (JCVariableDecl)inits.head; + accept(COLON); + JCExpression expr = parseExpression(); + accept(RPAREN); + JCStatement body = parseStatement(); + return F.at(pos).ForeachLoop(var, expr, body); + } else { + accept(SEMI); + JCExpression cond = S.token() == SEMI ? null : parseExpression(); + accept(SEMI); + List<JCExpressionStatement> steps = S.token() == RPAREN ? List.<JCExpressionStatement>nil() : forUpdate(); + accept(RPAREN); + JCStatement body = parseStatement(); + return F.at(pos).ForLoop(inits, cond, steps, body); + } + } + case WHILE: { + S.nextToken(); + JCExpression cond = parExpression(); + JCStatement body = parseStatement(); + return F.at(pos).WhileLoop(cond, body); + } + case DO: { + S.nextToken(); + JCStatement body = parseStatement(); + accept(WHILE); + JCExpression cond = parExpression(); + JCDoWhileLoop t = to(F.at(pos).DoLoop(body, cond)); + accept(SEMI); + return t; + } + case TRY: { + S.nextToken(); + JCBlock body = block(); + ListBuffer<JCCatch> catchers = new ListBuffer<JCCatch>(); + JCBlock finalizer = null; + if (S.token() == CATCH || S.token() == FINALLY) { + while (S.token() == CATCH) catchers.append(catchClause()); + if (S.token() == FINALLY) { + S.nextToken(); + finalizer = block(); + } + } else { + log.error(pos, "try.without.catch.or.finally"); + } + return F.at(pos).Try(body, catchers.toList(), finalizer); + } + case SWITCH: { + S.nextToken(); + JCExpression selector = parExpression(); + accept(LBRACE); + List<JCCase> cases = switchBlockStatementGroups(); + JCSwitch t = to(F.at(pos).Switch(selector, cases)); + accept(RBRACE); + return t; + } + case SYNCHRONIZED: { + S.nextToken(); + JCExpression lock = parExpression(); + JCBlock body = block(); + return F.at(pos).Synchronized(lock, body); + } + case RETURN: { + S.nextToken(); + JCExpression result = S.token() == SEMI ? null : parseExpression(); + JCReturn t = to(F.at(pos).Return(result)); + accept(SEMI); + return t; + } + case THROW: { + S.nextToken(); + JCExpression exc = parseExpression(); + JCThrow t = to(F.at(pos).Throw(exc)); + accept(SEMI); + return t; + } + case BREAK: { + S.nextToken(); + Name label = (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM) ? ident() : null; + JCBreak t = to(F.at(pos).Break(label)); + accept(SEMI); + return t; + } + case CONTINUE: { + S.nextToken(); + Name label = (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM) ? ident() : null; + JCContinue t = to(F.at(pos).Continue(label)); + accept(SEMI); + return t; + } + case SEMI: + S.nextToken(); + return toP(F.at(pos).Skip()); + case ELSE: + return toP(F.Exec(syntaxError("else.without.if"))); + case FINALLY: + return toP(F.Exec(syntaxError("finally.without.try"))); + case CATCH: + return toP(F.Exec(syntaxError("catch.without.try"))); + case ASSERT: { + if (allowAsserts && S.token() == ASSERT) { + S.nextToken(); + JCExpression assertion = parseExpression(); + JCExpression message = null; + if (S.token() == COLON) { + S.nextToken(); + message = parseExpression(); + } + JCAssert t = to(F.at(pos).Assert(assertion, message)); + accept(SEMI); + return t; + } + /* else fall through to default case */ + } + case ENUM: + default: + Name name = S.name(); + JCExpression expr = parseExpression(); + if (S.token() == COLON && expr.getTag() == JCTree.IDENT) { + S.nextToken(); + JCStatement stat = parseStatement(); + return F.at(pos).Labelled(name, stat); + } else { + // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon + JCExpressionStatement stat = to(F.at(pos).Exec(checkExprStat(expr))); + accept(SEMI); + return stat; + } + } + } + + /** CatchClause = CATCH "(" FormalParameter ")" Block + */ + JCCatch catchClause() { + int pos = S.pos(); + accept(CATCH); + accept(LPAREN); + JCVariableDecl formal = + variableDeclaratorId(optFinal(Flags.PARAMETER), + qualident()); + accept(RPAREN); + JCBlock body = block(); + return F.at(pos).Catch(formal, body); + } + + /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup } + * SwitchBlockStatementGroup = SwitchLabel BlockStatements + * SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":" + */ + List<JCCase> switchBlockStatementGroups() { + ListBuffer<JCCase> cases = new ListBuffer<JCCase>(); + while (true) { + int pos = S.pos(); + switch (S.token()) { + case CASE: { + S.nextToken(); + JCExpression pat = parseExpression(); + accept(COLON); + List<JCStatement> stats = blockStatements(); + JCCase c = F.at(pos).Case(pat, stats); + if (stats.isEmpty()) + storeEnd(c, S.prevEndPos()); + cases.append(c); + break; + } + case DEFAULT: { + S.nextToken(); + accept(COLON); + List<JCStatement> stats = blockStatements(); + JCCase c = F.at(pos).Case(null, stats); + if (stats.isEmpty()) + storeEnd(c, S.prevEndPos()); + cases.append(c); + break; + } + case RBRACE: case EOF: + return cases.toList(); + default: + S.nextToken(); // to ensure progress + syntaxError(pos, "expected3", + CASE, DEFAULT, RBRACE); + } + } + } + + /** MoreStatementExpressions = { COMMA StatementExpression } + */ + <T extends ListBuffer<? super JCExpressionStatement>> T moreStatementExpressions(int pos, + JCExpression first, + T stats) { + // This Exec is a "StatementExpression"; it subsumes no terminating token + stats.append(toP(F.at(pos).Exec(checkExprStat(first)))); + while (S.token() == COMMA) { + S.nextToken(); + pos = S.pos(); + JCExpression t = parseExpression(); + // This Exec is a "StatementExpression"; it subsumes no terminating token + stats.append(toP(F.at(pos).Exec(checkExprStat(t)))); + } + return stats; + } + + /** ForInit = StatementExpression MoreStatementExpressions + * | { FINAL | '@' Annotation } Type VariableDeclarators + */ + List<JCStatement> forInit() { + ListBuffer<JCStatement> stats = lb(); + int pos = S.pos(); + if (S.token() == FINAL || S.token() == MONKEYS_AT) { + return variableDeclarators(optFinal(0), parseType(), stats).toList(); + } else { + JCExpression t = term(EXPR | TYPE); + if ((lastmode & TYPE) != 0 && + (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM)) + return variableDeclarators(modifiersOpt(), t, stats).toList(); + else + return moreStatementExpressions(pos, t, stats).toList(); + } + } + + /** ForUpdate = StatementExpression MoreStatementExpressions + */ + List<JCExpressionStatement> forUpdate() { + return moreStatementExpressions(S.pos(), + parseExpression(), + new ListBuffer<JCExpressionStatement>()).toList(); + } + + /** AnnotationsOpt = { '@' Annotation } + */ + List<JCAnnotation> annotationsOpt() { + if (S.token() != MONKEYS_AT) return List.nil(); // optimization + ListBuffer<JCAnnotation> buf = new ListBuffer<JCAnnotation>(); + while (S.token() == MONKEYS_AT) { + int pos = S.pos(); + S.nextToken(); + buf.append(annotation(pos)); + } + return buf.toList(); + } + + /** ModifiersOpt = { Modifier } + * Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL + * | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@" + * | "@" Annotation + */ + JCModifiers modifiersOpt() { + return modifiersOpt(null); + } + JCModifiers modifiersOpt(JCModifiers partial) { + long flags = (partial == null) ? 0 : partial.flags; + if (S.deprecatedFlag()) { + flags |= Flags.DEPRECATED; + S.resetDeprecatedFlag(); + } + ListBuffer<JCAnnotation> annotations = new ListBuffer<JCAnnotation>(); + if (partial != null) annotations.appendList(partial.annotations); + int pos = S.pos(); + int lastPos = Position.NOPOS; + loop: + while (true) { + long flag; + switch (S.token()) { + case PRIVATE : flag = Flags.PRIVATE; break; + case PROTECTED : flag = Flags.PROTECTED; break; + case PUBLIC : flag = Flags.PUBLIC; break; + case STATIC : flag = Flags.STATIC; break; + case TRANSIENT : flag = Flags.TRANSIENT; break; + case FINAL : flag = Flags.FINAL; break; + case ABSTRACT : flag = Flags.ABSTRACT; break; + case NATIVE : flag = Flags.NATIVE; break; + case VOLATILE : flag = Flags.VOLATILE; break; + case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break; + case STRICTFP : flag = Flags.STRICTFP; break; + case MONKEYS_AT : flag = Flags.ANNOTATION; break; + default: break loop; + } + if ((flags & flag) != 0) log.error(S.pos(), "repeated.modifier"); + lastPos = S.pos(); + S.nextToken(); + if (flag == Flags.ANNOTATION) { + checkAnnotations(); + if (S.token() != INTERFACE) { + JCAnnotation ann = annotation(lastPos); + // if first modifier is an annotation, set pos to annotation's. + if (flags == 0 && annotations.isEmpty()) + pos = ann.pos; + annotations.append(ann); + lastPos = ann.pos; + flag = 0; + } + } + flags |= flag; + } + switch (S.token()) { + case ENUM: flags |= Flags.ENUM; break; + case INTERFACE: flags |= Flags.INTERFACE; break; + default: break; + } + + /* A modifiers tree with no modifier tokens or annotations + * has no text position. */ + if (flags == 0 && annotations.isEmpty()) + pos = Position.NOPOS; + + JCModifiers mods = F.at(pos).Modifiers(flags, annotations.toList()); + if (pos != Position.NOPOS) + storeEnd(mods, S.prevEndPos()); + return mods; + } + + /** Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ] + * @param pos position of "@" token + */ + JCAnnotation annotation(int pos) { + // accept(AT); // AT consumed by caller + checkAnnotations(); + JCTree ident = qualident(); + List<JCExpression> fieldValues = annotationFieldValuesOpt(); + JCAnnotation ann = F.at(pos).Annotation(ident, fieldValues); + storeEnd(ann, S.prevEndPos()); + return ann; + } + + List<JCExpression> annotationFieldValuesOpt() { + return (S.token() == LPAREN) ? annotationFieldValues() : List.<JCExpression>nil(); + } + + /** AnnotationFieldValues = "(" [ AnnotationFieldValue { "," AnnotationFieldValue } ] ")" */ + List<JCExpression> annotationFieldValues() { + accept(LPAREN); + ListBuffer<JCExpression> buf = new ListBuffer<JCExpression>(); + if (S.token() != RPAREN) { + buf.append(annotationFieldValue()); + while (S.token() == COMMA) { + S.nextToken(); + buf.append(annotationFieldValue()); + } + } + accept(RPAREN); + return buf.toList(); + } + + /** AnnotationFieldValue = AnnotationValue + * | Identifier "=" AnnotationValue + */ + JCExpression annotationFieldValue() { + if (S.token() == IDENTIFIER) { + mode = EXPR; + JCExpression t1 = term1(); + if (t1.getTag() == JCTree.IDENT && S.token() == EQ) { + int pos = S.pos(); + accept(EQ); + return toP(F.at(pos).Assign(t1, annotationValue())); + } else { + return t1; + } + } + return annotationValue(); + } + + /* AnnotationValue = ConditionalExpression + * | Annotation + * | "{" [ AnnotationValue { "," AnnotationValue } ] "}" + */ + JCExpression annotationValue() { + int pos; + switch (S.token()) { + case MONKEYS_AT: + pos = S.pos(); + S.nextToken(); + return annotation(pos); + case LBRACE: + pos = S.pos(); + accept(LBRACE); + ListBuffer<JCExpression> buf = new ListBuffer<JCExpression>(); + if (S.token() != RBRACE) { + buf.append(annotationValue()); + while (S.token() == COMMA) { + S.nextToken(); + if (S.token() == RPAREN) break; + buf.append(annotationValue()); + } + } + accept(RBRACE); + return toP(F.at(pos).NewArray(null, List.<JCExpression>nil(), buf.toList())); + default: + mode = EXPR; + return term1(); + } + } + + /** VariableDeclarators = VariableDeclarator { "," VariableDeclarator } + */ + public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods, + JCExpression type, + T vdefs) + { + return variableDeclaratorsRest(S.pos(), mods, type, ident(), false, null, vdefs); + } + + /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator } + * ConstantDeclaratorsRest = ConstantDeclaratorRest { "," ConstantDeclarator } + * + * @param reqInit Is an initializer always required? + * @param dc The documentation comment for the variable declarations, or null. + */ + <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos, + JCModifiers mods, + JCExpression type, + Name name, + boolean reqInit, + String dc, + T vdefs) + { + vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc)); + while (S.token() == COMMA) { + // All but last of multiple declarators subsume a comma + storeEnd((JCTree)vdefs.elems.last(), S.endPos()); + S.nextToken(); + vdefs.append(variableDeclarator(mods, type, reqInit, dc)); + } + return vdefs; + } + + /** VariableDeclarator = Ident VariableDeclaratorRest + * ConstantDeclarator = Ident ConstantDeclaratorRest + */ + JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, String dc) { + return variableDeclaratorRest(S.pos(), mods, type, ident(), reqInit, dc); + } + + /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer] + * ConstantDeclaratorRest = BracketsOpt "=" VariableInitializer + * + * @param reqInit Is an initializer always required? + * @param dc The documentation comment for the variable declarations, or null. + */ + JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name, + boolean reqInit, String dc) { + type = bracketsOpt(type); + JCExpression init = null; + if (S.token() == EQ) { + S.nextToken(); + init = variableInitializer(); + } + else if (reqInit) syntaxError(S.pos(), "expected", EQ); + JCVariableDecl result = + toP(F.at(pos).VarDef(mods, name, type, init)); + attach(result, dc); + return result; + } + + /** VariableDeclaratorId = Ident BracketsOpt + */ + JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) { + int pos = S.pos(); + Name name = ident(); + if ((mods.flags & Flags.VARARGS) == 0) + type = bracketsOpt(type); + return toP(F.at(pos).VarDef(mods, name, type, null)); + } + + /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration} + */ + public JCTree.JCCompilationUnit parseCompilationUnit() { + int pos = S.pos(); + JCExpression pid = null; + String dc = S.docComment(); + JCModifiers mods = null; + List<JCAnnotation> packageAnnotations = List.nil(); + if (S.token() == MONKEYS_AT) + mods = modifiersOpt(); + + if (S.token() == PACKAGE) { + if (mods != null) { + checkNoMods(mods.flags); + packageAnnotations = mods.annotations; + mods = null; + } + S.nextToken(); + pid = qualident(); + accept(SEMI); + } + ListBuffer<JCTree> defs = new ListBuffer<JCTree>(); + boolean checkForImports = true; + while (S.token() != EOF) { + if (S.pos() <= errorEndPos) { + // error recovery + skip(checkForImports, false, false, false); + if (S.token() == EOF) + break; + } + if (checkForImports && mods == null && S.token() == IMPORT) { + defs.append(importDeclaration()); + } else { + JCTree def = typeDeclaration(mods); + if (def instanceof JCExpressionStatement) + def = ((JCExpressionStatement)def).expr; + defs.append(def); + if (def instanceof JCClassDecl) + checkForImports = false; + mods = null; + } + } + JCTree.JCCompilationUnit toplevel = F.at(pos).TopLevel(packageAnnotations, pid, defs.toList()); + attach(toplevel, dc); + if (defs.elems.isEmpty()) + storeEnd(toplevel, S.prevEndPos()); + if (keepDocComments) + toplevel.docComments = docComments; + if (keepLineMap) + toplevel.lineMap = S.getLineMap(); + return toplevel; + } + + /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";" + */ + JCTree importDeclaration() { + int pos = S.pos(); + S.nextToken(); + boolean importStatic = false; + if (S.token() == STATIC) { + checkStaticImports(); + importStatic = true; + S.nextToken(); + } + JCExpression pid = toP(F.at(S.pos()).Ident(ident())); + do { + int pos1 = S.pos(); + accept(DOT); + if (S.token() == STAR) { + pid = to(F.at(pos1).Select(pid, names.asterisk)); + S.nextToken(); + break; + } else { + pid = toP(F.at(pos1).Select(pid, ident())); + } + } while (S.token() == DOT); + accept(SEMI); + return toP(F.at(pos).Import(pid, importStatic)); + } + + /** TypeDeclaration = ClassOrInterfaceOrEnumDeclaration + * | ";" + */ + JCTree typeDeclaration(JCModifiers mods) { + int pos = S.pos(); + if (mods == null && S.token() == SEMI) { + S.nextToken(); + return toP(F.at(pos).Skip()); + } else { + String dc = S.docComment(); + return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), dc); + } + } + + /** ClassOrInterfaceOrEnumDeclaration = ModifiersOpt + * (ClassDeclaration | InterfaceDeclaration | EnumDeclaration) + * @param mods Any modifiers starting the class or interface declaration + * @param dc The documentation comment for the class, or null. + */ + JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, String dc) { + if (S.token() == CLASS) { + return classDeclaration(mods, dc); + } else if (S.token() == INTERFACE) { + return interfaceDeclaration(mods, dc); + } else if (allowEnums) { + if (S.token() == ENUM) { + return enumDeclaration(mods, dc); + } else { + int pos = S.pos(); + List<JCTree> errs; + if (S.token() == IDENTIFIER) { + errs = List.<JCTree>of(mods, toP(F.at(pos).Ident(ident()))); + setErrorEndPos(S.pos()); + } else { + errs = List.<JCTree>of(mods); + } + return toP(F.Exec(syntaxError(pos, errs, "expected3", + CLASS, INTERFACE, ENUM))); + } + } else { + if (S.token() == ENUM) { + log.error(S.pos(), "enums.not.supported.in.source", source.name); + allowEnums = true; + return enumDeclaration(mods, dc); + } + int pos = S.pos(); + List<JCTree> errs; + if (S.token() == IDENTIFIER) { + errs = List.<JCTree>of(mods, toP(F.at(pos).Ident(ident()))); + setErrorEndPos(S.pos()); + } else { + errs = List.<JCTree>of(mods); + } + return toP(F.Exec(syntaxError(pos, errs, "expected2", + CLASS, INTERFACE))); + } + } + + /** ClassDeclaration = CLASS Ident TypeParametersOpt [EXTENDS Type] + * [IMPLEMENTS TypeList] ClassBody + * @param mods The modifiers starting the class declaration + * @param dc The documentation comment for the class, or null. + */ + JCClassDecl classDeclaration(JCModifiers mods, String dc) { + int pos = S.pos(); + accept(CLASS); + Name name = ident(); + + List<JCTypeParameter> typarams = typeParametersOpt(); + + JCTree extending = null; + if (S.token() == EXTENDS) { + S.nextToken(); + extending = parseType(); + } + List<JCExpression> implementing = List.nil(); + if (S.token() == IMPLEMENTS) { + S.nextToken(); + implementing = typeList(); + } + List<JCTree> defs = classOrInterfaceBody(name, false); + JCClassDecl result = toP(F.at(pos).ClassDef( + mods, name, typarams, extending, implementing, defs)); + attach(result, dc); + return result; + } + + /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt + * [EXTENDS TypeList] InterfaceBody + * @param mods The modifiers starting the interface declaration + * @param dc The documentation comment for the interface, or null. + */ + JCClassDecl interfaceDeclaration(JCModifiers mods, String dc) { + int pos = S.pos(); + accept(INTERFACE); + Name name = ident(); + + List<JCTypeParameter> typarams = typeParametersOpt(); + + List<JCExpression> extending = List.nil(); + if (S.token() == EXTENDS) { + S.nextToken(); + extending = typeList(); + } + List<JCTree> defs = classOrInterfaceBody(name, true); + JCClassDecl result = toP(F.at(pos).ClassDef( + mods, name, typarams, null, extending, defs)); + attach(result, dc); + return result; + } + + /** EnumDeclaration = ENUM Ident [IMPLEMENTS TypeList] EnumBody + * @param mods The modifiers starting the enum declaration + * @param dc The documentation comment for the enum, or null. + */ + JCClassDecl enumDeclaration(JCModifiers mods, String dc) { + int pos = S.pos(); + accept(ENUM); + Name name = ident(); + + List<JCExpression> implementing = List.nil(); + if (S.token() == IMPLEMENTS) { + S.nextToken(); + implementing = typeList(); + } + + List<JCTree> defs = enumBody(name); + JCModifiers newMods = + F.at(mods.pos).Modifiers(mods.flags|Flags.ENUM, mods.annotations); + JCClassDecl result = toP(F.at(pos). + ClassDef(newMods, name, List.<JCTypeParameter>nil(), + null, implementing, defs)); + attach(result, dc); + return result; + } + + /** EnumBody = "{" { EnumeratorDeclarationList } [","] + * [ ";" {ClassBodyDeclaration} ] "}" + */ + List<JCTree> enumBody(Name enumName) { + accept(LBRACE); + ListBuffer<JCTree> defs = new ListBuffer<JCTree>(); + if (S.token() == COMMA) { + S.nextToken(); + } else if (S.token() != RBRACE && S.token() != SEMI) { + defs.append(enumeratorDeclaration(enumName)); + while (S.token() == COMMA) { + S.nextToken(); + if (S.token() == RBRACE || S.token() == SEMI) break; + defs.append(enumeratorDeclaration(enumName)); + } + if (S.token() != SEMI && S.token() != RBRACE) { + defs.append(syntaxError(S.pos(), "expected3", + COMMA, RBRACE, SEMI)); + S.nextToken(); + } + } + if (S.token() == SEMI) { + S.nextToken(); + while (S.token() != RBRACE && S.token() != EOF) { + defs.appendList(classOrInterfaceBodyDeclaration(enumName, + false)); + if (S.pos() <= errorEndPos) { + // error recovery + skip(false, true, true, false); + } + } + } + accept(RBRACE); + return defs.toList(); + } + + /** EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ] + */ + JCTree enumeratorDeclaration(Name enumName) { + String dc = S.docComment(); + int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM; + if (S.deprecatedFlag()) { + flags |= Flags.DEPRECATED; + S.resetDeprecatedFlag(); + } + int pos = S.pos(); + List<JCAnnotation> annotations = annotationsOpt(); + JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations); + List<JCExpression> typeArgs = typeArgumentsOpt(); + int identPos = S.pos(); + Name name = ident(); + int createPos = S.pos(); + List<JCExpression> args = (S.token() == LPAREN) + ? arguments() : List.<JCExpression>nil(); + JCClassDecl body = null; + if (S.token() == LBRACE) { + JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC); + List<JCTree> defs = classOrInterfaceBody(names.empty, false); + body = toP(F.at(identPos).AnonymousClassDef(mods1, defs)); + } + if (args.isEmpty() && body == null) + createPos = Position.NOPOS; + JCIdent ident = F.at(Position.NOPOS).Ident(enumName); + JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body); + if (createPos != Position.NOPOS) + storeEnd(create, S.prevEndPos()); + ident = F.at(Position.NOPOS).Ident(enumName); + JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create)); + attach(result, dc); + return result; + } + + /** TypeList = Type {"," Type} + */ + List<JCExpression> typeList() { + ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>(); + ts.append(parseType()); + while (S.token() == COMMA) { + S.nextToken(); + ts.append(parseType()); + } + return ts.toList(); + } + + /** ClassBody = "{" {ClassBodyDeclaration} "}" + * InterfaceBody = "{" {InterfaceBodyDeclaration} "}" + */ + List<JCTree> classOrInterfaceBody(Name className, boolean isInterface) { + accept(LBRACE); + if (S.pos() <= errorEndPos) { + // error recovery + skip(false, true, false, false); + if (S.token() == LBRACE) + S.nextToken(); + } + ListBuffer<JCTree> defs = new ListBuffer<JCTree>(); + while (S.token() != RBRACE && S.token() != EOF) { + defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface)); + if (S.pos() <= errorEndPos) { + // error recovery + skip(false, true, true, false); + } + } + accept(RBRACE); + return defs.toList(); + } + + /** ClassBodyDeclaration = + * ";" + * | [STATIC] Block + * | ModifiersOpt + * ( Type Ident + * ( VariableDeclaratorsRest ";" | MethodDeclaratorRest ) + * | VOID Ident MethodDeclaratorRest + * | TypeParameters (Type | VOID) Ident MethodDeclaratorRest + * | Ident ConstructorDeclaratorRest + * | TypeParameters Ident ConstructorDeclaratorRest + * | ClassOrInterfaceOrEnumDeclaration + * ) + * InterfaceBodyDeclaration = + * ";" + * | ModifiersOpt Type Ident + * ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" ) + */ + List<JCTree> classOrInterfaceBodyDeclaration(Name className, boolean isInterface) { + if (S.token() == SEMI) { + S.nextToken(); + return List.<JCTree>of(F.at(Position.NOPOS).Block(0, List.<JCStatement>nil())); + } else { + String dc = S.docComment(); + int pos = S.pos(); + JCModifiers mods = modifiersOpt(); + if (S.token() == CLASS || + S.token() == INTERFACE || + allowEnums && S.token() == ENUM) { + return List.<JCTree>of(classOrInterfaceOrEnumDeclaration(mods, dc)); + } else if (S.token() == LBRACE && !isInterface && + (mods.flags & Flags.StandardFlags & ~Flags.STATIC) == 0 && + mods.annotations.isEmpty()) { + return List.<JCTree>of(block(pos, mods.flags)); + } else { + pos = S.pos(); + List<JCTypeParameter> typarams = typeParametersOpt(); + // Hack alert: if there are type arguments but no Modifiers, the start + // position will be lost unless we set the Modifiers position. There + // should be an AST node for type parameters (BugId 5005090). + if (typarams.length() > 0 && mods.pos == Position.NOPOS) { + mods.pos = pos; + } + Token token = S.token(); + Name name = S.name(); + pos = S.pos(); + JCExpression type; + boolean isVoid = S.token() == VOID; + if (isVoid) { + type = to(F.at(pos).TypeIdent(TypeTags.VOID)); + S.nextToken(); + } else { + type = parseType(); + } + if (S.token() == LPAREN && !isInterface && type.getTag() == JCTree.IDENT) { + if (isInterface || name != className) + log.error(pos, "invalid.meth.decl.ret.type.req"); + return List.of(methodDeclaratorRest( + pos, mods, null, names.init, typarams, + isInterface, true, dc)); + } else { + pos = S.pos(); + name = ident(); + if (S.token() == LPAREN) { + return List.of(methodDeclaratorRest( + pos, mods, type, name, typarams, + isInterface, isVoid, dc)); + } else if (!isVoid && typarams.isEmpty()) { + List<JCTree> defs = + variableDeclaratorsRest(pos, mods, type, name, isInterface, dc, + new ListBuffer<JCTree>()).toList(); + storeEnd(defs.last(), S.endPos()); + accept(SEMI); + return defs; + } else { + pos = S.pos(); + List<JCTree> err = isVoid + ? List.<JCTree>of(toP(F.at(pos).MethodDef(mods, name, type, typarams, + List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null))) + : null; + return List.<JCTree>of(syntaxError(S.pos(), err, "expected", LPAREN)); + } + } + } + } + } + + /** MethodDeclaratorRest = + * FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";") + * VoidMethodDeclaratorRest = + * FormalParameters [Throws TypeList] ( MethodBody | ";") + * InterfaceMethodDeclaratorRest = + * FormalParameters BracketsOpt [THROWS TypeList] ";" + * VoidInterfaceMethodDeclaratorRest = + * FormalParameters [THROWS TypeList] ";" + * ConstructorDeclaratorRest = + * "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody + */ + JCTree methodDeclaratorRest(int pos, + JCModifiers mods, + JCExpression type, + Name name, + List<JCTypeParameter> typarams, + boolean isInterface, boolean isVoid, + String dc) { + List<JCVariableDecl> params = formalParameters(); + if (!isVoid) type = bracketsOpt(type); + List<JCExpression> thrown = List.nil(); + if (S.token() == THROWS) { + S.nextToken(); + thrown = qualidentList(); + } + JCBlock body = null; + JCExpression defaultValue; + if (S.token() == LBRACE) { + body = block(); + defaultValue = null; + } else { + if (S.token() == DEFAULT) { + accept(DEFAULT); + defaultValue = annotationValue(); + } else { + defaultValue = null; + } + accept(SEMI); + if (S.pos() <= errorEndPos) { + // error recovery + skip(false, true, false, false); + if (S.token() == LBRACE) { + body = block(); + } + } + } + JCMethodDecl result = + toP(F.at(pos).MethodDef(mods, name, type, typarams, + params, thrown, + body, defaultValue)); + attach(result, dc); + return result; + } + + /** QualidentList = Qualident {"," Qualident} + */ + List<JCExpression> qualidentList() { + ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>(); + ts.append(qualident()); + while (S.token() == COMMA) { + S.nextToken(); + ts.append(qualident()); + } + return ts.toList(); + } + + /** TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"] + */ + List<JCTypeParameter> typeParametersOpt() { + if (S.token() == LT) { + checkGenerics(); + ListBuffer<JCTypeParameter> typarams = new ListBuffer<JCTypeParameter>(); + S.nextToken(); + typarams.append(typeParameter()); + while (S.token() == COMMA) { + S.nextToken(); + typarams.append(typeParameter()); + } + accept(GT); + return typarams.toList(); + } else { + return List.nil(); + } + } + + /** TypeParameter = TypeVariable [TypeParameterBound] + * TypeParameterBound = EXTENDS Type {"&" Type} + * TypeVariable = Ident + */ + JCTypeParameter typeParameter() { + int pos = S.pos(); + Name name = ident(); + ListBuffer<JCExpression> bounds = new ListBuffer<JCExpression>(); + if (S.token() == EXTENDS) { + S.nextToken(); + bounds.append(parseType()); + while (S.token() == AMP) { + S.nextToken(); + bounds.append(parseType()); + } + } + return toP(F.at(pos).TypeParameter(name, bounds.toList())); + } + + /** FormalParameters = "(" [ FormalParameterList ] ")" + * FormalParameterList = [ FormalParameterListNovarargs , ] LastFormalParameter + * FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter + */ + List<JCVariableDecl> formalParameters() { + ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); + JCVariableDecl lastParam = null; + accept(LPAREN); + if (S.token() != RPAREN) { + params.append(lastParam = formalParameter()); + while ((lastParam.mods.flags & Flags.VARARGS) == 0 && S.token() == COMMA) { + S.nextToken(); + params.append(lastParam = formalParameter()); + } + } + accept(RPAREN); + return params.toList(); + } + + JCModifiers optFinal(long flags) { + JCModifiers mods = modifiersOpt(); + checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED)); + mods.flags |= flags; + return mods; + } + + /** FormalParameter = { FINAL | '@' Annotation } Type VariableDeclaratorId + * LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter + */ + JCVariableDecl formalParameter() { + JCModifiers mods = optFinal(Flags.PARAMETER); + JCExpression type = parseType(); + if (S.token() == ELLIPSIS) { + checkVarargs(); + mods.flags |= Flags.VARARGS; + type = to(F.at(S.pos()).TypeArray(type)); + S.nextToken(); + } + return variableDeclaratorId(mods, type); + } + +/* ---------- auxiliary methods -------------- */ + + /** Check that given tree is a legal expression statement. + */ + protected JCExpression checkExprStat(JCExpression t) { + switch(t.getTag()) { + case JCTree.PREINC: case JCTree.PREDEC: + case JCTree.POSTINC: case JCTree.POSTDEC: + case JCTree.ASSIGN: + case JCTree.BITOR_ASG: case JCTree.BITXOR_ASG: case JCTree.BITAND_ASG: + case JCTree.SL_ASG: case JCTree.SR_ASG: case JCTree.USR_ASG: + case JCTree.PLUS_ASG: case JCTree.MINUS_ASG: + case JCTree.MUL_ASG: case JCTree.DIV_ASG: case JCTree.MOD_ASG: + case JCTree.APPLY: case JCTree.NEWCLASS: + case JCTree.ERRONEOUS: + return t; + default: + log.error(t.pos, "not.stmt"); + return F.at(t.pos).Erroneous(List.<JCTree>of(t)); + } + } + + /** Return precedence of operator represented by token, + * -1 if token is not a binary operator. @see TreeInfo.opPrec + */ + static int prec(Token token) { + int oc = optag(token); + return (oc >= 0) ? TreeInfo.opPrec(oc) : -1; + } + + /** Return operation tag of binary operator represented by token, + * -1 if token is not a binary operator. + */ + static int optag(Token token) { + switch (token) { + case BARBAR: + return JCTree.OR; + case AMPAMP: + return JCTree.AND; + case BAR: + return JCTree.BITOR; + case BAREQ: + return JCTree.BITOR_ASG; + case CARET: + return JCTree.BITXOR; + case CARETEQ: + return JCTree.BITXOR_ASG; + case AMP: + return JCTree.BITAND; + case AMPEQ: + return JCTree.BITAND_ASG; + case EQEQ: + return JCTree.EQ; + case BANGEQ: + return JCTree.NE; + case LT: + return JCTree.LT; + case GT: + return JCTree.GT; + case LTEQ: + return JCTree.LE; + case GTEQ: + return JCTree.GE; + case LTLT: + return JCTree.SL; + case LTLTEQ: + return JCTree.SL_ASG; + case GTGT: + return JCTree.SR; + case GTGTEQ: + return JCTree.SR_ASG; + case GTGTGT: + return JCTree.USR; + case GTGTGTEQ: + return JCTree.USR_ASG; + case PLUS: + return JCTree.PLUS; + case PLUSEQ: + return JCTree.PLUS_ASG; + case SUB: + return JCTree.MINUS; + case SUBEQ: + return JCTree.MINUS_ASG; + case STAR: + return JCTree.MUL; + case STAREQ: + return JCTree.MUL_ASG; + case SLASH: + return JCTree.DIV; + case SLASHEQ: + return JCTree.DIV_ASG; + case PERCENT: + return JCTree.MOD; + case PERCENTEQ: + return JCTree.MOD_ASG; + case INSTANCEOF: + return JCTree.TYPETEST; + default: + return -1; + } + } + + /** Return operation tag of unary operator represented by token, + * -1 if token is not a binary operator. + */ + static int unoptag(Token token) { + switch (token) { + case PLUS: + return JCTree.POS; + case SUB: + return JCTree.NEG; + case BANG: + return JCTree.NOT; + case TILDE: + return JCTree.COMPL; + case PLUSPLUS: + return JCTree.PREINC; + case SUBSUB: + return JCTree.PREDEC; + default: + return -1; + } + } + + /** Return type tag of basic type represented by token, + * -1 if token is not a basic type identifier. + */ + static int typetag(Token token) { + switch (token) { + case BYTE: + return TypeTags.BYTE; + case CHAR: + return TypeTags.CHAR; + case SHORT: + return TypeTags.SHORT; + case INT: + return TypeTags.INT; + case LONG: + return TypeTags.LONG; + case FLOAT: + return TypeTags.FLOAT; + case DOUBLE: + return TypeTags.DOUBLE; + case BOOLEAN: + return TypeTags.BOOLEAN; + default: + return -1; + } + } + + void checkGenerics() { + if (!allowGenerics) { + log.error(S.pos(), "generics.not.supported.in.source", source.name); + allowGenerics = true; + } + } + void checkVarargs() { + if (!allowVarargs) { + log.error(S.pos(), "varargs.not.supported.in.source", source.name); + allowVarargs = true; + } + } + void checkForeach() { + if (!allowForeach) { + log.error(S.pos(), "foreach.not.supported.in.source", source.name); + allowForeach = true; + } + } + void checkStaticImports() { + if (!allowStaticImport) { + log.error(S.pos(), "static.import.not.supported.in.source", source.name); + allowStaticImport = true; + } + } + void checkAnnotations() { + if (!allowAnnotations) { + log.error(S.pos(), "annotations.not.supported.in.source", source.name); + allowAnnotations = true; + } + } +}
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/Parser.java Tue Sep 09 10:28:21 2008 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Parser.java Tue Sep 09 10:40:50 2008 -0700 @@ -23,2834 +23,44 @@ * have any questions. */ + package com.sun.tools.javac.parser; -import java.util.*; - -import com.sun.tools.javac.tree.*; -import com.sun.tools.javac.code.*; -import com.sun.tools.javac.util.*; -import com.sun.tools.javac.util.List; -import static com.sun.tools.javac.util.ListBuffer.lb; - -import com.sun.tools.javac.tree.JCTree.*; - -import static com.sun.tools.javac.parser.Token.*; - -/** The parser maps a token sequence into an abstract syntax - * tree. It operates by recursive descent, with code derived - * systematically from an LL(1) grammar. For efficiency reasons, an - * operator precedence scheme is used for parsing binary operation - * expressions. - * - * <p><b>This is NOT part of any API supported by Sun Microsystems. If - * you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice.</b> - */ -public class Parser { - - /** A factory for creating parsers. */ - public static class Factory { - /** The context key for the parser factory. */ - protected static final Context.Key<Parser.Factory> parserFactoryKey = - new Context.Key<Parser.Factory>(); - - /** Get the Factory instance for this context. */ - public static Factory instance(Context context) { - Factory instance = context.get(parserFactoryKey); - if (instance == null) - instance = new Factory(context); - return instance; - } - - final TreeMaker F; - final Log log; - final Keywords keywords; - final Source source; - final Name.Table names; - final Options options; - - /** Create a new parser factory. */ - protected Factory(Context context) { - context.put(parserFactoryKey, this); - this.F = TreeMaker.instance(context); - this.log = Log.instance(context); - this.names = Name.Table.instance(context); - this.keywords = Keywords.instance(context); - this.source = Source.instance(context); - this.options = Options.instance(context); - } - - /** - * Create a new Parser. - * @param S Lexer for getting tokens while parsing - * @param keepDocComments true if javadoc comments should be kept - * @param genEndPos true if end positions should be generated - */ - public Parser newParser(Lexer S, boolean keepDocComments, boolean genEndPos) { - if (!genEndPos) - return new Parser(this, S, keepDocComments); - else - return new EndPosParser(this, S, keepDocComments); - } - } - - /** The number of precedence levels of infix operators. - */ - private static final int infixPrecedenceLevels = 10; - - /** The scanner used for lexical analysis. - */ - private Lexer S; - - /** The factory to be used for abstract syntax tree construction. - */ - protected TreeMaker F; - - /** The log to be used for error diagnostics. - */ - private Log log; - - /** The keyword table. */ - private Keywords keywords; - - /** The Source language setting. */ - private Source source; - - /** The name table. */ - private Name.Table names; - - /** Construct a parser from a given scanner, tree factory and log. - */ - protected Parser(Factory fac, - Lexer S, - boolean keepDocComments) { - this.S = S; - S.nextToken(); // prime the pump - this.F = fac.F; - this.log = fac.log; - this.names = fac.names; - this.keywords = fac.keywords; - this.source = fac.source; - Options options = fac.options; - this.allowGenerics = source.allowGenerics(); - this.allowVarargs = source.allowVarargs(); - this.allowAsserts = source.allowAsserts(); - this.allowEnums = source.allowEnums(); - this.allowForeach = source.allowForeach(); - this.allowStaticImport = source.allowStaticImport(); - this.allowAnnotations = source.allowAnnotations(); - this.keepDocComments = keepDocComments; - if (keepDocComments) docComments = new HashMap<JCTree,String>(); - this.errorTree = F.Erroneous(); - } - - /** Switch: Should generics be recognized? - */ - boolean allowGenerics; - - /** Switch: Should varargs be recognized? - */ - boolean allowVarargs; - - /** Switch: should we recognize assert statements, or just give a warning? - */ - boolean allowAsserts; - - /** Switch: should we recognize enums, or just give a warning? - */ - boolean allowEnums; - - /** Switch: should we recognize foreach? - */ - boolean allowForeach; - - /** Switch: should we recognize foreach? - */ - boolean allowStaticImport; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCStatement; - /** Switch: should we recognize annotations? - */ - boolean allowAnnotations; - - /** Switch: should we keep docComments? - */ - boolean keepDocComments; - - /** When terms are parsed, the mode determines which is expected: - * mode = EXPR : an expression - * mode = TYPE : a type - * mode = NOPARAMS : no parameters allowed for type - * mode = TYPEARG : type argument - */ - static final int EXPR = 1; - static final int TYPE = 2; - static final int NOPARAMS = 4; - static final int TYPEARG = 8; - - /** The current mode. - */ - private int mode = 0; - - /** The mode of the term that was parsed last. - */ - private int lastmode = 0; - -/* ---------- error recovery -------------- */ - - private JCErroneous errorTree; - - /** Skip forward until a suitable stop token is found. - */ - private void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) { - while (true) { - switch (S.token()) { - case SEMI: - S.nextToken(); - return; - case PUBLIC: - case FINAL: - case ABSTRACT: - case MONKEYS_AT: - case EOF: - case CLASS: - case INTERFACE: - case ENUM: - return; - case IMPORT: - if (stopAtImport) - return; - break; - case LBRACE: - case RBRACE: - case PRIVATE: - case PROTECTED: - case STATIC: - case TRANSIENT: - case NATIVE: - case VOLATILE: - case SYNCHRONIZED: - case STRICTFP: - case LT: - case BYTE: - case SHORT: - case CHAR: - case INT: - case LONG: - case FLOAT: - case DOUBLE: - case BOOLEAN: - case VOID: - if (stopAtMemberDecl) - return; - break; - case IDENTIFIER: - if (stopAtIdentifier) - return; - break; - case CASE: - case DEFAULT: - case IF: - case FOR: - case WHILE: - case DO: - case TRY: - case SWITCH: - case RETURN: - case THROW: - case BREAK: - case CONTINUE: - case ELSE: - case FINALLY: - case CATCH: - if (stopAtStatement) - return; - break; - } - S.nextToken(); - } - } - - private JCErroneous syntaxError(int pos, String key, Token... args) { - return syntaxError(pos, null, key, args); - } - - private JCErroneous syntaxError(int pos, List<JCTree> errs, String key, Token... args) { - setErrorEndPos(pos); - reportSyntaxError(pos, key, (Object[])args); - return toP(F.at(pos).Erroneous(errs)); - } - - private int errorPos = Position.NOPOS; +/** + * Reads syntactic units from source code. + * Parsers are normally created from a ParserFactory. + * + * <p><b>This is NOT part of any API supported by Sun Microsystems. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public interface Parser { /** - * Report a syntax error at given position using the given - * argument unless one was already reported at the same position. - */ - private void reportSyntaxError(int pos, String key, Object... args) { - if (pos > S.errPos() || pos == Position.NOPOS) { - if (S.token() == EOF) - log.error(pos, "premature.eof"); - else - log.error(pos, key, args); - } - S.errPos(pos); - if (S.pos() == errorPos) - S.nextToken(); // guarantee progress - errorPos = S.pos(); - } - - - /** Generate a syntax error at current position unless one was already - * reported at the same position. - */ - private JCErroneous syntaxError(String key) { - return syntaxError(S.pos(), key); - } - - /** Generate a syntax error at current position unless one was - * already reported at the same position. - */ - private JCErroneous syntaxError(String key, Token arg) { - return syntaxError(S.pos(), key, arg); - } - - /** If next input token matches given token, skip it, otherwise report - * an error. + * Parse a compilation unit. + * @return a compilation unit */ - public void accept(Token token) { - if (S.token() == token) { - S.nextToken(); - } else { - setErrorEndPos(S.pos()); - reportSyntaxError(S.prevEndPos(), "expected", token); - } - } - - /** Report an illegal start of expression/type error at given position. - */ - JCExpression illegal(int pos) { - setErrorEndPos(S.pos()); - if ((mode & EXPR) != 0) - return syntaxError(pos, "illegal.start.of.expr"); - else - return syntaxError(pos, "illegal.start.of.type"); - - } - - /** Report an illegal start of expression/type error at current position. - */ - JCExpression illegal() { - return illegal(S.pos()); - } - - /** Diagnose a modifier flag from the set, if any. */ - void checkNoMods(long mods) { - if (mods != 0) { - long lowestMod = mods & -mods; - log.error(S.pos(), "mod.not.allowed.here", - Flags.asFlagSet(lowestMod)); - } - } - -/* ---------- doc comments --------- */ - - /** A hashtable to store all documentation comments - * indexed by the tree nodes they refer to. - * defined only if option flag keepDocComment is set. - */ - Map<JCTree, String> docComments; - - /** Make an entry into docComments hashtable, - * provided flag keepDocComments is set and given doc comment is non-null. - * @param tree The tree to be used as index in the hashtable - * @param dc The doc comment to associate with the tree, or null. - */ - void attach(JCTree tree, String dc) { - if (keepDocComments && dc != null) { -// System.out.println("doc comment = ");System.out.println(dc);//DEBUG - docComments.put(tree, dc); - } - } - -/* -------- source positions ------- */ - - private int errorEndPos = -1; - - private void setErrorEndPos(int errPos) { - if (errPos > errorEndPos) - errorEndPos = errPos; - } - - protected int getErrorEndPos() { - return errorEndPos; - } - - /** - * Store ending position for a tree. - * @param tree The tree. - * @param endpos The ending position to associate with the tree. - */ - protected void storeEnd(JCTree tree, int endpos) {} - - /** - * Store ending position for a tree. The ending position should - * be the ending position of the current token. - * @param t The tree. - */ - protected <T extends JCTree> T to(T t) { return t; } - - /** - * Store ending position for a tree. The ending position should - * be greater of the ending position of the previous token and errorEndPos. - * @param t The tree. - */ - protected <T extends JCTree> T toP(T t) { return t; } - - /** Get the start position for a tree node. The start position is - * defined to be the position of the first character of the first - * token of the node's source text. - * @param tree The tree node - */ - public int getStartPos(JCTree tree) { - return TreeInfo.getStartPos(tree); - } - - /** - * Get the end position for a tree node. The end position is - * defined to be the position of the last character of the last - * token of the node's source text. Returns Position.NOPOS if end - * positions are not generated or the position is otherwise not - * found. - * @param tree The tree node - */ - public int getEndPos(JCTree tree) { - return Position.NOPOS; - } - - - -/* ---------- parsing -------------- */ - - /** - * Ident = IDENTIFIER - */ - Name ident() { - if (S.token() == IDENTIFIER) { - Name name = S.name(); - S.nextToken(); - return name; - } else if (S.token() == ASSERT) { - if (allowAsserts) { - log.error(S.pos(), "assert.as.identifier"); - S.nextToken(); - return names.error; - } else { - log.warning(S.pos(), "assert.as.identifier"); - Name name = S.name(); - S.nextToken(); - return name; - } - } else if (S.token() == ENUM) { - if (allowEnums) { - log.error(S.pos(), "enum.as.identifier"); - S.nextToken(); - return names.error; - } else { - log.warning(S.pos(), "enum.as.identifier"); - Name name = S.name(); - S.nextToken(); - return name; - } - } else { - accept(IDENTIFIER); - return names.error; - } -} - - /** - * Qualident = Ident { DOT Ident } - */ - public JCExpression qualident() { - JCExpression t = toP(F.at(S.pos()).Ident(ident())); - while (S.token() == DOT) { - int pos = S.pos(); - S.nextToken(); - t = toP(F.at(pos).Select(t, ident())); - } - return t; - } - - /** - * Literal = - * INTLITERAL - * | LONGLITERAL - * | FLOATLITERAL - * | DOUBLELITERAL - * | CHARLITERAL - * | STRINGLITERAL - * | TRUE - * | FALSE - * | NULL - */ - JCExpression literal(Name prefix) { - int pos = S.pos(); - JCExpression t = errorTree; - switch (S.token()) { - case INTLITERAL: - try { - t = F.at(pos).Literal( - TypeTags.INT, - Convert.string2int(strval(prefix), S.radix())); - } catch (NumberFormatException ex) { - log.error(S.pos(), "int.number.too.large", strval(prefix)); - } - break; - case LONGLITERAL: - try { - t = F.at(pos).Literal( - TypeTags.LONG, - new Long(Convert.string2long(strval(prefix), S.radix()))); - } catch (NumberFormatException ex) { - log.error(S.pos(), "int.number.too.large", strval(prefix)); - } - break; - case FLOATLITERAL: { - String proper = (S.radix() == 16 ? ("0x"+ S.stringVal()) : S.stringVal()); - Float n; - try { - n = Float.valueOf(proper); - } catch (NumberFormatException ex) { - // error already repoted in scanner - n = Float.NaN; - } - if (n.floatValue() == 0.0f && !isZero(proper)) - log.error(S.pos(), "fp.number.too.small"); - else if (n.floatValue() == Float.POSITIVE_INFINITY) - log.error(S.pos(), "fp.number.too.large"); - else - t = F.at(pos).Literal(TypeTags.FLOAT, n); - break; - } - case DOUBLELITERAL: { - String proper = (S.radix() == 16 ? ("0x"+ S.stringVal()) : S.stringVal()); - Double n; - try { - n = Double.valueOf(proper); - } catch (NumberFormatException ex) { - // error already reported in scanner - n = Double.NaN; - } - if (n.doubleValue() == 0.0d && !isZero(proper)) - log.error(S.pos(), "fp.number.too.small"); - else if (n.doubleValue() == Double.POSITIVE_INFINITY) - log.error(S.pos(), "fp.number.too.large"); - else - t = F.at(pos).Literal(TypeTags.DOUBLE, n); - break; - } - case CHARLITERAL: - t = F.at(pos).Literal( - TypeTags.CHAR, - S.stringVal().charAt(0) + 0); - break; - case STRINGLITERAL: - t = F.at(pos).Literal( - TypeTags.CLASS, - S.stringVal()); - break; - case TRUE: case FALSE: - t = F.at(pos).Literal( - TypeTags.BOOLEAN, - (S.token() == TRUE ? 1 : 0)); - break; - case NULL: - t = F.at(pos).Literal( - TypeTags.BOT, - null); - break; - default: - assert false; - } - if (t == errorTree) - t = F.at(pos).Erroneous(); - storeEnd(t, S.endPos()); - S.nextToken(); - return t; - } -//where - boolean isZero(String s) { - char[] cs = s.toCharArray(); - int base = ((Character.toLowerCase(s.charAt(1)) == 'x') ? 16 : 10); - int i = ((base==16) ? 2 : 0); - while (i < cs.length && (cs[i] == '0' || cs[i] == '.')) i++; - return !(i < cs.length && (Character.digit(cs[i], base) > 0)); - } - - String strval(Name prefix) { - String s = S.stringVal(); - return (prefix.len == 0) ? s : prefix + s; - } - - /** terms can be either expressions or types. - */ - public JCExpression expression() { - return term(EXPR); - } - - public JCExpression type() { - return term(TYPE); - } - - JCExpression term(int newmode) { - int prevmode = mode; - mode = newmode; - JCExpression t = term(); - lastmode = mode; - mode = prevmode; - return t; - } + JCCompilationUnit parseCompilationUnit(); /** - * Expression = Expression1 [ExpressionRest] - * ExpressionRest = [AssignmentOperator Expression1] - * AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | - * "&=" | "|=" | "^=" | - * "%=" | "<<=" | ">>=" | ">>>=" - * Type = Type1 - * TypeNoParams = TypeNoParams1 - * StatementExpression = Expression - * ConstantExpression = Expression - */ - JCExpression term() { - JCExpression t = term1(); - if ((mode & EXPR) != 0 && - S.token() == EQ || PLUSEQ.compareTo(S.token()) <= 0 && S.token().compareTo(GTGTGTEQ) <= 0) - return termRest(t); - else - return t; - } - - JCExpression termRest(JCExpression t) { - switch (S.token()) { - case EQ: { - int pos = S.pos(); - S.nextToken(); - mode = EXPR; - JCExpression t1 = term(); - return toP(F.at(pos).Assign(t, t1)); - } - case PLUSEQ: - case SUBEQ: - case STAREQ: - case SLASHEQ: - case PERCENTEQ: - case AMPEQ: - case BAREQ: - case CARETEQ: - case LTLTEQ: - case GTGTEQ: - case GTGTGTEQ: - int pos = S.pos(); - Token token = S.token(); - S.nextToken(); - mode = EXPR; - JCExpression t1 = term(); - return F.at(pos).Assignop(optag(token), t, t1); - default: - return t; - } - } - - /** Expression1 = Expression2 [Expression1Rest] - * Type1 = Type2 - * TypeNoParams1 = TypeNoParams2 - */ - JCExpression term1() { - JCExpression t = term2(); - if ((mode & EXPR) != 0 && S.token() == QUES) { - mode = EXPR; - return term1Rest(t); - } else { - return t; - } - } - - /** Expression1Rest = ["?" Expression ":" Expression1] - */ - JCExpression term1Rest(JCExpression t) { - if (S.token() == QUES) { - int pos = S.pos(); - S.nextToken(); - JCExpression t1 = term(); - accept(COLON); - JCExpression t2 = term1(); - return F.at(pos).Conditional(t, t1, t2); - } else { - return t; - } - } - - /** Expression2 = Expression3 [Expression2Rest] - * Type2 = Type3 - * TypeNoParams2 = TypeNoParams3 - */ - JCExpression term2() { - JCExpression t = term3(); - if ((mode & EXPR) != 0 && prec(S.token()) >= TreeInfo.orPrec) { - mode = EXPR; - return term2Rest(t, TreeInfo.orPrec); - } else { - return t; - } - } - - /* Expression2Rest = {infixop Expression3} - * | Expression3 instanceof Type - * infixop = "||" - * | "&&" - * | "|" - * | "^" - * | "&" - * | "==" | "!=" - * | "<" | ">" | "<=" | ">=" - * | "<<" | ">>" | ">>>" - * | "+" | "-" - * | "*" | "/" | "%" - */ - JCExpression term2Rest(JCExpression t, int minprec) { - List<JCExpression[]> savedOd = odStackSupply.elems; - JCExpression[] odStack = newOdStack(); - List<Token[]> savedOp = opStackSupply.elems; - Token[] opStack = newOpStack(); - // optimization, was odStack = new Tree[...]; opStack = new Tree[...]; - int top = 0; - odStack[0] = t; - int startPos = S.pos(); - Token topOp = ERROR; - while (prec(S.token()) >= minprec) { - opStack[top] = topOp; - top++; - topOp = S.token(); - int pos = S.pos(); - S.nextToken(); - odStack[top] = topOp == INSTANCEOF ? type() : term3(); - while (top > 0 && prec(topOp) >= prec(S.token())) { - odStack[top-1] = makeOp(pos, topOp, odStack[top-1], - odStack[top]); - top--; - topOp = opStack[top]; - } - } - assert top == 0; - t = odStack[0]; - - if (t.getTag() == JCTree.PLUS) { - StringBuffer buf = foldStrings(t); - if (buf != null) { - t = toP(F.at(startPos).Literal(TypeTags.CLASS, buf.toString())); - } - } - - odStackSupply.elems = savedOd; // optimization - opStackSupply.elems = savedOp; // optimization - return t; - } -//where - /** Construct a binary or type test node. - */ - private JCExpression makeOp(int pos, - Token topOp, - JCExpression od1, - JCExpression od2) - { - if (topOp == INSTANCEOF) { - return F.at(pos).TypeTest(od1, od2); - } else { - return F.at(pos).Binary(optag(topOp), od1, od2); - } - } - /** If tree is a concatenation of string literals, replace it - * by a single literal representing the concatenated string. - */ - protected StringBuffer foldStrings(JCTree tree) { - List<String> buf = List.nil(); - while (true) { - if (tree.getTag() == JCTree.LITERAL) { - JCLiteral lit = (JCLiteral) tree; - if (lit.typetag == TypeTags.CLASS) { - StringBuffer sbuf = - new StringBuffer((String)lit.value); - while (buf.nonEmpty()) { - sbuf.append(buf.head); - buf = buf.tail; - } - return sbuf; - } - } else if (tree.getTag() == JCTree.PLUS) { - JCBinary op = (JCBinary)tree; - if (op.rhs.getTag() == JCTree.LITERAL) { - JCLiteral lit = (JCLiteral) op.rhs; - if (lit.typetag == TypeTags.CLASS) { - buf = buf.prepend((String) lit.value); - tree = op.lhs; - continue; - } - } - } - return null; - } - } - - /** optimization: To save allocating a new operand/operator stack - * for every binary operation, we use supplys. - */ - ListBuffer<JCExpression[]> odStackSupply = new ListBuffer<JCExpression[]>(); - ListBuffer<Token[]> opStackSupply = new ListBuffer<Token[]>(); - - private JCExpression[] newOdStack() { - if (odStackSupply.elems == odStackSupply.last) - odStackSupply.append(new JCExpression[infixPrecedenceLevels + 1]); - JCExpression[] odStack = odStackSupply.elems.head; - odStackSupply.elems = odStackSupply.elems.tail; - return odStack; - } - - private Token[] newOpStack() { - if (opStackSupply.elems == opStackSupply.last) - opStackSupply.append(new Token[infixPrecedenceLevels + 1]); - Token[] opStack = opStackSupply.elems.head; - opStackSupply.elems = opStackSupply.elems.tail; - return opStack; - } - - /** Expression3 = PrefixOp Expression3 - * | "(" Expr | TypeNoParams ")" Expression3 - * | Primary {Selector} {PostfixOp} - * Primary = "(" Expression ")" - * | Literal - * | [TypeArguments] THIS [Arguments] - * | [TypeArguments] SUPER SuperSuffix - * | NEW [TypeArguments] Creator - * | Ident { "." Ident } - * [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" ) - * | Arguments - * | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator ) - * ] - * | BasicType BracketsOpt "." CLASS - * PrefixOp = "++" | "--" | "!" | "~" | "+" | "-" - * PostfixOp = "++" | "--" - * Type3 = Ident { "." Ident } [TypeArguments] {TypeSelector} BracketsOpt - * | BasicType - * TypeNoParams3 = Ident { "." Ident } BracketsOpt - * Selector = "." [TypeArguments] Ident [Arguments] - * | "." THIS - * | "." [TypeArguments] SUPER SuperSuffix - * | "." NEW [TypeArguments] InnerCreator - * | "[" Expression "]" - * TypeSelector = "." Ident [TypeArguments] - * SuperSuffix = Arguments | "." Ident [Arguments] + * Parse an expression. + * @return an expression */ - protected JCExpression term3() { - int pos = S.pos(); - JCExpression t; - List<JCExpression> typeArgs = typeArgumentsOpt(EXPR); - switch (S.token()) { - case QUES: - if ((mode & TYPE) != 0 && (mode & (TYPEARG|NOPARAMS)) == TYPEARG) { - mode = TYPE; - return typeArgument(); - } else - return illegal(); - case PLUSPLUS: case SUBSUB: case BANG: case TILDE: case PLUS: case SUB: - if (typeArgs == null && (mode & EXPR) != 0) { - Token token = S.token(); - S.nextToken(); - mode = EXPR; - if (token == SUB && - (S.token() == INTLITERAL || S.token() == LONGLITERAL) && - S.radix() == 10) { - mode = EXPR; - t = literal(names.hyphen); - } else { - t = term3(); - return F.at(pos).Unary(unoptag(token), t); - } - } else return illegal(); - break; - case LPAREN: - if (typeArgs == null && (mode & EXPR) != 0) { - S.nextToken(); - mode = EXPR | TYPE | NOPARAMS; - t = term3(); - if ((mode & TYPE) != 0 && S.token() == LT) { - // Could be a cast to a parameterized type - int op = JCTree.LT; - int pos1 = S.pos(); - S.nextToken(); - mode &= (EXPR | TYPE); - mode |= TYPEARG; - JCExpression t1 = term3(); - if ((mode & TYPE) != 0 && - (S.token() == COMMA || S.token() == GT)) { - mode = TYPE; - ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); - args.append(t1); - while (S.token() == COMMA) { - S.nextToken(); - args.append(typeArgument()); - } - accept(GT); - t = F.at(pos1).TypeApply(t, args.toList()); - checkGenerics(); - t = bracketsOpt(toP(t)); - } else if ((mode & EXPR) != 0) { - mode = EXPR; - t = F.at(pos1).Binary(op, t, term2Rest(t1, TreeInfo.shiftPrec)); - t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec))); - } else { - accept(GT); - } - } else { - t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec))); - } - accept(RPAREN); - lastmode = mode; - mode = EXPR; - if ((lastmode & EXPR) == 0) { - JCExpression t1 = term3(); - return F.at(pos).TypeCast(t, t1); - } else if ((lastmode & TYPE) != 0) { - switch (S.token()) { - /*case PLUSPLUS: case SUBSUB: */ - case BANG: case TILDE: - case LPAREN: case THIS: case SUPER: - case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: - case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL: - case TRUE: case FALSE: case NULL: - case NEW: case IDENTIFIER: case ASSERT: case ENUM: - case BYTE: case SHORT: case CHAR: case INT: - case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: - JCExpression t1 = term3(); - return F.at(pos).TypeCast(t, t1); - } - } - } else return illegal(); - t = toP(F.at(pos).Parens(t)); - break; - case THIS: - if ((mode & EXPR) != 0) { - mode = EXPR; - t = to(F.at(pos).Ident(names._this)); - S.nextToken(); - if (typeArgs == null) - t = argumentsOpt(null, t); - else - t = arguments(typeArgs, t); - typeArgs = null; - } else return illegal(); - break; - case SUPER: - if ((mode & EXPR) != 0) { - mode = EXPR; - t = to(superSuffix(typeArgs, F.at(pos).Ident(names._super))); - typeArgs = null; - } else return illegal(); - break; - case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL: - case CHARLITERAL: case STRINGLITERAL: - case TRUE: case FALSE: case NULL: - if (typeArgs == null && (mode & EXPR) != 0) { - mode = EXPR; - t = literal(names.empty); - } else return illegal(); - break; - case NEW: - if (typeArgs != null) return illegal(); - if ((mode & EXPR) != 0) { - mode = EXPR; - S.nextToken(); - if (S.token() == LT) typeArgs = typeArguments(); - t = creator(pos, typeArgs); - typeArgs = null; - } else return illegal(); - break; - case IDENTIFIER: case ASSERT: case ENUM: - if (typeArgs != null) return illegal(); - t = toP(F.at(S.pos()).Ident(ident())); - loop: while (true) { - pos = S.pos(); - switch (S.token()) { - case LBRACKET: - S.nextToken(); - if (S.token() == RBRACKET) { - S.nextToken(); - t = bracketsOpt(t); - t = toP(F.at(pos).TypeArray(t)); - t = bracketsSuffix(t); - } else { - if ((mode & EXPR) != 0) { - mode = EXPR; - JCExpression t1 = term(); - t = to(F.at(pos).Indexed(t, t1)); - } - accept(RBRACKET); - } - break loop; - case LPAREN: - if ((mode & EXPR) != 0) { - mode = EXPR; - t = arguments(typeArgs, t); - typeArgs = null; - } - break loop; - case DOT: - S.nextToken(); - int oldmode = mode; - mode &= ~NOPARAMS; - typeArgs = typeArgumentsOpt(EXPR); - mode = oldmode; - if ((mode & EXPR) != 0) { - switch (S.token()) { - case CLASS: - if (typeArgs != null) return illegal(); - mode = EXPR; - t = to(F.at(pos).Select(t, names._class)); - S.nextToken(); - break loop; - case THIS: - if (typeArgs != null) return illegal(); - mode = EXPR; - t = to(F.at(pos).Select(t, names._this)); - S.nextToken(); - break loop; - case SUPER: - mode = EXPR; - t = to(F.at(pos).Select(t, names._super)); - t = superSuffix(typeArgs, t); - typeArgs = null; - break loop; - case NEW: - if (typeArgs != null) return illegal(); - mode = EXPR; - int pos1 = S.pos(); - S.nextToken(); - if (S.token() == LT) typeArgs = typeArguments(); - t = innerCreator(pos1, typeArgs, t); - typeArgs = null; - break loop; - } - } - // typeArgs saved for next loop iteration. - t = toP(F.at(pos).Select(t, ident())); - break; - default: - break loop; - } - } - if (typeArgs != null) illegal(); - t = typeArgumentsOpt(t); - break; - case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT: - case DOUBLE: case BOOLEAN: - if (typeArgs != null) illegal(); - t = bracketsSuffix(bracketsOpt(basicType())); - break; - case VOID: - if (typeArgs != null) illegal(); - if ((mode & EXPR) != 0) { - S.nextToken(); - if (S.token() == DOT) { - JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTags.VOID)); - t = bracketsSuffix(ti); - } else { - return illegal(pos); - } - } else { - return illegal(); - } - break; - default: - return illegal(); - } - if (typeArgs != null) illegal(); - while (true) { - int pos1 = S.pos(); - if (S.token() == LBRACKET) { - S.nextToken(); - if ((mode & TYPE) != 0) { - int oldmode = mode; - mode = TYPE; - if (S.token() == RBRACKET) { - S.nextToken(); - t = bracketsOpt(t); - t = toP(F.at(pos1).TypeArray(t)); - return t; - } - mode = oldmode; - } - if ((mode & EXPR) != 0) { - mode = EXPR; - JCExpression t1 = term(); - t = to(F.at(pos1).Indexed(t, t1)); - } - accept(RBRACKET); - } else if (S.token() == DOT) { - S.nextToken(); - typeArgs = typeArgumentsOpt(EXPR); - if (S.token() == SUPER && (mode & EXPR) != 0) { - mode = EXPR; - t = to(F.at(pos1).Select(t, names._super)); - S.nextToken(); - t = arguments(typeArgs, t); - typeArgs = null; - } else if (S.token() == NEW && (mode & EXPR) != 0) { - if (typeArgs != null) return illegal(); - mode = EXPR; - int pos2 = S.pos(); - S.nextToken(); - if (S.token() == LT) typeArgs = typeArguments(); - t = innerCreator(pos2, typeArgs, t); - typeArgs = null; - } else { - t = toP(F.at(pos1).Select(t, ident())); - t = argumentsOpt(typeArgs, typeArgumentsOpt(t)); - typeArgs = null; - } - } else { - break; - } - } - while ((S.token() == PLUSPLUS || S.token() == SUBSUB) && (mode & EXPR) != 0) { - mode = EXPR; - t = to(F.at(S.pos()).Unary( - S.token() == PLUSPLUS ? JCTree.POSTINC : JCTree.POSTDEC, t)); - S.nextToken(); - } - return toP(t); - } - - /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments] - */ - JCExpression superSuffix(List<JCExpression> typeArgs, JCExpression t) { - S.nextToken(); - if (S.token() == LPAREN || typeArgs != null) { - t = arguments(typeArgs, t); - } else { - int pos = S.pos(); - accept(DOT); - typeArgs = (S.token() == LT) ? typeArguments() : null; - t = toP(F.at(pos).Select(t, ident())); - t = argumentsOpt(typeArgs, t); - } - return t; - } - - /** BasicType = BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE | BOOLEAN - */ - JCPrimitiveTypeTree basicType() { - JCPrimitiveTypeTree t = to(F.at(S.pos()).TypeIdent(typetag(S.token()))); - S.nextToken(); - return t; - } - - /** ArgumentsOpt = [ Arguments ] - */ - JCExpression argumentsOpt(List<JCExpression> typeArgs, JCExpression t) { - if ((mode & EXPR) != 0 && S.token() == LPAREN || typeArgs != null) { - mode = EXPR; - return arguments(typeArgs, t); - } else { - return t; - } - } - - /** Arguments = "(" [Expression { COMMA Expression }] ")" - */ - List<JCExpression> arguments() { - ListBuffer<JCExpression> args = lb(); - if (S.token() == LPAREN) { - S.nextToken(); - if (S.token() != RPAREN) { - args.append(expression()); - while (S.token() == COMMA) { - S.nextToken(); - args.append(expression()); - } - } - accept(RPAREN); - } else { - syntaxError(S.pos(), "expected", LPAREN); - } - return args.toList(); - } - - JCMethodInvocation arguments(List<JCExpression> typeArgs, JCExpression t) { - int pos = S.pos(); - List<JCExpression> args = arguments(); - return toP(F.at(pos).Apply(typeArgs, t, args)); - } - - /** TypeArgumentsOpt = [ TypeArguments ] - */ - JCExpression typeArgumentsOpt(JCExpression t) { - if (S.token() == LT && - (mode & TYPE) != 0 && - (mode & NOPARAMS) == 0) { - mode = TYPE; - checkGenerics(); - return typeArguments(t); - } else { - return t; - } - } - List<JCExpression> typeArgumentsOpt() { - return typeArgumentsOpt(TYPE); - } - - List<JCExpression> typeArgumentsOpt(int useMode) { - if (S.token() == LT) { - checkGenerics(); - if ((mode & useMode) == 0 || - (mode & NOPARAMS) != 0) { - illegal(); - } - mode = useMode; - return typeArguments(); - } - return null; - } + JCExpression parseExpression(); - /** TypeArguments = "<" TypeArgument {"," TypeArgument} ">" - */ - List<JCExpression> typeArguments() { - ListBuffer<JCExpression> args = lb(); - if (S.token() == LT) { - S.nextToken(); - args.append(((mode & EXPR) == 0) ? typeArgument() : type()); - while (S.token() == COMMA) { - S.nextToken(); - args.append(((mode & EXPR) == 0) ? typeArgument() : type()); - } - switch (S.token()) { - case GTGTGTEQ: - S.token(GTGTEQ); - break; - case GTGTEQ: - S.token(GTEQ); - break; - case GTEQ: - S.token(EQ); - break; - case GTGTGT: - S.token(GTGT); - break; - case GTGT: - S.token(GT); - break; - default: - accept(GT); - break; - } - } else { - syntaxError(S.pos(), "expected", LT); - } - return args.toList(); - } - - /** TypeArgument = Type - * | "?" - * | "?" EXTENDS Type {"&" Type} - * | "?" SUPER Type - */ - JCExpression typeArgument() { - if (S.token() != QUES) return type(); - int pos = S.pos(); - S.nextToken(); - if (S.token() == EXTENDS) { - TypeBoundKind t = to(F.at(S.pos()).TypeBoundKind(BoundKind.EXTENDS)); - S.nextToken(); - return F.at(pos).Wildcard(t, type()); - } else if (S.token() == SUPER) { - TypeBoundKind t = to(F.at(S.pos()).TypeBoundKind(BoundKind.SUPER)); - S.nextToken(); - return F.at(pos).Wildcard(t, type()); - } else if (S.token() == IDENTIFIER) { - //error recovery - reportSyntaxError(S.prevEndPos(), "expected3", - GT, EXTENDS, SUPER); - TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND); - JCExpression wc = toP(F.at(pos).Wildcard(t, null)); - JCIdent id = toP(F.at(S.pos()).Ident(ident())); - return F.at(pos).Erroneous(List.<JCTree>of(wc, id)); - } else { - TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND); - return toP(F.at(pos).Wildcard(t, null)); - } - } - - JCTypeApply typeArguments(JCExpression t) { - int pos = S.pos(); - List<JCExpression> args = typeArguments(); - return toP(F.at(pos).TypeApply(t, args)); - } - - /** BracketsOpt = {"[" "]"} - */ - private JCExpression bracketsOpt(JCExpression t) { - if (S.token() == LBRACKET) { - int pos = S.pos(); - S.nextToken(); - t = bracketsOptCont(t, pos); - F.at(pos); - } - return t; - } - - private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos) { - accept(RBRACKET); - t = bracketsOpt(t); - return toP(F.at(pos).TypeArray(t)); - } - - /** BracketsSuffixExpr = "." CLASS - * BracketsSuffixType = - */ - JCExpression bracketsSuffix(JCExpression t) { - if ((mode & EXPR) != 0 && S.token() == DOT) { - mode = EXPR; - int pos = S.pos(); - S.nextToken(); - accept(CLASS); - if (S.pos() == errorEndPos) { - // error recovery - Name name = null; - if (S.token() == IDENTIFIER) { - name = S.name(); - S.nextToken(); - } else { - name = names.error; - } - t = F.at(pos).Erroneous(List.<JCTree>of(toP(F.at(pos).Select(t, name)))); - } else { - t = toP(F.at(pos).Select(t, names._class)); - } - } else if ((mode & TYPE) != 0) { - mode = TYPE; - } else { - syntaxError(S.pos(), "dot.class.expected"); - } - return t; - } - - /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest ) - */ - JCExpression creator(int newpos, List<JCExpression> typeArgs) { - switch (S.token()) { - case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT: - case DOUBLE: case BOOLEAN: - if (typeArgs == null) - return arrayCreatorRest(newpos, basicType()); - break; - default: - } - JCExpression t = qualident(); - int oldmode = mode; - mode = TYPE; - if (S.token() == LT) { - checkGenerics(); - t = typeArguments(t); - } - while (S.token() == DOT) { - int pos = S.pos(); - S.nextToken(); - t = toP(F.at(pos).Select(t, ident())); - if (S.token() == LT) { - checkGenerics(); - t = typeArguments(t); - } - } - mode = oldmode; - if (S.token() == LBRACKET) { - JCExpression e = arrayCreatorRest(newpos, t); - if (typeArgs != null) { - int pos = newpos; - if (!typeArgs.isEmpty() && typeArgs.head.pos != Position.NOPOS) { - // note: this should always happen but we should - // not rely on this as the parser is continuously - // modified to improve error recovery. - pos = typeArgs.head.pos; - } - setErrorEndPos(S.prevEndPos()); - reportSyntaxError(pos, "cannot.create.array.with.type.arguments"); - return toP(F.at(newpos).Erroneous(typeArgs.prepend(e))); - } - return e; - } else if (S.token() == LPAREN) { - return classCreatorRest(newpos, null, typeArgs, t); - } else { - reportSyntaxError(S.pos(), "expected2", - LPAREN, LBRACKET); - t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.<JCExpression>nil(), null)); - return toP(F.at(newpos).Erroneous(List.<JCTree>of(t))); - } - } - - /** InnerCreator = Ident [TypeArguments] ClassCreatorRest - */ - JCExpression innerCreator(int newpos, List<JCExpression> typeArgs, JCExpression encl) { - JCExpression t = toP(F.at(S.pos()).Ident(ident())); - if (S.token() == LT) { - checkGenerics(); - t = typeArguments(t); - } - return classCreatorRest(newpos, encl, typeArgs, t); - } - - /** ArrayCreatorRest = "[" ( "]" BracketsOpt ArrayInitializer - * | Expression "]" {"[" Expression "]"} BracketsOpt ) - */ - JCExpression arrayCreatorRest(int newpos, JCExpression elemtype) { - accept(LBRACKET); - if (S.token() == RBRACKET) { - accept(RBRACKET); - elemtype = bracketsOpt(elemtype); - if (S.token() == LBRACE) { - return arrayInitializer(newpos, elemtype); - } else { - return syntaxError(S.pos(), "array.dimension.missing"); - } - } else { - ListBuffer<JCExpression> dims = new ListBuffer<JCExpression>(); - dims.append(expression()); - accept(RBRACKET); - while (S.token() == LBRACKET) { - int pos = S.pos(); - S.nextToken(); - if (S.token() == RBRACKET) { - elemtype = bracketsOptCont(elemtype, pos); - } else { - dims.append(expression()); - accept(RBRACKET); - } - } - return toP(F.at(newpos).NewArray(elemtype, dims.toList(), null)); - } - } - - /** ClassCreatorRest = Arguments [ClassBody] - */ - JCExpression classCreatorRest(int newpos, - JCExpression encl, - List<JCExpression> typeArgs, - JCExpression t) - { - List<JCExpression> args = arguments(); - JCClassDecl body = null; - if (S.token() == LBRACE) { - int pos = S.pos(); - List<JCTree> defs = classOrInterfaceBody(names.empty, false); - JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); - body = toP(F.at(pos).AnonymousClassDef(mods, defs)); - } - return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body)); - } - - /** ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}" - */ - JCExpression arrayInitializer(int newpos, JCExpression t) { - accept(LBRACE); - ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>(); - if (S.token() == COMMA) { - S.nextToken(); - } else if (S.token() != RBRACE) { - elems.append(variableInitializer()); - while (S.token() == COMMA) { - S.nextToken(); - if (S.token() == RBRACE) break; - elems.append(variableInitializer()); - } - } - accept(RBRACE); - return toP(F.at(newpos).NewArray(t, List.<JCExpression>nil(), elems.toList())); - } - - /** VariableInitializer = ArrayInitializer | Expression - */ - public JCExpression variableInitializer() { - return S.token() == LBRACE ? arrayInitializer(S.pos(), null) : expression(); - } - - /** ParExpression = "(" Expression ")" - */ - JCExpression parExpression() { - accept(LPAREN); - JCExpression t = expression(); - accept(RPAREN); - return t; - } - - /** Block = "{" BlockStatements "}" - */ - JCBlock block(int pos, long flags) { - accept(LBRACE); - List<JCStatement> stats = blockStatements(); - JCBlock t = F.at(pos).Block(flags, stats); - while (S.token() == CASE || S.token() == DEFAULT) { - syntaxError("orphaned", S.token()); - switchBlockStatementGroups(); - } - // the Block node has a field "endpos" for first char of last token, which is - // usually but not necessarily the last char of the last token. - t.endpos = S.pos(); - accept(RBRACE); - return toP(t); - } - - public JCBlock block() { - return block(S.pos(), 0); - } - - /** BlockStatements = { BlockStatement } - * BlockStatement = LocalVariableDeclarationStatement - * | ClassOrInterfaceOrEnumDeclaration - * | [Ident ":"] Statement - * LocalVariableDeclarationStatement - * = { FINAL | '@' Annotation } Type VariableDeclarators ";" - */ - @SuppressWarnings("fallthrough") - List<JCStatement> blockStatements() { -//todo: skip to anchor on error(?) - int lastErrPos = -1; - ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>(); - while (true) { - int pos = S.pos(); - switch (S.token()) { - case RBRACE: case CASE: case DEFAULT: case EOF: - return stats.toList(); - case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY: - case SWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK: - case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH: - stats.append(statement()); - break; - case MONKEYS_AT: - case FINAL: { - String dc = S.docComment(); - JCModifiers mods = modifiersOpt(); - if (S.token() == INTERFACE || - S.token() == CLASS || - allowEnums && S.token() == ENUM) { - stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); - } else { - JCExpression t = type(); - stats.appendList(variableDeclarators(mods, t, - new ListBuffer<JCStatement>())); - // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon - storeEnd(stats.elems.last(), S.endPos()); - accept(SEMI); - } - break; - } - case ABSTRACT: case STRICTFP: { - String dc = S.docComment(); - JCModifiers mods = modifiersOpt(); - stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); - break; - } - case INTERFACE: - case CLASS: - stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), - S.docComment())); - break; - case ENUM: - case ASSERT: - if (allowEnums && S.token() == ENUM) { - log.error(S.pos(), "local.enum"); - stats. - append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), - S.docComment())); - break; - } else if (allowAsserts && S.token() == ASSERT) { - stats.append(statement()); - break; - } - /* fall through to default */ - default: - Name name = S.name(); - JCExpression t = term(EXPR | TYPE); - if (S.token() == COLON && t.getTag() == JCTree.IDENT) { - S.nextToken(); - JCStatement stat = statement(); - stats.append(F.at(pos).Labelled(name, stat)); - } else if ((lastmode & TYPE) != 0 && - (S.token() == IDENTIFIER || - S.token() == ASSERT || - S.token() == ENUM)) { - pos = S.pos(); - JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); - F.at(pos); - stats.appendList(variableDeclarators(mods, t, - new ListBuffer<JCStatement>())); - // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon - storeEnd(stats.elems.last(), S.endPos()); - accept(SEMI); - } else { - // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon - stats.append(to(F.at(pos).Exec(checkExprStat(t)))); - accept(SEMI); - } - } - - // error recovery - if (S.pos() == lastErrPos) - return stats.toList(); - if (S.pos() <= errorEndPos) { - skip(false, true, true, true); - lastErrPos = S.pos(); - } - - // ensure no dangling /** @deprecated */ active - S.resetDeprecatedFlag(); - } - } - - /** Statement = - * Block - * | IF ParExpression Statement [ELSE Statement] - * | FOR "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement - * | FOR "(" FormalParameter : Expression ")" Statement - * | WHILE ParExpression Statement - * | DO Statement WHILE ParExpression ";" - * | TRY Block ( Catches | [Catches] FinallyPart ) - * | SWITCH ParExpression "{" SwitchBlockStatementGroups "}" - * | SYNCHRONIZED ParExpression Block - * | RETURN [Expression] ";" - * | THROW Expression ";" - * | BREAK [Ident] ";" - * | CONTINUE [Ident] ";" - * | ASSERT Expression [ ":" Expression ] ";" - * | ";" - * | ExpressionStatement - * | Ident ":" Statement + /** + * Parse a statement. + * @return an expression */ - @SuppressWarnings("fallthrough") - public JCStatement statement() { - int pos = S.pos(); - switch (S.token()) { - case LBRACE: - return block(); - case IF: { - S.nextToken(); - JCExpression cond = parExpression(); - JCStatement thenpart = statement(); - JCStatement elsepart = null; - if (S.token() == ELSE) { - S.nextToken(); - elsepart = statement(); - } - return F.at(pos).If(cond, thenpart, elsepart); - } - case FOR: { - S.nextToken(); - accept(LPAREN); - List<JCStatement> inits = S.token() == SEMI ? List.<JCStatement>nil() : forInit(); - if (inits.length() == 1 && - inits.head.getTag() == JCTree.VARDEF && - ((JCVariableDecl) inits.head).init == null && - S.token() == COLON) { - checkForeach(); - JCVariableDecl var = (JCVariableDecl)inits.head; - accept(COLON); - JCExpression expr = expression(); - accept(RPAREN); - JCStatement body = statement(); - return F.at(pos).ForeachLoop(var, expr, body); - } else { - accept(SEMI); - JCExpression cond = S.token() == SEMI ? null : expression(); - accept(SEMI); - List<JCExpressionStatement> steps = S.token() == RPAREN ? List.<JCExpressionStatement>nil() : forUpdate(); - accept(RPAREN); - JCStatement body = statement(); - return F.at(pos).ForLoop(inits, cond, steps, body); - } - } - case WHILE: { - S.nextToken(); - JCExpression cond = parExpression(); - JCStatement body = statement(); - return F.at(pos).WhileLoop(cond, body); - } - case DO: { - S.nextToken(); - JCStatement body = statement(); - accept(WHILE); - JCExpression cond = parExpression(); - JCDoWhileLoop t = to(F.at(pos).DoLoop(body, cond)); - accept(SEMI); - return t; - } - case TRY: { - S.nextToken(); - JCBlock body = block(); - ListBuffer<JCCatch> catchers = new ListBuffer<JCCatch>(); - JCBlock finalizer = null; - if (S.token() == CATCH || S.token() == FINALLY) { - while (S.token() == CATCH) catchers.append(catchClause()); - if (S.token() == FINALLY) { - S.nextToken(); - finalizer = block(); - } - } else { - log.error(pos, "try.without.catch.or.finally"); - } - return F.at(pos).Try(body, catchers.toList(), finalizer); - } - case SWITCH: { - S.nextToken(); - JCExpression selector = parExpression(); - accept(LBRACE); - List<JCCase> cases = switchBlockStatementGroups(); - JCSwitch t = to(F.at(pos).Switch(selector, cases)); - accept(RBRACE); - return t; - } - case SYNCHRONIZED: { - S.nextToken(); - JCExpression lock = parExpression(); - JCBlock body = block(); - return F.at(pos).Synchronized(lock, body); - } - case RETURN: { - S.nextToken(); - JCExpression result = S.token() == SEMI ? null : expression(); - JCReturn t = to(F.at(pos).Return(result)); - accept(SEMI); - return t; - } - case THROW: { - S.nextToken(); - JCExpression exc = expression(); - JCThrow t = to(F.at(pos).Throw(exc)); - accept(SEMI); - return t; - } - case BREAK: { - S.nextToken(); - Name label = (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM) ? ident() : null; - JCBreak t = to(F.at(pos).Break(label)); - accept(SEMI); - return t; - } - case CONTINUE: { - S.nextToken(); - Name label = (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM) ? ident() : null; - JCContinue t = to(F.at(pos).Continue(label)); - accept(SEMI); - return t; - } - case SEMI: - S.nextToken(); - return toP(F.at(pos).Skip()); - case ELSE: - return toP(F.Exec(syntaxError("else.without.if"))); - case FINALLY: - return toP(F.Exec(syntaxError("finally.without.try"))); - case CATCH: - return toP(F.Exec(syntaxError("catch.without.try"))); - case ASSERT: { - if (allowAsserts && S.token() == ASSERT) { - S.nextToken(); - JCExpression assertion = expression(); - JCExpression message = null; - if (S.token() == COLON) { - S.nextToken(); - message = expression(); - } - JCAssert t = to(F.at(pos).Assert(assertion, message)); - accept(SEMI); - return t; - } - /* else fall through to default case */ - } - case ENUM: - default: - Name name = S.name(); - JCExpression expr = expression(); - if (S.token() == COLON && expr.getTag() == JCTree.IDENT) { - S.nextToken(); - JCStatement stat = statement(); - return F.at(pos).Labelled(name, stat); - } else { - // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon - JCExpressionStatement stat = to(F.at(pos).Exec(checkExprStat(expr))); - accept(SEMI); - return stat; - } - } - } - - /** CatchClause = CATCH "(" FormalParameter ")" Block - */ - JCCatch catchClause() { - int pos = S.pos(); - accept(CATCH); - accept(LPAREN); - JCVariableDecl formal = - variableDeclaratorId(optFinal(Flags.PARAMETER), - qualident()); - accept(RPAREN); - JCBlock body = block(); - return F.at(pos).Catch(formal, body); - } - - /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup } - * SwitchBlockStatementGroup = SwitchLabel BlockStatements - * SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":" - */ - List<JCCase> switchBlockStatementGroups() { - ListBuffer<JCCase> cases = new ListBuffer<JCCase>(); - while (true) { - int pos = S.pos(); - switch (S.token()) { - case CASE: { - S.nextToken(); - JCExpression pat = expression(); - accept(COLON); - List<JCStatement> stats = blockStatements(); - JCCase c = F.at(pos).Case(pat, stats); - if (stats.isEmpty()) - storeEnd(c, S.prevEndPos()); - cases.append(c); - break; - } - case DEFAULT: { - S.nextToken(); - accept(COLON); - List<JCStatement> stats = blockStatements(); - JCCase c = F.at(pos).Case(null, stats); - if (stats.isEmpty()) - storeEnd(c, S.prevEndPos()); - cases.append(c); - break; - } - case RBRACE: case EOF: - return cases.toList(); - default: - S.nextToken(); // to ensure progress - syntaxError(pos, "expected3", - CASE, DEFAULT, RBRACE); - } - } - } - - /** MoreStatementExpressions = { COMMA StatementExpression } - */ - <T extends ListBuffer<? super JCExpressionStatement>> T moreStatementExpressions(int pos, - JCExpression first, - T stats) { - // This Exec is a "StatementExpression"; it subsumes no terminating token - stats.append(toP(F.at(pos).Exec(checkExprStat(first)))); - while (S.token() == COMMA) { - S.nextToken(); - pos = S.pos(); - JCExpression t = expression(); - // This Exec is a "StatementExpression"; it subsumes no terminating token - stats.append(toP(F.at(pos).Exec(checkExprStat(t)))); - } - return stats; - } - - /** ForInit = StatementExpression MoreStatementExpressions - * | { FINAL | '@' Annotation } Type VariableDeclarators - */ - List<JCStatement> forInit() { - ListBuffer<JCStatement> stats = lb(); - int pos = S.pos(); - if (S.token() == FINAL || S.token() == MONKEYS_AT) { - return variableDeclarators(optFinal(0), type(), stats).toList(); - } else { - JCExpression t = term(EXPR | TYPE); - if ((lastmode & TYPE) != 0 && - (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM)) - return variableDeclarators(modifiersOpt(), t, stats).toList(); - else - return moreStatementExpressions(pos, t, stats).toList(); - } - } - - /** ForUpdate = StatementExpression MoreStatementExpressions - */ - List<JCExpressionStatement> forUpdate() { - return moreStatementExpressions(S.pos(), - expression(), - new ListBuffer<JCExpressionStatement>()).toList(); - } - - /** AnnotationsOpt = { '@' Annotation } - */ - List<JCAnnotation> annotationsOpt() { - if (S.token() != MONKEYS_AT) return List.nil(); // optimization - ListBuffer<JCAnnotation> buf = new ListBuffer<JCAnnotation>(); - while (S.token() == MONKEYS_AT) { - int pos = S.pos(); - S.nextToken(); - buf.append(annotation(pos)); - } - return buf.toList(); - } + JCStatement parseStatement(); - /** ModifiersOpt = { Modifier } - * Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL - * | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@" - * | "@" Annotation - */ - JCModifiers modifiersOpt() { - return modifiersOpt(null); - } - JCModifiers modifiersOpt(JCModifiers partial) { - long flags = (partial == null) ? 0 : partial.flags; - if (S.deprecatedFlag()) { - flags |= Flags.DEPRECATED; - S.resetDeprecatedFlag(); - } - ListBuffer<JCAnnotation> annotations = new ListBuffer<JCAnnotation>(); - if (partial != null) annotations.appendList(partial.annotations); - int pos = S.pos(); - int lastPos = Position.NOPOS; - loop: - while (true) { - long flag; - switch (S.token()) { - case PRIVATE : flag = Flags.PRIVATE; break; - case PROTECTED : flag = Flags.PROTECTED; break; - case PUBLIC : flag = Flags.PUBLIC; break; - case STATIC : flag = Flags.STATIC; break; - case TRANSIENT : flag = Flags.TRANSIENT; break; - case FINAL : flag = Flags.FINAL; break; - case ABSTRACT : flag = Flags.ABSTRACT; break; - case NATIVE : flag = Flags.NATIVE; break; - case VOLATILE : flag = Flags.VOLATILE; break; - case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break; - case STRICTFP : flag = Flags.STRICTFP; break; - case MONKEYS_AT : flag = Flags.ANNOTATION; break; - default: break loop; - } - if ((flags & flag) != 0) log.error(S.pos(), "repeated.modifier"); - lastPos = S.pos(); - S.nextToken(); - if (flag == Flags.ANNOTATION) { - checkAnnotations(); - if (S.token() != INTERFACE) { - JCAnnotation ann = annotation(lastPos); - // if first modifier is an annotation, set pos to annotation's. - if (flags == 0 && annotations.isEmpty()) - pos = ann.pos; - annotations.append(ann); - lastPos = ann.pos; - flag = 0; - } - } - flags |= flag; - } - switch (S.token()) { - case ENUM: flags |= Flags.ENUM; break; - case INTERFACE: flags |= Flags.INTERFACE; break; - default: break; - } - - /* A modifiers tree with no modifier tokens or annotations - * has no text position. */ - if (flags == 0 && annotations.isEmpty()) - pos = Position.NOPOS; - - JCModifiers mods = F.at(pos).Modifiers(flags, annotations.toList()); - if (pos != Position.NOPOS) - storeEnd(mods, S.prevEndPos()); - return mods; - } - - /** Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ] - * @param pos position of "@" token - */ - JCAnnotation annotation(int pos) { - // accept(AT); // AT consumed by caller - checkAnnotations(); - JCTree ident = qualident(); - List<JCExpression> fieldValues = annotationFieldValuesOpt(); - JCAnnotation ann = F.at(pos).Annotation(ident, fieldValues); - storeEnd(ann, S.prevEndPos()); - return ann; - } - - List<JCExpression> annotationFieldValuesOpt() { - return (S.token() == LPAREN) ? annotationFieldValues() : List.<JCExpression>nil(); - } - - /** AnnotationFieldValues = "(" [ AnnotationFieldValue { "," AnnotationFieldValue } ] ")" */ - List<JCExpression> annotationFieldValues() { - accept(LPAREN); - ListBuffer<JCExpression> buf = new ListBuffer<JCExpression>(); - if (S.token() != RPAREN) { - buf.append(annotationFieldValue()); - while (S.token() == COMMA) { - S.nextToken(); - buf.append(annotationFieldValue()); - } - } - accept(RPAREN); - return buf.toList(); - } - - /** AnnotationFieldValue = AnnotationValue - * | Identifier "=" AnnotationValue - */ - JCExpression annotationFieldValue() { - if (S.token() == IDENTIFIER) { - mode = EXPR; - JCExpression t1 = term1(); - if (t1.getTag() == JCTree.IDENT && S.token() == EQ) { - int pos = S.pos(); - accept(EQ); - return toP(F.at(pos).Assign(t1, annotationValue())); - } else { - return t1; - } - } - return annotationValue(); - } - - /* AnnotationValue = ConditionalExpression - * | Annotation - * | "{" [ AnnotationValue { "," AnnotationValue } ] "}" - */ - JCExpression annotationValue() { - int pos; - switch (S.token()) { - case MONKEYS_AT: - pos = S.pos(); - S.nextToken(); - return annotation(pos); - case LBRACE: - pos = S.pos(); - accept(LBRACE); - ListBuffer<JCExpression> buf = new ListBuffer<JCExpression>(); - if (S.token() != RBRACE) { - buf.append(annotationValue()); - while (S.token() == COMMA) { - S.nextToken(); - if (S.token() == RPAREN) break; - buf.append(annotationValue()); - } - } - accept(RBRACE); - return toP(F.at(pos).NewArray(null, List.<JCExpression>nil(), buf.toList())); - default: - mode = EXPR; - return term1(); - } - } - - /** VariableDeclarators = VariableDeclarator { "," VariableDeclarator } - */ - public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods, - JCExpression type, - T vdefs) - { - return variableDeclaratorsRest(S.pos(), mods, type, ident(), false, null, vdefs); - } - - /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator } - * ConstantDeclaratorsRest = ConstantDeclaratorRest { "," ConstantDeclarator } - * - * @param reqInit Is an initializer always required? - * @param dc The documentation comment for the variable declarations, or null. - */ - <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos, - JCModifiers mods, - JCExpression type, - Name name, - boolean reqInit, - String dc, - T vdefs) - { - vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc)); - while (S.token() == COMMA) { - // All but last of multiple declarators subsume a comma - storeEnd((JCTree)vdefs.elems.last(), S.endPos()); - S.nextToken(); - vdefs.append(variableDeclarator(mods, type, reqInit, dc)); - } - return vdefs; - } - - /** VariableDeclarator = Ident VariableDeclaratorRest - * ConstantDeclarator = Ident ConstantDeclaratorRest - */ - JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, String dc) { - return variableDeclaratorRest(S.pos(), mods, type, ident(), reqInit, dc); - } - - /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer] - * ConstantDeclaratorRest = BracketsOpt "=" VariableInitializer - * - * @param reqInit Is an initializer always required? - * @param dc The documentation comment for the variable declarations, or null. - */ - JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name, - boolean reqInit, String dc) { - type = bracketsOpt(type); - JCExpression init = null; - if (S.token() == EQ) { - S.nextToken(); - init = variableInitializer(); - } - else if (reqInit) syntaxError(S.pos(), "expected", EQ); - JCVariableDecl result = - toP(F.at(pos).VarDef(mods, name, type, init)); - attach(result, dc); - return result; - } - - /** VariableDeclaratorId = Ident BracketsOpt - */ - JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) { - int pos = S.pos(); - Name name = ident(); - if ((mods.flags & Flags.VARARGS) == 0) - type = bracketsOpt(type); - return toP(F.at(pos).VarDef(mods, name, type, null)); - } - - /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration} - */ - public JCTree.JCCompilationUnit compilationUnit() { - int pos = S.pos(); - JCExpression pid = null; - String dc = S.docComment(); - JCModifiers mods = null; - List<JCAnnotation> packageAnnotations = List.nil(); - if (S.token() == MONKEYS_AT) - mods = modifiersOpt(); - - if (S.token() == PACKAGE) { - if (mods != null) { - checkNoMods(mods.flags); - packageAnnotations = mods.annotations; - mods = null; - } - S.nextToken(); - pid = qualident(); - accept(SEMI); - } - ListBuffer<JCTree> defs = new ListBuffer<JCTree>(); - boolean checkForImports = true; - while (S.token() != EOF) { - if (S.pos() <= errorEndPos) { - // error recovery - skip(checkForImports, false, false, false); - if (S.token() == EOF) - break; - } - if (checkForImports && mods == null && S.token() == IMPORT) { - defs.append(importDeclaration()); - } else { - JCTree def = typeDeclaration(mods); - if (def instanceof JCExpressionStatement) - def = ((JCExpressionStatement)def).expr; - defs.append(def); - if (def instanceof JCClassDecl) - checkForImports = false; - mods = null; - } - } - JCTree.JCCompilationUnit toplevel = F.at(pos).TopLevel(packageAnnotations, pid, defs.toList()); - attach(toplevel, dc); - if (defs.elems.isEmpty()) - storeEnd(toplevel, S.prevEndPos()); - if (keepDocComments) toplevel.docComments = docComments; - return toplevel; - } - - /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";" - */ - JCTree importDeclaration() { - int pos = S.pos(); - S.nextToken(); - boolean importStatic = false; - if (S.token() == STATIC) { - checkStaticImports(); - importStatic = true; - S.nextToken(); - } - JCExpression pid = toP(F.at(S.pos()).Ident(ident())); - do { - int pos1 = S.pos(); - accept(DOT); - if (S.token() == STAR) { - pid = to(F.at(pos1).Select(pid, names.asterisk)); - S.nextToken(); - break; - } else { - pid = toP(F.at(pos1).Select(pid, ident())); - } - } while (S.token() == DOT); - accept(SEMI); - return toP(F.at(pos).Import(pid, importStatic)); - } - - /** TypeDeclaration = ClassOrInterfaceOrEnumDeclaration - * | ";" - */ - JCTree typeDeclaration(JCModifiers mods) { - int pos = S.pos(); - if (mods == null && S.token() == SEMI) { - S.nextToken(); - return toP(F.at(pos).Skip()); - } else { - String dc = S.docComment(); - return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), dc); - } - } - - /** ClassOrInterfaceOrEnumDeclaration = ModifiersOpt - * (ClassDeclaration | InterfaceDeclaration | EnumDeclaration) - * @param mods Any modifiers starting the class or interface declaration - * @param dc The documentation comment for the class, or null. + /** + * Parse a type. + * @return an expression for a type */ - JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, String dc) { - if (S.token() == CLASS) { - return classDeclaration(mods, dc); - } else if (S.token() == INTERFACE) { - return interfaceDeclaration(mods, dc); - } else if (allowEnums) { - if (S.token() == ENUM) { - return enumDeclaration(mods, dc); - } else { - int pos = S.pos(); - List<JCTree> errs; - if (S.token() == IDENTIFIER) { - errs = List.<JCTree>of(mods, toP(F.at(pos).Ident(ident()))); - setErrorEndPos(S.pos()); - } else { - errs = List.<JCTree>of(mods); - } - return toP(F.Exec(syntaxError(pos, errs, "expected3", - CLASS, INTERFACE, ENUM))); - } - } else { - if (S.token() == ENUM) { - log.error(S.pos(), "enums.not.supported.in.source", source.name); - allowEnums = true; - return enumDeclaration(mods, dc); - } - int pos = S.pos(); - List<JCTree> errs; - if (S.token() == IDENTIFIER) { - errs = List.<JCTree>of(mods, toP(F.at(pos).Ident(ident()))); - setErrorEndPos(S.pos()); - } else { - errs = List.<JCTree>of(mods); - } - return toP(F.Exec(syntaxError(pos, errs, "expected2", - CLASS, INTERFACE))); - } - } - - /** ClassDeclaration = CLASS Ident TypeParametersOpt [EXTENDS Type] - * [IMPLEMENTS TypeList] ClassBody - * @param mods The modifiers starting the class declaration - * @param dc The documentation comment for the class, or null. - */ - JCClassDecl classDeclaration(JCModifiers mods, String dc) { - int pos = S.pos(); - accept(CLASS); - Name name = ident(); - - List<JCTypeParameter> typarams = typeParametersOpt(); - - JCTree extending = null; - if (S.token() == EXTENDS) { - S.nextToken(); - extending = type(); - } - List<JCExpression> implementing = List.nil(); - if (S.token() == IMPLEMENTS) { - S.nextToken(); - implementing = typeList(); - } - List<JCTree> defs = classOrInterfaceBody(name, false); - JCClassDecl result = toP(F.at(pos).ClassDef( - mods, name, typarams, extending, implementing, defs)); - attach(result, dc); - return result; - } - - /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt - * [EXTENDS TypeList] InterfaceBody - * @param mods The modifiers starting the interface declaration - * @param dc The documentation comment for the interface, or null. - */ - JCClassDecl interfaceDeclaration(JCModifiers mods, String dc) { - int pos = S.pos(); - accept(INTERFACE); - Name name = ident(); - - List<JCTypeParameter> typarams = typeParametersOpt(); - - List<JCExpression> extending = List.nil(); - if (S.token() == EXTENDS) { - S.nextToken(); - extending = typeList(); - } - List<JCTree> defs = classOrInterfaceBody(name, true); - JCClassDecl result = toP(F.at(pos).ClassDef( - mods, name, typarams, null, extending, defs)); - attach(result, dc); - return result; - } - - /** EnumDeclaration = ENUM Ident [IMPLEMENTS TypeList] EnumBody - * @param mods The modifiers starting the enum declaration - * @param dc The documentation comment for the enum, or null. - */ - JCClassDecl enumDeclaration(JCModifiers mods, String dc) { - int pos = S.pos(); - accept(ENUM); - Name name = ident(); - - List<JCExpression> implementing = List.nil(); - if (S.token() == IMPLEMENTS) { - S.nextToken(); - implementing = typeList(); - } - - List<JCTree> defs = enumBody(name); - JCModifiers newMods = - F.at(mods.pos).Modifiers(mods.flags|Flags.ENUM, mods.annotations); - JCClassDecl result = toP(F.at(pos). - ClassDef(newMods, name, List.<JCTypeParameter>nil(), - null, implementing, defs)); - attach(result, dc); - return result; - } - - /** EnumBody = "{" { EnumeratorDeclarationList } [","] - * [ ";" {ClassBodyDeclaration} ] "}" - */ - List<JCTree> enumBody(Name enumName) { - accept(LBRACE); - ListBuffer<JCTree> defs = new ListBuffer<JCTree>(); - if (S.token() == COMMA) { - S.nextToken(); - } else if (S.token() != RBRACE && S.token() != SEMI) { - defs.append(enumeratorDeclaration(enumName)); - while (S.token() == COMMA) { - S.nextToken(); - if (S.token() == RBRACE || S.token() == SEMI) break; - defs.append(enumeratorDeclaration(enumName)); - } - if (S.token() != SEMI && S.token() != RBRACE) { - defs.append(syntaxError(S.pos(), "expected3", - COMMA, RBRACE, SEMI)); - S.nextToken(); - } - } - if (S.token() == SEMI) { - S.nextToken(); - while (S.token() != RBRACE && S.token() != EOF) { - defs.appendList(classOrInterfaceBodyDeclaration(enumName, - false)); - if (S.pos() <= errorEndPos) { - // error recovery - skip(false, true, true, false); - } - } - } - accept(RBRACE); - return defs.toList(); - } - - /** EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ] - */ - JCTree enumeratorDeclaration(Name enumName) { - String dc = S.docComment(); - int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM; - if (S.deprecatedFlag()) { - flags |= Flags.DEPRECATED; - S.resetDeprecatedFlag(); - } - int pos = S.pos(); - List<JCAnnotation> annotations = annotationsOpt(); - JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations); - List<JCExpression> typeArgs = typeArgumentsOpt(); - int identPos = S.pos(); - Name name = ident(); - int createPos = S.pos(); - List<JCExpression> args = (S.token() == LPAREN) - ? arguments() : List.<JCExpression>nil(); - JCClassDecl body = null; - if (S.token() == LBRACE) { - JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC); - List<JCTree> defs = classOrInterfaceBody(names.empty, false); - body = toP(F.at(identPos).AnonymousClassDef(mods1, defs)); - } - if (args.isEmpty() && body == null) - createPos = Position.NOPOS; - JCIdent ident = F.at(Position.NOPOS).Ident(enumName); - JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body); - if (createPos != Position.NOPOS) - storeEnd(create, S.prevEndPos()); - ident = F.at(Position.NOPOS).Ident(enumName); - JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create)); - attach(result, dc); - return result; - } - - /** TypeList = Type {"," Type} - */ - List<JCExpression> typeList() { - ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>(); - ts.append(type()); - while (S.token() == COMMA) { - S.nextToken(); - ts.append(type()); - } - return ts.toList(); - } - - /** ClassBody = "{" {ClassBodyDeclaration} "}" - * InterfaceBody = "{" {InterfaceBodyDeclaration} "}" - */ - List<JCTree> classOrInterfaceBody(Name className, boolean isInterface) { - accept(LBRACE); - if (S.pos() <= errorEndPos) { - // error recovery - skip(false, true, false, false); - if (S.token() == LBRACE) - S.nextToken(); - } - ListBuffer<JCTree> defs = new ListBuffer<JCTree>(); - while (S.token() != RBRACE && S.token() != EOF) { - defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface)); - if (S.pos() <= errorEndPos) { - // error recovery - skip(false, true, true, false); - } - } - accept(RBRACE); - return defs.toList(); - } - - /** ClassBodyDeclaration = - * ";" - * | [STATIC] Block - * | ModifiersOpt - * ( Type Ident - * ( VariableDeclaratorsRest ";" | MethodDeclaratorRest ) - * | VOID Ident MethodDeclaratorRest - * | TypeParameters (Type | VOID) Ident MethodDeclaratorRest - * | Ident ConstructorDeclaratorRest - * | TypeParameters Ident ConstructorDeclaratorRest - * | ClassOrInterfaceOrEnumDeclaration - * ) - * InterfaceBodyDeclaration = - * ";" - * | ModifiersOpt Type Ident - * ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" ) - */ - List<JCTree> classOrInterfaceBodyDeclaration(Name className, boolean isInterface) { - if (S.token() == SEMI) { - S.nextToken(); - return List.<JCTree>of(F.at(Position.NOPOS).Block(0, List.<JCStatement>nil())); - } else { - String dc = S.docComment(); - int pos = S.pos(); - JCModifiers mods = modifiersOpt(); - if (S.token() == CLASS || - S.token() == INTERFACE || - allowEnums && S.token() == ENUM) { - return List.<JCTree>of(classOrInterfaceOrEnumDeclaration(mods, dc)); - } else if (S.token() == LBRACE && !isInterface && - (mods.flags & Flags.StandardFlags & ~Flags.STATIC) == 0 && - mods.annotations.isEmpty()) { - return List.<JCTree>of(block(pos, mods.flags)); - } else { - pos = S.pos(); - List<JCTypeParameter> typarams = typeParametersOpt(); - // Hack alert: if there are type arguments but no Modifiers, the start - // position will be lost unless we set the Modifiers position. There - // should be an AST node for type parameters (BugId 5005090). - if (typarams.length() > 0 && mods.pos == Position.NOPOS) { - mods.pos = pos; - } - Token token = S.token(); - Name name = S.name(); - pos = S.pos(); - JCExpression type; - boolean isVoid = S.token() == VOID; - if (isVoid) { - type = to(F.at(pos).TypeIdent(TypeTags.VOID)); - S.nextToken(); - } else { - type = type(); - } - if (S.token() == LPAREN && !isInterface && type.getTag() == JCTree.IDENT) { - if (isInterface || name != className) - log.error(pos, "invalid.meth.decl.ret.type.req"); - return List.of(methodDeclaratorRest( - pos, mods, null, names.init, typarams, - isInterface, true, dc)); - } else { - pos = S.pos(); - name = ident(); - if (S.token() == LPAREN) { - return List.of(methodDeclaratorRest( - pos, mods, type, name, typarams, - isInterface, isVoid, dc)); - } else if (!isVoid && typarams.isEmpty()) { - List<JCTree> defs = - variableDeclaratorsRest(pos, mods, type, name, isInterface, dc, - new ListBuffer<JCTree>()).toList(); - storeEnd(defs.last(), S.endPos()); - accept(SEMI); - return defs; - } else { - pos = S.pos(); - List<JCTree> err = isVoid - ? List.<JCTree>of(toP(F.at(pos).MethodDef(mods, name, type, typarams, - List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null))) - : null; - return List.<JCTree>of(syntaxError(S.pos(), err, "expected", LPAREN)); - } - } - } - } - } - - /** MethodDeclaratorRest = - * FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";") - * VoidMethodDeclaratorRest = - * FormalParameters [Throws TypeList] ( MethodBody | ";") - * InterfaceMethodDeclaratorRest = - * FormalParameters BracketsOpt [THROWS TypeList] ";" - * VoidInterfaceMethodDeclaratorRest = - * FormalParameters [THROWS TypeList] ";" - * ConstructorDeclaratorRest = - * "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody - */ - JCTree methodDeclaratorRest(int pos, - JCModifiers mods, - JCExpression type, - Name name, - List<JCTypeParameter> typarams, - boolean isInterface, boolean isVoid, - String dc) { - List<JCVariableDecl> params = formalParameters(); - if (!isVoid) type = bracketsOpt(type); - List<JCExpression> thrown = List.nil(); - if (S.token() == THROWS) { - S.nextToken(); - thrown = qualidentList(); - } - JCBlock body = null; - JCExpression defaultValue; - if (S.token() == LBRACE) { - body = block(); - defaultValue = null; - } else { - if (S.token() == DEFAULT) { - accept(DEFAULT); - defaultValue = annotationValue(); - } else { - defaultValue = null; - } - accept(SEMI); - if (S.pos() <= errorEndPos) { - // error recovery - skip(false, true, false, false); - if (S.token() == LBRACE) { - body = block(); - } - } - } - JCMethodDecl result = - toP(F.at(pos).MethodDef(mods, name, type, typarams, - params, thrown, - body, defaultValue)); - attach(result, dc); - return result; - } - - /** QualidentList = Qualident {"," Qualident} - */ - List<JCExpression> qualidentList() { - ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>(); - ts.append(qualident()); - while (S.token() == COMMA) { - S.nextToken(); - ts.append(qualident()); - } - return ts.toList(); - } - - /** TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"] - */ - List<JCTypeParameter> typeParametersOpt() { - if (S.token() == LT) { - checkGenerics(); - ListBuffer<JCTypeParameter> typarams = new ListBuffer<JCTypeParameter>(); - S.nextToken(); - typarams.append(typeParameter()); - while (S.token() == COMMA) { - S.nextToken(); - typarams.append(typeParameter()); - } - accept(GT); - return typarams.toList(); - } else { - return List.nil(); - } - } - - /** TypeParameter = TypeVariable [TypeParameterBound] - * TypeParameterBound = EXTENDS Type {"&" Type} - * TypeVariable = Ident - */ - JCTypeParameter typeParameter() { - int pos = S.pos(); - Name name = ident(); - ListBuffer<JCExpression> bounds = new ListBuffer<JCExpression>(); - if (S.token() == EXTENDS) { - S.nextToken(); - bounds.append(type()); - while (S.token() == AMP) { - S.nextToken(); - bounds.append(type()); - } - } - return toP(F.at(pos).TypeParameter(name, bounds.toList())); - } - - /** FormalParameters = "(" [ FormalParameterList ] ")" - * FormalParameterList = [ FormalParameterListNovarargs , ] LastFormalParameter - * FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter - */ - List<JCVariableDecl> formalParameters() { - ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); - JCVariableDecl lastParam = null; - accept(LPAREN); - if (S.token() != RPAREN) { - params.append(lastParam = formalParameter()); - while ((lastParam.mods.flags & Flags.VARARGS) == 0 && S.token() == COMMA) { - S.nextToken(); - params.append(lastParam = formalParameter()); - } - } - accept(RPAREN); - return params.toList(); - } - - JCModifiers optFinal(long flags) { - JCModifiers mods = modifiersOpt(); - checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED)); - mods.flags |= flags; - return mods; - } - - /** FormalParameter = { FINAL | '@' Annotation } Type VariableDeclaratorId - * LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter - */ - JCVariableDecl formalParameter() { - JCModifiers mods = optFinal(Flags.PARAMETER); - JCExpression type = type(); - if (S.token() == ELLIPSIS) { - checkVarargs(); - mods.flags |= Flags.VARARGS; - type = to(F.at(S.pos()).TypeArray(type)); - S.nextToken(); - } - return variableDeclaratorId(mods, type); - } - -/* ---------- auxiliary methods -------------- */ - - /** Check that given tree is a legal expression statement. - */ - protected JCExpression checkExprStat(JCExpression t) { - switch(t.getTag()) { - case JCTree.PREINC: case JCTree.PREDEC: - case JCTree.POSTINC: case JCTree.POSTDEC: - case JCTree.ASSIGN: - case JCTree.BITOR_ASG: case JCTree.BITXOR_ASG: case JCTree.BITAND_ASG: - case JCTree.SL_ASG: case JCTree.SR_ASG: case JCTree.USR_ASG: - case JCTree.PLUS_ASG: case JCTree.MINUS_ASG: - case JCTree.MUL_ASG: case JCTree.DIV_ASG: case JCTree.MOD_ASG: - case JCTree.APPLY: case JCTree.NEWCLASS: - case JCTree.ERRONEOUS: - return t; - default: - log.error(t.pos, "not.stmt"); - return F.at(t.pos).Erroneous(List.<JCTree>of(t)); - } - } - - /** Return precedence of operator represented by token, - * -1 if token is not a binary operator. @see TreeInfo.opPrec - */ - static int prec(Token token) { - int oc = optag(token); - return (oc >= 0) ? TreeInfo.opPrec(oc) : -1; - } - - /** Return operation tag of binary operator represented by token, - * -1 if token is not a binary operator. - */ - static int optag(Token token) { - switch (token) { - case BARBAR: - return JCTree.OR; - case AMPAMP: - return JCTree.AND; - case BAR: - return JCTree.BITOR; - case BAREQ: - return JCTree.BITOR_ASG; - case CARET: - return JCTree.BITXOR; - case CARETEQ: - return JCTree.BITXOR_ASG; - case AMP: - return JCTree.BITAND; - case AMPEQ: - return JCTree.BITAND_ASG; - case EQEQ: - return JCTree.EQ; - case BANGEQ: - return JCTree.NE; - case LT: - return JCTree.LT; - case GT: - return JCTree.GT; - case LTEQ: - return JCTree.LE; - case GTEQ: - return JCTree.GE; - case LTLT: - return JCTree.SL; - case LTLTEQ: - return JCTree.SL_ASG; - case GTGT: - return JCTree.SR; - case GTGTEQ: - return JCTree.SR_ASG; - case GTGTGT: - return JCTree.USR; - case GTGTGTEQ: - return JCTree.USR_ASG; - case PLUS: - return JCTree.PLUS; - case PLUSEQ: - return JCTree.PLUS_ASG; - case SUB: - return JCTree.MINUS; - case SUBEQ: - return JCTree.MINUS_ASG; - case STAR: - return JCTree.MUL; - case STAREQ: - return JCTree.MUL_ASG; - case SLASH: - return JCTree.DIV; - case SLASHEQ: - return JCTree.DIV_ASG; - case PERCENT: - return JCTree.MOD; - case PERCENTEQ: - return JCTree.MOD_ASG; - case INSTANCEOF: - return JCTree.TYPETEST; - default: - return -1; - } - } - - /** Return operation tag of unary operator represented by token, - * -1 if token is not a binary operator. - */ - static int unoptag(Token token) { - switch (token) { - case PLUS: - return JCTree.POS; - case SUB: - return JCTree.NEG; - case BANG: - return JCTree.NOT; - case TILDE: - return JCTree.COMPL; - case PLUSPLUS: - return JCTree.PREINC; - case SUBSUB: - return JCTree.PREDEC; - default: - return -1; - } - } - - /** Return type tag of basic type represented by token, - * -1 if token is not a basic type identifier. - */ - static int typetag(Token token) { - switch (token) { - case BYTE: - return TypeTags.BYTE; - case CHAR: - return TypeTags.CHAR; - case SHORT: - return TypeTags.SHORT; - case INT: - return TypeTags.INT; - case LONG: - return TypeTags.LONG; - case FLOAT: - return TypeTags.FLOAT; - case DOUBLE: - return TypeTags.DOUBLE; - case BOOLEAN: - return TypeTags.BOOLEAN; - default: - return -1; - } - } - - void checkGenerics() { - if (!allowGenerics) { - log.error(S.pos(), "generics.not.supported.in.source", source.name); - allowGenerics = true; - } - } - void checkVarargs() { - if (!allowVarargs) { - log.error(S.pos(), "varargs.not.supported.in.source", source.name); - allowVarargs = true; - } - } - void checkForeach() { - if (!allowForeach) { - log.error(S.pos(), "foreach.not.supported.in.source", source.name); - allowForeach = true; - } - } - void checkStaticImports() { - if (!allowStaticImport) { - log.error(S.pos(), "static.import.not.supported.in.source", source.name); - allowStaticImport = true; - } - } - void checkAnnotations() { - if (!allowAnnotations) { - log.error(S.pos(), "annotations.not.supported.in.source", source.name); - allowAnnotations = true; - } - } + JCExpression parseType(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/ParserFactory.java Tue Sep 09 10:40:50 2008 -0700 @@ -0,0 +1,79 @@ +/* + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.javac.parser; + +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Options; + +/** + * A factory for creating parsers. + */ +public class ParserFactory { + + /** The context key for the parser factory. */ + protected static final Context.Key<ParserFactory> parserFactoryKey = new Context.Key<ParserFactory>(); + + public static ParserFactory instance(Context context) { + ParserFactory instance = context.get(parserFactoryKey); + if (instance == null) { + instance = new ParserFactory(context); + } + return instance; + } + + final TreeMaker F; + final Log log; + final Keywords keywords; + final Source source; + final Name.Table names; + final Options options; + final Scanner.Factory scannerFactory; + + protected ParserFactory(Context context) { + super(); + context.put(parserFactoryKey, this); + this.F = TreeMaker.instance(context); + this.log = Log.instance(context); + this.names = Name.Table.instance(context); + this.keywords = Keywords.instance(context); + this.source = Source.instance(context); + this.options = Options.instance(context); + this.scannerFactory = Scanner.Factory.instance(context); + } + + public Parser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) { + Lexer lexer = scannerFactory.newScanner(input); + if (keepEndPos) { + return new EndPosParser(this, lexer, keepDocComments, keepLineMap); + } else { + return new JavacParser(this, lexer, keepDocComments, keepLineMap); + } + } +}
--- a/langtools/test/tools/javac/6304921/TestLog.java Tue Sep 09 10:28:21 2008 -0700 +++ b/langtools/test/tools/javac/6304921/TestLog.java Tue Sep 09 10:40:50 2008 -0700 @@ -34,6 +34,7 @@ import javax.tools.SimpleJavaFileObject; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.parser.Parser; +import com.sun.tools.javac.parser.ParserFactory; import com.sun.tools.javac.parser.Scanner; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeScanner; @@ -60,7 +61,7 @@ JavacFileManager.preRegister(context); Scanner.Factory sfac = Scanner.Factory.instance(context); - Parser.Factory pfac = Parser.Factory.instance(context); + ParserFactory pfac = ParserFactory.instance(context); final String text = "public class Foo {\n" @@ -74,9 +75,9 @@ JavaFileObject fo = new StringJavaFileObject("Foo", text); log.useSource(fo); - Scanner s = sfac.newScanner(fo.getCharContent(true)); - Parser parser = pfac.newParser(s, false, genEndPos); - JCTree.JCCompilationUnit tree = parser.compilationUnit(); + CharSequence cs = fo.getCharContent(true); + Parser parser = pfac.newParser(cs, false, genEndPos, false); + JCTree.JCCompilationUnit tree = parser.parseCompilationUnit(); log.setEndPosTable(fo, tree.endPositions); TreeScanner ts = new LogTester(log, tree.endPositions);