Thu, 04 Oct 2012 13:04:53 +0100
7177387: Add target-typing support in method context
Summary: Add support for deferred types and speculative attribution
Reviewed-by: jjg, dlsmith
1 /*
2 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.javac.parser;
28 import java.util.*;
30 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
32 import com.sun.tools.javac.code.*;
33 import com.sun.tools.javac.parser.Tokens.*;
34 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
35 import com.sun.tools.javac.tree.*;
36 import com.sun.tools.javac.tree.JCTree.*;
37 import com.sun.tools.javac.util.*;
38 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
39 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
40 import com.sun.tools.javac.util.List;
42 import static com.sun.tools.javac.parser.Tokens.TokenKind.*;
43 import static com.sun.tools.javac.parser.Tokens.TokenKind.ASSERT;
44 import static com.sun.tools.javac.parser.Tokens.TokenKind.CASE;
45 import static com.sun.tools.javac.parser.Tokens.TokenKind.CATCH;
46 import static com.sun.tools.javac.parser.Tokens.TokenKind.EQ;
47 import static com.sun.tools.javac.parser.Tokens.TokenKind.GT;
48 import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
49 import static com.sun.tools.javac.parser.Tokens.TokenKind.LT;
50 import static com.sun.tools.javac.util.ListBuffer.lb;
51 import static com.sun.tools.javac.tree.JCTree.Tag.*;
53 /** The parser maps a token sequence into an abstract syntax
54 * tree. It operates by recursive descent, with code derived
55 * systematically from an LL(1) grammar. For efficiency reasons, an
56 * operator precedence scheme is used for parsing binary operation
57 * expressions.
58 *
59 * <p><b>This is NOT part of any supported API.
60 * If you write code that depends on this, you do so at your own risk.
61 * This code and its internal interfaces are subject to change or
62 * deletion without notice.</b>
63 */
64 public class JavacParser implements Parser {
66 /** The number of precedence levels of infix operators.
67 */
68 private static final int infixPrecedenceLevels = 10;
70 /** The scanner used for lexical analysis.
71 */
72 protected Lexer S;
74 /** The factory to be used for abstract syntax tree construction.
75 */
76 protected TreeMaker F;
78 /** The log to be used for error diagnostics.
79 */
80 private Log log;
82 /** The Source language setting. */
83 private Source source;
85 /** The name table. */
86 private Names names;
88 /** End position mappings container */
89 private final AbstractEndPosTable endPosTable;
91 /** Construct a parser from a given scanner, tree factory and log.
92 */
93 protected JavacParser(ParserFactory fac,
94 Lexer S,
95 boolean keepDocComments,
96 boolean keepLineMap,
97 boolean keepEndPositions) {
98 this.S = S;
99 nextToken(); // prime the pump
100 this.F = fac.F;
101 this.log = fac.log;
102 this.names = fac.names;
103 this.source = fac.source;
104 this.allowGenerics = source.allowGenerics();
105 this.allowVarargs = source.allowVarargs();
106 this.allowAsserts = source.allowAsserts();
107 this.allowEnums = source.allowEnums();
108 this.allowForeach = source.allowForeach();
109 this.allowStaticImport = source.allowStaticImport();
110 this.allowAnnotations = source.allowAnnotations();
111 this.allowTWR = source.allowTryWithResources();
112 this.allowDiamond = source.allowDiamond();
113 this.allowMulticatch = source.allowMulticatch();
114 this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true);
115 this.allowLambda = source.allowLambda() &&
116 fac.options.isSet("allowLambda"); //pre-lambda guard
117 this.allowMethodReferences = source.allowMethodReferences() &&
118 fac.options.isSet("allowMethodReferences"); //pre-lambda guard
119 this.keepDocComments = keepDocComments;
120 docComments = newDocCommentTable(keepDocComments);
121 this.keepLineMap = keepLineMap;
122 this.errorTree = F.Erroneous();
123 endPosTable = newEndPosTable(keepEndPositions);
124 }
126 protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
127 return keepEndPositions
128 ? new SimpleEndPosTable()
129 : new EmptyEndPosTable();
130 }
132 protected DocCommentTable newDocCommentTable(boolean keepDocComments) {
133 return keepDocComments ? new SimpleDocCommentTable() : null;
134 }
136 /** Switch: Should generics be recognized?
137 */
138 boolean allowGenerics;
140 /** Switch: Should diamond operator be recognized?
141 */
142 boolean allowDiamond;
144 /** Switch: Should multicatch clause be accepted?
145 */
146 boolean allowMulticatch;
148 /** Switch: Should varargs be recognized?
149 */
150 boolean allowVarargs;
152 /** Switch: should we recognize assert statements, or just give a warning?
153 */
154 boolean allowAsserts;
156 /** Switch: should we recognize enums, or just give a warning?
157 */
158 boolean allowEnums;
160 /** Switch: should we recognize foreach?
161 */
162 boolean allowForeach;
164 /** Switch: should we recognize foreach?
165 */
166 boolean allowStaticImport;
168 /** Switch: should we recognize annotations?
169 */
170 boolean allowAnnotations;
172 /** Switch: should we recognize try-with-resources?
173 */
174 boolean allowTWR;
176 /** Switch: should we fold strings?
177 */
178 boolean allowStringFolding;
180 /** Switch: should we recognize lambda expressions?
181 */
182 boolean allowLambda;
184 /** Switch: should we allow method/constructor references?
185 */
186 boolean allowMethodReferences;
188 /** Switch: should we keep docComments?
189 */
190 boolean keepDocComments;
192 /** Switch: should we keep line table?
193 */
194 boolean keepLineMap;
196 /** When terms are parsed, the mode determines which is expected:
197 * mode = EXPR : an expression
198 * mode = TYPE : a type
199 * mode = NOPARAMS : no parameters allowed for type
200 * mode = TYPEARG : type argument
201 */
202 static final int EXPR = 0x1;
203 static final int TYPE = 0x2;
204 static final int NOPARAMS = 0x4;
205 static final int TYPEARG = 0x8;
206 static final int DIAMOND = 0x10;
208 /** The current mode.
209 */
210 private int mode = 0;
212 /** The mode of the term that was parsed last.
213 */
214 private int lastmode = 0;
216 /* ---------- token management -------------- */
218 protected Token token;
220 protected void nextToken() {
221 S.nextToken();
222 token = S.token();
223 }
225 protected boolean peekToken(TokenKind tk) {
226 return S.token(1).kind == tk;
227 }
229 protected boolean peekToken(TokenKind tk1, TokenKind tk2) {
230 return S.token(1).kind == tk1 &&
231 S.token(2).kind == tk2;
232 }
234 protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) {
235 return S.token(1).kind == tk1 &&
236 S.token(2).kind == tk2 &&
237 S.token(3).kind == tk3;
238 }
240 protected boolean peekToken(TokenKind... kinds) {
241 for (int lookahead = 0 ; lookahead < kinds.length ; lookahead++) {
242 if (S.token(lookahead + 1).kind != kinds[lookahead]) {
243 return false;
244 }
245 }
246 return true;
247 }
249 /* ---------- error recovery -------------- */
251 private JCErroneous errorTree;
253 /** Skip forward until a suitable stop token is found.
254 */
255 private void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) {
256 while (true) {
257 switch (token.kind) {
258 case SEMI:
259 nextToken();
260 return;
261 case PUBLIC:
262 case FINAL:
263 case ABSTRACT:
264 case MONKEYS_AT:
265 case EOF:
266 case CLASS:
267 case INTERFACE:
268 case ENUM:
269 return;
270 case IMPORT:
271 if (stopAtImport)
272 return;
273 break;
274 case LBRACE:
275 case RBRACE:
276 case PRIVATE:
277 case PROTECTED:
278 case STATIC:
279 case TRANSIENT:
280 case NATIVE:
281 case VOLATILE:
282 case SYNCHRONIZED:
283 case STRICTFP:
284 case LT:
285 case BYTE:
286 case SHORT:
287 case CHAR:
288 case INT:
289 case LONG:
290 case FLOAT:
291 case DOUBLE:
292 case BOOLEAN:
293 case VOID:
294 if (stopAtMemberDecl)
295 return;
296 break;
297 case IDENTIFIER:
298 if (stopAtIdentifier)
299 return;
300 break;
301 case CASE:
302 case DEFAULT:
303 case IF:
304 case FOR:
305 case WHILE:
306 case DO:
307 case TRY:
308 case SWITCH:
309 case RETURN:
310 case THROW:
311 case BREAK:
312 case CONTINUE:
313 case ELSE:
314 case FINALLY:
315 case CATCH:
316 if (stopAtStatement)
317 return;
318 break;
319 }
320 nextToken();
321 }
322 }
324 private JCErroneous syntaxError(int pos, String key, TokenKind... args) {
325 return syntaxError(pos, List.<JCTree>nil(), key, args);
326 }
328 private JCErroneous syntaxError(int pos, List<JCTree> errs, String key, TokenKind... args) {
329 setErrorEndPos(pos);
330 JCErroneous err = F.at(pos).Erroneous(errs);
331 reportSyntaxError(err, key, (Object[])args);
332 if (errs != null) {
333 JCTree last = errs.last();
334 if (last != null)
335 storeEnd(last, pos);
336 }
337 return toP(err);
338 }
340 private int errorPos = Position.NOPOS;
342 /**
343 * Report a syntax using the given the position parameter and arguments,
344 * unless one was already reported at the same position.
345 */
346 private void reportSyntaxError(int pos, String key, Object... args) {
347 JCDiagnostic.DiagnosticPosition diag = new JCDiagnostic.SimpleDiagnosticPosition(pos);
348 reportSyntaxError(diag, key, args);
349 }
351 /**
352 * Report a syntax error using the given DiagnosticPosition object and
353 * arguments, unless one was already reported at the same position.
354 */
355 private void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, String key, Object... args) {
356 int pos = diagPos.getPreferredPosition();
357 if (pos > S.errPos() || pos == Position.NOPOS) {
358 if (token.kind == EOF) {
359 error(diagPos, "premature.eof");
360 } else {
361 error(diagPos, key, args);
362 }
363 }
364 S.errPos(pos);
365 if (token.pos == errorPos)
366 nextToken(); // guarantee progress
367 errorPos = token.pos;
368 }
371 /** Generate a syntax error at current position unless one was already
372 * reported at the same position.
373 */
374 private JCErroneous syntaxError(String key) {
375 return syntaxError(token.pos, key);
376 }
378 /** Generate a syntax error at current position unless one was
379 * already reported at the same position.
380 */
381 private JCErroneous syntaxError(String key, TokenKind arg) {
382 return syntaxError(token.pos, key, arg);
383 }
385 /** If next input token matches given token, skip it, otherwise report
386 * an error.
387 */
388 public void accept(TokenKind tk) {
389 if (token.kind == tk) {
390 nextToken();
391 } else {
392 setErrorEndPos(token.pos);
393 reportSyntaxError(S.prevToken().endPos, "expected", tk);
394 }
395 }
397 /** Report an illegal start of expression/type error at given position.
398 */
399 JCExpression illegal(int pos) {
400 setErrorEndPos(pos);
401 if ((mode & EXPR) != 0)
402 return syntaxError(pos, "illegal.start.of.expr");
403 else
404 return syntaxError(pos, "illegal.start.of.type");
406 }
408 /** Report an illegal start of expression/type error at current position.
409 */
410 JCExpression illegal() {
411 return illegal(token.pos);
412 }
414 /** Diagnose a modifier flag from the set, if any. */
415 void checkNoMods(long mods) {
416 if (mods != 0) {
417 long lowestMod = mods & -mods;
418 error(token.pos, "mod.not.allowed.here",
419 Flags.asFlagSet(lowestMod));
420 }
421 }
423 /* ---------- doc comments --------- */
425 /** A table to store all documentation comments
426 * indexed by the tree nodes they refer to.
427 * defined only if option flag keepDocComment is set.
428 */
429 private final DocCommentTable docComments;
431 /** Make an entry into docComments hashtable,
432 * provided flag keepDocComments is set and given doc comment is non-null.
433 * @param tree The tree to be used as index in the hashtable
434 * @param dc The doc comment to associate with the tree, or null.
435 */
436 void attach(JCTree tree, Comment dc) {
437 if (keepDocComments && dc != null) {
438 // System.out.println("doc comment = ");System.out.println(dc);//DEBUG
439 docComments.putComment(tree, dc);
440 }
441 }
443 /* -------- source positions ------- */
445 private void setErrorEndPos(int errPos) {
446 endPosTable.setErrorEndPos(errPos);
447 }
449 private void storeEnd(JCTree tree, int endpos) {
450 endPosTable.storeEnd(tree, endpos);
451 }
453 private <T extends JCTree> T to(T t) {
454 return endPosTable.to(t);
455 }
457 private <T extends JCTree> T toP(T t) {
458 return endPosTable.toP(t);
459 }
461 /** Get the start position for a tree node. The start position is
462 * defined to be the position of the first character of the first
463 * token of the node's source text.
464 * @param tree The tree node
465 */
466 public int getStartPos(JCTree tree) {
467 return TreeInfo.getStartPos(tree);
468 }
470 /**
471 * Get the end position for a tree node. The end position is
472 * defined to be the position of the last character of the last
473 * token of the node's source text. Returns Position.NOPOS if end
474 * positions are not generated or the position is otherwise not
475 * found.
476 * @param tree The tree node
477 */
478 public int getEndPos(JCTree tree) {
479 return endPosTable.getEndPos(tree);
480 }
484 /* ---------- parsing -------------- */
486 /**
487 * Ident = IDENTIFIER
488 */
489 Name ident() {
490 if (token.kind == IDENTIFIER) {
491 Name name = token.name();
492 nextToken();
493 return name;
494 } else if (token.kind == ASSERT) {
495 if (allowAsserts) {
496 error(token.pos, "assert.as.identifier");
497 nextToken();
498 return names.error;
499 } else {
500 warning(token.pos, "assert.as.identifier");
501 Name name = token.name();
502 nextToken();
503 return name;
504 }
505 } else if (token.kind == ENUM) {
506 if (allowEnums) {
507 error(token.pos, "enum.as.identifier");
508 nextToken();
509 return names.error;
510 } else {
511 warning(token.pos, "enum.as.identifier");
512 Name name = token.name();
513 nextToken();
514 return name;
515 }
516 } else {
517 accept(IDENTIFIER);
518 return names.error;
519 }
520 }
522 /**
523 * Qualident = Ident { DOT Ident }
524 */
525 public JCExpression qualident() {
526 JCExpression t = toP(F.at(token.pos).Ident(ident()));
527 while (token.kind == DOT) {
528 int pos = token.pos;
529 nextToken();
530 t = toP(F.at(pos).Select(t, ident()));
531 }
532 return t;
533 }
535 JCExpression literal(Name prefix) {
536 return literal(prefix, token.pos);
537 }
539 /**
540 * Literal =
541 * INTLITERAL
542 * | LONGLITERAL
543 * | FLOATLITERAL
544 * | DOUBLELITERAL
545 * | CHARLITERAL
546 * | STRINGLITERAL
547 * | TRUE
548 * | FALSE
549 * | NULL
550 */
551 JCExpression literal(Name prefix, int pos) {
552 JCExpression t = errorTree;
553 switch (token.kind) {
554 case INTLITERAL:
555 try {
556 t = F.at(pos).Literal(
557 TypeTags.INT,
558 Convert.string2int(strval(prefix), token.radix()));
559 } catch (NumberFormatException ex) {
560 error(token.pos, "int.number.too.large", strval(prefix));
561 }
562 break;
563 case LONGLITERAL:
564 try {
565 t = F.at(pos).Literal(
566 TypeTags.LONG,
567 new Long(Convert.string2long(strval(prefix), token.radix())));
568 } catch (NumberFormatException ex) {
569 error(token.pos, "int.number.too.large", strval(prefix));
570 }
571 break;
572 case FLOATLITERAL: {
573 String proper = token.radix() == 16 ?
574 ("0x"+ token.stringVal()) :
575 token.stringVal();
576 Float n;
577 try {
578 n = Float.valueOf(proper);
579 } catch (NumberFormatException ex) {
580 // error already reported in scanner
581 n = Float.NaN;
582 }
583 if (n.floatValue() == 0.0f && !isZero(proper))
584 error(token.pos, "fp.number.too.small");
585 else if (n.floatValue() == Float.POSITIVE_INFINITY)
586 error(token.pos, "fp.number.too.large");
587 else
588 t = F.at(pos).Literal(TypeTags.FLOAT, n);
589 break;
590 }
591 case DOUBLELITERAL: {
592 String proper = token.radix() == 16 ?
593 ("0x"+ token.stringVal()) :
594 token.stringVal();
595 Double n;
596 try {
597 n = Double.valueOf(proper);
598 } catch (NumberFormatException ex) {
599 // error already reported in scanner
600 n = Double.NaN;
601 }
602 if (n.doubleValue() == 0.0d && !isZero(proper))
603 error(token.pos, "fp.number.too.small");
604 else if (n.doubleValue() == Double.POSITIVE_INFINITY)
605 error(token.pos, "fp.number.too.large");
606 else
607 t = F.at(pos).Literal(TypeTags.DOUBLE, n);
608 break;
609 }
610 case CHARLITERAL:
611 t = F.at(pos).Literal(
612 TypeTags.CHAR,
613 token.stringVal().charAt(0) + 0);
614 break;
615 case STRINGLITERAL:
616 t = F.at(pos).Literal(
617 TypeTags.CLASS,
618 token.stringVal());
619 break;
620 case TRUE: case FALSE:
621 t = F.at(pos).Literal(
622 TypeTags.BOOLEAN,
623 (token.kind == TRUE ? 1 : 0));
624 break;
625 case NULL:
626 t = F.at(pos).Literal(
627 TypeTags.BOT,
628 null);
629 break;
630 default:
631 Assert.error();
632 }
633 if (t == errorTree)
634 t = F.at(pos).Erroneous();
635 storeEnd(t, token.endPos);
636 nextToken();
637 return t;
638 }
639 //where
640 boolean isZero(String s) {
641 char[] cs = s.toCharArray();
642 int base = ((cs.length > 1 && Character.toLowerCase(cs[1]) == 'x') ? 16 : 10);
643 int i = ((base==16) ? 2 : 0);
644 while (i < cs.length && (cs[i] == '0' || cs[i] == '.')) i++;
645 return !(i < cs.length && (Character.digit(cs[i], base) > 0));
646 }
648 String strval(Name prefix) {
649 String s = token.stringVal();
650 return prefix.isEmpty() ? s : prefix + s;
651 }
653 /** terms can be either expressions or types.
654 */
655 public JCExpression parseExpression() {
656 return term(EXPR);
657 }
659 public JCExpression parseType() {
660 return term(TYPE);
661 }
663 JCExpression term(int newmode) {
664 int prevmode = mode;
665 mode = newmode;
666 JCExpression t = term();
667 lastmode = mode;
668 mode = prevmode;
669 return t;
670 }
672 /**
673 * {@literal
674 * Expression = Expression1 [ExpressionRest]
675 * ExpressionRest = [AssignmentOperator Expression1]
676 * AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" |
677 * "&=" | "|=" | "^=" |
678 * "%=" | "<<=" | ">>=" | ">>>="
679 * Type = Type1
680 * TypeNoParams = TypeNoParams1
681 * StatementExpression = Expression
682 * ConstantExpression = Expression
683 * }
684 */
685 JCExpression term() {
686 JCExpression t = term1();
687 if ((mode & EXPR) != 0 &&
688 token.kind == EQ || PLUSEQ.compareTo(token.kind) <= 0 && token.kind.compareTo(GTGTGTEQ) <= 0)
689 return termRest(t);
690 else
691 return t;
692 }
694 JCExpression termRest(JCExpression t) {
695 switch (token.kind) {
696 case EQ: {
697 int pos = token.pos;
698 nextToken();
699 mode = EXPR;
700 JCExpression t1 = term();
701 return toP(F.at(pos).Assign(t, t1));
702 }
703 case PLUSEQ:
704 case SUBEQ:
705 case STAREQ:
706 case SLASHEQ:
707 case PERCENTEQ:
708 case AMPEQ:
709 case BAREQ:
710 case CARETEQ:
711 case LTLTEQ:
712 case GTGTEQ:
713 case GTGTGTEQ:
714 int pos = token.pos;
715 TokenKind tk = token.kind;
716 nextToken();
717 mode = EXPR;
718 JCExpression t1 = term();
719 return F.at(pos).Assignop(optag(tk), t, t1);
720 default:
721 return t;
722 }
723 }
725 /** Expression1 = Expression2 [Expression1Rest]
726 * Type1 = Type2
727 * TypeNoParams1 = TypeNoParams2
728 */
729 JCExpression term1() {
730 JCExpression t = term2();
731 if ((mode & EXPR) != 0 && token.kind == QUES) {
732 mode = EXPR;
733 return term1Rest(t);
734 } else {
735 return t;
736 }
737 }
739 /** Expression1Rest = ["?" Expression ":" Expression1]
740 */
741 JCExpression term1Rest(JCExpression t) {
742 if (token.kind == QUES) {
743 int pos = token.pos;
744 nextToken();
745 JCExpression t1 = term();
746 accept(COLON);
747 JCExpression t2 = term1();
748 return F.at(pos).Conditional(t, t1, t2);
749 } else {
750 return t;
751 }
752 }
754 /** Expression2 = Expression3 [Expression2Rest]
755 * Type2 = Type3
756 * TypeNoParams2 = TypeNoParams3
757 */
758 JCExpression term2() {
759 JCExpression t = term3();
760 if ((mode & EXPR) != 0 && prec(token.kind) >= TreeInfo.orPrec) {
761 mode = EXPR;
762 return term2Rest(t, TreeInfo.orPrec);
763 } else {
764 return t;
765 }
766 }
768 /* Expression2Rest = {infixop Expression3}
769 * | Expression3 instanceof Type
770 * infixop = "||"
771 * | "&&"
772 * | "|"
773 * | "^"
774 * | "&"
775 * | "==" | "!="
776 * | "<" | ">" | "<=" | ">="
777 * | "<<" | ">>" | ">>>"
778 * | "+" | "-"
779 * | "*" | "/" | "%"
780 */
781 JCExpression term2Rest(JCExpression t, int minprec) {
782 List<JCExpression[]> savedOd = odStackSupply.elems;
783 JCExpression[] odStack = newOdStack();
784 List<Token[]> savedOp = opStackSupply.elems;
785 Token[] opStack = newOpStack();
787 // optimization, was odStack = new Tree[...]; opStack = new Tree[...];
788 int top = 0;
789 odStack[0] = t;
790 int startPos = token.pos;
791 Token topOp = Tokens.DUMMY;
792 while (prec(token.kind) >= minprec) {
793 opStack[top] = topOp;
794 top++;
795 topOp = token;
796 nextToken();
797 odStack[top] = (topOp.kind == INSTANCEOF) ? parseType() : term3();
798 while (top > 0 && prec(topOp.kind) >= prec(token.kind)) {
799 odStack[top-1] = makeOp(topOp.pos, topOp.kind, odStack[top-1],
800 odStack[top]);
801 top--;
802 topOp = opStack[top];
803 }
804 }
805 Assert.check(top == 0);
806 t = odStack[0];
808 if (t.hasTag(JCTree.Tag.PLUS)) {
809 StringBuffer buf = foldStrings(t);
810 if (buf != null) {
811 t = toP(F.at(startPos).Literal(TypeTags.CLASS, buf.toString()));
812 }
813 }
815 odStackSupply.elems = savedOd; // optimization
816 opStackSupply.elems = savedOp; // optimization
817 return t;
818 }
819 //where
820 /** Construct a binary or type test node.
821 */
822 private JCExpression makeOp(int pos,
823 TokenKind topOp,
824 JCExpression od1,
825 JCExpression od2)
826 {
827 if (topOp == INSTANCEOF) {
828 return F.at(pos).TypeTest(od1, od2);
829 } else {
830 return F.at(pos).Binary(optag(topOp), od1, od2);
831 }
832 }
833 /** If tree is a concatenation of string literals, replace it
834 * by a single literal representing the concatenated string.
835 */
836 protected StringBuffer foldStrings(JCTree tree) {
837 if (!allowStringFolding)
838 return null;
839 List<String> buf = List.nil();
840 while (true) {
841 if (tree.hasTag(LITERAL)) {
842 JCLiteral lit = (JCLiteral) tree;
843 if (lit.typetag == TypeTags.CLASS) {
844 StringBuffer sbuf =
845 new StringBuffer((String)lit.value);
846 while (buf.nonEmpty()) {
847 sbuf.append(buf.head);
848 buf = buf.tail;
849 }
850 return sbuf;
851 }
852 } else if (tree.hasTag(JCTree.Tag.PLUS)) {
853 JCBinary op = (JCBinary)tree;
854 if (op.rhs.hasTag(LITERAL)) {
855 JCLiteral lit = (JCLiteral) op.rhs;
856 if (lit.typetag == TypeTags.CLASS) {
857 buf = buf.prepend((String) lit.value);
858 tree = op.lhs;
859 continue;
860 }
861 }
862 }
863 return null;
864 }
865 }
867 /** optimization: To save allocating a new operand/operator stack
868 * for every binary operation, we use supplys.
869 */
870 ListBuffer<JCExpression[]> odStackSupply = new ListBuffer<JCExpression[]>();
871 ListBuffer<Token[]> opStackSupply = new ListBuffer<Token[]>();
873 private JCExpression[] newOdStack() {
874 if (odStackSupply.elems == odStackSupply.last)
875 odStackSupply.append(new JCExpression[infixPrecedenceLevels + 1]);
876 JCExpression[] odStack = odStackSupply.elems.head;
877 odStackSupply.elems = odStackSupply.elems.tail;
878 return odStack;
879 }
881 private Token[] newOpStack() {
882 if (opStackSupply.elems == opStackSupply.last)
883 opStackSupply.append(new Token[infixPrecedenceLevels + 1]);
884 Token[] opStack = opStackSupply.elems.head;
885 opStackSupply.elems = opStackSupply.elems.tail;
886 return opStack;
887 }
889 /**
890 * Expression3 = PrefixOp Expression3
891 * | "(" Expr | TypeNoParams ")" Expression3
892 * | Primary {Selector} {PostfixOp}
893 *
894 * {@literal
895 * Primary = "(" Expression ")"
896 * | Literal
897 * | [TypeArguments] THIS [Arguments]
898 * | [TypeArguments] SUPER SuperSuffix
899 * | NEW [TypeArguments] Creator
900 * | "(" Arguments ")" "->" ( Expression | Block )
901 * | Ident "->" ( Expression | Block )
902 * | Ident { "." Ident }
903 * | Expression3 MemberReferenceSuffix
904 * [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
905 * | Arguments
906 * | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
907 * ]
908 * | BasicType BracketsOpt "." CLASS
909 * }
910 *
911 * PrefixOp = "++" | "--" | "!" | "~" | "+" | "-"
912 * PostfixOp = "++" | "--"
913 * Type3 = Ident { "." Ident } [TypeArguments] {TypeSelector} BracketsOpt
914 * | BasicType
915 * TypeNoParams3 = Ident { "." Ident } BracketsOpt
916 * Selector = "." [TypeArguments] Ident [Arguments]
917 * | "." THIS
918 * | "." [TypeArguments] SUPER SuperSuffix
919 * | "." NEW [TypeArguments] InnerCreator
920 * | "[" Expression "]"
921 * TypeSelector = "." Ident [TypeArguments]
922 * SuperSuffix = Arguments | "." Ident [Arguments]
923 */
924 protected JCExpression term3() {
925 int pos = token.pos;
926 JCExpression t;
927 List<JCExpression> typeArgs = typeArgumentsOpt(EXPR);
928 switch (token.kind) {
929 case QUES:
930 if ((mode & TYPE) != 0 && (mode & (TYPEARG|NOPARAMS)) == TYPEARG) {
931 mode = TYPE;
932 return typeArgument();
933 } else
934 return illegal();
935 case PLUSPLUS: case SUBSUB: case BANG: case TILDE: case PLUS: case SUB:
936 if (typeArgs == null && (mode & EXPR) != 0) {
937 TokenKind tk = token.kind;
938 nextToken();
939 mode = EXPR;
940 if (tk == SUB &&
941 (token.kind == INTLITERAL || token.kind == LONGLITERAL) &&
942 token.radix() == 10) {
943 mode = EXPR;
944 t = literal(names.hyphen, pos);
945 } else {
946 t = term3();
947 return F.at(pos).Unary(unoptag(tk), t);
948 }
949 } else return illegal();
950 break;
951 case LPAREN:
952 if (typeArgs == null && (mode & EXPR) != 0) {
953 if (peekToken(FINAL) ||
954 peekToken(RPAREN) ||
955 peekToken(IDENTIFIER, COMMA) ||
956 peekToken(IDENTIFIER, RPAREN, ARROW)) {
957 //implicit n-ary lambda
958 t = lambdaExpressionOrStatement(true, peekToken(FINAL), pos);
959 break;
960 } else {
961 nextToken();
962 mode = EXPR | TYPE | NOPARAMS;
963 t = term3();
964 if ((mode & TYPE) != 0 && token.kind == LT) {
965 // Could be a cast to a parameterized type
966 JCTree.Tag op = JCTree.Tag.LT;
967 int pos1 = token.pos;
968 nextToken();
969 mode &= (EXPR | TYPE);
970 mode |= TYPEARG;
971 JCExpression t1 = term3();
972 if ((mode & TYPE) != 0 &&
973 (token.kind == COMMA || token.kind == GT)) {
974 mode = TYPE;
975 ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
976 args.append(t1);
977 while (token.kind == COMMA) {
978 nextToken();
979 args.append(typeArgument());
980 }
981 accept(GT);
982 t = toP(F.at(pos1).TypeApply(t, args.toList()));
983 checkGenerics();
984 mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type
985 t = term3Rest(t, typeArgs);
986 if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) {
987 //explicit lambda (w/ generic type)
988 mode = EXPR;
989 JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
990 if (token.kind == ELLIPSIS) {
991 mods.flags = Flags.VARARGS;
992 t = to(F.at(token.pos).TypeArray(t));
993 nextToken();
994 }
995 t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
996 break;
997 }
998 } else if ((mode & EXPR) != 0) {
999 mode = EXPR;
1000 JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
1001 t = F.at(pos1).Binary(op, t, e);
1002 t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
1003 } else {
1004 accept(GT);
1005 }
1006 } else if ((mode & TYPE) != 0 &&
1007 (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) {
1008 //explicit lambda (w/ non-generic type)
1009 mode = EXPR;
1010 JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
1011 if (token.kind == ELLIPSIS) {
1012 mods.flags = Flags.VARARGS;
1013 t = to(F.at(token.pos).TypeArray(t));
1014 nextToken();
1015 }
1016 t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
1017 break;
1018 } else {
1019 t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
1020 }
1021 }
1023 accept(RPAREN);
1024 lastmode = mode;
1025 mode = EXPR;
1026 if ((lastmode & EXPR) == 0) {
1027 JCExpression t1 = term3();
1028 return F.at(pos).TypeCast(t, t1);
1029 } else if ((lastmode & TYPE) != 0) {
1030 switch (token.kind) {
1031 /*case PLUSPLUS: case SUBSUB: */
1032 case BANG: case TILDE:
1033 case LPAREN: case THIS: case SUPER:
1034 case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
1035 case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
1036 case TRUE: case FALSE: case NULL:
1037 case NEW: case IDENTIFIER: case ASSERT: case ENUM:
1038 case BYTE: case SHORT: case CHAR: case INT:
1039 case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
1040 JCExpression t1 = term3();
1041 return F.at(pos).TypeCast(t, t1);
1042 }
1043 }
1044 } else {
1045 return illegal();
1046 }
1047 t = toP(F.at(pos).Parens(t));
1048 break;
1049 case THIS:
1050 if ((mode & EXPR) != 0) {
1051 mode = EXPR;
1052 t = to(F.at(pos).Ident(names._this));
1053 nextToken();
1054 if (typeArgs == null)
1055 t = argumentsOpt(null, t);
1056 else
1057 t = arguments(typeArgs, t);
1058 typeArgs = null;
1059 } else return illegal();
1060 break;
1061 case SUPER:
1062 if ((mode & EXPR) != 0) {
1063 mode = EXPR;
1064 t = to(F.at(pos).Ident(names._super));
1065 t = superSuffix(typeArgs, t);
1066 typeArgs = null;
1067 } else return illegal();
1068 break;
1069 case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL:
1070 case CHARLITERAL: case STRINGLITERAL:
1071 case TRUE: case FALSE: case NULL:
1072 if (typeArgs == null && (mode & EXPR) != 0) {
1073 mode = EXPR;
1074 t = literal(names.empty);
1075 } else return illegal();
1076 break;
1077 case NEW:
1078 if (typeArgs != null) return illegal();
1079 if ((mode & EXPR) != 0) {
1080 mode = EXPR;
1081 nextToken();
1082 if (token.kind == LT) typeArgs = typeArguments(false);
1083 t = creator(pos, typeArgs);
1084 typeArgs = null;
1085 } else return illegal();
1086 break;
1087 case IDENTIFIER: case ASSERT: case ENUM:
1088 if (typeArgs != null) return illegal();
1089 if ((mode & EXPR) != 0 && peekToken(ARROW)) {
1090 t = lambdaExpressionOrStatement(false, false, pos);
1091 } else {
1092 t = toP(F.at(token.pos).Ident(ident()));
1093 loop: while (true) {
1094 pos = token.pos;
1095 switch (token.kind) {
1096 case LBRACKET:
1097 nextToken();
1098 if (token.kind == RBRACKET) {
1099 nextToken();
1100 t = bracketsOpt(t);
1101 t = toP(F.at(pos).TypeArray(t));
1102 t = bracketsSuffix(t);
1103 } else {
1104 if ((mode & EXPR) != 0) {
1105 mode = EXPR;
1106 JCExpression t1 = term();
1107 t = to(F.at(pos).Indexed(t, t1));
1108 }
1109 accept(RBRACKET);
1110 }
1111 break loop;
1112 case LPAREN:
1113 if ((mode & EXPR) != 0) {
1114 mode = EXPR;
1115 t = arguments(typeArgs, t);
1116 typeArgs = null;
1117 }
1118 break loop;
1119 case DOT:
1120 nextToken();
1121 int oldmode = mode;
1122 mode &= ~NOPARAMS;
1123 typeArgs = typeArgumentsOpt(EXPR);
1124 mode = oldmode;
1125 if ((mode & EXPR) != 0) {
1126 switch (token.kind) {
1127 case CLASS:
1128 if (typeArgs != null) return illegal();
1129 mode = EXPR;
1130 t = to(F.at(pos).Select(t, names._class));
1131 nextToken();
1132 break loop;
1133 case THIS:
1134 if (typeArgs != null) return illegal();
1135 mode = EXPR;
1136 t = to(F.at(pos).Select(t, names._this));
1137 nextToken();
1138 break loop;
1139 case SUPER:
1140 mode = EXPR;
1141 t = to(F.at(pos).Select(t, names._super));
1142 t = superSuffix(typeArgs, t);
1143 typeArgs = null;
1144 break loop;
1145 case NEW:
1146 if (typeArgs != null) return illegal();
1147 mode = EXPR;
1148 int pos1 = token.pos;
1149 nextToken();
1150 if (token.kind == LT) typeArgs = typeArguments(false);
1151 t = innerCreator(pos1, typeArgs, t);
1152 typeArgs = null;
1153 break loop;
1154 }
1155 }
1156 // typeArgs saved for next loop iteration.
1157 t = toP(F.at(pos).Select(t, ident()));
1158 break;
1159 case LT:
1160 if ((mode & TYPE) == 0 && isUnboundMemberRef()) {
1161 //this is an unbound method reference whose qualifier
1162 //is a generic type i.e. A<S>#m
1163 int pos1 = token.pos;
1164 accept(LT);
1165 ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
1166 args.append(typeArgument());
1167 while (token.kind == COMMA) {
1168 nextToken();
1169 args.append(typeArgument());
1170 }
1171 accept(GT);
1172 t = toP(F.at(pos1).TypeApply(t, args.toList()));
1173 checkGenerics();
1174 while (token.kind == DOT) {
1175 nextToken();
1176 mode = TYPE;
1177 t = toP(F.at(token.pos).Select(t, ident()));
1178 t = typeArgumentsOpt(t);
1179 }
1180 if (token.kind != HASH) {
1181 //method reference expected here
1182 t = illegal();
1183 }
1184 mode = EXPR;
1185 return term3Rest(t, typeArgs);
1186 }
1187 break loop;
1188 default:
1189 break loop;
1190 }
1191 }
1192 }
1193 if (typeArgs != null) illegal();
1194 t = typeArgumentsOpt(t);
1195 break;
1196 case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
1197 case DOUBLE: case BOOLEAN:
1198 if (typeArgs != null) illegal();
1199 t = bracketsSuffix(bracketsOpt(basicType()));
1200 break;
1201 case VOID:
1202 if (typeArgs != null) illegal();
1203 if ((mode & EXPR) != 0) {
1204 nextToken();
1205 if (token.kind == DOT) {
1206 JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTags.VOID));
1207 t = bracketsSuffix(ti);
1208 } else {
1209 return illegal(pos);
1210 }
1211 } else {
1212 // Support the corner case of myMethodHandle.<void>invoke() by passing
1213 // a void type (like other primitive types) to the next phase.
1214 // The error will be reported in Attr.attribTypes or Attr.visitApply.
1215 JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTags.VOID));
1216 nextToken();
1217 return ti;
1218 //return illegal();
1219 }
1220 break;
1221 default:
1222 return illegal();
1223 }
1224 return term3Rest(t, typeArgs);
1225 }
1227 JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
1228 if (typeArgs != null) illegal();
1229 while (true) {
1230 int pos1 = token.pos;
1231 if (token.kind == LBRACKET) {
1232 nextToken();
1233 if ((mode & TYPE) != 0) {
1234 int oldmode = mode;
1235 mode = TYPE;
1236 if (token.kind == RBRACKET) {
1237 nextToken();
1238 t = bracketsOpt(t);
1239 t = toP(F.at(pos1).TypeArray(t));
1240 return t;
1241 }
1242 mode = oldmode;
1243 }
1244 if ((mode & EXPR) != 0) {
1245 mode = EXPR;
1246 JCExpression t1 = term();
1247 t = to(F.at(pos1).Indexed(t, t1));
1248 }
1249 accept(RBRACKET);
1250 } else if (token.kind == DOT) {
1251 nextToken();
1252 typeArgs = typeArgumentsOpt(EXPR);
1253 if (token.kind == SUPER && (mode & EXPR) != 0) {
1254 mode = EXPR;
1255 t = to(F.at(pos1).Select(t, names._super));
1256 nextToken();
1257 t = arguments(typeArgs, t);
1258 typeArgs = null;
1259 } else if (token.kind == NEW && (mode & EXPR) != 0) {
1260 if (typeArgs != null) return illegal();
1261 mode = EXPR;
1262 int pos2 = token.pos;
1263 nextToken();
1264 if (token.kind == LT) typeArgs = typeArguments(false);
1265 t = innerCreator(pos2, typeArgs, t);
1266 typeArgs = null;
1267 } else {
1268 t = toP(F.at(pos1).Select(t, ident()));
1269 t = argumentsOpt(typeArgs, typeArgumentsOpt(t));
1270 typeArgs = null;
1271 }
1272 } else if ((mode & EXPR) != 0 && token.kind == HASH) {
1273 mode = EXPR;
1274 if (typeArgs != null) return illegal();
1275 accept(HASH);
1276 t = memberReferenceSuffix(pos1, t);
1277 } else {
1278 break;
1279 }
1280 }
1281 while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && (mode & EXPR) != 0) {
1282 mode = EXPR;
1283 t = to(F.at(token.pos).Unary(
1284 token.kind == PLUSPLUS ? POSTINC : POSTDEC, t));
1285 nextToken();
1286 }
1287 return toP(t);
1288 }
1290 /**
1291 * If we see an identifier followed by a '<' it could be an unbound
1292 * method reference or a binary expression. To disambiguate, look for a
1293 * matching '>' and see if the subsequent terminal is either '.' or '#'.
1294 */
1295 @SuppressWarnings("fallthrough")
1296 boolean isUnboundMemberRef() {
1297 int pos = 0, depth = 0;
1298 for (Token t = S.token(pos) ; ; t = S.token(++pos)) {
1299 switch (t.kind) {
1300 case IDENTIFIER: case QUES: case EXTENDS: case SUPER:
1301 case DOT: case RBRACKET: case LBRACKET: case COMMA:
1302 case BYTE: case SHORT: case INT: case LONG: case FLOAT:
1303 case DOUBLE: case BOOLEAN: case CHAR:
1304 break;
1305 case LT:
1306 depth++; break;
1307 case GTGTGT:
1308 depth--;
1309 case GTGT:
1310 depth--;
1311 case GT:
1312 depth--;
1313 if (depth == 0) {
1314 return
1315 S.token(pos + 1).kind == TokenKind.DOT ||
1316 S.token(pos + 1).kind == TokenKind.HASH;
1317 }
1318 break;
1319 default:
1320 return false;
1321 }
1322 }
1323 }
1325 JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
1326 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
1327 params.append(firstParam);
1328 JCVariableDecl lastParam = firstParam;
1329 while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
1330 nextToken();
1331 params.append(lastParam = formalParameter());
1332 }
1333 accept(RPAREN);
1334 return lambdaExpressionOrStatementRest(params.toList(), pos);
1335 }
1337 JCExpression lambdaExpressionOrStatement(boolean hasParens, boolean explicitParams, int pos) {
1338 List<JCVariableDecl> params = explicitParams ?
1339 formalParameters() :
1340 implicitParameters(hasParens);
1342 return lambdaExpressionOrStatementRest(params, pos);
1343 }
1345 JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
1346 if (token.kind != ARROW) {
1347 //better error recovery
1348 return F.at(pos).Erroneous(args);
1349 }
1351 checkLambda();
1352 accept(ARROW);
1354 return token.kind == LBRACE ?
1355 lambdaStatement(args, pos, pos) :
1356 lambdaExpression(args, pos);
1357 }
1359 JCExpression lambdaStatement(List<JCVariableDecl> args, int pos, int pos2) {
1360 JCBlock block = block(pos2, 0);
1361 return toP(F.at(pos).Lambda(args, block));
1362 }
1364 JCExpression lambdaExpression(List<JCVariableDecl> args, int pos) {
1365 JCTree expr = parseExpression();
1366 return toP(F.at(pos).Lambda(args, expr));
1367 }
1369 /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments]
1370 */
1371 JCExpression superSuffix(List<JCExpression> typeArgs, JCExpression t) {
1372 nextToken();
1373 if (token.kind == LPAREN || typeArgs != null) {
1374 t = arguments(typeArgs, t);
1375 } else if (token.kind == HASH) {
1376 if (typeArgs != null) return illegal();
1377 t = memberReferenceSuffix(t);
1378 } else {
1379 int pos = token.pos;
1380 accept(DOT);
1381 typeArgs = (token.kind == LT) ? typeArguments(false) : null;
1382 t = toP(F.at(pos).Select(t, ident()));
1383 t = argumentsOpt(typeArgs, t);
1384 }
1385 return t;
1386 }
1388 /** BasicType = BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE | BOOLEAN
1389 */
1390 JCPrimitiveTypeTree basicType() {
1391 JCPrimitiveTypeTree t = to(F.at(token.pos).TypeIdent(typetag(token.kind)));
1392 nextToken();
1393 return t;
1394 }
1396 /** ArgumentsOpt = [ Arguments ]
1397 */
1398 JCExpression argumentsOpt(List<JCExpression> typeArgs, JCExpression t) {
1399 if ((mode & EXPR) != 0 && token.kind == LPAREN || typeArgs != null) {
1400 mode = EXPR;
1401 return arguments(typeArgs, t);
1402 } else {
1403 return t;
1404 }
1405 }
1407 /** Arguments = "(" [Expression { COMMA Expression }] ")"
1408 */
1409 List<JCExpression> arguments() {
1410 ListBuffer<JCExpression> args = lb();
1411 if (token.kind == LPAREN) {
1412 nextToken();
1413 if (token.kind != RPAREN) {
1414 args.append(parseExpression());
1415 while (token.kind == COMMA) {
1416 nextToken();
1417 args.append(parseExpression());
1418 }
1419 }
1420 accept(RPAREN);
1421 } else {
1422 syntaxError(token.pos, "expected", LPAREN);
1423 }
1424 return args.toList();
1425 }
1427 JCMethodInvocation arguments(List<JCExpression> typeArgs, JCExpression t) {
1428 int pos = token.pos;
1429 List<JCExpression> args = arguments();
1430 return toP(F.at(pos).Apply(typeArgs, t, args));
1431 }
1433 /** TypeArgumentsOpt = [ TypeArguments ]
1434 */
1435 JCExpression typeArgumentsOpt(JCExpression t) {
1436 if (token.kind == LT &&
1437 (mode & TYPE) != 0 &&
1438 (mode & NOPARAMS) == 0) {
1439 mode = TYPE;
1440 checkGenerics();
1441 return typeArguments(t, false);
1442 } else {
1443 return t;
1444 }
1445 }
1446 List<JCExpression> typeArgumentsOpt() {
1447 return typeArgumentsOpt(TYPE);
1448 }
1450 List<JCExpression> typeArgumentsOpt(int useMode) {
1451 if (token.kind == LT) {
1452 checkGenerics();
1453 if ((mode & useMode) == 0 ||
1454 (mode & NOPARAMS) != 0) {
1455 illegal();
1456 }
1457 mode = useMode;
1458 return typeArguments(false);
1459 }
1460 return null;
1461 }
1463 /**
1464 * {@literal
1465 * TypeArguments = "<" TypeArgument {"," TypeArgument} ">"
1466 * }
1467 */
1468 List<JCExpression> typeArguments(boolean diamondAllowed) {
1469 if (token.kind == LT) {
1470 nextToken();
1471 if (token.kind == GT && diamondAllowed) {
1472 checkDiamond();
1473 mode |= DIAMOND;
1474 nextToken();
1475 return List.nil();
1476 } else {
1477 ListBuffer<JCExpression> args = ListBuffer.lb();
1478 args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
1479 while (token.kind == COMMA) {
1480 nextToken();
1481 args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
1482 }
1483 switch (token.kind) {
1485 case GTGTGTEQ: case GTGTEQ: case GTEQ:
1486 case GTGTGT: case GTGT:
1487 token = S.split();
1488 break;
1489 case GT:
1490 nextToken();
1491 break;
1492 default:
1493 args.append(syntaxError(token.pos, "expected", GT));
1494 break;
1495 }
1496 return args.toList();
1497 }
1498 } else {
1499 return List.<JCExpression>of(syntaxError(token.pos, "expected", LT));
1500 }
1501 }
1503 /**
1504 * {@literal
1505 * TypeArgument = Type
1506 * | "?"
1507 * | "?" EXTENDS Type {"&" Type}
1508 * | "?" SUPER Type
1509 * }
1510 */
1511 JCExpression typeArgument() {
1512 if (token.kind != QUES) return parseType();
1513 int pos = token.pos;
1514 nextToken();
1515 if (token.kind == EXTENDS) {
1516 TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.EXTENDS));
1517 nextToken();
1518 JCExpression bound = parseType();
1519 return F.at(pos).Wildcard(t, bound);
1520 } else if (token.kind == SUPER) {
1521 TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.SUPER));
1522 nextToken();
1523 JCExpression bound = parseType();
1524 return F.at(pos).Wildcard(t, bound);
1525 } else if (token.kind == IDENTIFIER) {
1526 //error recovery
1527 TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
1528 JCExpression wc = toP(F.at(pos).Wildcard(t, null));
1529 JCIdent id = toP(F.at(token.pos).Ident(ident()));
1530 JCErroneous err = F.at(pos).Erroneous(List.<JCTree>of(wc, id));
1531 reportSyntaxError(err, "expected3", GT, EXTENDS, SUPER);
1532 return err;
1533 } else {
1534 TypeBoundKind t = toP(F.at(pos).TypeBoundKind(BoundKind.UNBOUND));
1535 return toP(F.at(pos).Wildcard(t, null));
1536 }
1537 }
1539 JCTypeApply typeArguments(JCExpression t, boolean diamondAllowed) {
1540 int pos = token.pos;
1541 List<JCExpression> args = typeArguments(diamondAllowed);
1542 return toP(F.at(pos).TypeApply(t, args));
1543 }
1545 /** BracketsOpt = {"[" "]"}
1546 */
1547 private JCExpression bracketsOpt(JCExpression t) {
1548 if (token.kind == LBRACKET) {
1549 int pos = token.pos;
1550 nextToken();
1551 t = bracketsOptCont(t, pos);
1552 F.at(pos);
1553 }
1554 return t;
1555 }
1557 private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos) {
1558 accept(RBRACKET);
1559 t = bracketsOpt(t);
1560 return toP(F.at(pos).TypeArray(t));
1561 }
1563 /** BracketsSuffixExpr = "." CLASS
1564 * BracketsSuffixType =
1565 */
1566 JCExpression bracketsSuffix(JCExpression t) {
1567 if ((mode & EXPR) != 0 && token.kind == DOT) {
1568 mode = EXPR;
1569 int pos = token.pos;
1570 nextToken();
1571 accept(CLASS);
1572 if (token.pos == endPosTable.errorEndPos) {
1573 // error recovery
1574 Name name = null;
1575 if (token.kind == IDENTIFIER) {
1576 name = token.name();
1577 nextToken();
1578 } else {
1579 name = names.error;
1580 }
1581 t = F.at(pos).Erroneous(List.<JCTree>of(toP(F.at(pos).Select(t, name))));
1582 } else {
1583 t = toP(F.at(pos).Select(t, names._class));
1584 }
1585 } else if ((mode & TYPE) != 0) {
1586 mode = TYPE;
1587 } else {
1588 syntaxError(token.pos, "dot.class.expected");
1589 }
1590 return t;
1591 }
1593 /**
1594 * MemberReferenceSuffix = "#" [TypeArguments] Ident
1595 * | "#" [TypeArguments] "new"
1596 */
1597 JCExpression memberReferenceSuffix(JCExpression t) {
1598 int pos1 = token.pos;
1599 accept(HASH);
1600 return memberReferenceSuffix(pos1, t);
1601 }
1603 JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
1604 checkMethodReferences();
1605 mode = EXPR;
1606 List<JCExpression> typeArgs = null;
1607 if (token.kind == LT) {
1608 typeArgs = typeArguments(false);
1609 }
1610 Name refName = null;
1611 ReferenceMode refMode = null;
1612 if (token.kind == NEW) {
1613 refMode = ReferenceMode.NEW;
1614 refName = names.init;
1615 nextToken();
1616 } else {
1617 refMode = ReferenceMode.INVOKE;
1618 refName = ident();
1619 }
1620 return toP(F.at(t.getStartPosition()).Reference(refMode, refName, t, typeArgs));
1621 }
1623 /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
1624 */
1625 JCExpression creator(int newpos, List<JCExpression> typeArgs) {
1626 switch (token.kind) {
1627 case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
1628 case DOUBLE: case BOOLEAN:
1629 if (typeArgs == null)
1630 return arrayCreatorRest(newpos, basicType());
1631 break;
1632 default:
1633 }
1634 JCExpression t = qualident();
1635 int oldmode = mode;
1636 mode = TYPE;
1637 boolean diamondFound = false;
1638 int lastTypeargsPos = -1;
1639 if (token.kind == LT) {
1640 checkGenerics();
1641 lastTypeargsPos = token.pos;
1642 t = typeArguments(t, true);
1643 diamondFound = (mode & DIAMOND) != 0;
1644 }
1645 while (token.kind == DOT) {
1646 if (diamondFound) {
1647 //cannot select after a diamond
1648 illegal();
1649 }
1650 int pos = token.pos;
1651 nextToken();
1652 t = toP(F.at(pos).Select(t, ident()));
1653 if (token.kind == LT) {
1654 lastTypeargsPos = token.pos;
1655 checkGenerics();
1656 t = typeArguments(t, true);
1657 diamondFound = (mode & DIAMOND) != 0;
1658 }
1659 }
1660 mode = oldmode;
1661 if (token.kind == LBRACKET) {
1662 JCExpression e = arrayCreatorRest(newpos, t);
1663 if (diamondFound) {
1664 reportSyntaxError(lastTypeargsPos, "cannot.create.array.with.diamond");
1665 return toP(F.at(newpos).Erroneous(List.of(e)));
1666 }
1667 else if (typeArgs != null) {
1668 int pos = newpos;
1669 if (!typeArgs.isEmpty() && typeArgs.head.pos != Position.NOPOS) {
1670 // note: this should always happen but we should
1671 // not rely on this as the parser is continuously
1672 // modified to improve error recovery.
1673 pos = typeArgs.head.pos;
1674 }
1675 setErrorEndPos(S.prevToken().endPos);
1676 JCErroneous err = F.at(pos).Erroneous(typeArgs.prepend(e));
1677 reportSyntaxError(err, "cannot.create.array.with.type.arguments");
1678 return toP(err);
1679 }
1680 return e;
1681 } else if (token.kind == LPAREN) {
1682 return classCreatorRest(newpos, null, typeArgs, t);
1683 } else {
1684 setErrorEndPos(token.pos);
1685 reportSyntaxError(token.pos, "expected2", LPAREN, LBRACKET);
1686 t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.<JCExpression>nil(), null));
1687 return toP(F.at(newpos).Erroneous(List.<JCTree>of(t)));
1688 }
1689 }
1691 /** InnerCreator = Ident [TypeArguments] ClassCreatorRest
1692 */
1693 JCExpression innerCreator(int newpos, List<JCExpression> typeArgs, JCExpression encl) {
1694 JCExpression t = toP(F.at(token.pos).Ident(ident()));
1695 if (token.kind == LT) {
1696 int oldmode = mode;
1697 checkGenerics();
1698 t = typeArguments(t, true);
1699 mode = oldmode;
1700 }
1701 return classCreatorRest(newpos, encl, typeArgs, t);
1702 }
1704 /** ArrayCreatorRest = "[" ( "]" BracketsOpt ArrayInitializer
1705 * | Expression "]" {"[" Expression "]"} BracketsOpt )
1706 */
1707 JCExpression arrayCreatorRest(int newpos, JCExpression elemtype) {
1708 accept(LBRACKET);
1709 if (token.kind == RBRACKET) {
1710 accept(RBRACKET);
1711 elemtype = bracketsOpt(elemtype);
1712 if (token.kind == LBRACE) {
1713 return arrayInitializer(newpos, elemtype);
1714 } else {
1715 JCExpression t = toP(F.at(newpos).NewArray(elemtype, List.<JCExpression>nil(), null));
1716 return syntaxError(token.pos, List.<JCTree>of(t), "array.dimension.missing");
1717 }
1718 } else {
1719 ListBuffer<JCExpression> dims = new ListBuffer<JCExpression>();
1720 dims.append(parseExpression());
1721 accept(RBRACKET);
1722 while (token.kind == LBRACKET) {
1723 int pos = token.pos;
1724 nextToken();
1725 if (token.kind == RBRACKET) {
1726 elemtype = bracketsOptCont(elemtype, pos);
1727 } else {
1728 dims.append(parseExpression());
1729 accept(RBRACKET);
1730 }
1731 }
1732 return toP(F.at(newpos).NewArray(elemtype, dims.toList(), null));
1733 }
1734 }
1736 /** ClassCreatorRest = Arguments [ClassBody]
1737 */
1738 JCNewClass classCreatorRest(int newpos,
1739 JCExpression encl,
1740 List<JCExpression> typeArgs,
1741 JCExpression t)
1742 {
1743 List<JCExpression> args = arguments();
1744 JCClassDecl body = null;
1745 if (token.kind == LBRACE) {
1746 int pos = token.pos;
1747 List<JCTree> defs = classOrInterfaceBody(names.empty, false);
1748 JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
1749 body = toP(F.at(pos).AnonymousClassDef(mods, defs));
1750 }
1751 return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
1752 }
1754 /** ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}"
1755 */
1756 JCExpression arrayInitializer(int newpos, JCExpression t) {
1757 accept(LBRACE);
1758 ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>();
1759 if (token.kind == COMMA) {
1760 nextToken();
1761 } else if (token.kind != RBRACE) {
1762 elems.append(variableInitializer());
1763 while (token.kind == COMMA) {
1764 nextToken();
1765 if (token.kind == RBRACE) break;
1766 elems.append(variableInitializer());
1767 }
1768 }
1769 accept(RBRACE);
1770 return toP(F.at(newpos).NewArray(t, List.<JCExpression>nil(), elems.toList()));
1771 }
1773 /** VariableInitializer = ArrayInitializer | Expression
1774 */
1775 public JCExpression variableInitializer() {
1776 return token.kind == LBRACE ? arrayInitializer(token.pos, null) : parseExpression();
1777 }
1779 /** ParExpression = "(" Expression ")"
1780 */
1781 JCExpression parExpression() {
1782 int pos = token.pos;
1783 accept(LPAREN);
1784 JCExpression t = parseExpression();
1785 accept(RPAREN);
1786 return toP(F.at(pos).Parens(t));
1787 }
1789 /** Block = "{" BlockStatements "}"
1790 */
1791 JCBlock block(int pos, long flags) {
1792 accept(LBRACE);
1793 List<JCStatement> stats = blockStatements();
1794 JCBlock t = F.at(pos).Block(flags, stats);
1795 while (token.kind == CASE || token.kind == DEFAULT) {
1796 syntaxError("orphaned", token.kind);
1797 switchBlockStatementGroups();
1798 }
1799 // the Block node has a field "endpos" for first char of last token, which is
1800 // usually but not necessarily the last char of the last token.
1801 t.endpos = token.pos;
1802 accept(RBRACE);
1803 return toP(t);
1804 }
1806 public JCBlock block() {
1807 return block(token.pos, 0);
1808 }
1810 /** BlockStatements = { BlockStatement }
1811 * BlockStatement = LocalVariableDeclarationStatement
1812 * | ClassOrInterfaceOrEnumDeclaration
1813 * | [Ident ":"] Statement
1814 * LocalVariableDeclarationStatement
1815 * = { FINAL | '@' Annotation } Type VariableDeclarators ";"
1816 */
1817 @SuppressWarnings("fallthrough")
1818 List<JCStatement> blockStatements() {
1819 //todo: skip to anchor on error(?)
1820 ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>();
1821 while (true) {
1822 List<JCStatement> stat = blockStatement();
1823 if (stat.isEmpty()) {
1824 return stats.toList();
1825 } else {
1826 if (token.pos <= endPosTable.errorEndPos) {
1827 skip(false, true, true, true);
1828 }
1829 stats.addAll(stat);
1830 }
1831 }
1832 }
1834 /*
1835 * This method parses a statement treating it as a block, relaxing the
1836 * JLS restrictions, allows us to parse more faulty code, doing so
1837 * enables us to provide better and accurate diagnostics to the user.
1838 */
1839 JCStatement parseStatementAsBlock() {
1840 int pos = token.pos;
1841 List<JCStatement> stats = blockStatement();
1842 if (stats.isEmpty()) {
1843 JCErroneous e = F.at(pos).Erroneous();
1844 error(e, "illegal.start.of.stmt");
1845 return F.at(pos).Exec(e);
1846 } else {
1847 JCStatement first = stats.head;
1848 String error = null;
1849 switch (first.getTag()) {
1850 case CLASSDEF:
1851 error = "class.not.allowed";
1852 break;
1853 case VARDEF:
1854 error = "variable.not.allowed";
1855 break;
1856 }
1857 if (error != null) {
1858 error(first, error);
1859 List<JCBlock> blist = List.of(F.at(first.pos).Block(0, stats));
1860 return toP(F.at(pos).Exec(F.at(first.pos).Erroneous(blist)));
1861 }
1862 return first;
1863 }
1864 }
1866 @SuppressWarnings("fallthrough")
1867 List<JCStatement> blockStatement() {
1868 //todo: skip to anchor on error(?)
1869 int pos = token.pos;
1870 switch (token.kind) {
1871 case RBRACE: case CASE: case DEFAULT: case EOF:
1872 return List.nil();
1873 case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY:
1874 case SWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK:
1875 case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH:
1876 return List.of(parseStatement());
1877 case MONKEYS_AT:
1878 case FINAL: {
1879 Comment dc = token.comment(CommentStyle.JAVADOC);
1880 JCModifiers mods = modifiersOpt();
1881 if (token.kind == INTERFACE ||
1882 token.kind == CLASS ||
1883 allowEnums && token.kind == ENUM) {
1884 return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
1885 } else {
1886 JCExpression t = parseType();
1887 ListBuffer<JCStatement> stats =
1888 variableDeclarators(mods, t, new ListBuffer<JCStatement>());
1889 // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
1890 storeEnd(stats.elems.last(), token.endPos);
1891 accept(SEMI);
1892 return stats.toList();
1893 }
1894 }
1895 case ABSTRACT: case STRICTFP: {
1896 Comment dc = token.comment(CommentStyle.JAVADOC);
1897 JCModifiers mods = modifiersOpt();
1898 return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
1899 }
1900 case INTERFACE:
1901 case CLASS:
1902 Comment dc = token.comment(CommentStyle.JAVADOC);
1903 return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
1904 case ENUM:
1905 case ASSERT:
1906 if (allowEnums && token.kind == ENUM) {
1907 error(token.pos, "local.enum");
1908 dc = token.comment(CommentStyle.JAVADOC);
1909 return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
1910 } else if (allowAsserts && token.kind == ASSERT) {
1911 return List.of(parseStatement());
1912 }
1913 /* fall through to default */
1914 default:
1915 Token prevToken = token;
1916 JCExpression t = term(EXPR | TYPE);
1917 if (token.kind == COLON && t.hasTag(IDENT)) {
1918 nextToken();
1919 JCStatement stat = parseStatement();
1920 return List.<JCStatement>of(F.at(pos).Labelled(prevToken.name(), stat));
1921 } else if ((lastmode & TYPE) != 0 &&
1922 (token.kind == IDENTIFIER ||
1923 token.kind == ASSERT ||
1924 token.kind == ENUM)) {
1925 pos = token.pos;
1926 JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
1927 F.at(pos);
1928 ListBuffer<JCStatement> stats =
1929 variableDeclarators(mods, t, new ListBuffer<JCStatement>());
1930 // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
1931 storeEnd(stats.elems.last(), token.endPos);
1932 accept(SEMI);
1933 return stats.toList();
1934 } else {
1935 // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
1936 JCExpressionStatement expr = to(F.at(pos).Exec(checkExprStat(t)));
1937 accept(SEMI);
1938 return List.<JCStatement>of(expr);
1939 }
1940 }
1941 }
1943 /** Statement =
1944 * Block
1945 * | IF ParExpression Statement [ELSE Statement]
1946 * | FOR "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement
1947 * | FOR "(" FormalParameter : Expression ")" Statement
1948 * | WHILE ParExpression Statement
1949 * | DO Statement WHILE ParExpression ";"
1950 * | TRY Block ( Catches | [Catches] FinallyPart )
1951 * | TRY "(" ResourceSpecification ";"opt ")" Block [Catches] [FinallyPart]
1952 * | SWITCH ParExpression "{" SwitchBlockStatementGroups "}"
1953 * | SYNCHRONIZED ParExpression Block
1954 * | RETURN [Expression] ";"
1955 * | THROW Expression ";"
1956 * | BREAK [Ident] ";"
1957 * | CONTINUE [Ident] ";"
1958 * | ASSERT Expression [ ":" Expression ] ";"
1959 * | ";"
1960 * | ExpressionStatement
1961 * | Ident ":" Statement
1962 */
1963 @SuppressWarnings("fallthrough")
1964 public JCStatement parseStatement() {
1965 int pos = token.pos;
1966 switch (token.kind) {
1967 case LBRACE:
1968 return block();
1969 case IF: {
1970 nextToken();
1971 JCExpression cond = parExpression();
1972 JCStatement thenpart = parseStatementAsBlock();
1973 JCStatement elsepart = null;
1974 if (token.kind == ELSE) {
1975 nextToken();
1976 elsepart = parseStatementAsBlock();
1977 }
1978 return F.at(pos).If(cond, thenpart, elsepart);
1979 }
1980 case FOR: {
1981 nextToken();
1982 accept(LPAREN);
1983 List<JCStatement> inits = token.kind == SEMI ? List.<JCStatement>nil() : forInit();
1984 if (inits.length() == 1 &&
1985 inits.head.hasTag(VARDEF) &&
1986 ((JCVariableDecl) inits.head).init == null &&
1987 token.kind == COLON) {
1988 checkForeach();
1989 JCVariableDecl var = (JCVariableDecl)inits.head;
1990 accept(COLON);
1991 JCExpression expr = parseExpression();
1992 accept(RPAREN);
1993 JCStatement body = parseStatementAsBlock();
1994 return F.at(pos).ForeachLoop(var, expr, body);
1995 } else {
1996 accept(SEMI);
1997 JCExpression cond = token.kind == SEMI ? null : parseExpression();
1998 accept(SEMI);
1999 List<JCExpressionStatement> steps = token.kind == RPAREN ? List.<JCExpressionStatement>nil() : forUpdate();
2000 accept(RPAREN);
2001 JCStatement body = parseStatementAsBlock();
2002 return F.at(pos).ForLoop(inits, cond, steps, body);
2003 }
2004 }
2005 case WHILE: {
2006 nextToken();
2007 JCExpression cond = parExpression();
2008 JCStatement body = parseStatementAsBlock();
2009 return F.at(pos).WhileLoop(cond, body);
2010 }
2011 case DO: {
2012 nextToken();
2013 JCStatement body = parseStatementAsBlock();
2014 accept(WHILE);
2015 JCExpression cond = parExpression();
2016 JCDoWhileLoop t = to(F.at(pos).DoLoop(body, cond));
2017 accept(SEMI);
2018 return t;
2019 }
2020 case TRY: {
2021 nextToken();
2022 List<JCTree> resources = List.<JCTree>nil();
2023 if (token.kind == LPAREN) {
2024 checkTryWithResources();
2025 nextToken();
2026 resources = resources();
2027 accept(RPAREN);
2028 }
2029 JCBlock body = block();
2030 ListBuffer<JCCatch> catchers = new ListBuffer<JCCatch>();
2031 JCBlock finalizer = null;
2032 if (token.kind == CATCH || token.kind == FINALLY) {
2033 while (token.kind == CATCH) catchers.append(catchClause());
2034 if (token.kind == FINALLY) {
2035 nextToken();
2036 finalizer = block();
2037 }
2038 } else {
2039 if (allowTWR) {
2040 if (resources.isEmpty())
2041 error(pos, "try.without.catch.finally.or.resource.decls");
2042 } else
2043 error(pos, "try.without.catch.or.finally");
2044 }
2045 return F.at(pos).Try(resources, body, catchers.toList(), finalizer);
2046 }
2047 case SWITCH: {
2048 nextToken();
2049 JCExpression selector = parExpression();
2050 accept(LBRACE);
2051 List<JCCase> cases = switchBlockStatementGroups();
2052 JCSwitch t = to(F.at(pos).Switch(selector, cases));
2053 accept(RBRACE);
2054 return t;
2055 }
2056 case SYNCHRONIZED: {
2057 nextToken();
2058 JCExpression lock = parExpression();
2059 JCBlock body = block();
2060 return F.at(pos).Synchronized(lock, body);
2061 }
2062 case RETURN: {
2063 nextToken();
2064 JCExpression result = token.kind == SEMI ? null : parseExpression();
2065 JCReturn t = to(F.at(pos).Return(result));
2066 accept(SEMI);
2067 return t;
2068 }
2069 case THROW: {
2070 nextToken();
2071 JCExpression exc = parseExpression();
2072 JCThrow t = to(F.at(pos).Throw(exc));
2073 accept(SEMI);
2074 return t;
2075 }
2076 case BREAK: {
2077 nextToken();
2078 Name label = (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM) ? ident() : null;
2079 JCBreak t = to(F.at(pos).Break(label));
2080 accept(SEMI);
2081 return t;
2082 }
2083 case CONTINUE: {
2084 nextToken();
2085 Name label = (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM) ? ident() : null;
2086 JCContinue t = to(F.at(pos).Continue(label));
2087 accept(SEMI);
2088 return t;
2089 }
2090 case SEMI:
2091 nextToken();
2092 return toP(F.at(pos).Skip());
2093 case ELSE:
2094 return toP(F.Exec(syntaxError("else.without.if")));
2095 case FINALLY:
2096 return toP(F.Exec(syntaxError("finally.without.try")));
2097 case CATCH:
2098 return toP(F.Exec(syntaxError("catch.without.try")));
2099 case ASSERT: {
2100 if (allowAsserts && token.kind == ASSERT) {
2101 nextToken();
2102 JCExpression assertion = parseExpression();
2103 JCExpression message = null;
2104 if (token.kind == COLON) {
2105 nextToken();
2106 message = parseExpression();
2107 }
2108 JCAssert t = to(F.at(pos).Assert(assertion, message));
2109 accept(SEMI);
2110 return t;
2111 }
2112 /* else fall through to default case */
2113 }
2114 case ENUM:
2115 default:
2116 Token prevToken = token;
2117 JCExpression expr = parseExpression();
2118 if (token.kind == COLON && expr.hasTag(IDENT)) {
2119 nextToken();
2120 JCStatement stat = parseStatement();
2121 return F.at(pos).Labelled(prevToken.name(), stat);
2122 } else {
2123 // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
2124 JCExpressionStatement stat = to(F.at(pos).Exec(checkExprStat(expr)));
2125 accept(SEMI);
2126 return stat;
2127 }
2128 }
2129 }
2131 /** CatchClause = CATCH "(" FormalParameter ")" Block
2132 */
2133 protected JCCatch catchClause() {
2134 int pos = token.pos;
2135 accept(CATCH);
2136 accept(LPAREN);
2137 JCModifiers mods = optFinal(Flags.PARAMETER);
2138 List<JCExpression> catchTypes = catchTypes();
2139 JCExpression paramType = catchTypes.size() > 1 ?
2140 toP(F.at(catchTypes.head.getStartPosition()).TypeUnion(catchTypes)) :
2141 catchTypes.head;
2142 JCVariableDecl formal = variableDeclaratorId(mods, paramType);
2143 accept(RPAREN);
2144 JCBlock body = block();
2145 return F.at(pos).Catch(formal, body);
2146 }
2148 List<JCExpression> catchTypes() {
2149 ListBuffer<JCExpression> catchTypes = ListBuffer.lb();
2150 catchTypes.add(parseType());
2151 while (token.kind == BAR) {
2152 checkMulticatch();
2153 nextToken();
2154 catchTypes.add(qualident());
2155 }
2156 return catchTypes.toList();
2157 }
2159 /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup }
2160 * SwitchBlockStatementGroup = SwitchLabel BlockStatements
2161 * SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":"
2162 */
2163 List<JCCase> switchBlockStatementGroups() {
2164 ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
2165 while (true) {
2166 int pos = token.pos;
2167 switch (token.kind) {
2168 case CASE:
2169 case DEFAULT:
2170 cases.append(switchBlockStatementGroup());
2171 break;
2172 case RBRACE: case EOF:
2173 return cases.toList();
2174 default:
2175 nextToken(); // to ensure progress
2176 syntaxError(pos, "expected3",
2177 CASE, DEFAULT, RBRACE);
2178 }
2179 }
2180 }
2182 protected JCCase switchBlockStatementGroup() {
2183 int pos = token.pos;
2184 List<JCStatement> stats;
2185 JCCase c;
2186 switch (token.kind) {
2187 case CASE:
2188 nextToken();
2189 JCExpression pat = parseExpression();
2190 accept(COLON);
2191 stats = blockStatements();
2192 c = F.at(pos).Case(pat, stats);
2193 if (stats.isEmpty())
2194 storeEnd(c, S.prevToken().endPos);
2195 return c;
2196 case DEFAULT:
2197 nextToken();
2198 accept(COLON);
2199 stats = blockStatements();
2200 c = F.at(pos).Case(null, stats);
2201 if (stats.isEmpty())
2202 storeEnd(c, S.prevToken().endPos);
2203 return c;
2204 }
2205 throw new AssertionError("should not reach here");
2206 }
2208 /** MoreStatementExpressions = { COMMA StatementExpression }
2209 */
2210 <T extends ListBuffer<? super JCExpressionStatement>> T moreStatementExpressions(int pos,
2211 JCExpression first,
2212 T stats) {
2213 // This Exec is a "StatementExpression"; it subsumes no terminating token
2214 stats.append(toP(F.at(pos).Exec(checkExprStat(first))));
2215 while (token.kind == COMMA) {
2216 nextToken();
2217 pos = token.pos;
2218 JCExpression t = parseExpression();
2219 // This Exec is a "StatementExpression"; it subsumes no terminating token
2220 stats.append(toP(F.at(pos).Exec(checkExprStat(t))));
2221 }
2222 return stats;
2223 }
2225 /** ForInit = StatementExpression MoreStatementExpressions
2226 * | { FINAL | '@' Annotation } Type VariableDeclarators
2227 */
2228 List<JCStatement> forInit() {
2229 ListBuffer<JCStatement> stats = lb();
2230 int pos = token.pos;
2231 if (token.kind == FINAL || token.kind == MONKEYS_AT) {
2232 return variableDeclarators(optFinal(0), parseType(), stats).toList();
2233 } else {
2234 JCExpression t = term(EXPR | TYPE);
2235 if ((lastmode & TYPE) != 0 &&
2236 (token.kind == IDENTIFIER || token.kind == ASSERT ||
2237 token.kind == ENUM)) {
2238 return variableDeclarators(modifiersOpt(), t, stats).toList();
2239 } else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
2240 error(pos, "bad.initializer", "for-loop");
2241 return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
2242 } else {
2243 return moreStatementExpressions(pos, t, stats).toList();
2244 }
2245 }
2246 }
2248 /** ForUpdate = StatementExpression MoreStatementExpressions
2249 */
2250 List<JCExpressionStatement> forUpdate() {
2251 return moreStatementExpressions(token.pos,
2252 parseExpression(),
2253 new ListBuffer<JCExpressionStatement>()).toList();
2254 }
2256 /** AnnotationsOpt = { '@' Annotation }
2257 */
2258 List<JCAnnotation> annotationsOpt() {
2259 if (token.kind != MONKEYS_AT) return List.nil(); // optimization
2260 ListBuffer<JCAnnotation> buf = new ListBuffer<JCAnnotation>();
2261 while (token.kind == MONKEYS_AT) {
2262 int pos = token.pos;
2263 nextToken();
2264 buf.append(annotation(pos));
2265 }
2266 return buf.toList();
2267 }
2269 /** ModifiersOpt = { Modifier }
2270 * Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL
2271 * | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@"
2272 * | "@" Annotation
2273 */
2274 JCModifiers modifiersOpt() {
2275 return modifiersOpt(null);
2276 }
2277 protected JCModifiers modifiersOpt(JCModifiers partial) {
2278 long flags;
2279 ListBuffer<JCAnnotation> annotations = new ListBuffer<JCAnnotation>();
2280 int pos;
2281 if (partial == null) {
2282 flags = 0;
2283 pos = token.pos;
2284 } else {
2285 flags = partial.flags;
2286 annotations.appendList(partial.annotations);
2287 pos = partial.pos;
2288 }
2289 if (token.deprecatedFlag()) {
2290 flags |= Flags.DEPRECATED;
2291 }
2292 int lastPos = Position.NOPOS;
2293 loop:
2294 while (true) {
2295 long flag;
2296 switch (token.kind) {
2297 case PRIVATE : flag = Flags.PRIVATE; break;
2298 case PROTECTED : flag = Flags.PROTECTED; break;
2299 case PUBLIC : flag = Flags.PUBLIC; break;
2300 case STATIC : flag = Flags.STATIC; break;
2301 case TRANSIENT : flag = Flags.TRANSIENT; break;
2302 case FINAL : flag = Flags.FINAL; break;
2303 case ABSTRACT : flag = Flags.ABSTRACT; break;
2304 case NATIVE : flag = Flags.NATIVE; break;
2305 case VOLATILE : flag = Flags.VOLATILE; break;
2306 case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break;
2307 case STRICTFP : flag = Flags.STRICTFP; break;
2308 case MONKEYS_AT : flag = Flags.ANNOTATION; break;
2309 case ERROR : flag = 0; nextToken(); break;
2310 default: break loop;
2311 }
2312 if ((flags & flag) != 0) error(token.pos, "repeated.modifier");
2313 lastPos = token.pos;
2314 nextToken();
2315 if (flag == Flags.ANNOTATION) {
2316 checkAnnotations();
2317 if (token.kind != INTERFACE) {
2318 JCAnnotation ann = annotation(lastPos);
2319 // if first modifier is an annotation, set pos to annotation's.
2320 if (flags == 0 && annotations.isEmpty())
2321 pos = ann.pos;
2322 annotations.append(ann);
2323 lastPos = ann.pos;
2324 flag = 0;
2325 }
2326 }
2327 flags |= flag;
2328 }
2329 switch (token.kind) {
2330 case ENUM: flags |= Flags.ENUM; break;
2331 case INTERFACE: flags |= Flags.INTERFACE; break;
2332 default: break;
2333 }
2335 /* A modifiers tree with no modifier tokens or annotations
2336 * has no text position. */
2337 if ((flags & (Flags.ModifierFlags | Flags.ANNOTATION)) == 0 && annotations.isEmpty())
2338 pos = Position.NOPOS;
2340 JCModifiers mods = F.at(pos).Modifiers(flags, annotations.toList());
2341 if (pos != Position.NOPOS)
2342 storeEnd(mods, S.prevToken().endPos);
2343 return mods;
2344 }
2346 /** Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ]
2347 * @param pos position of "@" token
2348 */
2349 JCAnnotation annotation(int pos) {
2350 // accept(AT); // AT consumed by caller
2351 checkAnnotations();
2352 JCTree ident = qualident();
2353 List<JCExpression> fieldValues = annotationFieldValuesOpt();
2354 JCAnnotation ann = F.at(pos).Annotation(ident, fieldValues);
2355 storeEnd(ann, S.prevToken().endPos);
2356 return ann;
2357 }
2359 List<JCExpression> annotationFieldValuesOpt() {
2360 return (token.kind == LPAREN) ? annotationFieldValues() : List.<JCExpression>nil();
2361 }
2363 /** AnnotationFieldValues = "(" [ AnnotationFieldValue { "," AnnotationFieldValue } ] ")" */
2364 List<JCExpression> annotationFieldValues() {
2365 accept(LPAREN);
2366 ListBuffer<JCExpression> buf = new ListBuffer<JCExpression>();
2367 if (token.kind != RPAREN) {
2368 buf.append(annotationFieldValue());
2369 while (token.kind == COMMA) {
2370 nextToken();
2371 buf.append(annotationFieldValue());
2372 }
2373 }
2374 accept(RPAREN);
2375 return buf.toList();
2376 }
2378 /** AnnotationFieldValue = AnnotationValue
2379 * | Identifier "=" AnnotationValue
2380 */
2381 JCExpression annotationFieldValue() {
2382 if (token.kind == IDENTIFIER) {
2383 mode = EXPR;
2384 JCExpression t1 = term1();
2385 if (t1.hasTag(IDENT) && token.kind == EQ) {
2386 int pos = token.pos;
2387 accept(EQ);
2388 JCExpression v = annotationValue();
2389 return toP(F.at(pos).Assign(t1, v));
2390 } else {
2391 return t1;
2392 }
2393 }
2394 return annotationValue();
2395 }
2397 /* AnnotationValue = ConditionalExpression
2398 * | Annotation
2399 * | "{" [ AnnotationValue { "," AnnotationValue } ] [","] "}"
2400 */
2401 JCExpression annotationValue() {
2402 int pos;
2403 switch (token.kind) {
2404 case MONKEYS_AT:
2405 pos = token.pos;
2406 nextToken();
2407 return annotation(pos);
2408 case LBRACE:
2409 pos = token.pos;
2410 accept(LBRACE);
2411 ListBuffer<JCExpression> buf = new ListBuffer<JCExpression>();
2412 if (token.kind != RBRACE) {
2413 buf.append(annotationValue());
2414 while (token.kind == COMMA) {
2415 nextToken();
2416 if (token.kind == RBRACE) break;
2417 buf.append(annotationValue());
2418 }
2419 }
2420 accept(RBRACE);
2421 return toP(F.at(pos).NewArray(null, List.<JCExpression>nil(), buf.toList()));
2422 default:
2423 mode = EXPR;
2424 return term1();
2425 }
2426 }
2428 /** VariableDeclarators = VariableDeclarator { "," VariableDeclarator }
2429 */
2430 public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
2431 JCExpression type,
2432 T vdefs)
2433 {
2434 return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs);
2435 }
2437 /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
2438 * ConstantDeclaratorsRest = ConstantDeclaratorRest { "," ConstantDeclarator }
2439 *
2440 * @param reqInit Is an initializer always required?
2441 * @param dc The documentation comment for the variable declarations, or null.
2442 */
2443 <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos,
2444 JCModifiers mods,
2445 JCExpression type,
2446 Name name,
2447 boolean reqInit,
2448 Comment dc,
2449 T vdefs)
2450 {
2451 vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc));
2452 while (token.kind == COMMA) {
2453 // All but last of multiple declarators subsume a comma
2454 storeEnd((JCTree)vdefs.elems.last(), token.endPos);
2455 nextToken();
2456 vdefs.append(variableDeclarator(mods, type, reqInit, dc));
2457 }
2458 return vdefs;
2459 }
2461 /** VariableDeclarator = Ident VariableDeclaratorRest
2462 * ConstantDeclarator = Ident ConstantDeclaratorRest
2463 */
2464 JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
2465 return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
2466 }
2468 /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
2469 * ConstantDeclaratorRest = BracketsOpt "=" VariableInitializer
2470 *
2471 * @param reqInit Is an initializer always required?
2472 * @param dc The documentation comment for the variable declarations, or null.
2473 */
2474 JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
2475 boolean reqInit, Comment dc) {
2476 type = bracketsOpt(type);
2477 JCExpression init = null;
2478 if (token.kind == EQ) {
2479 nextToken();
2480 init = variableInitializer();
2481 }
2482 else if (reqInit) syntaxError(token.pos, "expected", EQ);
2483 JCVariableDecl result =
2484 toP(F.at(pos).VarDef(mods, name, type, init));
2485 attach(result, dc);
2486 return result;
2487 }
2489 /** VariableDeclaratorId = Ident BracketsOpt
2490 */
2491 JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
2492 int pos = token.pos;
2493 Name name = ident();
2494 if ((mods.flags & Flags.VARARGS) != 0 &&
2495 token.kind == LBRACKET) {
2496 log.error(token.pos, "varargs.and.old.array.syntax");
2497 }
2498 type = bracketsOpt(type);
2499 return toP(F.at(pos).VarDef(mods, name, type, null));
2500 }
2502 /** Resources = Resource { ";" Resources }
2503 */
2504 List<JCTree> resources() {
2505 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
2506 defs.append(resource());
2507 while (token.kind == SEMI) {
2508 // All but last of multiple declarators must subsume a semicolon
2509 storeEnd(defs.elems.last(), token.endPos);
2510 int semiColonPos = token.pos;
2511 nextToken();
2512 if (token.kind == RPAREN) { // Optional trailing semicolon
2513 // after last resource
2514 break;
2515 }
2516 defs.append(resource());
2517 }
2518 return defs.toList();
2519 }
2521 /** Resource = VariableModifiersOpt Type VariableDeclaratorId = Expression
2522 */
2523 protected JCTree resource() {
2524 JCModifiers optFinal = optFinal(Flags.FINAL);
2525 JCExpression type = parseType();
2526 int pos = token.pos;
2527 Name ident = ident();
2528 return variableDeclaratorRest(pos, optFinal, type, ident, true, null);
2529 }
2531 /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration}
2532 */
2533 public JCTree.JCCompilationUnit parseCompilationUnit() {
2534 Token firstToken = token;
2535 JCExpression pid = null;
2536 JCModifiers mods = null;
2537 boolean consumedToplevelDoc = false;
2538 boolean seenImport = false;
2539 boolean seenPackage = false;
2540 List<JCAnnotation> packageAnnotations = List.nil();
2541 if (token.kind == MONKEYS_AT)
2542 mods = modifiersOpt();
2544 if (token.kind == PACKAGE) {
2545 seenPackage = true;
2546 if (mods != null) {
2547 checkNoMods(mods.flags);
2548 packageAnnotations = mods.annotations;
2549 mods = null;
2550 }
2551 nextToken();
2552 pid = qualident();
2553 accept(SEMI);
2554 }
2555 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
2556 boolean checkForImports = true;
2557 boolean firstTypeDecl = true;
2558 while (token.kind != EOF) {
2559 if (token.pos <= endPosTable.errorEndPos) {
2560 // error recovery
2561 skip(checkForImports, false, false, false);
2562 if (token.kind == EOF)
2563 break;
2564 }
2565 if (checkForImports && mods == null && token.kind == IMPORT) {
2566 seenImport = true;
2567 defs.append(importDeclaration());
2568 } else {
2569 Comment docComment = token.comment(CommentStyle.JAVADOC);
2570 if (firstTypeDecl && !seenImport && !seenPackage) {
2571 docComment = firstToken.comment(CommentStyle.JAVADOC);
2572 consumedToplevelDoc = true;
2573 }
2574 JCTree def = typeDeclaration(mods, docComment);
2575 if (def instanceof JCExpressionStatement)
2576 def = ((JCExpressionStatement)def).expr;
2577 defs.append(def);
2578 if (def instanceof JCClassDecl)
2579 checkForImports = false;
2580 mods = null;
2581 firstTypeDecl = false;
2582 }
2583 }
2584 JCTree.JCCompilationUnit toplevel = F.at(firstToken.pos).TopLevel(packageAnnotations, pid, defs.toList());
2585 if (!consumedToplevelDoc)
2586 attach(toplevel, firstToken.comment(CommentStyle.JAVADOC));
2587 if (defs.elems.isEmpty())
2588 storeEnd(toplevel, S.prevToken().endPos);
2589 if (keepDocComments)
2590 toplevel.docComments = docComments;
2591 if (keepLineMap)
2592 toplevel.lineMap = S.getLineMap();
2593 toplevel.endPositions = this.endPosTable;
2594 return toplevel;
2595 }
2597 /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";"
2598 */
2599 JCTree importDeclaration() {
2600 int pos = token.pos;
2601 nextToken();
2602 boolean importStatic = false;
2603 if (token.kind == STATIC) {
2604 checkStaticImports();
2605 importStatic = true;
2606 nextToken();
2607 }
2608 JCExpression pid = toP(F.at(token.pos).Ident(ident()));
2609 do {
2610 int pos1 = token.pos;
2611 accept(DOT);
2612 if (token.kind == STAR) {
2613 pid = to(F.at(pos1).Select(pid, names.asterisk));
2614 nextToken();
2615 break;
2616 } else {
2617 pid = toP(F.at(pos1).Select(pid, ident()));
2618 }
2619 } while (token.kind == DOT);
2620 accept(SEMI);
2621 return toP(F.at(pos).Import(pid, importStatic));
2622 }
2624 /** TypeDeclaration = ClassOrInterfaceOrEnumDeclaration
2625 * | ";"
2626 */
2627 JCTree typeDeclaration(JCModifiers mods, Comment docComment) {
2628 int pos = token.pos;
2629 if (mods == null && token.kind == SEMI) {
2630 nextToken();
2631 return toP(F.at(pos).Skip());
2632 } else {
2633 return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment);
2634 }
2635 }
2637 /** ClassOrInterfaceOrEnumDeclaration = ModifiersOpt
2638 * (ClassDeclaration | InterfaceDeclaration | EnumDeclaration)
2639 * @param mods Any modifiers starting the class or interface declaration
2640 * @param dc The documentation comment for the class, or null.
2641 */
2642 JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
2643 if (token.kind == CLASS) {
2644 return classDeclaration(mods, dc);
2645 } else if (token.kind == INTERFACE) {
2646 return interfaceDeclaration(mods, dc);
2647 } else if (allowEnums) {
2648 if (token.kind == ENUM) {
2649 return enumDeclaration(mods, dc);
2650 } else {
2651 int pos = token.pos;
2652 List<JCTree> errs;
2653 if (token.kind == IDENTIFIER) {
2654 errs = List.<JCTree>of(mods, toP(F.at(pos).Ident(ident())));
2655 setErrorEndPos(token.pos);
2656 } else {
2657 errs = List.<JCTree>of(mods);
2658 }
2659 return toP(F.Exec(syntaxError(pos, errs, "expected3",
2660 CLASS, INTERFACE, ENUM)));
2661 }
2662 } else {
2663 if (token.kind == ENUM) {
2664 error(token.pos, "enums.not.supported.in.source", source.name);
2665 allowEnums = true;
2666 return enumDeclaration(mods, dc);
2667 }
2668 int pos = token.pos;
2669 List<JCTree> errs;
2670 if (token.kind == IDENTIFIER) {
2671 errs = List.<JCTree>of(mods, toP(F.at(pos).Ident(ident())));
2672 setErrorEndPos(token.pos);
2673 } else {
2674 errs = List.<JCTree>of(mods);
2675 }
2676 return toP(F.Exec(syntaxError(pos, errs, "expected2",
2677 CLASS, INTERFACE)));
2678 }
2679 }
2681 /** ClassDeclaration = CLASS Ident TypeParametersOpt [EXTENDS Type]
2682 * [IMPLEMENTS TypeList] ClassBody
2683 * @param mods The modifiers starting the class declaration
2684 * @param dc The documentation comment for the class, or null.
2685 */
2686 protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
2687 int pos = token.pos;
2688 accept(CLASS);
2689 Name name = ident();
2691 List<JCTypeParameter> typarams = typeParametersOpt();
2693 JCExpression extending = null;
2694 if (token.kind == EXTENDS) {
2695 nextToken();
2696 extending = parseType();
2697 }
2698 List<JCExpression> implementing = List.nil();
2699 if (token.kind == IMPLEMENTS) {
2700 nextToken();
2701 implementing = typeList();
2702 }
2703 List<JCTree> defs = classOrInterfaceBody(name, false);
2704 JCClassDecl result = toP(F.at(pos).ClassDef(
2705 mods, name, typarams, extending, implementing, defs));
2706 attach(result, dc);
2707 return result;
2708 }
2710 /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
2711 * [EXTENDS TypeList] InterfaceBody
2712 * @param mods The modifiers starting the interface declaration
2713 * @param dc The documentation comment for the interface, or null.
2714 */
2715 protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
2716 int pos = token.pos;
2717 accept(INTERFACE);
2718 Name name = ident();
2720 List<JCTypeParameter> typarams = typeParametersOpt();
2722 List<JCExpression> extending = List.nil();
2723 if (token.kind == EXTENDS) {
2724 nextToken();
2725 extending = typeList();
2726 }
2727 List<JCTree> defs = classOrInterfaceBody(name, true);
2728 JCClassDecl result = toP(F.at(pos).ClassDef(
2729 mods, name, typarams, null, extending, defs));
2730 attach(result, dc);
2731 return result;
2732 }
2734 /** EnumDeclaration = ENUM Ident [IMPLEMENTS TypeList] EnumBody
2735 * @param mods The modifiers starting the enum declaration
2736 * @param dc The documentation comment for the enum, or null.
2737 */
2738 protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
2739 int pos = token.pos;
2740 accept(ENUM);
2741 Name name = ident();
2743 List<JCExpression> implementing = List.nil();
2744 if (token.kind == IMPLEMENTS) {
2745 nextToken();
2746 implementing = typeList();
2747 }
2749 List<JCTree> defs = enumBody(name);
2750 mods.flags |= Flags.ENUM;
2751 JCClassDecl result = toP(F.at(pos).
2752 ClassDef(mods, name, List.<JCTypeParameter>nil(),
2753 null, implementing, defs));
2754 attach(result, dc);
2755 return result;
2756 }
2758 /** EnumBody = "{" { EnumeratorDeclarationList } [","]
2759 * [ ";" {ClassBodyDeclaration} ] "}"
2760 */
2761 List<JCTree> enumBody(Name enumName) {
2762 accept(LBRACE);
2763 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
2764 if (token.kind == COMMA) {
2765 nextToken();
2766 } else if (token.kind != RBRACE && token.kind != SEMI) {
2767 defs.append(enumeratorDeclaration(enumName));
2768 while (token.kind == COMMA) {
2769 nextToken();
2770 if (token.kind == RBRACE || token.kind == SEMI) break;
2771 defs.append(enumeratorDeclaration(enumName));
2772 }
2773 if (token.kind != SEMI && token.kind != RBRACE) {
2774 defs.append(syntaxError(token.pos, "expected3",
2775 COMMA, RBRACE, SEMI));
2776 nextToken();
2777 }
2778 }
2779 if (token.kind == SEMI) {
2780 nextToken();
2781 while (token.kind != RBRACE && token.kind != EOF) {
2782 defs.appendList(classOrInterfaceBodyDeclaration(enumName,
2783 false));
2784 if (token.pos <= endPosTable.errorEndPos) {
2785 // error recovery
2786 skip(false, true, true, false);
2787 }
2788 }
2789 }
2790 accept(RBRACE);
2791 return defs.toList();
2792 }
2794 /** EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ]
2795 */
2796 JCTree enumeratorDeclaration(Name enumName) {
2797 Comment dc = token.comment(CommentStyle.JAVADOC);
2798 int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM;
2799 if (token.deprecatedFlag()) {
2800 flags |= Flags.DEPRECATED;
2801 }
2802 int pos = token.pos;
2803 List<JCAnnotation> annotations = annotationsOpt();
2804 JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations);
2805 List<JCExpression> typeArgs = typeArgumentsOpt();
2806 int identPos = token.pos;
2807 Name name = ident();
2808 int createPos = token.pos;
2809 List<JCExpression> args = (token.kind == LPAREN)
2810 ? arguments() : List.<JCExpression>nil();
2811 JCClassDecl body = null;
2812 if (token.kind == LBRACE) {
2813 JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC);
2814 List<JCTree> defs = classOrInterfaceBody(names.empty, false);
2815 body = toP(F.at(identPos).AnonymousClassDef(mods1, defs));
2816 }
2817 if (args.isEmpty() && body == null)
2818 createPos = identPos;
2819 JCIdent ident = F.at(identPos).Ident(enumName);
2820 JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body);
2821 if (createPos != identPos)
2822 storeEnd(create, S.prevToken().endPos);
2823 ident = F.at(identPos).Ident(enumName);
2824 JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create));
2825 attach(result, dc);
2826 return result;
2827 }
2829 /** TypeList = Type {"," Type}
2830 */
2831 List<JCExpression> typeList() {
2832 ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>();
2833 ts.append(parseType());
2834 while (token.kind == COMMA) {
2835 nextToken();
2836 ts.append(parseType());
2837 }
2838 return ts.toList();
2839 }
2841 /** ClassBody = "{" {ClassBodyDeclaration} "}"
2842 * InterfaceBody = "{" {InterfaceBodyDeclaration} "}"
2843 */
2844 List<JCTree> classOrInterfaceBody(Name className, boolean isInterface) {
2845 accept(LBRACE);
2846 if (token.pos <= endPosTable.errorEndPos) {
2847 // error recovery
2848 skip(false, true, false, false);
2849 if (token.kind == LBRACE)
2850 nextToken();
2851 }
2852 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
2853 while (token.kind != RBRACE && token.kind != EOF) {
2854 defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface));
2855 if (token.pos <= endPosTable.errorEndPos) {
2856 // error recovery
2857 skip(false, true, true, false);
2858 }
2859 }
2860 accept(RBRACE);
2861 return defs.toList();
2862 }
2864 /** ClassBodyDeclaration =
2865 * ";"
2866 * | [STATIC] Block
2867 * | ModifiersOpt
2868 * ( Type Ident
2869 * ( VariableDeclaratorsRest ";" | MethodDeclaratorRest )
2870 * | VOID Ident MethodDeclaratorRest
2871 * | TypeParameters (Type | VOID) Ident MethodDeclaratorRest
2872 * | Ident ConstructorDeclaratorRest
2873 * | TypeParameters Ident ConstructorDeclaratorRest
2874 * | ClassOrInterfaceOrEnumDeclaration
2875 * )
2876 * InterfaceBodyDeclaration =
2877 * ";"
2878 * | ModifiersOpt Type Ident
2879 * ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" )
2880 */
2881 protected List<JCTree> classOrInterfaceBodyDeclaration(Name className, boolean isInterface) {
2882 if (token.kind == SEMI) {
2883 nextToken();
2884 return List.<JCTree>nil();
2885 } else {
2886 Comment dc = token.comment(CommentStyle.JAVADOC);
2887 int pos = token.pos;
2888 JCModifiers mods = modifiersOpt();
2889 if (token.kind == CLASS ||
2890 token.kind == INTERFACE ||
2891 allowEnums && token.kind == ENUM) {
2892 return List.<JCTree>of(classOrInterfaceOrEnumDeclaration(mods, dc));
2893 } else if (token.kind == LBRACE && !isInterface &&
2894 (mods.flags & Flags.StandardFlags & ~Flags.STATIC) == 0 &&
2895 mods.annotations.isEmpty()) {
2896 return List.<JCTree>of(block(pos, mods.flags));
2897 } else {
2898 pos = token.pos;
2899 List<JCTypeParameter> typarams = typeParametersOpt();
2900 // if there are type parameters but no modifiers, save the start
2901 // position of the method in the modifiers.
2902 if (typarams.nonEmpty() && mods.pos == Position.NOPOS) {
2903 mods.pos = pos;
2904 storeEnd(mods, pos);
2905 }
2906 Token tk = token;
2907 pos = token.pos;
2908 JCExpression type;
2909 boolean isVoid = token.kind == VOID;
2910 if (isVoid) {
2911 type = to(F.at(pos).TypeIdent(TypeTags.VOID));
2912 nextToken();
2913 } else {
2914 type = parseType();
2915 }
2916 if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
2917 if (isInterface || tk.name() != className)
2918 error(pos, "invalid.meth.decl.ret.type.req");
2919 return List.of(methodDeclaratorRest(
2920 pos, mods, null, names.init, typarams,
2921 isInterface, true, dc));
2922 } else {
2923 pos = token.pos;
2924 Name name = ident();
2925 if (token.kind == LPAREN) {
2926 return List.of(methodDeclaratorRest(
2927 pos, mods, type, name, typarams,
2928 isInterface, isVoid, dc));
2929 } else if (!isVoid && typarams.isEmpty()) {
2930 List<JCTree> defs =
2931 variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
2932 new ListBuffer<JCTree>()).toList();
2933 storeEnd(defs.last(), token.endPos);
2934 accept(SEMI);
2935 return defs;
2936 } else {
2937 pos = token.pos;
2938 List<JCTree> err = isVoid
2939 ? List.<JCTree>of(toP(F.at(pos).MethodDef(mods, name, type, typarams,
2940 List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null)))
2941 : null;
2942 return List.<JCTree>of(syntaxError(token.pos, err, "expected", LPAREN));
2943 }
2944 }
2945 }
2946 }
2947 }
2949 /** MethodDeclaratorRest =
2950 * FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
2951 * VoidMethodDeclaratorRest =
2952 * FormalParameters [Throws TypeList] ( MethodBody | ";")
2953 * InterfaceMethodDeclaratorRest =
2954 * FormalParameters BracketsOpt [THROWS TypeList] ";"
2955 * VoidInterfaceMethodDeclaratorRest =
2956 * FormalParameters [THROWS TypeList] ";"
2957 * ConstructorDeclaratorRest =
2958 * "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody
2959 */
2960 protected JCTree methodDeclaratorRest(int pos,
2961 JCModifiers mods,
2962 JCExpression type,
2963 Name name,
2964 List<JCTypeParameter> typarams,
2965 boolean isInterface, boolean isVoid,
2966 Comment dc) {
2967 List<JCVariableDecl> params = formalParameters();
2968 if (!isVoid) type = bracketsOpt(type);
2969 List<JCExpression> thrown = List.nil();
2970 if (token.kind == THROWS) {
2971 nextToken();
2972 thrown = qualidentList();
2973 }
2974 JCBlock body = null;
2975 JCExpression defaultValue;
2976 if (token.kind == LBRACE) {
2977 body = block();
2978 defaultValue = null;
2979 } else {
2980 if (token.kind == DEFAULT) {
2981 accept(DEFAULT);
2982 defaultValue = annotationValue();
2983 } else {
2984 defaultValue = null;
2985 }
2986 accept(SEMI);
2987 if (token.pos <= endPosTable.errorEndPos) {
2988 // error recovery
2989 skip(false, true, false, false);
2990 if (token.kind == LBRACE) {
2991 body = block();
2992 }
2993 }
2994 }
2996 JCMethodDecl result =
2997 toP(F.at(pos).MethodDef(mods, name, type, typarams,
2998 params, thrown,
2999 body, defaultValue));
3000 attach(result, dc);
3001 return result;
3002 }
3004 /** QualidentList = Qualident {"," Qualident}
3005 */
3006 List<JCExpression> qualidentList() {
3007 ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>();
3008 ts.append(qualident());
3009 while (token.kind == COMMA) {
3010 nextToken();
3011 ts.append(qualident());
3012 }
3013 return ts.toList();
3014 }
3016 /**
3017 * {@literal
3018 * TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"]
3019 * }
3020 */
3021 List<JCTypeParameter> typeParametersOpt() {
3022 if (token.kind == LT) {
3023 checkGenerics();
3024 ListBuffer<JCTypeParameter> typarams = new ListBuffer<JCTypeParameter>();
3025 nextToken();
3026 typarams.append(typeParameter());
3027 while (token.kind == COMMA) {
3028 nextToken();
3029 typarams.append(typeParameter());
3030 }
3031 accept(GT);
3032 return typarams.toList();
3033 } else {
3034 return List.nil();
3035 }
3036 }
3038 /**
3039 * {@literal
3040 * TypeParameter = TypeVariable [TypeParameterBound]
3041 * TypeParameterBound = EXTENDS Type {"&" Type}
3042 * TypeVariable = Ident
3043 * }
3044 */
3045 JCTypeParameter typeParameter() {
3046 int pos = token.pos;
3047 Name name = ident();
3048 ListBuffer<JCExpression> bounds = new ListBuffer<JCExpression>();
3049 if (token.kind == EXTENDS) {
3050 nextToken();
3051 bounds.append(parseType());
3052 while (token.kind == AMP) {
3053 nextToken();
3054 bounds.append(parseType());
3055 }
3056 }
3057 return toP(F.at(pos).TypeParameter(name, bounds.toList()));
3058 }
3060 /** FormalParameters = "(" [ FormalParameterList ] ")"
3061 * FormalParameterList = [ FormalParameterListNovarargs , ] LastFormalParameter
3062 * FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter
3063 */
3064 List<JCVariableDecl> formalParameters() {
3065 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
3066 JCVariableDecl lastParam = null;
3067 accept(LPAREN);
3068 if (token.kind != RPAREN) {
3069 params.append(lastParam = formalParameter());
3070 while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
3071 nextToken();
3072 params.append(lastParam = formalParameter());
3073 }
3074 }
3075 accept(RPAREN);
3076 return params.toList();
3077 }
3079 List<JCVariableDecl> implicitParameters(boolean hasParens) {
3080 if (hasParens) {
3081 accept(LPAREN);
3082 }
3083 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
3084 if (token.kind != RPAREN && token.kind != ARROW) {
3085 params.append(implicitParameter());
3086 while (token.kind == COMMA) {
3087 nextToken();
3088 params.append(implicitParameter());
3089 }
3090 }
3091 if (hasParens) {
3092 accept(RPAREN);
3093 }
3094 return params.toList();
3095 }
3097 JCModifiers optFinal(long flags) {
3098 JCModifiers mods = modifiersOpt();
3099 checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED));
3100 mods.flags |= flags;
3101 return mods;
3102 }
3104 /** FormalParameter = { FINAL | '@' Annotation } Type VariableDeclaratorId
3105 * LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter
3106 */
3107 protected JCVariableDecl formalParameter() {
3108 JCModifiers mods = optFinal(Flags.PARAMETER);
3109 JCExpression type = parseType();
3110 if (token.kind == ELLIPSIS) {
3111 checkVarargs();
3112 mods.flags |= Flags.VARARGS;
3113 type = to(F.at(token.pos).TypeArray(type));
3114 nextToken();
3115 }
3116 return variableDeclaratorId(mods, type);
3117 }
3119 protected JCVariableDecl implicitParameter() {
3120 JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
3121 return variableDeclaratorId(mods, null);
3122 }
3124 /* ---------- auxiliary methods -------------- */
3126 void error(int pos, String key, Object ... args) {
3127 log.error(DiagnosticFlag.SYNTAX, pos, key, args);
3128 }
3130 void error(DiagnosticPosition pos, String key, Object ... args) {
3131 log.error(DiagnosticFlag.SYNTAX, pos, key, args);
3132 }
3134 void warning(int pos, String key, Object ... args) {
3135 log.warning(pos, key, args);
3136 }
3138 /** Check that given tree is a legal expression statement.
3139 */
3140 protected JCExpression checkExprStat(JCExpression t) {
3141 switch(t.getTag()) {
3142 case PREINC: case PREDEC:
3143 case POSTINC: case POSTDEC:
3144 case ASSIGN:
3145 case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
3146 case SL_ASG: case SR_ASG: case USR_ASG:
3147 case PLUS_ASG: case MINUS_ASG:
3148 case MUL_ASG: case DIV_ASG: case MOD_ASG:
3149 case APPLY: case NEWCLASS:
3150 case ERRONEOUS:
3151 return t;
3152 default:
3153 JCExpression ret = F.at(t.pos).Erroneous(List.<JCTree>of(t));
3154 error(ret, "not.stmt");
3155 return ret;
3156 }
3157 }
3159 /** Return precedence of operator represented by token,
3160 * -1 if token is not a binary operator. @see TreeInfo.opPrec
3161 */
3162 static int prec(TokenKind token) {
3163 JCTree.Tag oc = optag(token);
3164 return (oc != NO_TAG) ? TreeInfo.opPrec(oc) : -1;
3165 }
3167 /**
3168 * Return the lesser of two positions, making allowance for either one
3169 * being unset.
3170 */
3171 static int earlier(int pos1, int pos2) {
3172 if (pos1 == Position.NOPOS)
3173 return pos2;
3174 if (pos2 == Position.NOPOS)
3175 return pos1;
3176 return (pos1 < pos2 ? pos1 : pos2);
3177 }
3179 /** Return operation tag of binary operator represented by token,
3180 * No_TAG if token is not a binary operator.
3181 */
3182 static JCTree.Tag optag(TokenKind token) {
3183 switch (token) {
3184 case BARBAR:
3185 return OR;
3186 case AMPAMP:
3187 return AND;
3188 case BAR:
3189 return BITOR;
3190 case BAREQ:
3191 return BITOR_ASG;
3192 case CARET:
3193 return BITXOR;
3194 case CARETEQ:
3195 return BITXOR_ASG;
3196 case AMP:
3197 return BITAND;
3198 case AMPEQ:
3199 return BITAND_ASG;
3200 case EQEQ:
3201 return JCTree.Tag.EQ;
3202 case BANGEQ:
3203 return NE;
3204 case LT:
3205 return JCTree.Tag.LT;
3206 case GT:
3207 return JCTree.Tag.GT;
3208 case LTEQ:
3209 return LE;
3210 case GTEQ:
3211 return GE;
3212 case LTLT:
3213 return SL;
3214 case LTLTEQ:
3215 return SL_ASG;
3216 case GTGT:
3217 return SR;
3218 case GTGTEQ:
3219 return SR_ASG;
3220 case GTGTGT:
3221 return USR;
3222 case GTGTGTEQ:
3223 return USR_ASG;
3224 case PLUS:
3225 return JCTree.Tag.PLUS;
3226 case PLUSEQ:
3227 return PLUS_ASG;
3228 case SUB:
3229 return MINUS;
3230 case SUBEQ:
3231 return MINUS_ASG;
3232 case STAR:
3233 return MUL;
3234 case STAREQ:
3235 return MUL_ASG;
3236 case SLASH:
3237 return DIV;
3238 case SLASHEQ:
3239 return DIV_ASG;
3240 case PERCENT:
3241 return MOD;
3242 case PERCENTEQ:
3243 return MOD_ASG;
3244 case INSTANCEOF:
3245 return TYPETEST;
3246 default:
3247 return NO_TAG;
3248 }
3249 }
3251 /** Return operation tag of unary operator represented by token,
3252 * No_TAG if token is not a binary operator.
3253 */
3254 static JCTree.Tag unoptag(TokenKind token) {
3255 switch (token) {
3256 case PLUS:
3257 return POS;
3258 case SUB:
3259 return NEG;
3260 case BANG:
3261 return NOT;
3262 case TILDE:
3263 return COMPL;
3264 case PLUSPLUS:
3265 return PREINC;
3266 case SUBSUB:
3267 return PREDEC;
3268 default:
3269 return NO_TAG;
3270 }
3271 }
3273 /** Return type tag of basic type represented by token,
3274 * -1 if token is not a basic type identifier.
3275 */
3276 static int typetag(TokenKind token) {
3277 switch (token) {
3278 case BYTE:
3279 return TypeTags.BYTE;
3280 case CHAR:
3281 return TypeTags.CHAR;
3282 case SHORT:
3283 return TypeTags.SHORT;
3284 case INT:
3285 return TypeTags.INT;
3286 case LONG:
3287 return TypeTags.LONG;
3288 case FLOAT:
3289 return TypeTags.FLOAT;
3290 case DOUBLE:
3291 return TypeTags.DOUBLE;
3292 case BOOLEAN:
3293 return TypeTags.BOOLEAN;
3294 default:
3295 return -1;
3296 }
3297 }
3299 void checkGenerics() {
3300 if (!allowGenerics) {
3301 error(token.pos, "generics.not.supported.in.source", source.name);
3302 allowGenerics = true;
3303 }
3304 }
3305 void checkVarargs() {
3306 if (!allowVarargs) {
3307 error(token.pos, "varargs.not.supported.in.source", source.name);
3308 allowVarargs = true;
3309 }
3310 }
3311 void checkForeach() {
3312 if (!allowForeach) {
3313 error(token.pos, "foreach.not.supported.in.source", source.name);
3314 allowForeach = true;
3315 }
3316 }
3317 void checkStaticImports() {
3318 if (!allowStaticImport) {
3319 error(token.pos, "static.import.not.supported.in.source", source.name);
3320 allowStaticImport = true;
3321 }
3322 }
3323 void checkAnnotations() {
3324 if (!allowAnnotations) {
3325 error(token.pos, "annotations.not.supported.in.source", source.name);
3326 allowAnnotations = true;
3327 }
3328 }
3329 void checkDiamond() {
3330 if (!allowDiamond) {
3331 error(token.pos, "diamond.not.supported.in.source", source.name);
3332 allowDiamond = true;
3333 }
3334 }
3335 void checkMulticatch() {
3336 if (!allowMulticatch) {
3337 error(token.pos, "multicatch.not.supported.in.source", source.name);
3338 allowMulticatch = true;
3339 }
3340 }
3341 void checkTryWithResources() {
3342 if (!allowTWR) {
3343 error(token.pos, "try.with.resources.not.supported.in.source", source.name);
3344 allowTWR = true;
3345 }
3346 }
3347 void checkLambda() {
3348 if (!allowLambda) {
3349 log.error(token.pos, "lambda.not.supported.in.source", source.name);
3350 allowLambda = true;
3351 }
3352 }
3353 void checkMethodReferences() {
3354 if (!allowMethodReferences) {
3355 log.error(token.pos, "method.references.not.supported.in.source", source.name);
3356 allowMethodReferences = true;
3357 }
3358 }
3360 /*
3361 * a functional source tree and end position mappings
3362 */
3363 protected class SimpleEndPosTable extends AbstractEndPosTable {
3365 private final Map<JCTree, Integer> endPosMap;
3367 SimpleEndPosTable() {
3368 endPosMap = new HashMap<JCTree, Integer>();
3369 }
3371 protected void storeEnd(JCTree tree, int endpos) {
3372 endPosMap.put(tree, errorEndPos > endpos ? errorEndPos : endpos);
3373 }
3375 protected <T extends JCTree> T to(T t) {
3376 storeEnd(t, token.endPos);
3377 return t;
3378 }
3380 protected <T extends JCTree> T toP(T t) {
3381 storeEnd(t, S.prevToken().endPos);
3382 return t;
3383 }
3385 public int getEndPos(JCTree tree) {
3386 Integer value = endPosMap.get(tree);
3387 return (value == null) ? Position.NOPOS : value;
3388 }
3390 public int replaceTree(JCTree oldTree, JCTree newTree) {
3391 Integer pos = endPosMap.remove(oldTree);
3392 if (pos != null) {
3393 endPosMap.put(newTree, pos);
3394 return pos;
3395 }
3396 return Position.NOPOS;
3397 }
3398 }
3400 /*
3401 * a default skeletal implementation without any mapping overhead.
3402 */
3403 protected class EmptyEndPosTable extends AbstractEndPosTable {
3405 protected void storeEnd(JCTree tree, int endpos) { /* empty */ }
3407 protected <T extends JCTree> T to(T t) {
3408 return t;
3409 }
3411 protected <T extends JCTree> T toP(T t) {
3412 return t;
3413 }
3415 public int getEndPos(JCTree tree) {
3416 return Position.NOPOS;
3417 }
3419 public int replaceTree(JCTree oldTree, JCTree newTree) {
3420 return Position.NOPOS;
3421 }
3423 }
3425 protected abstract class AbstractEndPosTable implements EndPosTable {
3427 /**
3428 * Store the last error position.
3429 */
3430 protected int errorEndPos;
3432 /**
3433 * Store ending position for a tree, the value of which is the greater
3434 * of last error position and the given ending position.
3435 * @param tree The tree.
3436 * @param endpos The ending position to associate with the tree.
3437 */
3438 protected abstract void storeEnd(JCTree tree, int endpos);
3440 /**
3441 * Store current token's ending position for a tree, the value of which
3442 * will be the greater of last error position and the ending position of
3443 * the current token.
3444 * @param t The tree.
3445 */
3446 protected abstract <T extends JCTree> T to(T t);
3448 /**
3449 * Store current token's ending position for a tree, the value of which
3450 * will be the greater of last error position and the ending position of
3451 * the previous token.
3452 * @param t The tree.
3453 */
3454 protected abstract <T extends JCTree> T toP(T t);
3456 /**
3457 * Set the error position during the parsing phases, the value of which
3458 * will be set only if it is greater than the last stored error position.
3459 * @param errPos The error position
3460 */
3461 protected void setErrorEndPos(int errPos) {
3462 if (errPos > errorEndPos) {
3463 errorEndPos = errPos;
3464 }
3465 }
3466 }
3467 }