Wed, 10 Oct 2012 18:44:21 -0700
8000310: Clean up use of StringBuffer in langtools
Reviewed-by: bpatel
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 StringBuilder 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 StringBuilder 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 StringBuilder sbuf =
845 new StringBuilder((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(MONKEYS_AT) ||
954 peekToken(FINAL) ||
955 peekToken(RPAREN) ||
956 peekToken(IDENTIFIER, COMMA) ||
957 peekToken(IDENTIFIER, RPAREN, ARROW)) {
958 //implicit n-ary lambda
959 t = lambdaExpressionOrStatement(true, peekToken(MONKEYS_AT) || peekToken(FINAL), pos);
960 break;
961 } else {
962 nextToken();
963 mode = EXPR | TYPE | NOPARAMS;
964 t = term3();
965 if ((mode & TYPE) != 0 && token.kind == LT) {
966 // Could be a cast to a parameterized type
967 JCTree.Tag op = JCTree.Tag.LT;
968 int pos1 = token.pos;
969 nextToken();
970 mode &= (EXPR | TYPE);
971 mode |= TYPEARG;
972 JCExpression t1 = term3();
973 if ((mode & TYPE) != 0 &&
974 (token.kind == COMMA || token.kind == GT)) {
975 mode = TYPE;
976 ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
977 args.append(t1);
978 while (token.kind == COMMA) {
979 nextToken();
980 args.append(typeArgument());
981 }
982 accept(GT);
983 t = toP(F.at(pos1).TypeApply(t, args.toList()));
984 checkGenerics();
985 mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type
986 t = term3Rest(t, typeArgs);
987 if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) {
988 //explicit lambda (w/ generic type)
989 mode = EXPR;
990 JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
991 if (token.kind == ELLIPSIS) {
992 mods.flags = Flags.VARARGS;
993 t = to(F.at(token.pos).TypeArray(t));
994 nextToken();
995 }
996 t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
997 break;
998 }
999 } else if ((mode & EXPR) != 0) {
1000 mode = EXPR;
1001 JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
1002 t = F.at(pos1).Binary(op, t, e);
1003 t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
1004 } else {
1005 accept(GT);
1006 }
1007 } else if ((mode & TYPE) != 0 &&
1008 (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) {
1009 //explicit lambda (w/ non-generic type)
1010 mode = EXPR;
1011 JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
1012 if (token.kind == ELLIPSIS) {
1013 mods.flags = Flags.VARARGS;
1014 t = to(F.at(token.pos).TypeArray(t));
1015 nextToken();
1016 }
1017 t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
1018 break;
1019 } else {
1020 t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
1021 }
1022 }
1024 accept(RPAREN);
1025 lastmode = mode;
1026 mode = EXPR;
1027 if ((lastmode & EXPR) == 0) {
1028 JCExpression t1 = term3();
1029 return F.at(pos).TypeCast(t, t1);
1030 } else if ((lastmode & TYPE) != 0) {
1031 switch (token.kind) {
1032 /*case PLUSPLUS: case SUBSUB: */
1033 case BANG: case TILDE:
1034 case LPAREN: case THIS: case SUPER:
1035 case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
1036 case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
1037 case TRUE: case FALSE: case NULL:
1038 case NEW: case IDENTIFIER: case ASSERT: case ENUM:
1039 case BYTE: case SHORT: case CHAR: case INT:
1040 case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
1041 JCExpression t1 = term3();
1042 return F.at(pos).TypeCast(t, t1);
1043 }
1044 }
1045 } else {
1046 return illegal();
1047 }
1048 t = toP(F.at(pos).Parens(t));
1049 break;
1050 case THIS:
1051 if ((mode & EXPR) != 0) {
1052 mode = EXPR;
1053 t = to(F.at(pos).Ident(names._this));
1054 nextToken();
1055 if (typeArgs == null)
1056 t = argumentsOpt(null, t);
1057 else
1058 t = arguments(typeArgs, t);
1059 typeArgs = null;
1060 } else return illegal();
1061 break;
1062 case SUPER:
1063 if ((mode & EXPR) != 0) {
1064 mode = EXPR;
1065 t = to(F.at(pos).Ident(names._super));
1066 t = superSuffix(typeArgs, t);
1067 typeArgs = null;
1068 } else return illegal();
1069 break;
1070 case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL:
1071 case CHARLITERAL: case STRINGLITERAL:
1072 case TRUE: case FALSE: case NULL:
1073 if (typeArgs == null && (mode & EXPR) != 0) {
1074 mode = EXPR;
1075 t = literal(names.empty);
1076 } else return illegal();
1077 break;
1078 case NEW:
1079 if (typeArgs != null) return illegal();
1080 if ((mode & EXPR) != 0) {
1081 mode = EXPR;
1082 nextToken();
1083 if (token.kind == LT) typeArgs = typeArguments(false);
1084 t = creator(pos, typeArgs);
1085 typeArgs = null;
1086 } else return illegal();
1087 break;
1088 case IDENTIFIER: case ASSERT: case ENUM:
1089 if (typeArgs != null) return illegal();
1090 if ((mode & EXPR) != 0 && peekToken(ARROW)) {
1091 t = lambdaExpressionOrStatement(false, false, pos);
1092 } else {
1093 t = toP(F.at(token.pos).Ident(ident()));
1094 loop: while (true) {
1095 pos = token.pos;
1096 switch (token.kind) {
1097 case LBRACKET:
1098 nextToken();
1099 if (token.kind == RBRACKET) {
1100 nextToken();
1101 t = bracketsOpt(t);
1102 t = toP(F.at(pos).TypeArray(t));
1103 t = bracketsSuffix(t);
1104 } else {
1105 if ((mode & EXPR) != 0) {
1106 mode = EXPR;
1107 JCExpression t1 = term();
1108 t = to(F.at(pos).Indexed(t, t1));
1109 }
1110 accept(RBRACKET);
1111 }
1112 break loop;
1113 case LPAREN:
1114 if ((mode & EXPR) != 0) {
1115 mode = EXPR;
1116 t = arguments(typeArgs, t);
1117 typeArgs = null;
1118 }
1119 break loop;
1120 case DOT:
1121 nextToken();
1122 int oldmode = mode;
1123 mode &= ~NOPARAMS;
1124 typeArgs = typeArgumentsOpt(EXPR);
1125 mode = oldmode;
1126 if ((mode & EXPR) != 0) {
1127 switch (token.kind) {
1128 case CLASS:
1129 if (typeArgs != null) return illegal();
1130 mode = EXPR;
1131 t = to(F.at(pos).Select(t, names._class));
1132 nextToken();
1133 break loop;
1134 case THIS:
1135 if (typeArgs != null) return illegal();
1136 mode = EXPR;
1137 t = to(F.at(pos).Select(t, names._this));
1138 nextToken();
1139 break loop;
1140 case SUPER:
1141 mode = EXPR;
1142 t = to(F.at(pos).Select(t, names._super));
1143 t = superSuffix(typeArgs, t);
1144 typeArgs = null;
1145 break loop;
1146 case NEW:
1147 if (typeArgs != null) return illegal();
1148 mode = EXPR;
1149 int pos1 = token.pos;
1150 nextToken();
1151 if (token.kind == LT) typeArgs = typeArguments(false);
1152 t = innerCreator(pos1, typeArgs, t);
1153 typeArgs = null;
1154 break loop;
1155 }
1156 }
1157 // typeArgs saved for next loop iteration.
1158 t = toP(F.at(pos).Select(t, ident()));
1159 break;
1160 case LT:
1161 if ((mode & TYPE) == 0 && isUnboundMemberRef()) {
1162 //this is an unbound method reference whose qualifier
1163 //is a generic type i.e. A<S>::m
1164 int pos1 = token.pos;
1165 accept(LT);
1166 ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
1167 args.append(typeArgument());
1168 while (token.kind == COMMA) {
1169 nextToken();
1170 args.append(typeArgument());
1171 }
1172 accept(GT);
1173 t = toP(F.at(pos1).TypeApply(t, args.toList()));
1174 checkGenerics();
1175 while (token.kind == DOT) {
1176 nextToken();
1177 mode = TYPE;
1178 t = toP(F.at(token.pos).Select(t, ident()));
1179 t = typeArgumentsOpt(t);
1180 }
1181 t = bracketsOpt(t);
1182 if (token.kind != COLCOL) {
1183 //method reference expected here
1184 t = illegal();
1185 }
1186 mode = EXPR;
1187 return term3Rest(t, typeArgs);
1188 }
1189 break loop;
1190 default:
1191 break loop;
1192 }
1193 }
1194 }
1195 if (typeArgs != null) illegal();
1196 t = typeArgumentsOpt(t);
1197 break;
1198 case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
1199 case DOUBLE: case BOOLEAN:
1200 if (typeArgs != null) illegal();
1201 t = bracketsSuffix(bracketsOpt(basicType()));
1202 break;
1203 case VOID:
1204 if (typeArgs != null) illegal();
1205 if ((mode & EXPR) != 0) {
1206 nextToken();
1207 if (token.kind == DOT) {
1208 JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTags.VOID));
1209 t = bracketsSuffix(ti);
1210 } else {
1211 return illegal(pos);
1212 }
1213 } else {
1214 // Support the corner case of myMethodHandle.<void>invoke() by passing
1215 // a void type (like other primitive types) to the next phase.
1216 // The error will be reported in Attr.attribTypes or Attr.visitApply.
1217 JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTags.VOID));
1218 nextToken();
1219 return ti;
1220 //return illegal();
1221 }
1222 break;
1223 default:
1224 return illegal();
1225 }
1226 return term3Rest(t, typeArgs);
1227 }
1229 JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
1230 if (typeArgs != null) illegal();
1231 while (true) {
1232 int pos1 = token.pos;
1233 if (token.kind == LBRACKET) {
1234 nextToken();
1235 if ((mode & TYPE) != 0) {
1236 int oldmode = mode;
1237 mode = TYPE;
1238 if (token.kind == RBRACKET) {
1239 nextToken();
1240 t = bracketsOpt(t);
1241 t = toP(F.at(pos1).TypeArray(t));
1242 if (token.kind == COLCOL) {
1243 mode = EXPR;
1244 continue;
1245 }
1246 return t;
1247 }
1248 mode = oldmode;
1249 }
1250 if ((mode & EXPR) != 0) {
1251 mode = EXPR;
1252 JCExpression t1 = term();
1253 t = to(F.at(pos1).Indexed(t, t1));
1254 }
1255 accept(RBRACKET);
1256 } else if (token.kind == DOT) {
1257 nextToken();
1258 typeArgs = typeArgumentsOpt(EXPR);
1259 if (token.kind == SUPER && (mode & EXPR) != 0) {
1260 mode = EXPR;
1261 t = to(F.at(pos1).Select(t, names._super));
1262 nextToken();
1263 t = arguments(typeArgs, t);
1264 typeArgs = null;
1265 } else if (token.kind == NEW && (mode & EXPR) != 0) {
1266 if (typeArgs != null) return illegal();
1267 mode = EXPR;
1268 int pos2 = token.pos;
1269 nextToken();
1270 if (token.kind == LT) typeArgs = typeArguments(false);
1271 t = innerCreator(pos2, typeArgs, t);
1272 typeArgs = null;
1273 } else {
1274 t = toP(F.at(pos1).Select(t, ident()));
1275 t = argumentsOpt(typeArgs, typeArgumentsOpt(t));
1276 typeArgs = null;
1277 }
1278 } else if ((mode & EXPR) != 0 && token.kind == COLCOL) {
1279 mode = EXPR;
1280 if (typeArgs != null) return illegal();
1281 accept(COLCOL);
1282 t = memberReferenceSuffix(pos1, t);
1283 } else {
1284 break;
1285 }
1286 }
1287 while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && (mode & EXPR) != 0) {
1288 mode = EXPR;
1289 t = to(F.at(token.pos).Unary(
1290 token.kind == PLUSPLUS ? POSTINC : POSTDEC, t));
1291 nextToken();
1292 }
1293 return toP(t);
1294 }
1296 /**
1297 * If we see an identifier followed by a '<' it could be an unbound
1298 * method reference or a binary expression. To disambiguate, look for a
1299 * matching '>' and see if the subsequent terminal is either '.' or '#'.
1300 */
1301 @SuppressWarnings("fallthrough")
1302 boolean isUnboundMemberRef() {
1303 int pos = 0, depth = 0;
1304 for (Token t = S.token(pos) ; ; t = S.token(++pos)) {
1305 switch (t.kind) {
1306 case IDENTIFIER: case QUES: case EXTENDS: case SUPER:
1307 case DOT: case RBRACKET: case LBRACKET: case COMMA:
1308 case BYTE: case SHORT: case INT: case LONG: case FLOAT:
1309 case DOUBLE: case BOOLEAN: case CHAR:
1310 break;
1311 case LT:
1312 depth++; break;
1313 case GTGTGT:
1314 depth--;
1315 case GTGT:
1316 depth--;
1317 case GT:
1318 depth--;
1319 if (depth == 0) {
1320 TokenKind nextKind = S.token(pos + 1).kind;
1321 return
1322 nextKind == TokenKind.DOT ||
1323 nextKind == TokenKind.LBRACKET ||
1324 nextKind == TokenKind.COLCOL;
1325 }
1326 break;
1327 default:
1328 return false;
1329 }
1330 }
1331 }
1333 JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
1334 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
1335 params.append(firstParam);
1336 JCVariableDecl lastParam = firstParam;
1337 while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
1338 nextToken();
1339 params.append(lastParam = formalParameter());
1340 }
1341 accept(RPAREN);
1342 return lambdaExpressionOrStatementRest(params.toList(), pos);
1343 }
1345 JCExpression lambdaExpressionOrStatement(boolean hasParens, boolean explicitParams, int pos) {
1346 List<JCVariableDecl> params = explicitParams ?
1347 formalParameters() :
1348 implicitParameters(hasParens);
1350 return lambdaExpressionOrStatementRest(params, pos);
1351 }
1353 JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
1354 checkLambda();
1355 accept(ARROW);
1357 return token.kind == LBRACE ?
1358 lambdaStatement(args, pos, pos) :
1359 lambdaExpression(args, pos);
1360 }
1362 JCExpression lambdaStatement(List<JCVariableDecl> args, int pos, int pos2) {
1363 JCBlock block = block(pos2, 0);
1364 return toP(F.at(pos).Lambda(args, block));
1365 }
1367 JCExpression lambdaExpression(List<JCVariableDecl> args, int pos) {
1368 JCTree expr = parseExpression();
1369 return toP(F.at(pos).Lambda(args, expr));
1370 }
1372 /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments]
1373 */
1374 JCExpression superSuffix(List<JCExpression> typeArgs, JCExpression t) {
1375 nextToken();
1376 if (token.kind == LPAREN || typeArgs != null) {
1377 t = arguments(typeArgs, t);
1378 } else if (token.kind == COLCOL) {
1379 if (typeArgs != null) return illegal();
1380 t = memberReferenceSuffix(t);
1381 } else {
1382 int pos = token.pos;
1383 accept(DOT);
1384 typeArgs = (token.kind == LT) ? typeArguments(false) : null;
1385 t = toP(F.at(pos).Select(t, ident()));
1386 t = argumentsOpt(typeArgs, t);
1387 }
1388 return t;
1389 }
1391 /** BasicType = BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE | BOOLEAN
1392 */
1393 JCPrimitiveTypeTree basicType() {
1394 JCPrimitiveTypeTree t = to(F.at(token.pos).TypeIdent(typetag(token.kind)));
1395 nextToken();
1396 return t;
1397 }
1399 /** ArgumentsOpt = [ Arguments ]
1400 */
1401 JCExpression argumentsOpt(List<JCExpression> typeArgs, JCExpression t) {
1402 if ((mode & EXPR) != 0 && token.kind == LPAREN || typeArgs != null) {
1403 mode = EXPR;
1404 return arguments(typeArgs, t);
1405 } else {
1406 return t;
1407 }
1408 }
1410 /** Arguments = "(" [Expression { COMMA Expression }] ")"
1411 */
1412 List<JCExpression> arguments() {
1413 ListBuffer<JCExpression> args = lb();
1414 if (token.kind == LPAREN) {
1415 nextToken();
1416 if (token.kind != RPAREN) {
1417 args.append(parseExpression());
1418 while (token.kind == COMMA) {
1419 nextToken();
1420 args.append(parseExpression());
1421 }
1422 }
1423 accept(RPAREN);
1424 } else {
1425 syntaxError(token.pos, "expected", LPAREN);
1426 }
1427 return args.toList();
1428 }
1430 JCMethodInvocation arguments(List<JCExpression> typeArgs, JCExpression t) {
1431 int pos = token.pos;
1432 List<JCExpression> args = arguments();
1433 return toP(F.at(pos).Apply(typeArgs, t, args));
1434 }
1436 /** TypeArgumentsOpt = [ TypeArguments ]
1437 */
1438 JCExpression typeArgumentsOpt(JCExpression t) {
1439 if (token.kind == LT &&
1440 (mode & TYPE) != 0 &&
1441 (mode & NOPARAMS) == 0) {
1442 mode = TYPE;
1443 checkGenerics();
1444 return typeArguments(t, false);
1445 } else {
1446 return t;
1447 }
1448 }
1449 List<JCExpression> typeArgumentsOpt() {
1450 return typeArgumentsOpt(TYPE);
1451 }
1453 List<JCExpression> typeArgumentsOpt(int useMode) {
1454 if (token.kind == LT) {
1455 checkGenerics();
1456 if ((mode & useMode) == 0 ||
1457 (mode & NOPARAMS) != 0) {
1458 illegal();
1459 }
1460 mode = useMode;
1461 return typeArguments(false);
1462 }
1463 return null;
1464 }
1466 /**
1467 * {@literal
1468 * TypeArguments = "<" TypeArgument {"," TypeArgument} ">"
1469 * }
1470 */
1471 List<JCExpression> typeArguments(boolean diamondAllowed) {
1472 if (token.kind == LT) {
1473 nextToken();
1474 if (token.kind == GT && diamondAllowed) {
1475 checkDiamond();
1476 mode |= DIAMOND;
1477 nextToken();
1478 return List.nil();
1479 } else {
1480 ListBuffer<JCExpression> args = ListBuffer.lb();
1481 args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
1482 while (token.kind == COMMA) {
1483 nextToken();
1484 args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
1485 }
1486 switch (token.kind) {
1488 case GTGTGTEQ: case GTGTEQ: case GTEQ:
1489 case GTGTGT: case GTGT:
1490 token = S.split();
1491 break;
1492 case GT:
1493 nextToken();
1494 break;
1495 default:
1496 args.append(syntaxError(token.pos, "expected", GT));
1497 break;
1498 }
1499 return args.toList();
1500 }
1501 } else {
1502 return List.<JCExpression>of(syntaxError(token.pos, "expected", LT));
1503 }
1504 }
1506 /**
1507 * {@literal
1508 * TypeArgument = Type
1509 * | "?"
1510 * | "?" EXTENDS Type {"&" Type}
1511 * | "?" SUPER Type
1512 * }
1513 */
1514 JCExpression typeArgument() {
1515 if (token.kind != QUES) return parseType();
1516 int pos = token.pos;
1517 nextToken();
1518 if (token.kind == EXTENDS) {
1519 TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.EXTENDS));
1520 nextToken();
1521 JCExpression bound = parseType();
1522 return F.at(pos).Wildcard(t, bound);
1523 } else if (token.kind == SUPER) {
1524 TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.SUPER));
1525 nextToken();
1526 JCExpression bound = parseType();
1527 return F.at(pos).Wildcard(t, bound);
1528 } else if (token.kind == IDENTIFIER) {
1529 //error recovery
1530 TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
1531 JCExpression wc = toP(F.at(pos).Wildcard(t, null));
1532 JCIdent id = toP(F.at(token.pos).Ident(ident()));
1533 JCErroneous err = F.at(pos).Erroneous(List.<JCTree>of(wc, id));
1534 reportSyntaxError(err, "expected3", GT, EXTENDS, SUPER);
1535 return err;
1536 } else {
1537 TypeBoundKind t = toP(F.at(pos).TypeBoundKind(BoundKind.UNBOUND));
1538 return toP(F.at(pos).Wildcard(t, null));
1539 }
1540 }
1542 JCTypeApply typeArguments(JCExpression t, boolean diamondAllowed) {
1543 int pos = token.pos;
1544 List<JCExpression> args = typeArguments(diamondAllowed);
1545 return toP(F.at(pos).TypeApply(t, args));
1546 }
1548 /** BracketsOpt = {"[" "]"}
1549 */
1550 private JCExpression bracketsOpt(JCExpression t) {
1551 if (token.kind == LBRACKET) {
1552 int pos = token.pos;
1553 nextToken();
1554 t = bracketsOptCont(t, pos);
1555 F.at(pos);
1556 }
1557 return t;
1558 }
1560 private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos) {
1561 accept(RBRACKET);
1562 t = bracketsOpt(t);
1563 return toP(F.at(pos).TypeArray(t));
1564 }
1566 /** BracketsSuffixExpr = "." CLASS
1567 * BracketsSuffixType =
1568 */
1569 JCExpression bracketsSuffix(JCExpression t) {
1570 if ((mode & EXPR) != 0 && token.kind == DOT) {
1571 mode = EXPR;
1572 int pos = token.pos;
1573 nextToken();
1574 accept(CLASS);
1575 if (token.pos == endPosTable.errorEndPos) {
1576 // error recovery
1577 Name name = null;
1578 if (token.kind == IDENTIFIER) {
1579 name = token.name();
1580 nextToken();
1581 } else {
1582 name = names.error;
1583 }
1584 t = F.at(pos).Erroneous(List.<JCTree>of(toP(F.at(pos).Select(t, name))));
1585 } else {
1586 t = toP(F.at(pos).Select(t, names._class));
1587 }
1588 } else if ((mode & TYPE) != 0) {
1589 if (token.kind != COLCOL) {
1590 mode = TYPE;
1591 }
1592 } else if (token.kind != COLCOL) {
1593 syntaxError(token.pos, "dot.class.expected");
1594 }
1595 return t;
1596 }
1598 /**
1599 * MemberReferenceSuffix = "::" [TypeArguments] Ident
1600 * | "::" [TypeArguments] "new"
1601 */
1602 JCExpression memberReferenceSuffix(JCExpression t) {
1603 int pos1 = token.pos;
1604 accept(COLCOL);
1605 return memberReferenceSuffix(pos1, t);
1606 }
1608 JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
1609 checkMethodReferences();
1610 mode = EXPR;
1611 List<JCExpression> typeArgs = null;
1612 if (token.kind == LT) {
1613 typeArgs = typeArguments(false);
1614 }
1615 Name refName = null;
1616 ReferenceMode refMode = null;
1617 if (token.kind == NEW) {
1618 refMode = ReferenceMode.NEW;
1619 refName = names.init;
1620 nextToken();
1621 } else {
1622 refMode = ReferenceMode.INVOKE;
1623 refName = ident();
1624 }
1625 return toP(F.at(t.getStartPosition()).Reference(refMode, refName, t, typeArgs));
1626 }
1628 /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
1629 */
1630 JCExpression creator(int newpos, List<JCExpression> typeArgs) {
1631 switch (token.kind) {
1632 case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
1633 case DOUBLE: case BOOLEAN:
1634 if (typeArgs == null)
1635 return arrayCreatorRest(newpos, basicType());
1636 break;
1637 default:
1638 }
1639 JCExpression t = qualident();
1640 int oldmode = mode;
1641 mode = TYPE;
1642 boolean diamondFound = false;
1643 int lastTypeargsPos = -1;
1644 if (token.kind == LT) {
1645 checkGenerics();
1646 lastTypeargsPos = token.pos;
1647 t = typeArguments(t, true);
1648 diamondFound = (mode & DIAMOND) != 0;
1649 }
1650 while (token.kind == DOT) {
1651 if (diamondFound) {
1652 //cannot select after a diamond
1653 illegal();
1654 }
1655 int pos = token.pos;
1656 nextToken();
1657 t = toP(F.at(pos).Select(t, ident()));
1658 if (token.kind == LT) {
1659 lastTypeargsPos = token.pos;
1660 checkGenerics();
1661 t = typeArguments(t, true);
1662 diamondFound = (mode & DIAMOND) != 0;
1663 }
1664 }
1665 mode = oldmode;
1666 if (token.kind == LBRACKET) {
1667 JCExpression e = arrayCreatorRest(newpos, t);
1668 if (diamondFound) {
1669 reportSyntaxError(lastTypeargsPos, "cannot.create.array.with.diamond");
1670 return toP(F.at(newpos).Erroneous(List.of(e)));
1671 }
1672 else if (typeArgs != null) {
1673 int pos = newpos;
1674 if (!typeArgs.isEmpty() && typeArgs.head.pos != Position.NOPOS) {
1675 // note: this should always happen but we should
1676 // not rely on this as the parser is continuously
1677 // modified to improve error recovery.
1678 pos = typeArgs.head.pos;
1679 }
1680 setErrorEndPos(S.prevToken().endPos);
1681 JCErroneous err = F.at(pos).Erroneous(typeArgs.prepend(e));
1682 reportSyntaxError(err, "cannot.create.array.with.type.arguments");
1683 return toP(err);
1684 }
1685 return e;
1686 } else if (token.kind == LPAREN) {
1687 return classCreatorRest(newpos, null, typeArgs, t);
1688 } else {
1689 setErrorEndPos(token.pos);
1690 reportSyntaxError(token.pos, "expected2", LPAREN, LBRACKET);
1691 t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.<JCExpression>nil(), null));
1692 return toP(F.at(newpos).Erroneous(List.<JCTree>of(t)));
1693 }
1694 }
1696 /** InnerCreator = Ident [TypeArguments] ClassCreatorRest
1697 */
1698 JCExpression innerCreator(int newpos, List<JCExpression> typeArgs, JCExpression encl) {
1699 JCExpression t = toP(F.at(token.pos).Ident(ident()));
1700 if (token.kind == LT) {
1701 int oldmode = mode;
1702 checkGenerics();
1703 t = typeArguments(t, true);
1704 mode = oldmode;
1705 }
1706 return classCreatorRest(newpos, encl, typeArgs, t);
1707 }
1709 /** ArrayCreatorRest = "[" ( "]" BracketsOpt ArrayInitializer
1710 * | Expression "]" {"[" Expression "]"} BracketsOpt )
1711 */
1712 JCExpression arrayCreatorRest(int newpos, JCExpression elemtype) {
1713 accept(LBRACKET);
1714 if (token.kind == RBRACKET) {
1715 accept(RBRACKET);
1716 elemtype = bracketsOpt(elemtype);
1717 if (token.kind == LBRACE) {
1718 return arrayInitializer(newpos, elemtype);
1719 } else {
1720 JCExpression t = toP(F.at(newpos).NewArray(elemtype, List.<JCExpression>nil(), null));
1721 return syntaxError(token.pos, List.<JCTree>of(t), "array.dimension.missing");
1722 }
1723 } else {
1724 ListBuffer<JCExpression> dims = new ListBuffer<JCExpression>();
1725 dims.append(parseExpression());
1726 accept(RBRACKET);
1727 while (token.kind == LBRACKET) {
1728 int pos = token.pos;
1729 nextToken();
1730 if (token.kind == RBRACKET) {
1731 elemtype = bracketsOptCont(elemtype, pos);
1732 } else {
1733 dims.append(parseExpression());
1734 accept(RBRACKET);
1735 }
1736 }
1737 return toP(F.at(newpos).NewArray(elemtype, dims.toList(), null));
1738 }
1739 }
1741 /** ClassCreatorRest = Arguments [ClassBody]
1742 */
1743 JCNewClass classCreatorRest(int newpos,
1744 JCExpression encl,
1745 List<JCExpression> typeArgs,
1746 JCExpression t)
1747 {
1748 List<JCExpression> args = arguments();
1749 JCClassDecl body = null;
1750 if (token.kind == LBRACE) {
1751 int pos = token.pos;
1752 List<JCTree> defs = classOrInterfaceBody(names.empty, false);
1753 JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
1754 body = toP(F.at(pos).AnonymousClassDef(mods, defs));
1755 }
1756 return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
1757 }
1759 /** ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}"
1760 */
1761 JCExpression arrayInitializer(int newpos, JCExpression t) {
1762 accept(LBRACE);
1763 ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>();
1764 if (token.kind == COMMA) {
1765 nextToken();
1766 } else if (token.kind != RBRACE) {
1767 elems.append(variableInitializer());
1768 while (token.kind == COMMA) {
1769 nextToken();
1770 if (token.kind == RBRACE) break;
1771 elems.append(variableInitializer());
1772 }
1773 }
1774 accept(RBRACE);
1775 return toP(F.at(newpos).NewArray(t, List.<JCExpression>nil(), elems.toList()));
1776 }
1778 /** VariableInitializer = ArrayInitializer | Expression
1779 */
1780 public JCExpression variableInitializer() {
1781 return token.kind == LBRACE ? arrayInitializer(token.pos, null) : parseExpression();
1782 }
1784 /** ParExpression = "(" Expression ")"
1785 */
1786 JCExpression parExpression() {
1787 int pos = token.pos;
1788 accept(LPAREN);
1789 JCExpression t = parseExpression();
1790 accept(RPAREN);
1791 return toP(F.at(pos).Parens(t));
1792 }
1794 /** Block = "{" BlockStatements "}"
1795 */
1796 JCBlock block(int pos, long flags) {
1797 accept(LBRACE);
1798 List<JCStatement> stats = blockStatements();
1799 JCBlock t = F.at(pos).Block(flags, stats);
1800 while (token.kind == CASE || token.kind == DEFAULT) {
1801 syntaxError("orphaned", token.kind);
1802 switchBlockStatementGroups();
1803 }
1804 // the Block node has a field "endpos" for first char of last token, which is
1805 // usually but not necessarily the last char of the last token.
1806 t.endpos = token.pos;
1807 accept(RBRACE);
1808 return toP(t);
1809 }
1811 public JCBlock block() {
1812 return block(token.pos, 0);
1813 }
1815 /** BlockStatements = { BlockStatement }
1816 * BlockStatement = LocalVariableDeclarationStatement
1817 * | ClassOrInterfaceOrEnumDeclaration
1818 * | [Ident ":"] Statement
1819 * LocalVariableDeclarationStatement
1820 * = { FINAL | '@' Annotation } Type VariableDeclarators ";"
1821 */
1822 @SuppressWarnings("fallthrough")
1823 List<JCStatement> blockStatements() {
1824 //todo: skip to anchor on error(?)
1825 ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>();
1826 while (true) {
1827 List<JCStatement> stat = blockStatement();
1828 if (stat.isEmpty()) {
1829 return stats.toList();
1830 } else {
1831 if (token.pos <= endPosTable.errorEndPos) {
1832 skip(false, true, true, true);
1833 }
1834 stats.addAll(stat);
1835 }
1836 }
1837 }
1839 /*
1840 * This method parses a statement treating it as a block, relaxing the
1841 * JLS restrictions, allows us to parse more faulty code, doing so
1842 * enables us to provide better and accurate diagnostics to the user.
1843 */
1844 JCStatement parseStatementAsBlock() {
1845 int pos = token.pos;
1846 List<JCStatement> stats = blockStatement();
1847 if (stats.isEmpty()) {
1848 JCErroneous e = F.at(pos).Erroneous();
1849 error(e, "illegal.start.of.stmt");
1850 return F.at(pos).Exec(e);
1851 } else {
1852 JCStatement first = stats.head;
1853 String error = null;
1854 switch (first.getTag()) {
1855 case CLASSDEF:
1856 error = "class.not.allowed";
1857 break;
1858 case VARDEF:
1859 error = "variable.not.allowed";
1860 break;
1861 }
1862 if (error != null) {
1863 error(first, error);
1864 List<JCBlock> blist = List.of(F.at(first.pos).Block(0, stats));
1865 return toP(F.at(pos).Exec(F.at(first.pos).Erroneous(blist)));
1866 }
1867 return first;
1868 }
1869 }
1871 @SuppressWarnings("fallthrough")
1872 List<JCStatement> blockStatement() {
1873 //todo: skip to anchor on error(?)
1874 int pos = token.pos;
1875 switch (token.kind) {
1876 case RBRACE: case CASE: case DEFAULT: case EOF:
1877 return List.nil();
1878 case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY:
1879 case SWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK:
1880 case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH:
1881 return List.of(parseStatement());
1882 case MONKEYS_AT:
1883 case FINAL: {
1884 Comment dc = token.comment(CommentStyle.JAVADOC);
1885 JCModifiers mods = modifiersOpt();
1886 if (token.kind == INTERFACE ||
1887 token.kind == CLASS ||
1888 allowEnums && token.kind == ENUM) {
1889 return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
1890 } else {
1891 JCExpression t = parseType();
1892 ListBuffer<JCStatement> stats =
1893 variableDeclarators(mods, t, new ListBuffer<JCStatement>());
1894 // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
1895 storeEnd(stats.elems.last(), token.endPos);
1896 accept(SEMI);
1897 return stats.toList();
1898 }
1899 }
1900 case ABSTRACT: case STRICTFP: {
1901 Comment dc = token.comment(CommentStyle.JAVADOC);
1902 JCModifiers mods = modifiersOpt();
1903 return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
1904 }
1905 case INTERFACE:
1906 case CLASS:
1907 Comment dc = token.comment(CommentStyle.JAVADOC);
1908 return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
1909 case ENUM:
1910 case ASSERT:
1911 if (allowEnums && token.kind == ENUM) {
1912 error(token.pos, "local.enum");
1913 dc = token.comment(CommentStyle.JAVADOC);
1914 return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
1915 } else if (allowAsserts && token.kind == ASSERT) {
1916 return List.of(parseStatement());
1917 }
1918 /* fall through to default */
1919 default:
1920 Token prevToken = token;
1921 JCExpression t = term(EXPR | TYPE);
1922 if (token.kind == COLON && t.hasTag(IDENT)) {
1923 nextToken();
1924 JCStatement stat = parseStatement();
1925 return List.<JCStatement>of(F.at(pos).Labelled(prevToken.name(), stat));
1926 } else if ((lastmode & TYPE) != 0 &&
1927 (token.kind == IDENTIFIER ||
1928 token.kind == ASSERT ||
1929 token.kind == ENUM)) {
1930 pos = token.pos;
1931 JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
1932 F.at(pos);
1933 ListBuffer<JCStatement> stats =
1934 variableDeclarators(mods, t, new ListBuffer<JCStatement>());
1935 // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
1936 storeEnd(stats.elems.last(), token.endPos);
1937 accept(SEMI);
1938 return stats.toList();
1939 } else {
1940 // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
1941 JCExpressionStatement expr = to(F.at(pos).Exec(checkExprStat(t)));
1942 accept(SEMI);
1943 return List.<JCStatement>of(expr);
1944 }
1945 }
1946 }
1948 /** Statement =
1949 * Block
1950 * | IF ParExpression Statement [ELSE Statement]
1951 * | FOR "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement
1952 * | FOR "(" FormalParameter : Expression ")" Statement
1953 * | WHILE ParExpression Statement
1954 * | DO Statement WHILE ParExpression ";"
1955 * | TRY Block ( Catches | [Catches] FinallyPart )
1956 * | TRY "(" ResourceSpecification ";"opt ")" Block [Catches] [FinallyPart]
1957 * | SWITCH ParExpression "{" SwitchBlockStatementGroups "}"
1958 * | SYNCHRONIZED ParExpression Block
1959 * | RETURN [Expression] ";"
1960 * | THROW Expression ";"
1961 * | BREAK [Ident] ";"
1962 * | CONTINUE [Ident] ";"
1963 * | ASSERT Expression [ ":" Expression ] ";"
1964 * | ";"
1965 * | ExpressionStatement
1966 * | Ident ":" Statement
1967 */
1968 @SuppressWarnings("fallthrough")
1969 public JCStatement parseStatement() {
1970 int pos = token.pos;
1971 switch (token.kind) {
1972 case LBRACE:
1973 return block();
1974 case IF: {
1975 nextToken();
1976 JCExpression cond = parExpression();
1977 JCStatement thenpart = parseStatementAsBlock();
1978 JCStatement elsepart = null;
1979 if (token.kind == ELSE) {
1980 nextToken();
1981 elsepart = parseStatementAsBlock();
1982 }
1983 return F.at(pos).If(cond, thenpart, elsepart);
1984 }
1985 case FOR: {
1986 nextToken();
1987 accept(LPAREN);
1988 List<JCStatement> inits = token.kind == SEMI ? List.<JCStatement>nil() : forInit();
1989 if (inits.length() == 1 &&
1990 inits.head.hasTag(VARDEF) &&
1991 ((JCVariableDecl) inits.head).init == null &&
1992 token.kind == COLON) {
1993 checkForeach();
1994 JCVariableDecl var = (JCVariableDecl)inits.head;
1995 accept(COLON);
1996 JCExpression expr = parseExpression();
1997 accept(RPAREN);
1998 JCStatement body = parseStatementAsBlock();
1999 return F.at(pos).ForeachLoop(var, expr, body);
2000 } else {
2001 accept(SEMI);
2002 JCExpression cond = token.kind == SEMI ? null : parseExpression();
2003 accept(SEMI);
2004 List<JCExpressionStatement> steps = token.kind == RPAREN ? List.<JCExpressionStatement>nil() : forUpdate();
2005 accept(RPAREN);
2006 JCStatement body = parseStatementAsBlock();
2007 return F.at(pos).ForLoop(inits, cond, steps, body);
2008 }
2009 }
2010 case WHILE: {
2011 nextToken();
2012 JCExpression cond = parExpression();
2013 JCStatement body = parseStatementAsBlock();
2014 return F.at(pos).WhileLoop(cond, body);
2015 }
2016 case DO: {
2017 nextToken();
2018 JCStatement body = parseStatementAsBlock();
2019 accept(WHILE);
2020 JCExpression cond = parExpression();
2021 JCDoWhileLoop t = to(F.at(pos).DoLoop(body, cond));
2022 accept(SEMI);
2023 return t;
2024 }
2025 case TRY: {
2026 nextToken();
2027 List<JCTree> resources = List.<JCTree>nil();
2028 if (token.kind == LPAREN) {
2029 checkTryWithResources();
2030 nextToken();
2031 resources = resources();
2032 accept(RPAREN);
2033 }
2034 JCBlock body = block();
2035 ListBuffer<JCCatch> catchers = new ListBuffer<JCCatch>();
2036 JCBlock finalizer = null;
2037 if (token.kind == CATCH || token.kind == FINALLY) {
2038 while (token.kind == CATCH) catchers.append(catchClause());
2039 if (token.kind == FINALLY) {
2040 nextToken();
2041 finalizer = block();
2042 }
2043 } else {
2044 if (allowTWR) {
2045 if (resources.isEmpty())
2046 error(pos, "try.without.catch.finally.or.resource.decls");
2047 } else
2048 error(pos, "try.without.catch.or.finally");
2049 }
2050 return F.at(pos).Try(resources, body, catchers.toList(), finalizer);
2051 }
2052 case SWITCH: {
2053 nextToken();
2054 JCExpression selector = parExpression();
2055 accept(LBRACE);
2056 List<JCCase> cases = switchBlockStatementGroups();
2057 JCSwitch t = to(F.at(pos).Switch(selector, cases));
2058 accept(RBRACE);
2059 return t;
2060 }
2061 case SYNCHRONIZED: {
2062 nextToken();
2063 JCExpression lock = parExpression();
2064 JCBlock body = block();
2065 return F.at(pos).Synchronized(lock, body);
2066 }
2067 case RETURN: {
2068 nextToken();
2069 JCExpression result = token.kind == SEMI ? null : parseExpression();
2070 JCReturn t = to(F.at(pos).Return(result));
2071 accept(SEMI);
2072 return t;
2073 }
2074 case THROW: {
2075 nextToken();
2076 JCExpression exc = parseExpression();
2077 JCThrow t = to(F.at(pos).Throw(exc));
2078 accept(SEMI);
2079 return t;
2080 }
2081 case BREAK: {
2082 nextToken();
2083 Name label = (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM) ? ident() : null;
2084 JCBreak t = to(F.at(pos).Break(label));
2085 accept(SEMI);
2086 return t;
2087 }
2088 case CONTINUE: {
2089 nextToken();
2090 Name label = (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM) ? ident() : null;
2091 JCContinue t = to(F.at(pos).Continue(label));
2092 accept(SEMI);
2093 return t;
2094 }
2095 case SEMI:
2096 nextToken();
2097 return toP(F.at(pos).Skip());
2098 case ELSE:
2099 return toP(F.Exec(syntaxError("else.without.if")));
2100 case FINALLY:
2101 return toP(F.Exec(syntaxError("finally.without.try")));
2102 case CATCH:
2103 return toP(F.Exec(syntaxError("catch.without.try")));
2104 case ASSERT: {
2105 if (allowAsserts && token.kind == ASSERT) {
2106 nextToken();
2107 JCExpression assertion = parseExpression();
2108 JCExpression message = null;
2109 if (token.kind == COLON) {
2110 nextToken();
2111 message = parseExpression();
2112 }
2113 JCAssert t = to(F.at(pos).Assert(assertion, message));
2114 accept(SEMI);
2115 return t;
2116 }
2117 /* else fall through to default case */
2118 }
2119 case ENUM:
2120 default:
2121 Token prevToken = token;
2122 JCExpression expr = parseExpression();
2123 if (token.kind == COLON && expr.hasTag(IDENT)) {
2124 nextToken();
2125 JCStatement stat = parseStatement();
2126 return F.at(pos).Labelled(prevToken.name(), stat);
2127 } else {
2128 // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
2129 JCExpressionStatement stat = to(F.at(pos).Exec(checkExprStat(expr)));
2130 accept(SEMI);
2131 return stat;
2132 }
2133 }
2134 }
2136 /** CatchClause = CATCH "(" FormalParameter ")" Block
2137 */
2138 protected JCCatch catchClause() {
2139 int pos = token.pos;
2140 accept(CATCH);
2141 accept(LPAREN);
2142 JCModifiers mods = optFinal(Flags.PARAMETER);
2143 List<JCExpression> catchTypes = catchTypes();
2144 JCExpression paramType = catchTypes.size() > 1 ?
2145 toP(F.at(catchTypes.head.getStartPosition()).TypeUnion(catchTypes)) :
2146 catchTypes.head;
2147 JCVariableDecl formal = variableDeclaratorId(mods, paramType);
2148 accept(RPAREN);
2149 JCBlock body = block();
2150 return F.at(pos).Catch(formal, body);
2151 }
2153 List<JCExpression> catchTypes() {
2154 ListBuffer<JCExpression> catchTypes = ListBuffer.lb();
2155 catchTypes.add(parseType());
2156 while (token.kind == BAR) {
2157 checkMulticatch();
2158 nextToken();
2159 catchTypes.add(qualident());
2160 }
2161 return catchTypes.toList();
2162 }
2164 /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup }
2165 * SwitchBlockStatementGroup = SwitchLabel BlockStatements
2166 * SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":"
2167 */
2168 List<JCCase> switchBlockStatementGroups() {
2169 ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
2170 while (true) {
2171 int pos = token.pos;
2172 switch (token.kind) {
2173 case CASE:
2174 case DEFAULT:
2175 cases.append(switchBlockStatementGroup());
2176 break;
2177 case RBRACE: case EOF:
2178 return cases.toList();
2179 default:
2180 nextToken(); // to ensure progress
2181 syntaxError(pos, "expected3",
2182 CASE, DEFAULT, RBRACE);
2183 }
2184 }
2185 }
2187 protected JCCase switchBlockStatementGroup() {
2188 int pos = token.pos;
2189 List<JCStatement> stats;
2190 JCCase c;
2191 switch (token.kind) {
2192 case CASE:
2193 nextToken();
2194 JCExpression pat = parseExpression();
2195 accept(COLON);
2196 stats = blockStatements();
2197 c = F.at(pos).Case(pat, stats);
2198 if (stats.isEmpty())
2199 storeEnd(c, S.prevToken().endPos);
2200 return c;
2201 case DEFAULT:
2202 nextToken();
2203 accept(COLON);
2204 stats = blockStatements();
2205 c = F.at(pos).Case(null, stats);
2206 if (stats.isEmpty())
2207 storeEnd(c, S.prevToken().endPos);
2208 return c;
2209 }
2210 throw new AssertionError("should not reach here");
2211 }
2213 /** MoreStatementExpressions = { COMMA StatementExpression }
2214 */
2215 <T extends ListBuffer<? super JCExpressionStatement>> T moreStatementExpressions(int pos,
2216 JCExpression first,
2217 T stats) {
2218 // This Exec is a "StatementExpression"; it subsumes no terminating token
2219 stats.append(toP(F.at(pos).Exec(checkExprStat(first))));
2220 while (token.kind == COMMA) {
2221 nextToken();
2222 pos = token.pos;
2223 JCExpression t = parseExpression();
2224 // This Exec is a "StatementExpression"; it subsumes no terminating token
2225 stats.append(toP(F.at(pos).Exec(checkExprStat(t))));
2226 }
2227 return stats;
2228 }
2230 /** ForInit = StatementExpression MoreStatementExpressions
2231 * | { FINAL | '@' Annotation } Type VariableDeclarators
2232 */
2233 List<JCStatement> forInit() {
2234 ListBuffer<JCStatement> stats = lb();
2235 int pos = token.pos;
2236 if (token.kind == FINAL || token.kind == MONKEYS_AT) {
2237 return variableDeclarators(optFinal(0), parseType(), stats).toList();
2238 } else {
2239 JCExpression t = term(EXPR | TYPE);
2240 if ((lastmode & TYPE) != 0 &&
2241 (token.kind == IDENTIFIER || token.kind == ASSERT ||
2242 token.kind == ENUM)) {
2243 return variableDeclarators(modifiersOpt(), t, stats).toList();
2244 } else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
2245 error(pos, "bad.initializer", "for-loop");
2246 return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
2247 } else {
2248 return moreStatementExpressions(pos, t, stats).toList();
2249 }
2250 }
2251 }
2253 /** ForUpdate = StatementExpression MoreStatementExpressions
2254 */
2255 List<JCExpressionStatement> forUpdate() {
2256 return moreStatementExpressions(token.pos,
2257 parseExpression(),
2258 new ListBuffer<JCExpressionStatement>()).toList();
2259 }
2261 /** AnnotationsOpt = { '@' Annotation }
2262 */
2263 List<JCAnnotation> annotationsOpt() {
2264 if (token.kind != MONKEYS_AT) return List.nil(); // optimization
2265 ListBuffer<JCAnnotation> buf = new ListBuffer<JCAnnotation>();
2266 while (token.kind == MONKEYS_AT) {
2267 int pos = token.pos;
2268 nextToken();
2269 buf.append(annotation(pos));
2270 }
2271 return buf.toList();
2272 }
2274 /** ModifiersOpt = { Modifier }
2275 * Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL
2276 * | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@"
2277 * | "@" Annotation
2278 */
2279 JCModifiers modifiersOpt() {
2280 return modifiersOpt(null);
2281 }
2282 protected JCModifiers modifiersOpt(JCModifiers partial) {
2283 long flags;
2284 ListBuffer<JCAnnotation> annotations = new ListBuffer<JCAnnotation>();
2285 int pos;
2286 if (partial == null) {
2287 flags = 0;
2288 pos = token.pos;
2289 } else {
2290 flags = partial.flags;
2291 annotations.appendList(partial.annotations);
2292 pos = partial.pos;
2293 }
2294 if (token.deprecatedFlag()) {
2295 flags |= Flags.DEPRECATED;
2296 }
2297 int lastPos = Position.NOPOS;
2298 loop:
2299 while (true) {
2300 long flag;
2301 switch (token.kind) {
2302 case PRIVATE : flag = Flags.PRIVATE; break;
2303 case PROTECTED : flag = Flags.PROTECTED; break;
2304 case PUBLIC : flag = Flags.PUBLIC; break;
2305 case STATIC : flag = Flags.STATIC; break;
2306 case TRANSIENT : flag = Flags.TRANSIENT; break;
2307 case FINAL : flag = Flags.FINAL; break;
2308 case ABSTRACT : flag = Flags.ABSTRACT; break;
2309 case NATIVE : flag = Flags.NATIVE; break;
2310 case VOLATILE : flag = Flags.VOLATILE; break;
2311 case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break;
2312 case STRICTFP : flag = Flags.STRICTFP; break;
2313 case MONKEYS_AT : flag = Flags.ANNOTATION; break;
2314 case ERROR : flag = 0; nextToken(); break;
2315 default: break loop;
2316 }
2317 if ((flags & flag) != 0) error(token.pos, "repeated.modifier");
2318 lastPos = token.pos;
2319 nextToken();
2320 if (flag == Flags.ANNOTATION) {
2321 checkAnnotations();
2322 if (token.kind != INTERFACE) {
2323 JCAnnotation ann = annotation(lastPos);
2324 // if first modifier is an annotation, set pos to annotation's.
2325 if (flags == 0 && annotations.isEmpty())
2326 pos = ann.pos;
2327 annotations.append(ann);
2328 lastPos = ann.pos;
2329 flag = 0;
2330 }
2331 }
2332 flags |= flag;
2333 }
2334 switch (token.kind) {
2335 case ENUM: flags |= Flags.ENUM; break;
2336 case INTERFACE: flags |= Flags.INTERFACE; break;
2337 default: break;
2338 }
2340 /* A modifiers tree with no modifier tokens or annotations
2341 * has no text position. */
2342 if ((flags & (Flags.ModifierFlags | Flags.ANNOTATION)) == 0 && annotations.isEmpty())
2343 pos = Position.NOPOS;
2345 JCModifiers mods = F.at(pos).Modifiers(flags, annotations.toList());
2346 if (pos != Position.NOPOS)
2347 storeEnd(mods, S.prevToken().endPos);
2348 return mods;
2349 }
2351 /** Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ]
2352 * @param pos position of "@" token
2353 */
2354 JCAnnotation annotation(int pos) {
2355 // accept(AT); // AT consumed by caller
2356 checkAnnotations();
2357 JCTree ident = qualident();
2358 List<JCExpression> fieldValues = annotationFieldValuesOpt();
2359 JCAnnotation ann = F.at(pos).Annotation(ident, fieldValues);
2360 storeEnd(ann, S.prevToken().endPos);
2361 return ann;
2362 }
2364 List<JCExpression> annotationFieldValuesOpt() {
2365 return (token.kind == LPAREN) ? annotationFieldValues() : List.<JCExpression>nil();
2366 }
2368 /** AnnotationFieldValues = "(" [ AnnotationFieldValue { "," AnnotationFieldValue } ] ")" */
2369 List<JCExpression> annotationFieldValues() {
2370 accept(LPAREN);
2371 ListBuffer<JCExpression> buf = new ListBuffer<JCExpression>();
2372 if (token.kind != RPAREN) {
2373 buf.append(annotationFieldValue());
2374 while (token.kind == COMMA) {
2375 nextToken();
2376 buf.append(annotationFieldValue());
2377 }
2378 }
2379 accept(RPAREN);
2380 return buf.toList();
2381 }
2383 /** AnnotationFieldValue = AnnotationValue
2384 * | Identifier "=" AnnotationValue
2385 */
2386 JCExpression annotationFieldValue() {
2387 if (token.kind == IDENTIFIER) {
2388 mode = EXPR;
2389 JCExpression t1 = term1();
2390 if (t1.hasTag(IDENT) && token.kind == EQ) {
2391 int pos = token.pos;
2392 accept(EQ);
2393 JCExpression v = annotationValue();
2394 return toP(F.at(pos).Assign(t1, v));
2395 } else {
2396 return t1;
2397 }
2398 }
2399 return annotationValue();
2400 }
2402 /* AnnotationValue = ConditionalExpression
2403 * | Annotation
2404 * | "{" [ AnnotationValue { "," AnnotationValue } ] [","] "}"
2405 */
2406 JCExpression annotationValue() {
2407 int pos;
2408 switch (token.kind) {
2409 case MONKEYS_AT:
2410 pos = token.pos;
2411 nextToken();
2412 return annotation(pos);
2413 case LBRACE:
2414 pos = token.pos;
2415 accept(LBRACE);
2416 ListBuffer<JCExpression> buf = new ListBuffer<JCExpression>();
2417 if (token.kind != RBRACE) {
2418 buf.append(annotationValue());
2419 while (token.kind == COMMA) {
2420 nextToken();
2421 if (token.kind == RBRACE) break;
2422 buf.append(annotationValue());
2423 }
2424 }
2425 accept(RBRACE);
2426 return toP(F.at(pos).NewArray(null, List.<JCExpression>nil(), buf.toList()));
2427 default:
2428 mode = EXPR;
2429 return term1();
2430 }
2431 }
2433 /** VariableDeclarators = VariableDeclarator { "," VariableDeclarator }
2434 */
2435 public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
2436 JCExpression type,
2437 T vdefs)
2438 {
2439 return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs);
2440 }
2442 /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
2443 * ConstantDeclaratorsRest = ConstantDeclaratorRest { "," ConstantDeclarator }
2444 *
2445 * @param reqInit Is an initializer always required?
2446 * @param dc The documentation comment for the variable declarations, or null.
2447 */
2448 <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos,
2449 JCModifiers mods,
2450 JCExpression type,
2451 Name name,
2452 boolean reqInit,
2453 Comment dc,
2454 T vdefs)
2455 {
2456 vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc));
2457 while (token.kind == COMMA) {
2458 // All but last of multiple declarators subsume a comma
2459 storeEnd((JCTree)vdefs.elems.last(), token.endPos);
2460 nextToken();
2461 vdefs.append(variableDeclarator(mods, type, reqInit, dc));
2462 }
2463 return vdefs;
2464 }
2466 /** VariableDeclarator = Ident VariableDeclaratorRest
2467 * ConstantDeclarator = Ident ConstantDeclaratorRest
2468 */
2469 JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
2470 return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
2471 }
2473 /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
2474 * ConstantDeclaratorRest = BracketsOpt "=" VariableInitializer
2475 *
2476 * @param reqInit Is an initializer always required?
2477 * @param dc The documentation comment for the variable declarations, or null.
2478 */
2479 JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
2480 boolean reqInit, Comment dc) {
2481 type = bracketsOpt(type);
2482 JCExpression init = null;
2483 if (token.kind == EQ) {
2484 nextToken();
2485 init = variableInitializer();
2486 }
2487 else if (reqInit) syntaxError(token.pos, "expected", EQ);
2488 JCVariableDecl result =
2489 toP(F.at(pos).VarDef(mods, name, type, init));
2490 attach(result, dc);
2491 return result;
2492 }
2494 /** VariableDeclaratorId = Ident BracketsOpt
2495 */
2496 JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
2497 int pos = token.pos;
2498 Name name = ident();
2499 if ((mods.flags & Flags.VARARGS) != 0 &&
2500 token.kind == LBRACKET) {
2501 log.error(token.pos, "varargs.and.old.array.syntax");
2502 }
2503 type = bracketsOpt(type);
2504 return toP(F.at(pos).VarDef(mods, name, type, null));
2505 }
2507 /** Resources = Resource { ";" Resources }
2508 */
2509 List<JCTree> resources() {
2510 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
2511 defs.append(resource());
2512 while (token.kind == SEMI) {
2513 // All but last of multiple declarators must subsume a semicolon
2514 storeEnd(defs.elems.last(), token.endPos);
2515 int semiColonPos = token.pos;
2516 nextToken();
2517 if (token.kind == RPAREN) { // Optional trailing semicolon
2518 // after last resource
2519 break;
2520 }
2521 defs.append(resource());
2522 }
2523 return defs.toList();
2524 }
2526 /** Resource = VariableModifiersOpt Type VariableDeclaratorId = Expression
2527 */
2528 protected JCTree resource() {
2529 JCModifiers optFinal = optFinal(Flags.FINAL);
2530 JCExpression type = parseType();
2531 int pos = token.pos;
2532 Name ident = ident();
2533 return variableDeclaratorRest(pos, optFinal, type, ident, true, null);
2534 }
2536 /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration}
2537 */
2538 public JCTree.JCCompilationUnit parseCompilationUnit() {
2539 Token firstToken = token;
2540 JCExpression pid = null;
2541 JCModifiers mods = null;
2542 boolean consumedToplevelDoc = false;
2543 boolean seenImport = false;
2544 boolean seenPackage = false;
2545 List<JCAnnotation> packageAnnotations = List.nil();
2546 if (token.kind == MONKEYS_AT)
2547 mods = modifiersOpt();
2549 if (token.kind == PACKAGE) {
2550 seenPackage = true;
2551 if (mods != null) {
2552 checkNoMods(mods.flags);
2553 packageAnnotations = mods.annotations;
2554 mods = null;
2555 }
2556 nextToken();
2557 pid = qualident();
2558 accept(SEMI);
2559 }
2560 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
2561 boolean checkForImports = true;
2562 boolean firstTypeDecl = true;
2563 while (token.kind != EOF) {
2564 if (token.pos <= endPosTable.errorEndPos) {
2565 // error recovery
2566 skip(checkForImports, false, false, false);
2567 if (token.kind == EOF)
2568 break;
2569 }
2570 if (checkForImports && mods == null && token.kind == IMPORT) {
2571 seenImport = true;
2572 defs.append(importDeclaration());
2573 } else {
2574 Comment docComment = token.comment(CommentStyle.JAVADOC);
2575 if (firstTypeDecl && !seenImport && !seenPackage) {
2576 docComment = firstToken.comment(CommentStyle.JAVADOC);
2577 consumedToplevelDoc = true;
2578 }
2579 JCTree def = typeDeclaration(mods, docComment);
2580 if (def instanceof JCExpressionStatement)
2581 def = ((JCExpressionStatement)def).expr;
2582 defs.append(def);
2583 if (def instanceof JCClassDecl)
2584 checkForImports = false;
2585 mods = null;
2586 firstTypeDecl = false;
2587 }
2588 }
2589 JCTree.JCCompilationUnit toplevel = F.at(firstToken.pos).TopLevel(packageAnnotations, pid, defs.toList());
2590 if (!consumedToplevelDoc)
2591 attach(toplevel, firstToken.comment(CommentStyle.JAVADOC));
2592 if (defs.elems.isEmpty())
2593 storeEnd(toplevel, S.prevToken().endPos);
2594 if (keepDocComments)
2595 toplevel.docComments = docComments;
2596 if (keepLineMap)
2597 toplevel.lineMap = S.getLineMap();
2598 toplevel.endPositions = this.endPosTable;
2599 return toplevel;
2600 }
2602 /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";"
2603 */
2604 JCTree importDeclaration() {
2605 int pos = token.pos;
2606 nextToken();
2607 boolean importStatic = false;
2608 if (token.kind == STATIC) {
2609 checkStaticImports();
2610 importStatic = true;
2611 nextToken();
2612 }
2613 JCExpression pid = toP(F.at(token.pos).Ident(ident()));
2614 do {
2615 int pos1 = token.pos;
2616 accept(DOT);
2617 if (token.kind == STAR) {
2618 pid = to(F.at(pos1).Select(pid, names.asterisk));
2619 nextToken();
2620 break;
2621 } else {
2622 pid = toP(F.at(pos1).Select(pid, ident()));
2623 }
2624 } while (token.kind == DOT);
2625 accept(SEMI);
2626 return toP(F.at(pos).Import(pid, importStatic));
2627 }
2629 /** TypeDeclaration = ClassOrInterfaceOrEnumDeclaration
2630 * | ";"
2631 */
2632 JCTree typeDeclaration(JCModifiers mods, Comment docComment) {
2633 int pos = token.pos;
2634 if (mods == null && token.kind == SEMI) {
2635 nextToken();
2636 return toP(F.at(pos).Skip());
2637 } else {
2638 return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment);
2639 }
2640 }
2642 /** ClassOrInterfaceOrEnumDeclaration = ModifiersOpt
2643 * (ClassDeclaration | InterfaceDeclaration | EnumDeclaration)
2644 * @param mods Any modifiers starting the class or interface declaration
2645 * @param dc The documentation comment for the class, or null.
2646 */
2647 JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
2648 if (token.kind == CLASS) {
2649 return classDeclaration(mods, dc);
2650 } else if (token.kind == INTERFACE) {
2651 return interfaceDeclaration(mods, dc);
2652 } else if (allowEnums) {
2653 if (token.kind == ENUM) {
2654 return enumDeclaration(mods, dc);
2655 } else {
2656 int pos = token.pos;
2657 List<JCTree> errs;
2658 if (token.kind == IDENTIFIER) {
2659 errs = List.<JCTree>of(mods, toP(F.at(pos).Ident(ident())));
2660 setErrorEndPos(token.pos);
2661 } else {
2662 errs = List.<JCTree>of(mods);
2663 }
2664 return toP(F.Exec(syntaxError(pos, errs, "expected3",
2665 CLASS, INTERFACE, ENUM)));
2666 }
2667 } else {
2668 if (token.kind == ENUM) {
2669 error(token.pos, "enums.not.supported.in.source", source.name);
2670 allowEnums = true;
2671 return enumDeclaration(mods, dc);
2672 }
2673 int pos = token.pos;
2674 List<JCTree> errs;
2675 if (token.kind == IDENTIFIER) {
2676 errs = List.<JCTree>of(mods, toP(F.at(pos).Ident(ident())));
2677 setErrorEndPos(token.pos);
2678 } else {
2679 errs = List.<JCTree>of(mods);
2680 }
2681 return toP(F.Exec(syntaxError(pos, errs, "expected2",
2682 CLASS, INTERFACE)));
2683 }
2684 }
2686 /** ClassDeclaration = CLASS Ident TypeParametersOpt [EXTENDS Type]
2687 * [IMPLEMENTS TypeList] ClassBody
2688 * @param mods The modifiers starting the class declaration
2689 * @param dc The documentation comment for the class, or null.
2690 */
2691 protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
2692 int pos = token.pos;
2693 accept(CLASS);
2694 Name name = ident();
2696 List<JCTypeParameter> typarams = typeParametersOpt();
2698 JCExpression extending = null;
2699 if (token.kind == EXTENDS) {
2700 nextToken();
2701 extending = parseType();
2702 }
2703 List<JCExpression> implementing = List.nil();
2704 if (token.kind == IMPLEMENTS) {
2705 nextToken();
2706 implementing = typeList();
2707 }
2708 List<JCTree> defs = classOrInterfaceBody(name, false);
2709 JCClassDecl result = toP(F.at(pos).ClassDef(
2710 mods, name, typarams, extending, implementing, defs));
2711 attach(result, dc);
2712 return result;
2713 }
2715 /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
2716 * [EXTENDS TypeList] InterfaceBody
2717 * @param mods The modifiers starting the interface declaration
2718 * @param dc The documentation comment for the interface, or null.
2719 */
2720 protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
2721 int pos = token.pos;
2722 accept(INTERFACE);
2723 Name name = ident();
2725 List<JCTypeParameter> typarams = typeParametersOpt();
2727 List<JCExpression> extending = List.nil();
2728 if (token.kind == EXTENDS) {
2729 nextToken();
2730 extending = typeList();
2731 }
2732 List<JCTree> defs = classOrInterfaceBody(name, true);
2733 JCClassDecl result = toP(F.at(pos).ClassDef(
2734 mods, name, typarams, null, extending, defs));
2735 attach(result, dc);
2736 return result;
2737 }
2739 /** EnumDeclaration = ENUM Ident [IMPLEMENTS TypeList] EnumBody
2740 * @param mods The modifiers starting the enum declaration
2741 * @param dc The documentation comment for the enum, or null.
2742 */
2743 protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
2744 int pos = token.pos;
2745 accept(ENUM);
2746 Name name = ident();
2748 List<JCExpression> implementing = List.nil();
2749 if (token.kind == IMPLEMENTS) {
2750 nextToken();
2751 implementing = typeList();
2752 }
2754 List<JCTree> defs = enumBody(name);
2755 mods.flags |= Flags.ENUM;
2756 JCClassDecl result = toP(F.at(pos).
2757 ClassDef(mods, name, List.<JCTypeParameter>nil(),
2758 null, implementing, defs));
2759 attach(result, dc);
2760 return result;
2761 }
2763 /** EnumBody = "{" { EnumeratorDeclarationList } [","]
2764 * [ ";" {ClassBodyDeclaration} ] "}"
2765 */
2766 List<JCTree> enumBody(Name enumName) {
2767 accept(LBRACE);
2768 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
2769 if (token.kind == COMMA) {
2770 nextToken();
2771 } else if (token.kind != RBRACE && token.kind != SEMI) {
2772 defs.append(enumeratorDeclaration(enumName));
2773 while (token.kind == COMMA) {
2774 nextToken();
2775 if (token.kind == RBRACE || token.kind == SEMI) break;
2776 defs.append(enumeratorDeclaration(enumName));
2777 }
2778 if (token.kind != SEMI && token.kind != RBRACE) {
2779 defs.append(syntaxError(token.pos, "expected3",
2780 COMMA, RBRACE, SEMI));
2781 nextToken();
2782 }
2783 }
2784 if (token.kind == SEMI) {
2785 nextToken();
2786 while (token.kind != RBRACE && token.kind != EOF) {
2787 defs.appendList(classOrInterfaceBodyDeclaration(enumName,
2788 false));
2789 if (token.pos <= endPosTable.errorEndPos) {
2790 // error recovery
2791 skip(false, true, true, false);
2792 }
2793 }
2794 }
2795 accept(RBRACE);
2796 return defs.toList();
2797 }
2799 /** EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ]
2800 */
2801 JCTree enumeratorDeclaration(Name enumName) {
2802 Comment dc = token.comment(CommentStyle.JAVADOC);
2803 int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM;
2804 if (token.deprecatedFlag()) {
2805 flags |= Flags.DEPRECATED;
2806 }
2807 int pos = token.pos;
2808 List<JCAnnotation> annotations = annotationsOpt();
2809 JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations);
2810 List<JCExpression> typeArgs = typeArgumentsOpt();
2811 int identPos = token.pos;
2812 Name name = ident();
2813 int createPos = token.pos;
2814 List<JCExpression> args = (token.kind == LPAREN)
2815 ? arguments() : List.<JCExpression>nil();
2816 JCClassDecl body = null;
2817 if (token.kind == LBRACE) {
2818 JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC);
2819 List<JCTree> defs = classOrInterfaceBody(names.empty, false);
2820 body = toP(F.at(identPos).AnonymousClassDef(mods1, defs));
2821 }
2822 if (args.isEmpty() && body == null)
2823 createPos = identPos;
2824 JCIdent ident = F.at(identPos).Ident(enumName);
2825 JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body);
2826 if (createPos != identPos)
2827 storeEnd(create, S.prevToken().endPos);
2828 ident = F.at(identPos).Ident(enumName);
2829 JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create));
2830 attach(result, dc);
2831 return result;
2832 }
2834 /** TypeList = Type {"," Type}
2835 */
2836 List<JCExpression> typeList() {
2837 ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>();
2838 ts.append(parseType());
2839 while (token.kind == COMMA) {
2840 nextToken();
2841 ts.append(parseType());
2842 }
2843 return ts.toList();
2844 }
2846 /** ClassBody = "{" {ClassBodyDeclaration} "}"
2847 * InterfaceBody = "{" {InterfaceBodyDeclaration} "}"
2848 */
2849 List<JCTree> classOrInterfaceBody(Name className, boolean isInterface) {
2850 accept(LBRACE);
2851 if (token.pos <= endPosTable.errorEndPos) {
2852 // error recovery
2853 skip(false, true, false, false);
2854 if (token.kind == LBRACE)
2855 nextToken();
2856 }
2857 ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
2858 while (token.kind != RBRACE && token.kind != EOF) {
2859 defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface));
2860 if (token.pos <= endPosTable.errorEndPos) {
2861 // error recovery
2862 skip(false, true, true, false);
2863 }
2864 }
2865 accept(RBRACE);
2866 return defs.toList();
2867 }
2869 /** ClassBodyDeclaration =
2870 * ";"
2871 * | [STATIC] Block
2872 * | ModifiersOpt
2873 * ( Type Ident
2874 * ( VariableDeclaratorsRest ";" | MethodDeclaratorRest )
2875 * | VOID Ident MethodDeclaratorRest
2876 * | TypeParameters (Type | VOID) Ident MethodDeclaratorRest
2877 * | Ident ConstructorDeclaratorRest
2878 * | TypeParameters Ident ConstructorDeclaratorRest
2879 * | ClassOrInterfaceOrEnumDeclaration
2880 * )
2881 * InterfaceBodyDeclaration =
2882 * ";"
2883 * | ModifiersOpt Type Ident
2884 * ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" )
2885 */
2886 protected List<JCTree> classOrInterfaceBodyDeclaration(Name className, boolean isInterface) {
2887 if (token.kind == SEMI) {
2888 nextToken();
2889 return List.<JCTree>nil();
2890 } else {
2891 Comment dc = token.comment(CommentStyle.JAVADOC);
2892 int pos = token.pos;
2893 JCModifiers mods = modifiersOpt();
2894 if (token.kind == CLASS ||
2895 token.kind == INTERFACE ||
2896 allowEnums && token.kind == ENUM) {
2897 return List.<JCTree>of(classOrInterfaceOrEnumDeclaration(mods, dc));
2898 } else if (token.kind == LBRACE && !isInterface &&
2899 (mods.flags & Flags.StandardFlags & ~Flags.STATIC) == 0 &&
2900 mods.annotations.isEmpty()) {
2901 return List.<JCTree>of(block(pos, mods.flags));
2902 } else {
2903 pos = token.pos;
2904 List<JCTypeParameter> typarams = typeParametersOpt();
2905 // if there are type parameters but no modifiers, save the start
2906 // position of the method in the modifiers.
2907 if (typarams.nonEmpty() && mods.pos == Position.NOPOS) {
2908 mods.pos = pos;
2909 storeEnd(mods, pos);
2910 }
2911 Token tk = token;
2912 pos = token.pos;
2913 JCExpression type;
2914 boolean isVoid = token.kind == VOID;
2915 if (isVoid) {
2916 type = to(F.at(pos).TypeIdent(TypeTags.VOID));
2917 nextToken();
2918 } else {
2919 type = parseType();
2920 }
2921 if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
2922 if (isInterface || tk.name() != className)
2923 error(pos, "invalid.meth.decl.ret.type.req");
2924 return List.of(methodDeclaratorRest(
2925 pos, mods, null, names.init, typarams,
2926 isInterface, true, dc));
2927 } else {
2928 pos = token.pos;
2929 Name name = ident();
2930 if (token.kind == LPAREN) {
2931 return List.of(methodDeclaratorRest(
2932 pos, mods, type, name, typarams,
2933 isInterface, isVoid, dc));
2934 } else if (!isVoid && typarams.isEmpty()) {
2935 List<JCTree> defs =
2936 variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
2937 new ListBuffer<JCTree>()).toList();
2938 storeEnd(defs.last(), token.endPos);
2939 accept(SEMI);
2940 return defs;
2941 } else {
2942 pos = token.pos;
2943 List<JCTree> err = isVoid
2944 ? List.<JCTree>of(toP(F.at(pos).MethodDef(mods, name, type, typarams,
2945 List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null)))
2946 : null;
2947 return List.<JCTree>of(syntaxError(token.pos, err, "expected", LPAREN));
2948 }
2949 }
2950 }
2951 }
2952 }
2954 /** MethodDeclaratorRest =
2955 * FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
2956 * VoidMethodDeclaratorRest =
2957 * FormalParameters [Throws TypeList] ( MethodBody | ";")
2958 * InterfaceMethodDeclaratorRest =
2959 * FormalParameters BracketsOpt [THROWS TypeList] ";"
2960 * VoidInterfaceMethodDeclaratorRest =
2961 * FormalParameters [THROWS TypeList] ";"
2962 * ConstructorDeclaratorRest =
2963 * "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody
2964 */
2965 protected JCTree methodDeclaratorRest(int pos,
2966 JCModifiers mods,
2967 JCExpression type,
2968 Name name,
2969 List<JCTypeParameter> typarams,
2970 boolean isInterface, boolean isVoid,
2971 Comment dc) {
2972 List<JCVariableDecl> params = formalParameters();
2973 if (!isVoid) type = bracketsOpt(type);
2974 List<JCExpression> thrown = List.nil();
2975 if (token.kind == THROWS) {
2976 nextToken();
2977 thrown = qualidentList();
2978 }
2979 JCBlock body = null;
2980 JCExpression defaultValue;
2981 if (token.kind == LBRACE) {
2982 body = block();
2983 defaultValue = null;
2984 } else {
2985 if (token.kind == DEFAULT) {
2986 accept(DEFAULT);
2987 defaultValue = annotationValue();
2988 } else {
2989 defaultValue = null;
2990 }
2991 accept(SEMI);
2992 if (token.pos <= endPosTable.errorEndPos) {
2993 // error recovery
2994 skip(false, true, false, false);
2995 if (token.kind == LBRACE) {
2996 body = block();
2997 }
2998 }
2999 }
3001 JCMethodDecl result =
3002 toP(F.at(pos).MethodDef(mods, name, type, typarams,
3003 params, thrown,
3004 body, defaultValue));
3005 attach(result, dc);
3006 return result;
3007 }
3009 /** QualidentList = Qualident {"," Qualident}
3010 */
3011 List<JCExpression> qualidentList() {
3012 ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>();
3013 ts.append(qualident());
3014 while (token.kind == COMMA) {
3015 nextToken();
3016 ts.append(qualident());
3017 }
3018 return ts.toList();
3019 }
3021 /**
3022 * {@literal
3023 * TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"]
3024 * }
3025 */
3026 List<JCTypeParameter> typeParametersOpt() {
3027 if (token.kind == LT) {
3028 checkGenerics();
3029 ListBuffer<JCTypeParameter> typarams = new ListBuffer<JCTypeParameter>();
3030 nextToken();
3031 typarams.append(typeParameter());
3032 while (token.kind == COMMA) {
3033 nextToken();
3034 typarams.append(typeParameter());
3035 }
3036 accept(GT);
3037 return typarams.toList();
3038 } else {
3039 return List.nil();
3040 }
3041 }
3043 /**
3044 * {@literal
3045 * TypeParameter = TypeVariable [TypeParameterBound]
3046 * TypeParameterBound = EXTENDS Type {"&" Type}
3047 * TypeVariable = Ident
3048 * }
3049 */
3050 JCTypeParameter typeParameter() {
3051 int pos = token.pos;
3052 Name name = ident();
3053 ListBuffer<JCExpression> bounds = new ListBuffer<JCExpression>();
3054 if (token.kind == EXTENDS) {
3055 nextToken();
3056 bounds.append(parseType());
3057 while (token.kind == AMP) {
3058 nextToken();
3059 bounds.append(parseType());
3060 }
3061 }
3062 return toP(F.at(pos).TypeParameter(name, bounds.toList()));
3063 }
3065 /** FormalParameters = "(" [ FormalParameterList ] ")"
3066 * FormalParameterList = [ FormalParameterListNovarargs , ] LastFormalParameter
3067 * FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter
3068 */
3069 List<JCVariableDecl> formalParameters() {
3070 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
3071 JCVariableDecl lastParam = null;
3072 accept(LPAREN);
3073 if (token.kind != RPAREN) {
3074 params.append(lastParam = formalParameter());
3075 while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
3076 nextToken();
3077 params.append(lastParam = formalParameter());
3078 }
3079 }
3080 accept(RPAREN);
3081 return params.toList();
3082 }
3084 List<JCVariableDecl> implicitParameters(boolean hasParens) {
3085 if (hasParens) {
3086 accept(LPAREN);
3087 }
3088 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
3089 if (token.kind != RPAREN && token.kind != ARROW) {
3090 params.append(implicitParameter());
3091 while (token.kind == COMMA) {
3092 nextToken();
3093 params.append(implicitParameter());
3094 }
3095 }
3096 if (hasParens) {
3097 accept(RPAREN);
3098 }
3099 return params.toList();
3100 }
3102 JCModifiers optFinal(long flags) {
3103 JCModifiers mods = modifiersOpt();
3104 checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED));
3105 mods.flags |= flags;
3106 return mods;
3107 }
3109 /** FormalParameter = { FINAL | '@' Annotation } Type VariableDeclaratorId
3110 * LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter
3111 */
3112 protected JCVariableDecl formalParameter() {
3113 JCModifiers mods = optFinal(Flags.PARAMETER);
3114 JCExpression type = parseType();
3115 if (token.kind == ELLIPSIS) {
3116 checkVarargs();
3117 mods.flags |= Flags.VARARGS;
3118 type = to(F.at(token.pos).TypeArray(type));
3119 nextToken();
3120 }
3121 return variableDeclaratorId(mods, type);
3122 }
3124 protected JCVariableDecl implicitParameter() {
3125 JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
3126 return variableDeclaratorId(mods, null);
3127 }
3129 /* ---------- auxiliary methods -------------- */
3131 void error(int pos, String key, Object ... args) {
3132 log.error(DiagnosticFlag.SYNTAX, pos, key, args);
3133 }
3135 void error(DiagnosticPosition pos, String key, Object ... args) {
3136 log.error(DiagnosticFlag.SYNTAX, pos, key, args);
3137 }
3139 void warning(int pos, String key, Object ... args) {
3140 log.warning(pos, key, args);
3141 }
3143 /** Check that given tree is a legal expression statement.
3144 */
3145 protected JCExpression checkExprStat(JCExpression t) {
3146 switch(t.getTag()) {
3147 case PREINC: case PREDEC:
3148 case POSTINC: case POSTDEC:
3149 case ASSIGN:
3150 case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
3151 case SL_ASG: case SR_ASG: case USR_ASG:
3152 case PLUS_ASG: case MINUS_ASG:
3153 case MUL_ASG: case DIV_ASG: case MOD_ASG:
3154 case APPLY: case NEWCLASS:
3155 case ERRONEOUS:
3156 return t;
3157 default:
3158 JCExpression ret = F.at(t.pos).Erroneous(List.<JCTree>of(t));
3159 error(ret, "not.stmt");
3160 return ret;
3161 }
3162 }
3164 /** Return precedence of operator represented by token,
3165 * -1 if token is not a binary operator. @see TreeInfo.opPrec
3166 */
3167 static int prec(TokenKind token) {
3168 JCTree.Tag oc = optag(token);
3169 return (oc != NO_TAG) ? TreeInfo.opPrec(oc) : -1;
3170 }
3172 /**
3173 * Return the lesser of two positions, making allowance for either one
3174 * being unset.
3175 */
3176 static int earlier(int pos1, int pos2) {
3177 if (pos1 == Position.NOPOS)
3178 return pos2;
3179 if (pos2 == Position.NOPOS)
3180 return pos1;
3181 return (pos1 < pos2 ? pos1 : pos2);
3182 }
3184 /** Return operation tag of binary operator represented by token,
3185 * No_TAG if token is not a binary operator.
3186 */
3187 static JCTree.Tag optag(TokenKind token) {
3188 switch (token) {
3189 case BARBAR:
3190 return OR;
3191 case AMPAMP:
3192 return AND;
3193 case BAR:
3194 return BITOR;
3195 case BAREQ:
3196 return BITOR_ASG;
3197 case CARET:
3198 return BITXOR;
3199 case CARETEQ:
3200 return BITXOR_ASG;
3201 case AMP:
3202 return BITAND;
3203 case AMPEQ:
3204 return BITAND_ASG;
3205 case EQEQ:
3206 return JCTree.Tag.EQ;
3207 case BANGEQ:
3208 return NE;
3209 case LT:
3210 return JCTree.Tag.LT;
3211 case GT:
3212 return JCTree.Tag.GT;
3213 case LTEQ:
3214 return LE;
3215 case GTEQ:
3216 return GE;
3217 case LTLT:
3218 return SL;
3219 case LTLTEQ:
3220 return SL_ASG;
3221 case GTGT:
3222 return SR;
3223 case GTGTEQ:
3224 return SR_ASG;
3225 case GTGTGT:
3226 return USR;
3227 case GTGTGTEQ:
3228 return USR_ASG;
3229 case PLUS:
3230 return JCTree.Tag.PLUS;
3231 case PLUSEQ:
3232 return PLUS_ASG;
3233 case SUB:
3234 return MINUS;
3235 case SUBEQ:
3236 return MINUS_ASG;
3237 case STAR:
3238 return MUL;
3239 case STAREQ:
3240 return MUL_ASG;
3241 case SLASH:
3242 return DIV;
3243 case SLASHEQ:
3244 return DIV_ASG;
3245 case PERCENT:
3246 return MOD;
3247 case PERCENTEQ:
3248 return MOD_ASG;
3249 case INSTANCEOF:
3250 return TYPETEST;
3251 default:
3252 return NO_TAG;
3253 }
3254 }
3256 /** Return operation tag of unary operator represented by token,
3257 * No_TAG if token is not a binary operator.
3258 */
3259 static JCTree.Tag unoptag(TokenKind token) {
3260 switch (token) {
3261 case PLUS:
3262 return POS;
3263 case SUB:
3264 return NEG;
3265 case BANG:
3266 return NOT;
3267 case TILDE:
3268 return COMPL;
3269 case PLUSPLUS:
3270 return PREINC;
3271 case SUBSUB:
3272 return PREDEC;
3273 default:
3274 return NO_TAG;
3275 }
3276 }
3278 /** Return type tag of basic type represented by token,
3279 * -1 if token is not a basic type identifier.
3280 */
3281 static int typetag(TokenKind token) {
3282 switch (token) {
3283 case BYTE:
3284 return TypeTags.BYTE;
3285 case CHAR:
3286 return TypeTags.CHAR;
3287 case SHORT:
3288 return TypeTags.SHORT;
3289 case INT:
3290 return TypeTags.INT;
3291 case LONG:
3292 return TypeTags.LONG;
3293 case FLOAT:
3294 return TypeTags.FLOAT;
3295 case DOUBLE:
3296 return TypeTags.DOUBLE;
3297 case BOOLEAN:
3298 return TypeTags.BOOLEAN;
3299 default:
3300 return -1;
3301 }
3302 }
3304 void checkGenerics() {
3305 if (!allowGenerics) {
3306 error(token.pos, "generics.not.supported.in.source", source.name);
3307 allowGenerics = true;
3308 }
3309 }
3310 void checkVarargs() {
3311 if (!allowVarargs) {
3312 error(token.pos, "varargs.not.supported.in.source", source.name);
3313 allowVarargs = true;
3314 }
3315 }
3316 void checkForeach() {
3317 if (!allowForeach) {
3318 error(token.pos, "foreach.not.supported.in.source", source.name);
3319 allowForeach = true;
3320 }
3321 }
3322 void checkStaticImports() {
3323 if (!allowStaticImport) {
3324 error(token.pos, "static.import.not.supported.in.source", source.name);
3325 allowStaticImport = true;
3326 }
3327 }
3328 void checkAnnotations() {
3329 if (!allowAnnotations) {
3330 error(token.pos, "annotations.not.supported.in.source", source.name);
3331 allowAnnotations = true;
3332 }
3333 }
3334 void checkDiamond() {
3335 if (!allowDiamond) {
3336 error(token.pos, "diamond.not.supported.in.source", source.name);
3337 allowDiamond = true;
3338 }
3339 }
3340 void checkMulticatch() {
3341 if (!allowMulticatch) {
3342 error(token.pos, "multicatch.not.supported.in.source", source.name);
3343 allowMulticatch = true;
3344 }
3345 }
3346 void checkTryWithResources() {
3347 if (!allowTWR) {
3348 error(token.pos, "try.with.resources.not.supported.in.source", source.name);
3349 allowTWR = true;
3350 }
3351 }
3352 void checkLambda() {
3353 if (!allowLambda) {
3354 log.error(token.pos, "lambda.not.supported.in.source", source.name);
3355 allowLambda = true;
3356 }
3357 }
3358 void checkMethodReferences() {
3359 if (!allowMethodReferences) {
3360 log.error(token.pos, "method.references.not.supported.in.source", source.name);
3361 allowMethodReferences = true;
3362 }
3363 }
3365 /*
3366 * a functional source tree and end position mappings
3367 */
3368 protected class SimpleEndPosTable extends AbstractEndPosTable {
3370 private final Map<JCTree, Integer> endPosMap;
3372 SimpleEndPosTable() {
3373 endPosMap = new HashMap<JCTree, Integer>();
3374 }
3376 protected void storeEnd(JCTree tree, int endpos) {
3377 endPosMap.put(tree, errorEndPos > endpos ? errorEndPos : endpos);
3378 }
3380 protected <T extends JCTree> T to(T t) {
3381 storeEnd(t, token.endPos);
3382 return t;
3383 }
3385 protected <T extends JCTree> T toP(T t) {
3386 storeEnd(t, S.prevToken().endPos);
3387 return t;
3388 }
3390 public int getEndPos(JCTree tree) {
3391 Integer value = endPosMap.get(tree);
3392 return (value == null) ? Position.NOPOS : value;
3393 }
3395 public int replaceTree(JCTree oldTree, JCTree newTree) {
3396 Integer pos = endPosMap.remove(oldTree);
3397 if (pos != null) {
3398 endPosMap.put(newTree, pos);
3399 return pos;
3400 }
3401 return Position.NOPOS;
3402 }
3403 }
3405 /*
3406 * a default skeletal implementation without any mapping overhead.
3407 */
3408 protected class EmptyEndPosTable extends AbstractEndPosTable {
3410 protected void storeEnd(JCTree tree, int endpos) { /* empty */ }
3412 protected <T extends JCTree> T to(T t) {
3413 return t;
3414 }
3416 protected <T extends JCTree> T toP(T t) {
3417 return t;
3418 }
3420 public int getEndPos(JCTree tree) {
3421 return Position.NOPOS;
3422 }
3424 public int replaceTree(JCTree oldTree, JCTree newTree) {
3425 return Position.NOPOS;
3426 }
3428 }
3430 protected abstract class AbstractEndPosTable implements EndPosTable {
3432 /**
3433 * Store the last error position.
3434 */
3435 protected int errorEndPos;
3437 /**
3438 * Store ending position for a tree, the value of which is the greater
3439 * of last error position and the given ending position.
3440 * @param tree The tree.
3441 * @param endpos The ending position to associate with the tree.
3442 */
3443 protected abstract void storeEnd(JCTree tree, int endpos);
3445 /**
3446 * Store current token's ending position for a tree, the value of which
3447 * will be the greater of last error position and the ending position of
3448 * the current token.
3449 * @param t The tree.
3450 */
3451 protected abstract <T extends JCTree> T to(T t);
3453 /**
3454 * Store current token's ending position for a tree, the value of which
3455 * will be the greater of last error position and the ending position of
3456 * the previous token.
3457 * @param t The tree.
3458 */
3459 protected abstract <T extends JCTree> T toP(T t);
3461 /**
3462 * Set the error position during the parsing phases, the value of which
3463 * will be set only if it is greater than the last stored error position.
3464 * @param errPos The error position
3465 */
3466 protected void setErrorEndPos(int errPos) {
3467 if (errPos > errorEndPos) {
3468 errorEndPos = errPos;
3469 }
3470 }
3471 }
3472 }